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