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