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