disk.c revision 158033
114239Sbde/* 266830Sobrien * ---------------------------------------------------------------------------- 366830Sobrien * "THE BEER-WARE LICENSE" (Revision 42): 466830Sobrien * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 566830Sobrien * can do whatever you want with this stuff. If we meet some day, and you think 666830Sobrien * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 766830Sobrien * ---------------------------------------------------------------------------- 866830Sobrien */ 966830Sobrien 1066830Sobrien#include <sys/cdefs.h> 1166830Sobrien__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 158033 2006-04-25 20:42:15Z maxim $"); 1266830Sobrien 1366830Sobrien#include <stdio.h> 1466830Sobrien#include <stdlib.h> 1566830Sobrien#include <unistd.h> 1666830Sobrien#include <fcntl.h> 1766830Sobrien#include <string.h> 1866830Sobrien#include <inttypes.h> 1966830Sobrien#include <err.h> 2066830Sobrien#include <sys/sysctl.h> 2166830Sobrien#include <sys/stdint.h> 2266830Sobrien#include <sys/types.h> 2366830Sobrien#include <sys/stat.h> 2466830Sobrien#include <sys/ioctl.h> 2566830Sobrien#include <sys/disklabel.h> 2666830Sobrien#include <sys/uuid.h> 2750472Speter#include <sys/gpt.h> 2866830Sobrien#include <paths.h> 2914239Sbde#include "libdisk.h" 30100280Sgordon 31100280Sgordon#include <ctype.h> 32100280Sgordon#include <errno.h> 33100280Sgordon#include <assert.h> 3413798Smpp#include <uuid.h> 351675Sache 367708Srgrimesconst enum platform platform = 371675Sache#if defined (P_DEBUG) 381675Sache P_DEBUG 391675Sache#elif defined (PC98) 401675Sache p_pc98 411675Sache#elif defined(__i386__) 421675Sache p_i386 431675Sache#elif defined(__alpha__) 441675Sache p_alpha 451675Sache#elif defined(__sparc64__) 461675Sache p_sparc64 4714239Sbde#elif defined(__ia64__) 4814239Sbde p_ia64 4914239Sbde#elif defined(__ppc__) 5014239Sbde p_ppc 511675Sache#elif defined(__amd64__) 521675Sache p_amd64 5395305Ssobomax#elif defined(__arm__) 5450454Ssheldonh p_arm 5550357Ssheldonh#else 5650454Ssheldonh IHAVENOIDEA 5750357Ssheldonh#endif 581675Sache ; 591675Sache 601675Sacheconst char * 611675Sachechunk_name(chunk_e type) 621675Sache{ 6314239Sbde switch(type) { 6414239Sbde case unused: return ("unused"); 6514239Sbde case mbr: return ("mbr"); 6614239Sbde case part: return ("part"); 671675Sache case gpt: return ("gpt"); 681675Sache case pc98: return ("pc98"); 691675Sache case sun: return ("sun"); 7050357Ssheldonh case freebsd: return ("freebsd"); 7150357Ssheldonh case fat: return ("fat"); 721675Sache case spare: return ("spare"); 7350357Ssheldonh case efi: return ("efi"); 741675Sache case apple: return ("apple"); 751675Sache default: return ("??"); 7650357Ssheldonh } 7750357Ssheldonh} 781675Sache 791675Sachestruct disk * 801675SacheOpen_Disk(const char *name) 811675Sache{ 821675Sache struct disk *d; 8314239Sbde char *conftxt; 8414239Sbde size_t txtsize; 8514239Sbde int error; 8614239Sbde 871675Sache error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0); 881675Sache if (error) { 897708Srgrimes warn("kern.geom.conftxt sysctl not available, giving up!"); 9050357Ssheldonh return (NULL); 911675Sache } 921675Sache conftxt = malloc(txtsize+1); 9350357Ssheldonh if (conftxt == NULL) { 9450357Ssheldonh warn("cannot malloc memory for conftxt"); 9550357Ssheldonh return (NULL); 9650357Ssheldonh } 971675Sache error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0); 981675Sache if (error) { 991675Sache warn("error reading kern.geom.conftxt from the system"); 1001675Sache free(conftxt); 1011675Sache return (NULL); 10214239Sbde } 10314239Sbde conftxt[txtsize] = '\0'; /* in case kernel bug is still there */ 10414239Sbde d = Int_Open_Disk(name, conftxt); 10514239Sbde free(conftxt); 1061675Sache 1071675Sache return (d); 1081675Sache} 1091675Sache 11050357Ssheldonhvoid 11150357SsheldonhDebug_Disk(struct disk *d) 11250357Ssheldonh{ 11350357Ssheldonh 1141675Sache printf("Debug_Disk(%s)", d->name); 1151675Sache 1161675Sache#ifndef __ia64__ 1171675Sache printf(" bios_geom=%lu/%lu/%lu = %lu\n", 1181675Sache d->bios_cyl, d->bios_hd, d->bios_sect, 1191675Sache d->bios_cyl * d->bios_hd * d->bios_sect); 1201675Sache#if defined(PC98) 1211675Sache printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 1221675Sache d->boot1, d->boot2, d->bootipl, d->bootmenu); 1231675Sache#elif defined(__i386__) || defined(__amd64__) 12414239Sbde printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 12514239Sbde d->boot1, d->boot2, d->bootmgr); 12614239Sbde#elif defined(__alpha__) 12714239Sbde printf(" boot1=%p, bootmgr=%p\n", 12850357Ssheldonh d->boot1, d->bootmgr); 1291675Sache#else 1301675Sache/* Should be: error "Debug_Disk: unknown arch"; */ 13150357Ssheldonh#endif 13250357Ssheldonh#else /* __ia64__ */ 13350357Ssheldonh printf(" media size=%lu, sector size=%lu\n", d->media_size, 1341675Sache d->sector_size); 1351675Sache#endif 1361675Sache 1371675Sache Debug_Chunk(d->chunks); 1381675Sache} 13914239Sbde 1401675Sachevoid 14114239SbdeFree_Disk(struct disk *d) 14214239Sbde{ 14314239Sbde if (d->chunks) 14414239Sbde Free_Chunk(d->chunks); 14514239Sbde if (d->name) 14614239Sbde free(d->name); 14714239Sbde#ifdef PC98 14814239Sbde if (d->bootipl) 14914239Sbde free(d->bootipl); 15014239Sbde if (d->bootmenu) 15134561Sdanny free(d->bootmenu); 15214239Sbde#else 15314239Sbde#if !defined(__ia64__) 15434561Sdanny if (d->bootmgr) 15514239Sbde free(d->bootmgr); 15614239Sbde#endif 15723607Sbde#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 57: return "Plan 9"; 354 case 77: return "QNX 4.X"; 355 case 78: return "QNX 4.X 2nd part"; 356 case 79: return "QNX 4.X 3rd part"; 357 case 84: return "OnTrack diskmgr"; 358 case 100: return "Netware 2.x"; 359 case 101: return "Netware 3.x"; 360 case 115: return "SCO UnixWare"; 361 case 128: return "Minix 1.1"; 362 case 129: return "Minix 1.5"; 363 case 130: return "linux_swap"; 364 case 131: return "ext2fs"; 365 case 133: return "linux extended"; 366 case 166: return "OpenBSD FFS"; /* 0xA6 */ 367 case 168: return "Mac OS-X"; 368 case 169: return "NetBSD FFS"; /* 0xA9 */ 369 case 171: return "Mac OS-X Boot"; 370 case 182: return "OpenBSD"; /* dedicated */ 371 case 183: return "bsd/os"; 372 case 184: return "bsd/os swap"; 373 case 191: return "Solaris (new)"; 374 case 238: return "EFI GPT"; 375 case 239: return "EFI Sys. Part."; 376 default: return "unknown"; 377 } 378 case fat: 379 return "fat"; 380 case freebsd: 381 switch (subtype) { 382#ifdef PC98 383 case 0xc494: return "freebsd"; 384#else 385 case 165: return "freebsd"; 386#endif 387 default: return "unknown"; 388 } 389 case extended: 390 return "extended"; 391 case part: 392 return "part"; 393 case efi: 394 return "efi"; 395 case unused: 396 return "unused"; 397 default: 398 return "unknown"; 399 } 400} 401