disk.c revision 106337
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 106337 2002-11-02 10:57:44Z phk $"); 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/diskslice.h> 27#include <sys/diskmbr.h> 28#include <paths.h> 29#include "libdisk.h" 30 31#include <ctype.h> 32#include <errno.h> 33#include <assert.h> 34 35#define DOSPTYP_EXTENDED 5 36#ifdef DEBUG 37#define DPRINT(x) warn x 38#define DPRINTX(x) warnx x 39#else 40#define DPRINT(x) 41#define DPRINTX(x) 42#endif 43 44const char * 45chunk_name(chunk_e type) 46{ 47 switch(type) { 48 case unused: return ("unused"); 49 case mbr: return ("mbr"); 50 case part: return ("part"); 51 case gpt: return ("gpt"); 52 case pc98: return ("pc98"); 53 case sun: return ("sun"); 54 case freebsd: return ("freebsd"); 55 case fat: return ("fat"); 56 case spare: return ("spare"); 57 default: return ("??"); 58 } 59}; 60 61struct disk * 62Open_Disk(const char *name) 63{ 64 return Int_Open_Disk(name); 65} 66 67struct disk * 68Int_Open_Disk(const char *name) 69{ 70 char *conftxt = NULL; 71 struct disk *d; 72 size_t txtsize; 73 int error, i; 74 char *p, *q, *r, *a, *b, *n, *t; 75 off_t o, len, off; 76 u_int l, s, ty, sc, hd, alt; 77 off_t lo[10]; 78 79 error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0); 80 if (error) { 81 warn("kern.geom.conftxt sysctl not available, giving up!"); 82 return (NULL); 83 } 84 conftxt = (char *) malloc(txtsize+1); 85 if (conftxt == NULL) { 86 DPRINT(("cannot malloc memory for conftxt")); 87 return (NULL); 88 } 89 error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0); 90 if (error) { 91 DPRINT(("error reading kern.geom.conftxt from the system")); 92 free(conftxt); 93 return (NULL); 94 } 95 conftxt[txtsize] = '\0'; /* in case kernel bug is still there */ 96 97 for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) { 98 if (*p == '\n') 99 p++; 100 a = strsep(&p, " "); 101 if (strcmp(a, "0")) 102 continue; 103 104 a = strsep(&p, " "); 105 if (strcmp(a, "DISK")) 106 continue; 107 108 a = strsep(&p, " "); 109 if (strcmp(a, name)) 110 continue; 111 break; 112 } 113 114 q = strchr(p, '\n'); 115 if (q != NULL) 116 *q++ = '\0'; 117 118 d = (struct disk *)calloc(sizeof *d, 1); 119 if(d == NULL) 120 return NULL; 121 122 d->name = strdup(name); 123 124 a = strsep(&p, " "); /* length in bytes */ 125 o = strtoimax(a, &r, 0); 126 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 127 128 a = strsep(&p, " "); /* sectorsize */ 129 s = strtoul(a, &r, 0); 130 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 131 132 d->sector_size = s; 133 134 if (Add_Chunk(d, 0, o / s, name, whole, 0, 0, "-")) 135 DPRINT(("Failed to add 'whole' chunk")); 136 137 len = o / s; 138 139 for (;;) { 140 a = strsep(&p, " "); 141 if (a == NULL) 142 break; 143 b = strsep(&p, " "); 144 o = strtoul(b, &r, 0); 145 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 146 if (!strcmp(a, "hd")) 147 d->bios_hd = o; 148 else if (!strcmp(a, "sc")) 149 d->bios_sect = o; 150 else 151 printf("HUH ? <%s> <%s>\n", a, b); 152 } 153 154 p = q; 155 lo[0] = 0; 156 157 for (; p != NULL && *p; p = q) { 158 q = strchr(p, '\n'); 159 if (q != NULL) 160 *q++ = '\0'; 161 a = strsep(&p, " "); /* Index */ 162 if (!strcmp(a, "0")) 163 break; 164 l = strtoimax(a, &r, 0); 165 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 166 t = strsep(&p, " "); /* Type {SUN, BSD, MBR, GPT} */ 167 n = strsep(&p, " "); /* name */ 168 a = strsep(&p, " "); /* len */ 169 len = strtoimax(a, &r, 0); 170 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 171 a = strsep(&p, " "); /* secsize */ 172 s = strtoimax(a, &r, 0); 173 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 174 for (;;) { 175 a = strsep(&p, " "); 176 if (a == NULL) 177 break; 178 b = strsep(&p, " "); 179 o = strtoimax(b, &r, 0); 180 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 181 if (!strcmp(a, "o")) 182 off = o; 183 else if (!strcmp(a, "i")) 184 i = o; 185 else if (!strcmp(a, "ty")) 186 ty = o; 187 else if (!strcmp(a, "sc")) 188 sc = o; 189 else if (!strcmp(a, "hd")) 190 hd = o; 191 else if (!strcmp(a, "alt")) 192 alt = o; 193 } 194 195 /* PLATFORM POLICY BEGIN ------------------------------------- */ 196 if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2) 197 continue; 198 if (platform == p_sparc64 && !strcmp(t, "SUN") && 199 d->chunks->part->part == NULL) { 200 d->bios_hd = hd; 201 d->bios_sect = sc; 202 o = d->chunks->size / (hd * sc); 203 o *= (hd * sc); 204 o -= alt * hd * sc; 205 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) 206 DPRINT(("Failed to add 'freebsd' chunk")); 207 } 208 if (platform == p_alpha && !strcmp(t, "BSD") && 209 d->chunks->part->part == NULL) { 210 o = d->chunks->size; 211 if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, 0, 0, "-")) 212 DPRINT(("Failed to add 'freebsd' chunk")); 213 } 214 if (!strcmp(t, "BSD") && i == RAW_PART) 215 continue; 216 /* PLATFORM POLICY END --------------------------------------- */ 217 218 off /= s; 219 len /= s; 220 off += lo[l - 1]; 221 lo[l] = off; 222 printf("%s [%s] %jd %jd\n", t, n, (intmax_t)(off / s), (intmax_t) (len / s)); 223 if (!strcmp(t, "SUN")) 224 i = Add_Chunk(d, off, len, n, part, 0, 0, 0); 225 else if (!strcmp(t, "MBR") && ty == 165) 226 i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0); 227 else if (!strcmp(t, "MBR")) 228 i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0); 229 else if (!strcmp(t, "BSD")) 230 i = Add_Chunk(d, off, len, n, part, 0, 0, 0); 231 else if (!strcmp(t, "PC98")) 232 i = Add_Chunk(d, off, len, n, pc98, 0, 0, 0); 233 else if (!strcmp(t, "GPT")) 234 i = Add_Chunk(d, off, len, n, gpt, 0, 0, 0); 235 else 236 {printf("BARF %d\n", __LINE__); exit(0); } 237 printf("error = %d\n", i); 238 } 239 /* PLATFORM POLICY BEGIN ------------------------------------- */ 240 /* We have a chance to do things on a blank disk here */ 241printf("c %p\n", d->chunks); 242printf("c->p %p\n", d->chunks->part); 243printf("c->p->p %p\n", d->chunks->part->part); 244 if (platform == p_sparc64 && d->chunks->part->part == NULL) { 245printf("HERE %d\n", __LINE__); 246 hd = d->bios_hd; 247 sc = d->bios_sect; 248 o = d->chunks->size / (hd * sc); 249 o *= (hd * sc); 250 o -= 2 * hd * sc; 251printf("HERE %d\n", __LINE__); 252 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) 253 DPRINT(("Failed to add 'freebsd' chunk")); 254 } 255 /* PLATFORM POLICY END --------------------------------------- */ 256 257 return (d); 258 i = 0; 259} 260 261void 262Debug_Disk(struct disk *d) 263{ 264 printf("Debug_Disk(%s)", d->name); 265#if 0 266 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect); 267#endif 268 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 269 d->bios_cyl, d->bios_hd, d->bios_sect, 270 d->bios_cyl * d->bios_hd * d->bios_sect); 271#if defined(PC98) 272 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 273 d->boot1, d->boot2, d->bootipl, d->bootmenu); 274#elif defined(__i386__) 275 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 276 d->boot1, d->boot2, d->bootmgr); 277#elif defined(__alpha__) 278 printf(" boot1=%p, bootmgr=%p\n", 279 d->boot1, d->bootmgr); 280#elif defined(__ia64__) 281 printf("\n"); 282#else 283/* Should be: error "Debug_Disk: unknown arch"; */ 284#endif 285 Debug_Chunk(d->chunks); 286} 287 288void 289Free_Disk(struct disk *d) 290{ 291 if(d->chunks) Free_Chunk(d->chunks); 292 if(d->name) free(d->name); 293#ifdef PC98 294 if(d->bootipl) free(d->bootipl); 295 if(d->bootmenu) free(d->bootmenu); 296#else 297#if !defined(__ia64__) 298 if(d->bootmgr) free(d->bootmgr); 299#endif 300#endif 301#if !defined(__ia64__) 302 if(d->boot1) free(d->boot1); 303#endif 304#if defined(__i386__) 305 if(d->boot2) free(d->boot2); 306#endif 307 free(d); 308} 309 310#if 0 311void 312Collapse_Disk(struct disk *d) 313{ 314 315 while(Collapse_Chunk(d, d->chunks)) 316 ; 317} 318#endif 319 320static int 321qstrcmp(const void* a, const void* b) 322{ 323 324 char *str1 = *(char**)a; 325 char *str2 = *(char**)b; 326 return strcmp(str1, str2); 327} 328 329char ** 330Disk_Names() 331{ 332 int disk_cnt; 333 static char **disks; 334 int error; 335 size_t listsize; 336 char *disklist; 337 338 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 339 if (error) { 340 warn("kern.disks sysctl not available"); 341 return NULL; 342 } 343 344 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 345 if (disks == NULL) 346 return NULL; 347 disklist = (char *)malloc(listsize + 1); 348 if (disklist == NULL) { 349 free(disks); 350 return NULL; 351 } 352 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 353 memset(disklist, 0, listsize + 1); 354 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 355 if (error) { 356 free(disklist); 357 free(disks); 358 return NULL; 359 } 360 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 361 disks[disk_cnt] = strsep(&disklist, " "); 362 if (disks[disk_cnt] == NULL) 363 break; 364 } 365 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 366 return disks; 367} 368 369#ifdef PC98 370void 371Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 372 const u_char *bootmenu, const size_t bootmenu_size) 373#else 374void 375Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 376#endif 377{ 378#if !defined(__ia64__) 379#ifdef PC98 380 if (bootipl_size % d->sector_size != 0) 381 return; 382 if (d->bootipl) 383 free(d->bootipl); 384 if (!bootipl) { 385 d->bootipl = NULL; 386 } else { 387 d->bootipl_size = bootipl_size; 388 d->bootipl = malloc(bootipl_size); 389 if(!d->bootipl) return; 390 memcpy(d->bootipl, bootipl, bootipl_size); 391 } 392 393 if (bootmenu_size % d->sector_size != 0) 394 return; 395 if (d->bootmenu) 396 free(d->bootmenu); 397 if (!bootmenu) { 398 d->bootmenu = NULL; 399 } else { 400 d->bootmenu_size = bootmenu_size; 401 d->bootmenu = malloc(bootmenu_size); 402 if(!d->bootmenu) return; 403 memcpy(d->bootmenu, bootmenu, bootmenu_size); 404 } 405#else 406 if (s % d->sector_size != 0) 407 return; 408 if (d->bootmgr) 409 free(d->bootmgr); 410 if (!b) { 411 d->bootmgr = NULL; 412 } else { 413 d->bootmgr_size = s; 414 d->bootmgr = malloc(s); 415 if(!d->bootmgr) return; 416 memcpy(d->bootmgr, b, s); 417 } 418#endif 419#endif 420} 421 422int 423Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 424{ 425#if defined(__i386__) 426 if (d->boot1) free(d->boot1); 427 d->boot1 = malloc(512); 428 if(!d->boot1) return -1; 429 memcpy(d->boot1, b1, 512); 430 if (d->boot2) free(d->boot2); 431 d->boot2 = malloc(15 * 512); 432 if(!d->boot2) return -1; 433 memcpy(d->boot2, b2, 15 * 512); 434#elif defined(__alpha__) 435 if (d->boot1) free(d->boot1); 436 d->boot1 = malloc(15 * 512); 437 if(!d->boot1) return -1; 438 memcpy(d->boot1, b1, 15 * 512); 439#elif defined(__sparc64__) 440 if (d->boot1 != NULL) 441 free(d->boot1); 442 d->boot1 = malloc(16 * 512); 443 if (d->boot1 == NULL) 444 return (-1); 445 memcpy(d->boot1, b1, 16 * 512); 446#elif defined(__ia64__) 447 /* nothing */ 448#else 449/* Should be: #error "Set_Boot_Blocks: unknown arch"; */ 450#endif 451 return 0; 452} 453 454#ifdef PC98 455const char * 456slice_type_name( int type, int subtype ) 457{ 458 459 switch (type) { 460 case 0: 461 return "whole"; 462 case 2: 463 return "fat"; 464 case 3: 465 switch (subtype) { 466 case 0xc494: return "freebsd"; 467 default: return "unknown"; 468 } 469 default: 470 return "unknown"; 471 } 472} 473#else /* PC98 */ 474const char * 475slice_type_name( int type, int subtype ) 476{ 477 478 switch (type) { 479 case 0: 480 return "whole"; 481 case 1: 482 switch (subtype) { 483 case 1: return "fat (12-bit)"; 484 case 2: return "XENIX /"; 485 case 3: return "XENIX /usr"; 486 case 4: return "fat (16-bit,<=32Mb)"; 487 case 5: return "extended DOS"; 488 case 6: return "fat (16-bit,>32Mb)"; 489 case 7: return "NTFS/HPFS/QNX"; 490 case 8: return "AIX bootable"; 491 case 9: return "AIX data"; 492 case 10: return "OS/2 bootmgr"; 493 case 11: return "fat (32-bit)"; 494 case 12: return "fat (32-bit,LBA)"; 495 case 14: return "fat (16-bit,>32Mb,LBA)"; 496 case 15: return "extended DOS, LBA"; 497 case 18: return "Compaq Diagnostic"; 498 case 84: return "OnTrack diskmgr"; 499 case 100: return "Netware 2.x"; 500 case 101: return "Netware 3.x"; 501 case 115: return "SCO UnixWare"; 502 case 128: return "Minix 1.1"; 503 case 129: return "Minix 1.5"; 504 case 130: return "linux_swap"; 505 case 131: return "ext2fs"; 506 case 166: return "OpenBSD FFS"; /* 0xA6 */ 507 case 169: return "NetBSD FFS"; /* 0xA9 */ 508 case 182: return "OpenBSD"; /* dedicated */ 509 case 183: return "bsd/os"; 510 case 184: return "bsd/os swap"; 511 case 238: return "EFI GPT"; 512 case 239: return "EFI Sys. Part."; 513 default: return "unknown"; 514 } 515 case 2: 516 return "fat"; 517 case 3: 518 switch (subtype) { 519 case 165: return "freebsd"; 520 default: return "unknown"; 521 } 522 case 4: 523 return "extended"; 524 case 5: 525 return "part"; 526 case 6: 527 return "unused"; 528 default: 529 return "unknown"; 530 } 531} 532#endif /* PC98 */ 533