disk.c revision 127595
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 127595 2004-03-30 01:39:00Z kuriyama $"); 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 default: return ("??"); 73 } 74}; 75 76struct disk * 77Open_Disk(const char *name) 78{ 79 char *conftxt; 80 size_t txtsize; 81 int error; 82 83 error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0); 84 if (error) { 85 warn("kern.geom.conftxt sysctl not available, giving up!"); 86 return (NULL); 87 } 88 conftxt = malloc(txtsize+1); 89 if (conftxt == NULL) { 90 warn("cannot malloc memory for conftxt"); 91 return (NULL); 92 } 93 error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0); 94 if (error) { 95 warn("error reading kern.geom.conftxt from the system"); 96 free(conftxt); 97 return (NULL); 98 } 99 conftxt[txtsize] = '\0'; /* in case kernel bug is still there */ 100 101 return Int_Open_Disk(name, conftxt); 102} 103 104void 105Debug_Disk(struct disk *d) 106{ 107 108 printf("Debug_Disk(%s)", d->name); 109 110#ifndef __ia64__ 111 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 112 d->bios_cyl, d->bios_hd, d->bios_sect, 113 d->bios_cyl * d->bios_hd * d->bios_sect); 114#if defined(PC98) 115 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 116 d->boot1, d->boot2, d->bootipl, d->bootmenu); 117#elif defined(__i386__) || defined(__amd64__) 118 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 119 d->boot1, d->boot2, d->bootmgr); 120#elif defined(__alpha__) 121 printf(" boot1=%p, bootmgr=%p\n", 122 d->boot1, d->bootmgr); 123#else 124/* Should be: error "Debug_Disk: unknown arch"; */ 125#endif 126#else /* __ia64__ */ 127 printf(" media size=%lu, sector size=%lu\n", d->media_size, 128 d->sector_size); 129#endif 130 131 Debug_Chunk(d->chunks); 132} 133 134void 135Free_Disk(struct disk *d) 136{ 137 if (d->chunks) 138 Free_Chunk(d->chunks); 139 if (d->name) 140 free(d->name); 141#ifdef PC98 142 if (d->bootipl) 143 free(d->bootipl); 144 if (d->bootmenu) 145 free(d->bootmenu); 146#else 147#if !defined(__ia64__) 148 if (d->bootmgr) 149 free(d->bootmgr); 150#endif 151#endif 152#if !defined(__ia64__) 153 if (d->boot1) 154 free(d->boot1); 155#endif 156#if defined(__i386__) || defined(__amd64__) 157 if (d->boot2) 158 free(d->boot2); 159#endif 160 free(d); 161} 162 163#if 0 164void 165Collapse_Disk(struct disk *d) 166{ 167 168 while (Collapse_Chunk(d, d->chunks)) 169 ; 170} 171#endif 172 173static int 174qstrcmp(const void* a, const void* b) 175{ 176 const char *str1 = *(char* const*)a; 177 const char *str2 = *(char* const*)b; 178 179 return strcmp(str1, str2); 180} 181 182char ** 183Disk_Names() 184{ 185 int disk_cnt; 186 static char **disks; 187 int error; 188 size_t listsize; 189 char *disklist; 190 191 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 192 if (error) { 193 warn("kern.disks sysctl not available"); 194 return NULL; 195 } 196 197 if (listsize == 0) 198 return (NULL); 199 200 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 201 if (disks == NULL) 202 return NULL; 203 disklist = (char *)malloc(listsize + 1); 204 if (disklist == NULL) { 205 free(disks); 206 return NULL; 207 } 208 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 209 memset(disklist, 0, listsize + 1); 210 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 211 if (error || disklist[0] == 0) { 212 free(disklist); 213 free(disks); 214 return NULL; 215 } 216 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 217 disks[disk_cnt] = strsep(&disklist, " "); 218 if (disks[disk_cnt] == NULL) 219 break; 220 } 221 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 222 return disks; 223} 224 225#ifdef PC98 226void 227Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 228 const u_char *bootmenu, const size_t bootmenu_size) 229#else 230void 231Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 232#endif 233{ 234#if !defined(__ia64__) 235#ifdef PC98 236 if (d->sector_size == 0) 237 return; 238 if (bootipl_size % d->sector_size != 0) 239 return; 240 if (d->bootipl) 241 free(d->bootipl); 242 if (!bootipl) { 243 d->bootipl = NULL; 244 } else { 245 d->bootipl_size = bootipl_size; 246 d->bootipl = malloc(bootipl_size); 247 if (!d->bootipl) 248 return; 249 memcpy(d->bootipl, bootipl, bootipl_size); 250 } 251 252 if (bootmenu_size % d->sector_size != 0) 253 return; 254 if (d->bootmenu) 255 free(d->bootmenu); 256 if (!bootmenu) { 257 d->bootmenu = NULL; 258 } else { 259 d->bootmenu_size = bootmenu_size; 260 d->bootmenu = malloc(bootmenu_size); 261 if (!d->bootmenu) 262 return; 263 memcpy(d->bootmenu, bootmenu, bootmenu_size); 264 } 265#else 266 if (d->sector_size == 0) 267 return; 268 if (s % d->sector_size != 0) 269 return; 270 if (d->bootmgr) 271 free(d->bootmgr); 272 if (!b) { 273 d->bootmgr = NULL; 274 } else { 275 d->bootmgr_size = s; 276 d->bootmgr = malloc(s); 277 if (!d->bootmgr) 278 return; 279 memcpy(d->bootmgr, b, s); 280 } 281#endif 282#endif 283} 284 285int 286Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 287{ 288#if defined(__i386__) || defined(__amd64__) 289 if (d->boot1) 290 free(d->boot1); 291 d->boot1 = malloc(512); 292 if (!d->boot1) 293 return -1; 294 memcpy(d->boot1, b1, 512); 295 if (d->boot2) 296 free(d->boot2); 297 d->boot2 = malloc(15 * 512); 298 if (!d->boot2) 299 return -1; 300 memcpy(d->boot2, b2, 15 * 512); 301#elif defined(__alpha__) 302 if (d->boot1) 303 free(d->boot1); 304 d->boot1 = malloc(15 * 512); 305 if (!d->boot1) 306 return -1; 307 memcpy(d->boot1, b1, 15 * 512); 308#elif defined(__sparc64__) 309 if (d->boot1 != NULL) 310 free(d->boot1); 311 d->boot1 = malloc(16 * 512); 312 if (d->boot1 == NULL) 313 return (-1); 314 memcpy(d->boot1, b1, 16 * 512); 315#elif defined(__ia64__) 316 /* nothing */ 317#else 318/* Should be: #error "Set_Boot_Blocks: unknown arch"; */ 319#endif 320 return 0; 321} 322 323#ifdef PC98 324const char * 325slice_type_name( int type, int subtype ) 326{ 327 328 switch (type) { 329 case whole: 330 return "whole"; 331 case fat: 332 return "fat"; 333 case freebsd: 334 switch (subtype) { 335 case 0xc494: return "freebsd"; 336 default: return "unknown"; 337 } 338 case unused: 339 return "unused"; 340 default: 341 return "unknown"; 342 } 343} 344#else /* PC98 */ 345const char * 346slice_type_name( int type, int subtype ) 347{ 348 349 switch (type) { 350 case whole: 351 return "whole"; 352 case mbr: 353 switch (subtype) { 354 case 1: return "fat (12-bit)"; 355 case 2: return "XENIX /"; 356 case 3: return "XENIX /usr"; 357 case 4: return "fat (16-bit,<=32Mb)"; 358 case 5: return "extended DOS"; 359 case 6: return "fat (16-bit,>32Mb)"; 360 case 7: return "NTFS/HPFS/QNX"; 361 case 8: return "AIX bootable"; 362 case 9: return "AIX data"; 363 case 10: return "OS/2 bootmgr"; 364 case 11: return "fat (32-bit)"; 365 case 12: return "fat (32-bit,LBA)"; 366 case 14: return "fat (16-bit,>32Mb,LBA)"; 367 case 15: return "extended DOS, LBA"; 368 case 18: return "Compaq Diagnostic"; 369 case 84: return "OnTrack diskmgr"; 370 case 100: return "Netware 2.x"; 371 case 101: return "Netware 3.x"; 372 case 115: return "SCO UnixWare"; 373 case 128: return "Minix 1.1"; 374 case 129: return "Minix 1.5"; 375 case 130: return "linux_swap"; 376 case 131: return "ext2fs"; 377 case 166: return "OpenBSD FFS"; /* 0xA6 */ 378 case 169: return "NetBSD FFS"; /* 0xA9 */ 379 case 182: return "OpenBSD"; /* dedicated */ 380 case 183: return "bsd/os"; 381 case 184: return "bsd/os swap"; 382 case 238: return "EFI GPT"; 383 case 239: return "EFI Sys. Part."; 384 default: return "unknown"; 385 } 386 case fat: 387 return "fat"; 388 case freebsd: 389 switch (subtype) { 390 case 165: return "freebsd"; 391 default: return "unknown"; 392 } 393 case extended: 394 return "extended"; 395 case part: 396 return "part"; 397 case efi: 398 return "efi"; 399 case unused: 400 return "unused"; 401 default: 402 return "unknown"; 403 } 404} 405#endif /* PC98 */ 406