disk.c revision 106135
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 106135 2002-10-29 12:13:36Z 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 if (Add_Chunk(d, 0, o / s, name, whole, 0, 0, "-")) 133 DPRINT(("Failed to add 'whole' chunk")); 134 135 len = o / s; 136 137 for (;;) { 138 a = strsep(&p, " "); 139 if (a == NULL) 140 break; 141 b = strsep(&p, " "); 142 o = strtoul(b, &r, 0); 143 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 144 if (!strcmp(a, "hd")) 145 d->bios_hd = o; 146 else if (!strcmp(a, "sc")) 147 d->bios_sect = o; 148 else 149 printf("HUH ? <%s> <%s>\n", a, b); 150 } 151 152 p = q; 153 lo[0] = 0; 154 155 for (; p != NULL && *p; p = q) { 156 q = strchr(p, '\n'); 157 if (q != NULL) 158 *q++ = '\0'; 159 a = strsep(&p, " "); /* Index */ 160 if (!strcmp(a, "0")) 161 break; 162 l = strtoimax(a, &r, 0); 163 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 164 t = strsep(&p, " "); /* Type {SUN, BSD, MBR, GPT} */ 165 n = strsep(&p, " "); /* name */ 166 a = strsep(&p, " "); /* len */ 167 len = strtoimax(a, &r, 0); 168 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 169 a = strsep(&p, " "); /* secsize */ 170 s = strtoimax(a, &r, 0); 171 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 172 for (;;) { 173 a = strsep(&p, " "); 174 if (a == NULL) 175 break; 176 b = strsep(&p, " "); 177 o = strtoimax(b, &r, 0); 178 if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } 179 if (!strcmp(a, "o")) 180 off = o; 181 else if (!strcmp(a, "i")) 182 i = o; 183 else if (!strcmp(a, "ty")) 184 ty = o; 185 else if (!strcmp(a, "sc")) 186 sc = o; 187 else if (!strcmp(a, "hd")) 188 hd = o; 189 else if (!strcmp(a, "alt")) 190 alt = o; 191 } 192 193 /* PLATFORM POLICY BEGIN ------------------------------------- */ 194 if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2) 195 continue; 196 if (platform == p_sparc64 && !strcmp(t, "SUN") && 197 d->chunks->part->part == NULL) { 198 d->bios_hd = hd; 199 d->bios_sect = sc; 200 o = d->chunks->size / (hd * sc); 201 o *= (hd * sc); 202 o -= alt * hd * sc; 203 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) 204 DPRINT(("Failed to add 'freebsd' chunk")); 205 } 206 if (platform == p_alpha && !strcmp(t, "BSD") && 207 d->chunks->part->part == NULL) { 208 o = d->chunks->size; 209 if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, 0, 0, "-")) 210 DPRINT(("Failed to add 'freebsd' chunk")); 211 } 212 if (platform == p_i386 && !strcmp(t, "BSD") && i == 2) 213 continue; 214 /* PLATFORM POLICY END --------------------------------------- */ 215 216 off /= s; 217 len /= s; 218 off += lo[l - 1]; 219 lo[l] = off; 220 printf("%s [%s] %jd %jd\n", t, n, (intmax_t)(off / s), (intmax_t) (len / s)); 221 if (!strcmp(t, "SUN")) 222 i = Add_Chunk(d, off, len, n, part, 0, 0, 0); 223 else if (!strcmp(t, "MBR") && ty == 165) 224 i = Add_Chunk(d, off, len, n, freebsd, 0, 0, 0); 225 else if (!strcmp(t, "MBR")) 226 i = Add_Chunk(d, off, len, n, mbr, 0, 0, 0); 227 else if (!strcmp(t, "BSD")) 228 i = Add_Chunk(d, off, len, n, part, 0, 0, 0); 229 else if (!strcmp(t, "PC98")) 230 i = Add_Chunk(d, off, len, n, pc98, 0, 0, 0); 231 else if (!strcmp(t, "GPT")) 232 i = Add_Chunk(d, off, len, n, gpt, 0, 0, 0); 233 else 234 {printf("BARF %d\n", __LINE__); exit(0); } 235 printf("error = %d\n", i); 236 } 237 /* PLATFORM POLICY BEGIN ------------------------------------- */ 238 /* We have a chance to do things on a blank disk here */ 239printf("c %p\n", d->chunks); 240printf("c->p %p\n", d->chunks->part); 241printf("c->p->p %p\n", d->chunks->part->part); 242 if (platform == p_sparc64 && d->chunks->part->part == NULL) { 243printf("HERE %d\n", __LINE__); 244 hd = d->bios_hd; 245 sc = d->bios_sect; 246 o = d->chunks->size / (hd * sc); 247 o *= (hd * sc); 248 o -= 2 * hd * sc; 249printf("HERE %d\n", __LINE__); 250 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) 251 DPRINT(("Failed to add 'freebsd' chunk")); 252 } 253 /* PLATFORM POLICY END --------------------------------------- */ 254 255 return (d); 256 i = 0; 257} 258 259void 260Debug_Disk(struct disk *d) 261{ 262 printf("Debug_Disk(%s)", d->name); 263#if 0 264 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect); 265#endif 266 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 267 d->bios_cyl, d->bios_hd, d->bios_sect, 268 d->bios_cyl * d->bios_hd * d->bios_sect); 269#if defined(__i386__) 270 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 271 d->boot1, d->boot2, d->bootmgr); 272#elif defined(__alpha__) 273 printf(" boot1=%p, bootmgr=%p\n", 274 d->boot1, d->bootmgr); 275#elif defined(__ia64__) 276 printf("\n"); 277#else 278/* Should be: error "Debug_Disk: unknown arch"; */ 279#endif 280 Debug_Chunk(d->chunks); 281} 282 283void 284Free_Disk(struct disk *d) 285{ 286 if(d->chunks) Free_Chunk(d->chunks); 287 if(d->name) free(d->name); 288#ifdef PC98 289 if(d->bootipl) free(d->bootipl); 290 if(d->bootmenu) free(d->bootmenu); 291#else 292#if !defined(__ia64__) 293 if(d->bootmgr) free(d->bootmgr); 294#endif 295#endif 296#if !defined(__ia64__) 297 if(d->boot1) free(d->boot1); 298#endif 299#if defined(__i386__) 300 if(d->boot2) free(d->boot2); 301#endif 302 free(d); 303} 304 305#if 0 306void 307Collapse_Disk(struct disk *d) 308{ 309 310 while(Collapse_Chunk(d, d->chunks)) 311 ; 312} 313#endif 314 315static int 316qstrcmp(const void* a, const void* b) 317{ 318 319 char *str1 = *(char**)a; 320 char *str2 = *(char**)b; 321 return strcmp(str1, str2); 322} 323 324char ** 325Disk_Names() 326{ 327 int disk_cnt; 328 static char **disks; 329 int error; 330 size_t listsize; 331 char *disklist; 332 333 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 334 if (error) { 335 warn("kern.disks sysctl not available"); 336 return NULL; 337 } 338 339 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 340 if (disks == NULL) 341 return NULL; 342 disklist = (char *)malloc(listsize + 1); 343 if (disklist == NULL) { 344 free(disks); 345 return NULL; 346 } 347 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 348 memset(disklist, 0, listsize + 1); 349 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 350 if (error) { 351 free(disklist); 352 free(disks); 353 return NULL; 354 } 355 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 356 disks[disk_cnt] = strsep(&disklist, " "); 357 if (disks[disk_cnt] == NULL) 358 break; 359 } 360 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 361 return disks; 362} 363 364void 365Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 366{ 367#if !defined(__ia64__) 368#ifdef PC98 369 if (bootipl_size % d->sector_size != 0) 370 return; 371 if (d->bootipl) 372 free(d->bootipl); 373 if (!bootipl) { 374 d->bootipl = NULL; 375 } else { 376 d->bootipl_size = bootipl_size; 377 d->bootipl = malloc(bootipl_size); 378 if(!d->bootipl) return; 379 memcpy(d->bootipl, bootipl, bootipl_size); 380 } 381 382 if (bootmenu_size % d->sector_size != 0) 383 return; 384 if (d->bootmenu) 385 free(d->bootmenu); 386 if (!bootmenu) { 387 d->bootmenu = NULL; 388 } else { 389 d->bootmenu_size = bootmenu_size; 390 d->bootmenu = malloc(bootmenu_size); 391 if(!d->bootmenu) return; 392 memcpy(d->bootmenu, bootmenu, bootmenu_size); 393 } 394#else 395 if (s % d->sector_size != 0) 396 return; 397 if (d->bootmgr) 398 free(d->bootmgr); 399 if (!b) { 400 d->bootmgr = NULL; 401 } else { 402 d->bootmgr_size = s; 403 d->bootmgr = malloc(s); 404 if(!d->bootmgr) return; 405 memcpy(d->bootmgr, b, s); 406 } 407#endif 408#endif 409} 410 411int 412Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 413{ 414#if defined(__i386__) 415 if (d->boot1) free(d->boot1); 416 d->boot1 = malloc(512); 417 if(!d->boot1) return -1; 418 memcpy(d->boot1, b1, 512); 419 if (d->boot2) free(d->boot2); 420 d->boot2 = malloc(15 * 512); 421 if(!d->boot2) return -1; 422 memcpy(d->boot2, b2, 15 * 512); 423#elif defined(__alpha__) 424 if (d->boot1) free(d->boot1); 425 d->boot1 = malloc(15 * 512); 426 if(!d->boot1) return -1; 427 memcpy(d->boot1, b1, 15 * 512); 428#elif defined(__ia64__) 429 /* nothing */ 430#else 431/* Should be: #error "Set_Boot_Blocks: unknown arch"; */ 432#endif 433 return 0; 434} 435 436const char * 437slice_type_name( int type, int subtype ) 438{ 439 switch (type) { 440 case 0: return "whole"; 441 case 1: switch (subtype) { 442 case 1: return "fat (12-bit)"; 443 case 2: return "XENIX /"; 444 case 3: return "XENIX /usr"; 445 case 4: return "fat (16-bit,<=32Mb)"; 446 case 5: return "extended DOS"; 447 case 6: return "fat (16-bit,>32Mb)"; 448 case 7: return "NTFS/HPFS/QNX"; 449 case 8: return "AIX bootable"; 450 case 9: return "AIX data"; 451 case 10: return "OS/2 bootmgr"; 452 case 11: return "fat (32-bit)"; 453 case 12: return "fat (32-bit,LBA)"; 454 case 14: return "fat (16-bit,>32Mb,LBA)"; 455 case 15: return "extended DOS, LBA"; 456 case 18: return "Compaq Diagnostic"; 457 case 84: return "OnTrack diskmgr"; 458 case 100: return "Netware 2.x"; 459 case 101: return "Netware 3.x"; 460 case 115: return "SCO UnixWare"; 461 case 128: return "Minix 1.1"; 462 case 129: return "Minix 1.5"; 463 case 130: return "linux_swap"; 464 case 131: return "ext2fs"; 465 case 166: return "OpenBSD FFS"; /* 0xA6 */ 466 case 169: return "NetBSD FFS"; /* 0xA9 */ 467 case 182: return "OpenBSD"; /* dedicated */ 468 case 183: return "bsd/os"; 469 case 184: return "bsd/os swap"; 470 case 238: return "EFI GPT"; 471 case 239: return "EFI Sys. Part."; 472 default: return "unknown"; 473 } 474 case 2: return "fat"; 475 case 3: switch (subtype) { 476 case 165: return "freebsd"; 477 default: return "unknown"; 478 } 479 case 4: return "extended"; 480 case 5: return "part"; 481 case 6: return "unused"; 482 default: return "unknown"; 483 } 484} 485