disk.c revision 139167
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 */ 9 10#include <sys/cdefs.h> 11__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 139167 2004-12-22 08:17:18Z yongari $"); 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <unistd.h> 16#include <fcntl.h> 17#include <string.h> 18#include <inttypes.h> 19#include <err.h> 20#include <sys/sysctl.h> 21#include <sys/stdint.h> 22#include <sys/types.h> 23#include <sys/stat.h> 24#include <sys/ioctl.h> 25#include <sys/disklabel.h> 26#include <sys/uuid.h> 27#include <sys/gpt.h> 28#include <paths.h> 29#include "libdisk.h" 30 31#include <ctype.h> 32#include <errno.h> 33#include <assert.h> 34#include <uuid.h> 35 36const enum platform platform = 37#if defined (P_DEBUG) 38 P_DEBUG 39#elif defined (PC98) 40 p_pc98 41#elif defined(__i386__) 42 p_i386 43#elif defined(__alpha__) 44 p_alpha 45#elif defined(__sparc64__) 46 p_sparc64 47#elif defined(__ia64__) 48 p_ia64 49#elif defined(__ppc__) 50 p_ppc 51#elif defined(__amd64__) 52 p_amd64 53#else 54 IHAVENOIDEA 55#endif 56 ; 57 58const char * 59chunk_name(chunk_e type) 60{ 61 switch(type) { 62 case unused: return ("unused"); 63 case mbr: return ("mbr"); 64 case part: return ("part"); 65 case gpt: return ("gpt"); 66 case pc98: return ("pc98"); 67 case sun: return ("sun"); 68 case freebsd: return ("freebsd"); 69 case fat: return ("fat"); 70 case spare: return ("spare"); 71 case efi: return ("efi"); 72 case apple: return ("apple"); 73 default: return ("??"); 74 } 75} 76 77struct disk * 78Open_Disk(const char *name) 79{ 80 struct disk *d; 81 char *conftxt; 82 size_t txtsize; 83 int error; 84 85 error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0); 86 if (error) { 87 warn("kern.geom.conftxt sysctl not available, giving up!"); 88 return (NULL); 89 } 90 conftxt = malloc(txtsize+1); 91 if (conftxt == NULL) { 92 warn("cannot malloc memory for conftxt"); 93 return (NULL); 94 } 95 error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0); 96 if (error) { 97 warn("error reading kern.geom.conftxt from the system"); 98 free(conftxt); 99 return (NULL); 100 } 101 conftxt[txtsize] = '\0'; /* in case kernel bug is still there */ 102 d = Int_Open_Disk(name, conftxt); 103 free(conftxt); 104 105 return (d); 106} 107 108void 109Debug_Disk(struct disk *d) 110{ 111 112 printf("Debug_Disk(%s)", d->name); 113 114#ifndef __ia64__ 115 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 116 d->bios_cyl, d->bios_hd, d->bios_sect, 117 d->bios_cyl * d->bios_hd * d->bios_sect); 118#if defined(PC98) 119 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 120 d->boot1, d->boot2, d->bootipl, d->bootmenu); 121#elif defined(__i386__) || defined(__amd64__) 122 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 123 d->boot1, d->boot2, d->bootmgr); 124#elif defined(__alpha__) 125 printf(" boot1=%p, bootmgr=%p\n", 126 d->boot1, d->bootmgr); 127#else 128/* Should be: error "Debug_Disk: unknown arch"; */ 129#endif 130#else /* __ia64__ */ 131 printf(" media size=%lu, sector size=%lu\n", d->media_size, 132 d->sector_size); 133#endif 134 135 Debug_Chunk(d->chunks); 136} 137 138void 139Free_Disk(struct disk *d) 140{ 141 if (d->chunks) 142 Free_Chunk(d->chunks); 143 if (d->name) 144 free(d->name); 145#ifdef PC98 146 if (d->bootipl) 147 free(d->bootipl); 148 if (d->bootmenu) 149 free(d->bootmenu); 150#else 151#if !defined(__ia64__) 152 if (d->bootmgr) 153 free(d->bootmgr); 154#endif 155#endif 156#if !defined(__ia64__) 157 if (d->boot1) 158 free(d->boot1); 159#endif 160#if defined(__i386__) || defined(__amd64__) 161 if (d->boot2) 162 free(d->boot2); 163#endif 164 free(d); 165} 166 167#if 0 168void 169Collapse_Disk(struct disk *d) 170{ 171 172 while (Collapse_Chunk(d, d->chunks)) 173 ; 174} 175#endif 176 177static int 178qstrcmp(const void* a, const void* b) 179{ 180 const char *str1 = *(char* const*)a; 181 const char *str2 = *(char* const*)b; 182 183 return strcmp(str1, str2); 184} 185 186char ** 187Disk_Names() 188{ 189 int disk_cnt; 190 static char **disks; 191 int error; 192 size_t listsize; 193 char *disklist; 194 195 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 196 if (error) { 197 warn("kern.disks sysctl not available"); 198 return NULL; 199 } 200 201 if (listsize == 0) 202 return (NULL); 203 204 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 205 if (disks == NULL) 206 return NULL; 207 disklist = (char *)malloc(listsize + 1); 208 if (disklist == NULL) { 209 free(disks); 210 return NULL; 211 } 212 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 213 memset(disklist, 0, listsize + 1); 214 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 215 if (error || disklist[0] == 0) { 216 free(disklist); 217 free(disks); 218 return NULL; 219 } 220 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 221 disks[disk_cnt] = strsep(&disklist, " "); 222 if (disks[disk_cnt] == NULL) 223 break; 224 } 225 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 226 return disks; 227} 228 229#ifdef PC98 230void 231Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 232 const u_char *bootmenu, const size_t bootmenu_size) 233#else 234void 235Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 236#endif 237{ 238#if !defined(__ia64__) 239#ifdef PC98 240 if (d->sector_size == 0) 241 return; 242 if (bootipl_size % d->sector_size != 0) 243 return; 244 if (d->bootipl) 245 free(d->bootipl); 246 if (!bootipl) { 247 d->bootipl = NULL; 248 } else { 249 d->bootipl_size = bootipl_size; 250 d->bootipl = malloc(bootipl_size); 251 if (!d->bootipl) 252 return; 253 memcpy(d->bootipl, bootipl, bootipl_size); 254 } 255 256 if (bootmenu_size % d->sector_size != 0) 257 return; 258 if (d->bootmenu) 259 free(d->bootmenu); 260 if (!bootmenu) { 261 d->bootmenu = NULL; 262 } else { 263 d->bootmenu_size = bootmenu_size; 264 d->bootmenu = malloc(bootmenu_size); 265 if (!d->bootmenu) 266 return; 267 memcpy(d->bootmenu, bootmenu, bootmenu_size); 268 } 269#else 270 if (d->sector_size == 0) 271 return; 272 if (s % d->sector_size != 0) 273 return; 274 if (d->bootmgr) 275 free(d->bootmgr); 276 if (!b) { 277 d->bootmgr = NULL; 278 } else { 279 d->bootmgr_size = s; 280 d->bootmgr = malloc(s); 281 if (!d->bootmgr) 282 return; 283 memcpy(d->bootmgr, b, s); 284 } 285#endif 286#endif 287} 288 289int 290Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 291{ 292#if defined(__i386__) || defined(__amd64__) 293 if (d->boot1) 294 free(d->boot1); 295 d->boot1 = malloc(512); 296 if (!d->boot1) 297 return -1; 298 memcpy(d->boot1, b1, 512); 299 if (d->boot2) 300 free(d->boot2); 301 d->boot2 = malloc(15 * 512); 302 if (!d->boot2) 303 return -1; 304 memcpy(d->boot2, b2, 15 * 512); 305#elif defined(__alpha__) 306 if (d->boot1) 307 free(d->boot1); 308 d->boot1 = malloc(15 * 512); 309 if (!d->boot1) 310 return -1; 311 memcpy(d->boot1, b1, 15 * 512); 312#elif defined(__sparc64__) 313 if (d->boot1 != NULL) 314 free(d->boot1); 315 d->boot1 = malloc(16 * 512); 316 if (d->boot1 == NULL) 317 return (-1); 318 memcpy(d->boot1, b1, 16 * 512); 319#elif defined(__ia64__) 320 /* nothing */ 321#else 322/* Should be: #error "Set_Boot_Blocks: unknown arch"; */ 323#endif 324 return 0; 325} 326 327#ifdef PC98 328const char * 329slice_type_name( int type, int subtype ) 330{ 331 332 switch (type) { 333 case whole: 334 return "whole"; 335 case fat: 336 return "fat"; 337 case freebsd: 338 switch (subtype) { 339 case 0xc494: return "freebsd"; 340 default: return "unknown"; 341 } 342 case unused: 343 return "unused"; 344 default: 345 return "unknown"; 346 } 347} 348#else /* PC98 */ 349const char * 350slice_type_name( int type, int subtype ) 351{ 352 353 switch (type) { 354 case whole: 355 return "whole"; 356 case mbr: 357 switch (subtype) { 358 case 1: return "fat (12-bit)"; 359 case 2: return "XENIX /"; 360 case 3: return "XENIX /usr"; 361 case 4: return "fat (16-bit,<=32Mb)"; 362 case 5: return "extended DOS"; 363 case 6: return "fat (16-bit,>32Mb)"; 364 case 7: return "NTFS/HPFS/QNX"; 365 case 8: return "AIX bootable"; 366 case 9: return "AIX data"; 367 case 10: return "OS/2 bootmgr"; 368 case 11: return "fat (32-bit)"; 369 case 12: return "fat (32-bit,LBA)"; 370 case 14: return "fat (16-bit,>32Mb,LBA)"; 371 case 15: return "extended DOS, LBA"; 372 case 18: return "Compaq Diagnostic"; 373 case 84: return "OnTrack diskmgr"; 374 case 100: return "Netware 2.x"; 375 case 101: return "Netware 3.x"; 376 case 115: return "SCO UnixWare"; 377 case 128: return "Minix 1.1"; 378 case 129: return "Minix 1.5"; 379 case 130: return "linux_swap"; 380 case 131: return "ext2fs"; 381 case 166: return "OpenBSD FFS"; /* 0xA6 */ 382 case 169: return "NetBSD FFS"; /* 0xA9 */ 383 case 182: return "OpenBSD"; /* dedicated */ 384 case 183: return "bsd/os"; 385 case 184: return "bsd/os swap"; 386 case 191: return "Solaris (new)"; 387 case 238: return "EFI GPT"; 388 case 239: return "EFI Sys. Part."; 389 default: return "unknown"; 390 } 391 case fat: 392 return "fat"; 393 case freebsd: 394 switch (subtype) { 395 case 165: return "freebsd"; 396 default: return "unknown"; 397 } 398 case extended: 399 return "extended"; 400 case part: 401 return "part"; 402 case efi: 403 return "efi"; 404 case unused: 405 return "unused"; 406 default: 407 return "unknown"; 408 } 409} 410#endif /* PC98 */ 411