1/* 2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/types.h> 25#include <CoreFoundation/CoreFoundation.h> 26#include <DiskArbitration/DiskArbitrationPrivate.h> 27#include <IOKit/IOKitLib.h> 28 29#include <fcntl.h> 30#include <dirent.h> 31#include <fsproperties.h> 32#include <paths.h> 33#include <unistd.h> 34#include <sys/ioctl.h> 35#include <sys/loadable_fs.h> 36#include <sys/mount.h> 37#include <sys/param.h> 38#include <sys/stat.h> 39#include <sys/ttycom.h> 40#include <sys/wait.h> 41#include <IOKit/IOBSD.h> 42#include <IOKit/storage/IOMedia.h> 43 44#define dwarning(a) { if (g.debug) { printf a; fflush(stdout); } } 45#define pwarning(a) { printf a; fflush(stdout); } 46 47#define APPLE_BOOT_UUID "426F6F74-0000-11AA-AA11-00306543ECAC" 48 49mach_port_t ioMasterPort; 50 51CFMutableDictionaryRef plistDict = nil; 52CFMutableArrayRef matchingArray = nil; 53 54struct Disk { 55 struct Disk * next; 56 char * ioBSDName; 57 unsigned flags; 58 io_object_t service; 59 UInt64 ioSize; 60}; 61 62typedef struct Disk Disk; 63typedef struct Disk * DiskPtr; 64 65typedef struct { 66 boolean_t verbose; 67 boolean_t debug; 68 DiskPtr Disks; 69 unsigned NumDisks; 70} GlobalStruct; 71 72GlobalStruct g; 73 74struct DiskVolume 75{ 76 char * fs_type; 77 char * disk_dev_name; 78 char * disk_name; 79 boolean_t removable; 80 boolean_t writable; 81 boolean_t internal; 82 boolean_t dirty; 83 boolean_t mounted; 84 UInt64 size; 85}; 86 87typedef struct DiskVolume DiskVolume, *DiskVolumePtr; 88 89struct DiskVolumes 90{ 91 CFMutableArrayRef list; 92}; 93typedef struct DiskVolumes DiskVolumes, *DiskVolumesPtr; 94 95 96char * 97daCreateCStringFromCFString(CFStringRef string) 98{ 99 /* 100 * result of daCreateCStringFromCFString should be released with free() 101 */ 102 103 CFStringEncoding encoding = kCFStringEncodingMacRoman; 104 CFIndex bufferLength = CFStringGetLength(string) + 1; 105 char *buffer = malloc(bufferLength); 106 107 if (buffer) { 108 if (CFStringGetCString(string, buffer, bufferLength, encoding) == FALSE) { 109 free(buffer); 110 buffer = malloc(1); 111 //See Radar 2457357. 112 buffer[0] = '\0'; 113 //See Radar 2457357. 114 } 115 } 116 return buffer; 117} /* daCreateCStringFromCFString */ 118 119char * 120fsDirForFS(char *fsname) 121{ 122 char *fsDir = malloc(MAXPATHLEN); 123 sprintf(fsDir, "%s/%s%s", FS_DIR_LOCATION, fsname, FS_DIR_SUFFIX); 124 return fsDir; 125 126} 127 128int 129suffixfs(const struct dirent * dp) 130{ 131 char *s; 132 if ((s = strstr(&dp->d_name[0], FS_DIR_SUFFIX))) 133 if (strlen(s) == strlen(FS_DIR_SUFFIX)) 134 return (1); 135 return (0); 136} 137 138void 139cacheFileSystemDictionaries() 140{ 141 142 if (!plistDict) { 143 144 struct dirent **fsdirs = NULL; 145 int nfs = 0; /* # filesystems defined in 146 * /usr/filesystems */ 147 int n; 148 149 plistDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 150 151 /* discover known filesystem types */ 152 nfs = scandir(FS_DIR_LOCATION, &fsdirs, suffixfs, NULL); 153 154 dwarning(("%d filesystems known:\n", nfs)); 155 for (n = 0; n < nfs; n++) { 156 char buf[MAXPATHLEN]; 157 CFDictionaryRef fsdict; 158 CFStringRef str; 159 CFURLRef bar; 160 CFStringRef zaz; 161 162 dwarning(("%s\n", &fsdirs[n]->d_name[0])); 163 sprintf(buf, "%s/%s", FS_DIR_LOCATION, &fsdirs[n]->d_name[0]); 164 //get their dictionaries, test that they are okay and add them into the plistDict 165 166 str = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); 167 bar = CFURLCreateWithFileSystemPath(NULL, str, kCFURLPOSIXPathStyle, 1); 168 169 fsdict = CFBundleCopyInfoDictionaryInDirectory(bar); 170 171 zaz = CFStringCreateWithCString(NULL, &fsdirs[n]->d_name[0], kCFStringEncodingUTF8); 172 173 CFDictionaryAddValue(plistDict, zaz, fsdict); 174 175 CFRelease(zaz); 176 CFRelease(bar); 177 CFRelease(str); 178 CFRelease(fsdict); 179 180 } 181 if (fsdirs) { 182 for (n = 0; n < nfs; n++) { 183 free((void *) fsdirs[n]); 184 } 185 free((void *) fsdirs); 186 } 187 } 188} 189 190CFComparisonResult 191compareDicts(const void *val1, const void *val2, void *context) 192{ 193 int val1ProbeOrder; 194 int val2ProbeOrder; 195 196 CFNumberRef val1Number = CFDictionaryGetValue(val1, CFSTR(kFSProbeOrderKey)); 197 CFNumberRef val2Number = CFDictionaryGetValue(val2, CFSTR(kFSProbeOrderKey)); 198 199 CFNumberGetValue(val1Number, kCFNumberIntType, &val1ProbeOrder); 200 CFNumberGetValue(val2Number, kCFNumberIntType, &val2ProbeOrder); 201 202 //printf("%d, %d\n", val1ProbeOrder, val2ProbeOrder); 203 204 if (val1ProbeOrder > val2ProbeOrder) { 205 return kCFCompareGreaterThan; 206 } else if (val1ProbeOrder < val2ProbeOrder) { 207 return kCFCompareLessThan; 208 } 209 return kCFCompareEqualTo; 210} 211 212void 213cacheFileSystemMatchingArray() 214{ 215 if (!matchingArray) { 216 217 struct dirent **fsdirs = NULL; 218 int nfs = 0; /* # filesystems defined in 219 * /usr/filesystems */ 220 int n; 221 int i = 0; 222 223 matchingArray = CFArrayCreateMutable(NULL, 0, NULL); 224 225 /* discover known filesystem types */ 226 nfs = scandir(FS_DIR_LOCATION, &fsdirs, suffixfs, NULL); 227 228 for (n = 0; n < nfs; n++) { 229 char buf[MAXPATHLEN]; 230 CFDictionaryRef fsdict; 231 CFDictionaryRef mediaTypeDict; 232 CFStringRef str; 233 CFURLRef bar; 234 235 sprintf(buf, "%s/%s", FS_DIR_LOCATION, &fsdirs[n]->d_name[0]); 236 //get their dictionaries, test that they are okay and add them into the plistDict 237 238 str = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); 239 bar = CFURLCreateWithFileSystemPath(NULL, str, kCFURLPOSIXPathStyle, 1); 240 241 fsdict = CFBundleCopyInfoDictionaryInDirectory(bar); 242 243 mediaTypeDict = CFDictionaryGetValue(fsdict, CFSTR(kFSMediaTypesKey)); 244 245 246 if (mediaTypeDict != NULL) { 247 int j = CFDictionaryGetCount(mediaTypeDict); 248 CFDictionaryRef *dicts = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * j); 249 CFDictionaryGetKeysAndValues(mediaTypeDict, NULL, (const void **) dicts); 250 251 for (i = 0; i < j; i++) { 252 CFStringRef zaz; 253 254 CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy(NULL, 0, dicts[i]); 255 zaz = CFStringCreateWithCString(NULL, &fsdirs[n]->d_name[0], kCFStringEncodingUTF8); 256 CFDictionaryAddValue(newDict, CFSTR("FSName"), zaz); 257 CFArrayAppendValue(matchingArray, newDict); 258 CFRelease(zaz); 259 } 260 free(dicts); 261 262 } 263 CFRelease(fsdict); 264 CFRelease(str); 265 CFRelease(bar); 266 267 } 268 if (fsdirs) { 269 for (n = 0; n < nfs; n++) { 270 free((void *) fsdirs[n]); 271 } 272 free((void *) fsdirs); 273 } 274 CFArraySortValues(matchingArray, CFRangeMake(0, CFArrayGetCount(matchingArray)), compareDicts, NULL); 275 } 276} 277 278char * 279resourcePathForFSName(char *fs) 280{ 281 char bundlePath[MAXPATHLEN]; 282 CFBundleRef bundle; 283 CFURLRef bundleUrl; 284 CFURLRef resourceUrl; 285 CFStringRef resourceString; 286 char *path; 287 char *resourcePath = malloc(MAXPATHLEN); 288 CFStringRef str; 289 290 sprintf(bundlePath, "%s/%s", FS_DIR_LOCATION, fs); 291 292 str = CFStringCreateWithCString(NULL, bundlePath, kCFStringEncodingMacRoman); 293 294 bundleUrl = CFURLCreateWithFileSystemPath(NULL, str, kCFURLPOSIXPathStyle, 1); 295 CFRelease(str); 296 bundle = CFBundleCreate(NULL, bundleUrl); 297 resourceUrl = CFBundleCopyResourcesDirectoryURL(bundle); 298 resourceString = CFURLCopyPath(resourceUrl); 299 300 path = daCreateCStringFromCFString(resourceString); 301 302 sprintf(resourcePath, "%s/%s", bundlePath, path); 303 304 CFRelease(bundleUrl); 305 CFRelease(bundle); 306 CFRelease(resourceUrl); 307 CFRelease(resourceString); 308 free(path); 309 310 return resourcePath; 311} 312 313char * 314repairPathForFileSystem(char *fsname) 315{ 316 CFDictionaryRef fsDict; 317 CFDictionaryRef personalities; 318 CFDictionaryRef personality; 319 CFStringRef fsckPath1; 320 char fs[128]; 321 char *fsckPath; 322 char *finalPath = malloc(MAXPATHLEN); 323 CFStringRef str; 324 325 if (strlen(fsname) == 0) { 326 return finalPath; 327 } 328 sprintf(fs, "%s%s", fsname, FS_DIR_SUFFIX); 329 str = CFStringCreateWithCString(NULL, fs, kCFStringEncodingMacRoman); 330 fsDict = (CFDictionaryRef) CFDictionaryGetValue(plistDict, str); 331 CFRelease(str); 332 333 if (!fsDict) { 334 return finalPath; 335 } 336 personalities = (CFDictionaryRef) CFDictionaryGetValue(fsDict, CFSTR(kFSPersonalitiesKey)); 337 338 { 339 int persCount = CFDictionaryGetCount(personalities); 340 CFDictionaryRef *dicts = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * persCount); 341 CFDictionaryGetKeysAndValues(personalities, NULL, (const void **) dicts); 342 personality = (CFDictionaryRef) dicts[0]; 343 free(dicts); 344 //(CFDictionaryRef) CFArrayGetValueAtIndex(personalities, 0); 345 346 } 347 348 fsckPath1 = (CFStringRef) CFDictionaryGetValue(personality, CFSTR(kFSRepairExecutableKey)); 349 350 if (fsckPath1) { 351 char *resourcePath = resourcePathForFSName(fs); 352 fsckPath = daCreateCStringFromCFString(fsckPath1); 353 354 sprintf(finalPath, "%s%s", resourcePath, fsckPath); 355 356 free(resourcePath); 357 free(fsckPath); 358 } 359 return finalPath; 360 361} 362 363char * 364repairArgsForFileSystem(char *fsname) 365{ 366 CFDictionaryRef fsDict; 367 CFDictionaryRef personalities; 368 CFDictionaryRef personality; 369 CFStringRef repairArgs1; 370 char fs[128]; 371 char *repairArgs; 372 CFStringRef str; 373 374 if (strlen(fsname) == 0) { 375 repairArgs = malloc(MAXPATHLEN); 376 return repairArgs; 377 } 378 sprintf(fs, "%s%s", fsname, FS_DIR_SUFFIX); 379 str = CFStringCreateWithCString(NULL, fs, kCFStringEncodingMacRoman); 380 fsDict = (CFDictionaryRef) CFDictionaryGetValue(plistDict, str); 381 CFRelease(str); 382 383 if (!fsDict) { 384 repairArgs = malloc(MAXPATHLEN); 385 return repairArgs; 386 } 387 personalities = (CFDictionaryRef) CFDictionaryGetValue(fsDict, CFSTR(kFSPersonalitiesKey)); 388 389 { 390 int persCount = CFDictionaryGetCount(personalities); 391 CFDictionaryRef *dicts = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * persCount); 392 CFDictionaryGetKeysAndValues(personalities, NULL, (const void **) dicts); 393 personality = (CFDictionaryRef) dicts[0]; 394 free(dicts); 395 //(CFDictionaryRef) CFArrayGetValueAtIndex(personalities, 0); 396 397 } 398 399 repairArgs1 = (CFStringRef) CFDictionaryGetValue(personality, CFSTR(kFSRepairArgumentsKey)); 400 401 if (repairArgs1) { 402 repairArgs = daCreateCStringFromCFString(repairArgs1); 403 } else { 404 repairArgs = malloc(MAXPATHLEN); 405 } 406 407 408 return repairArgs; 409 410} 411 412#define PIPEFULL (4 * 1024) 413static char * 414read_output(int fd) 415{ 416 char * buf = NULL; 417 ssize_t count; 418 ssize_t where = 0; 419 420 buf = malloc(PIPEFULL); 421 if (buf == NULL) { 422 return (NULL); 423 } 424 425 /* this handles up to PIPEFULL - 1 bytes */ 426 while (where < (PIPEFULL - 1) 427 && (count = read(fd, buf + where, PIPEFULL - 1 - where))) { 428 if (count == -1) { 429 free(buf); 430 return (NULL); 431 } 432 where += count; 433 } 434 buf[where] = '\0'; 435 return (buf); 436} 437 438void 439cleanUpAfterFork(int fdp[]) 440{ 441 int fd, maxfd = getdtablesize(); 442 443 /* Close all inherited file descriptors */ 444 445 for (fd = 0; fd < maxfd; fd++) 446 { 447 if (fdp == NULL || (fdp[0] != fd && fdp[1] != fd)) { 448 close(fd); 449 } 450 } 451 452 /* Disassociate ourselves from any controlling tty */ 453 454 if ((fd = open("/dev/tty", O_NDELAY)) >= 0) 455 { 456 ioctl(fd, TIOCNOTTY, 0); 457 close(fd); 458 } 459 460 /* Reset the user and group id's to their real values */ 461 462 setgid(getgid()); 463 setuid(getuid()); 464 465 (void)setsid(); 466 467 (void)chdir("/"); 468 469 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 470 /* point stdin -> /dev/null */ 471 (void)dup2(fd, STDIN_FILENO); 472 if (fdp != NULL) { 473 /* point stdout to one end of pipe fdp[1] */ 474 (void)dup2(fdp[1], STDOUT_FILENO); 475 476 /* close the other end */ 477 close(fdp[0]); 478 } 479 else { 480 (void)dup2(fd, STDOUT_FILENO); 481 } 482 (void)dup2(fd, STDERR_FILENO); 483 if (fd > 2) 484 (void)close (fd); 485 } 486 return; 487} 488 489boolean_t 490do_exec(const char * dir, const char * argv[], int * result, 491 char * * output) 492{ 493 int fdp[2]; 494 boolean_t got_result = FALSE; 495 int pid; 496 497 if (g.debug) { 498 const char * * scan; 499 printf("do_exec("); 500 for (scan = argv; *scan; scan++) { 501 printf("%s%s", (scan != argv) ? " " : "", *scan); 502 } 503 printf(")\n"); 504 } 505 if (output != NULL) { 506 *output = NULL; 507 if (pipe(fdp) == -1) { 508 pwarning(("do_exec(): pipe() failed, %s", 509 strerror(errno))); 510 return (FALSE); 511 } 512 } 513 if (access(argv[0], F_OK) == 0) { 514 pid = fork(); 515 if (pid == 0) { 516 /* CHILD PROCESS */ 517 if (output == NULL) 518 cleanUpAfterFork(NULL); 519 else 520 cleanUpAfterFork(fdp); 521 522 if (dir) { 523 chdir(dir); 524 } 525 execve(argv[0], (char * const *)argv, 0); 526 exit(-127); 527 } 528 else if (pid > 0) { /* PARENT PROCESS */ 529 int statusp; 530 int waitResult; 531 532 if (output != NULL) { 533 close(fdp[1]); 534 *output = read_output(fdp[0]); 535 close(fdp[0]); 536 } 537 dwarning(("wait4(pid=%d,&statusp,0,NULL)...\n", pid)); 538 waitResult = wait4(pid,&statusp,0,NULL); 539 dwarning(("wait4(pid=%d,&statusp,0,NULL) => %d\n", 540 pid, waitResult)); 541 if (waitResult > 0 542 && WIFEXITED(statusp)) { 543 got_result = TRUE; 544 *result = (int)(char)(WEXITSTATUS(statusp)); 545 } 546 } 547 else { 548 pwarning(("do_exec: fork() failed, %s", 549 strerror(errno))); 550 } 551 } 552 return (got_result); 553} 554 555DiskPtr NewDisk( char * ioBSDName, 556 io_object_t service, 557 unsigned flags, 558 UInt64 ioSize) 559{ 560 DiskPtr result; 561 562 dwarning(("%s(ioBSDName = '%s', flags = $%08x)\n", 563 __FUNCTION__, 564 ioBSDName, 565 flags )); 566 567 /* Allocate memory */ 568 569 result = (DiskPtr) malloc( sizeof( * result ) ); 570 if ( result == NULL ) 571 { 572 dwarning(("%s(...): malloc failed!\n", __FUNCTION__)); 573 /* result = NULL; */ 574 goto Return; 575 } 576 577 bzero( result, sizeof( * result ) ); 578 579 /* Link it onto the front of the list */ 580 581 result->next = g.Disks; 582 g.Disks = result; 583 584 /* Fill in the fields */ 585 586 result->ioBSDName = strdup( ioBSDName ? ioBSDName : "" ); 587 result->service = service; 588 result->ioSize = ioSize; 589 590 result->flags = flags; 591 592 /* Increment count */ 593 594 g.NumDisks ++ ; 595 596 /* Retain service */ 597 598 if ( service ) 599 { 600 IOObjectRetain( service ); 601 } 602 603Return: 604 return result; 605 606} // NewDisk 607 608static struct statfs * 609get_fsstat_list(int * number) 610{ 611 int n; 612 struct statfs * stat_p; 613 614 n = getfsstat(NULL, 0, MNT_NOWAIT); 615 if (n <= 0) 616 { 617 return (NULL); 618 } 619 620 stat_p = (struct statfs *)malloc(n * sizeof(*stat_p)); 621 if (stat_p == NULL) 622 { 623 return (NULL); 624 } 625 626 if (getfsstat(stat_p, n * sizeof(*stat_p), MNT_NOWAIT) <= 0) 627 { 628 free(stat_p); 629 return (NULL); 630 } 631 *number = n; 632 633 return (stat_p); 634} 635 636static struct statfs * 637fsstat_lookup_spec(struct statfs * list_p, int n, dev_t dev, char * fstype) 638{ 639 int i; 640 struct statfs * scan; 641 642 for (i = 0, scan = list_p; i < n; i++, scan++) 643 { 644 if (strcmp(scan->f_fstypename, fstype) == 0 645 && scan->f_fsid.val[0] == dev) { 646 return (scan); 647 } 648 } 649 return (NULL); 650} 651 652boolean_t 653fsck_needed(char * devname, char * fstype) 654{ 655 const char * argv[] = { 656 NULL, 657 "-q", 658 NULL, 659 NULL, 660 }; 661 char devpath[64]; 662 int result; 663 char *fsckCmd = repairPathForFileSystem(fstype); 664 665 snprintf(devpath, sizeof(devpath), "/dev/r%s", devname); 666 argv[0] = fsckCmd; 667 argv[2]= devpath; 668 if (do_exec(NULL, argv, &result, NULL) == FALSE) { 669 result = -1; 670 } 671 dwarning(("%s('%s'): '%s' => %d\n", __FUNCTION__, devname, fsckCmd, 672 result)); 673 free(fsckCmd); 674 675 if (result <= 0) { 676 return (FALSE); 677 } 678 return (TRUE); 679} 680 681/* foreignProbe: run the -p(robe) option of the given <fsName>.util program in a child process */ 682/* returns the volume name in volname_p */ 683 684static int 685foreignProbe(const char *fsName, const char *execPath, const char *probeCmd, const char *devName, int removable, int writable, char * * volname_p) 686{ 687 int result; 688 const char *childArgv[] = { execPath, 689 probeCmd, 690 devName, 691 removable ? DEVICE_REMOVABLE : DEVICE_FIXED, 692 writable? DEVICE_WRITABLE : DEVICE_READONLY, 693 0 }; 694 char *fsDir = fsDirForFS((char *)fsName); 695 696 dwarning(("%s('%s', '%s', removable=%d, writable=%d):\n'%s %s %s %s %s'\n", 697 __FUNCTION__, fsName, devName, removable, writable, execPath, childArgv[1], childArgv[2], childArgv[3], childArgv[4])); 698 699 700 if (do_exec(fsDir, childArgv, &result, volname_p) == FALSE) { 701 result = FSUR_IO_FAIL; 702 } 703 dwarning(("%s(...) => %d\n", __FUNCTION__, result)); 704 free(fsDir); 705 return result; 706} 707 708void setVar(char **var,char *val) 709{ 710 if (*var) 711 { 712 free(*var); 713 } 714 if (val == NULL) 715 { 716 *var = NULL; 717 } 718 else 719 { 720 *var = strdup(val); 721 } 722 723} 724void DiskVolume_setFSType(DiskVolumePtr diskVolume,char *t) 725{ 726 setVar(&(diskVolume->fs_type),t); 727} 728void DiskVolume_setDiskName(DiskVolumePtr diskVolume,char *t) 729{ 730 setVar(&(diskVolume->disk_name),t); 731} 732void DiskVolume_setDiskDevName(DiskVolumePtr diskVolume,char *t) 733{ 734 setVar(&(diskVolume->disk_dev_name),t); 735} 736void DiskVolume_setMounted(DiskVolumePtr diskVolume,boolean_t val) 737{ 738 diskVolume->mounted = val; 739} 740 741void DiskVolume_setWritable(DiskVolumePtr diskVolume,boolean_t val) 742{ 743 diskVolume->writable = val; 744} 745void DiskVolume_setRemovable(DiskVolumePtr diskVolume,boolean_t val) 746{ 747 diskVolume->removable = val; 748} 749void DiskVolume_setInternal(DiskVolumePtr diskVolume,boolean_t val) 750{ 751 diskVolume->internal = val; 752} 753void DiskVolume_setDirtyFS(DiskVolumePtr diskVolume,boolean_t val) 754{ 755 diskVolume->dirty = val; 756} 757void DiskVolume_new(DiskVolumePtr *diskVolume) 758{ 759 *diskVolume = malloc(sizeof(DiskVolume)); 760 (*diskVolume)->fs_type = nil; 761 (*diskVolume)->disk_dev_name = nil; 762 (*diskVolume)->disk_name = nil; 763} 764void DiskVolume_delete(DiskVolumePtr diskVolume) 765{ 766 int i; 767 char * * l[] = { &(diskVolume->fs_type), 768 &(diskVolume->disk_dev_name), 769 &(diskVolume->disk_name), 770 NULL }; 771 772 773 if(!diskVolume) 774 return; 775 776 for (i = 0; l[i] != NULL; i++) 777 { 778 if (*(l[i])) 779 { 780 free(*(l[i])); 781 } 782 *(l[i]) = NULL; 783 } 784 785 free(diskVolume); 786} 787 788static dev_t 789dev_from_spec(const char * specName) 790{ 791 struct stat sb; 792 793 if (stat(specName, &sb)) { 794 return (-1); 795 } 796 if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { 797 return (sb.st_rdev); 798 } 799 return (-1); 800} 801 802#define MAXNAMELEN 256 803DiskVolumePtr 804DiskVolumes_newVolume(DiskVolumesPtr diskList, DiskPtr media, boolean_t isRemovable, 805 boolean_t isWritable, boolean_t isInternal, 806 struct statfs * stat_p, int stat_number, UInt64 ioSize) 807{ 808 char * devname = media->ioBSDName; 809 struct statfs * fs_p; 810 dev_t fs_dev; 811 char * fsname = NULL; 812 int ret; 813 char specName[MAXNAMELEN]; 814 DiskVolumePtr volume = 0x0; 815 int matchingPointer = 0; 816 int count = CFArrayGetCount(matchingArray); 817 818 for (matchingPointer = 0;matchingPointer < count;matchingPointer++) { 819 820 // see if the diskPtr->service matches any of the filesystem types 821 // if it does test that first 822 // otherwise, start at the top of the list and test them alls 823 int matches; 824 CFDictionaryRef dictPointer = CFArrayGetValueAtIndex(matchingArray, matchingPointer); 825 CFDictionaryRef mediaProps = CFDictionaryGetValue(dictPointer, CFSTR(kFSMediaPropertiesKey)); 826 kern_return_t error; 827 828 error = IOServiceMatchPropertyTable(media->service, mediaProps, &matches); 829 830 if (error) { 831 dwarning(("some kind of error while matching service to array... %d\n", error)); 832 } 833 834 if (matches) { 835 CFStringRef utilArgsFromDict; 836 CFStringRef fsNameFromDict; 837 CFArrayRef fsNameArray; 838 CFStringRef utilPathFromDict; 839 840 char *utilPathFromDict2; 841 char *utilArgsFromDict2; 842 char *fsNameFromDict2; 843 char *fstype; 844 char *resourcePath; 845 846 char utilPath[MAXPATHLEN]; 847 848 dwarning(("********We have a match for devname = %s!!!**********\n", devname)); 849 850 utilArgsFromDict = CFDictionaryGetValue(dictPointer, CFSTR(kFSProbeArgumentsKey)); 851 fsNameFromDict = CFDictionaryGetValue(dictPointer, CFSTR("FSName")); 852 fsNameArray = CFStringCreateArrayBySeparatingStrings(NULL, fsNameFromDict, CFSTR(".")); 853 utilPathFromDict = CFDictionaryGetValue(dictPointer, CFSTR(kFSProbeExecutableKey)); 854 855 utilPathFromDict2 = daCreateCStringFromCFString(utilPathFromDict); 856 utilArgsFromDict2 = daCreateCStringFromCFString(utilArgsFromDict); 857 fsNameFromDict2 = daCreateCStringFromCFString(fsNameFromDict); 858 fstype = daCreateCStringFromCFString(CFArrayGetValueAtIndex(fsNameArray, 0)); 859 resourcePath = resourcePathForFSName(fsNameFromDict2); 860 861 sprintf(utilPath, "%s%s", resourcePath, utilPathFromDict2); 862 863 // clean up 864 CFRelease(fsNameArray); 865 free(utilPathFromDict2); 866 free(fsNameFromDict2); 867 free(resourcePath); 868 869 ret = foreignProbe(fstype, utilPath, utilArgsFromDict2, devname, isRemovable, isWritable, &fsname); 870 871 free(utilArgsFromDict2); 872 873 if (ret == FSUR_RECOGNIZED || ret == -9) 874 { 875 if (fsname == NULL) { 876 fsname = strdup(fstype); 877 } 878 879 DiskVolume_new(&volume); 880 DiskVolume_setDiskDevName(volume,devname); 881 DiskVolume_setFSType(volume,fstype); 882 DiskVolume_setDiskName(volume,fsname); 883 DiskVolume_setWritable(volume,isWritable); 884 DiskVolume_setRemovable(volume,isRemovable); 885 DiskVolume_setInternal(volume,isInternal); 886 DiskVolume_setMounted(volume,FALSE); 887 DiskVolume_setDirtyFS(volume,FALSE); 888 volume->size = ioSize; 889 890 sprintf(specName,"/dev/%s",devname); 891 fs_dev = dev_from_spec(specName); 892 893 fs_p = fsstat_lookup_spec(stat_p, stat_number, fs_dev, fstype); 894 if (fs_p) 895 { 896 /* already mounted */ 897 DiskVolume_setMounted(volume,TRUE); 898 } 899 else if (isWritable) 900 { 901 DiskVolume_setDirtyFS(volume,fsck_needed(devname,fstype)); 902 } 903 free(fstype); 904 if (fsname) 905 free(fsname); 906 fsname = NULL; 907 break; 908 } else { 909 free(fstype); 910 if (fsname) 911 free(fsname); 912 fsname = NULL; 913 dwarning(("Volume is bad\n")); 914 volume = 0x0; 915 } 916 917 } 918 } 919 920 return volume; 921} 922void DiskVolumes_new(DiskVolumesPtr *diskList) 923{ 924 *diskList = malloc(sizeof(DiskVolumes)); 925 (*diskList)->list = CFArrayCreateMutable(NULL,0,NULL); 926} 927void DiskVolumes_delete(DiskVolumesPtr diskList) 928{ 929 int i; 930 int count = CFArrayGetCount(diskList->list); 931 if(!diskList) 932 return; 933 934 for (i = 0; i < count; i++) 935 { 936 DiskVolume_delete((DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,i)); 937 } 938 939 CFArrayRemoveAllValues(diskList->list); 940 941 CFRelease(diskList->list); 942 943 free(diskList); 944} 945 946DiskVolumesPtr DiskVolumes_do_volumes(DiskVolumesPtr diskList) 947{ 948 DiskPtr diskPtr; 949 boolean_t success = FALSE; 950 struct statfs * stat_p; 951 int stat_number; 952 int nfs = 0; /* # filesystems defined in /usr/filesystems */ 953 struct dirent **fsdirs = NULL; 954 int n; /* iterator for nfs/fsdirs */ 955 956 stat_p = get_fsstat_list(&stat_number); 957 if (stat_p == NULL || stat_number == 0) 958 { 959 goto Return; 960 } 961 962 /* discover known filesystem types */ 963 nfs = scandir(FS_DIR_LOCATION, &fsdirs, suffixfs, NULL); 964 /* 965 * suffixfs ensured we have only names ending in ".fs" 966 * now we convert the periods to nulls to give us 967 * filesystem type strings. 968 */ 969 for (n = 0; n < nfs; n++) 970 { 971 *strrchr(&fsdirs[n]->d_name[0], '.') = '\0'; 972 } 973 if ( g.debug ) { 974 dwarning(("%d filesystems known:\n", nfs)); 975 for (n=0; n<nfs; n++) 976 { 977 dwarning(("%s\n", &fsdirs[n]->d_name[0])); 978 } 979 } 980 981 for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next ) 982 { 983 int isWritable, isRemovable, isInternal; 984 DiskVolumePtr volume = 0x0; 985 986 /* Initialize some convenient flags */ 987 988 isWritable = ( diskPtr->flags & kDiskArbDiskAppearedLockedMask ) == 0; 989 isRemovable = ( diskPtr->flags & kDiskArbDiskAppearedEjectableMask ) != 0; 990 isInternal = ( diskPtr->flags & kDiskArbDiskAppearedInternal ) != 0; 991 992 if ((diskPtr->flags & kDiskArbDiskAppearedNoSizeMask) != 0) { 993 continue; // if it's zero length, skip it 994 }; 995 996 volume = DiskVolumes_newVolume(diskList, 997 diskPtr, 998 isRemovable, 999 isWritable, 1000 isInternal, 1001 stat_p, 1002 stat_number, 1003 diskPtr->ioSize); 1004 1005 if (volume != nil) { 1006 CFArrayAppendValue(diskList->list,volume); 1007 } 1008 1009 } /* for */ 1010 1011 success = TRUE; 1012 1013Return: 1014 if (fsdirs) { 1015 for (n = 0; n < nfs; n++) { 1016 free((void *)fsdirs[n]); 1017 } 1018 free((void *)fsdirs); 1019 } 1020 if (stat_p) 1021 { 1022 free(stat_p); 1023 } 1024 1025 if (success) 1026 { 1027 return diskList; 1028 } 1029 1030 DiskVolumes_delete(diskList); 1031 return nil; 1032 1033} 1034 1035boolean_t 1036DiskVolumes_findDisk(DiskVolumesPtr diskList, boolean_t all, 1037 const char * volume_name) 1038{ 1039 DiskVolumePtr best = NULL; 1040 boolean_t found = FALSE; 1041 boolean_t best_is_internal = FALSE; 1042 int i; 1043 int count = CFArrayGetCount(diskList->list); 1044 1045 for (i = 0; i < count; i++) { 1046 DiskVolumePtr vol; 1047 1048 vol = (DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,i); 1049 if (vol->removable 1050 || vol->writable == FALSE 1051 || vol->mounted == TRUE 1052 || vol->dirty == TRUE 1053 || vol->fs_type == NULL 1054 || !(strcmp(vol->fs_type, "hfs") == 0 1055 || strcmp(vol->fs_type, "ufs") == 0)) { 1056 continue; 1057 } 1058 if (volume_name != NULL 1059 && strcmp(volume_name, vol->disk_name)) { 1060 continue; 1061 } 1062 found = TRUE; 1063 if (all == TRUE) { 1064 printf("%s %s\n", vol->disk_dev_name, vol->fs_type); 1065 } 1066 else if (best_is_internal && vol->internal == FALSE) { 1067 continue; 1068 } 1069 else { 1070 if (best == NULL || vol->size > best->size) { 1071 best_is_internal = vol->internal; 1072 best = vol; 1073 } 1074 } 1075 } 1076 if (best) { 1077 printf("%s %s\n", best->disk_dev_name, best->fs_type); 1078 } 1079 return (found); 1080} 1081 1082int DiskVolumes_count(DiskVolumesPtr diskList) 1083{ 1084 return CFArrayGetCount(diskList->list); 1085} 1086DiskVolumePtr DiskVolumes_objectAtIndex(DiskVolumesPtr diskList,int index) 1087{ 1088 return (DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,index); 1089} 1090 1091int diskIsInternal(io_registry_entry_t media) 1092{ 1093 io_registry_entry_t parent = 0; 1094 //(needs release 1095 io_registry_entry_t parentsParent = 0; 1096 //(needs release) 1097 io_registry_entry_t service = media; 1098 //mandatory initialization 1099 kern_return_t kr; 1100 1101 int isInternal = 0; 1102 //by default inited 1103 1104 kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); 1105 if (kr != KERN_SUCCESS) 1106 return 1; 1107 1108 while (parent) { 1109 1110 kr = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parentsParent); 1111 if (kr != KERN_SUCCESS) 1112 break; 1113 1114 if (IOObjectConformsTo(parent, "IOBlockStorageDevice")) 1115 { 1116 CFDictionaryRef characteristics = IORegistryEntryCreateCFProperty(parent, CFSTR("Protocol Characteristics"), kCFAllocatorDefault, kNilOptions); 1117 1118 if (characteristics) { 1119 CFStringRef connection; 1120 // CFShow(characteristics); 1121 connection = (CFStringRef) CFDictionaryGetValue(characteristics, CFSTR("Physical Interconnect Location")); 1122 if (connection) { 1123 CFComparisonResult result; 1124 assert(CFGetTypeID(connection) == CFStringGetTypeID()); 1125 1126 result = CFStringCompare(connection, CFSTR("Internal"), 0); 1127 if (result == kCFCompareEqualTo) { 1128 isInternal = 1; 1129 } 1130 } 1131 1132 CFRelease(characteristics); 1133 } 1134 break; 1135 } 1136 if (parent) 1137 IOObjectRelease(parent); 1138 parent = parentsParent; 1139 parentsParent = 0; 1140 1141 } 1142 1143 if (parent) 1144 IOObjectRelease(parent); 1145 if (parentsParent) 1146 IOObjectRelease(parentsParent); 1147 1148 return isInternal; 1149} 1150 1151void 1152GetDisksFromRegistry(io_iterator_t iter, int initialRun, int mountExisting) 1153{ 1154 kern_return_t kr; 1155 io_registry_entry_t entry; 1156 1157 io_name_t ioMediaName; 1158 UInt64 ioSize; 1159 int ioWritable, ioEjectable; 1160 unsigned flags; 1161 mach_port_t masterPort; 1162 mach_timespec_t timeSpec; 1163 1164 1165 timeSpec.tv_sec = (initialRun ? 10 : 1); 1166 timeSpec.tv_nsec = 0; 1167 1168 IOMasterPort(bootstrap_port, &masterPort); 1169 1170 //sleep(1); 1171 IOKitWaitQuiet(masterPort, &timeSpec); 1172 1173 while ((entry = IOIteratorNext(iter))) { 1174 char *ioBSDName = NULL; 1175 //(needs release) 1176 char *ioContent = NULL; 1177 //(needs release) 1178 CFBooleanRef boolean = 0; 1179 //(don 't release) 1180 CFNumberRef number = 0; 1181 //(don 't release) 1182 CFDictionaryRef properties = 0; 1183 //(needs release) 1184 CFStringRef string = 0; 1185 //(don 't release) 1186 1187 //MediaName 1188 1189 kr = IORegistryEntryGetName(entry, ioMediaName); 1190 if (KERN_SUCCESS != kr) { 1191 dwarning(("can't obtain name for media object\n")); 1192 goto Next; 1193 } 1194 //Get Properties 1195 1196 kr = IORegistryEntryCreateCFProperties(entry, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, kNilOptions); 1197 if (KERN_SUCCESS != kr) { 1198 dwarning(("can't obtain properties for '%s'\n", ioMediaName)); 1199 goto Next; 1200 } 1201 assert(CFGetTypeID(properties) == CFDictionaryGetTypeID()); 1202 1203 //BSDName 1204 1205 string = (CFStringRef) CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)); 1206 if (!string) { 1207 /* We're only interested in disks accessible via BSD */ 1208 dwarning(("kIOBSDNameKey property missing for '%s'\n", ioMediaName)); 1209 goto Next; 1210 } 1211 assert(CFGetTypeID(string) == CFStringGetTypeID()); 1212 1213 ioBSDName = daCreateCStringFromCFString(string); 1214 assert(ioBSDName); 1215 1216 dwarning(("ioBSDName = '%s'\t", ioBSDName)); 1217 1218 //Content 1219 1220 string = (CFStringRef) CFDictionaryGetValue(properties, CFSTR(kIOMediaContentKey)); 1221 if (!string) { 1222 dwarning(("\nkIOMediaContentKey property missing for '%s'\n", ioBSDName)); 1223 goto Next; 1224 } 1225 assert(CFGetTypeID(string) == CFStringGetTypeID()); 1226 1227 ioContent = daCreateCStringFromCFString(string); 1228 assert(ioContent); 1229 1230 dwarning(("ioContent = '%s'\t", ioContent)); 1231 1232 if (strcmp(ioContent, APPLE_BOOT_UUID) == 0 1233 || strcmp(ioContent, "Apple_Boot") == 0) { 1234 goto Next; 1235 } 1236 1237 //Writable 1238 1239 boolean = (CFBooleanRef) CFDictionaryGetValue(properties, CFSTR(kIOMediaWritableKey)); 1240 if (!boolean) { 1241 dwarning(("\nkIOMediaWritableKey property missing for '%s'\n", ioBSDName)); 1242 goto Next; 1243 } 1244 assert(CFGetTypeID(boolean) == CFBooleanGetTypeID()); 1245 1246 ioWritable = (kCFBooleanTrue == boolean); 1247 1248 dwarning(("ioWritable = %d\t", ioWritable)); 1249 1250 //Ejectable 1251 1252 boolean = (CFBooleanRef) CFDictionaryGetValue(properties, CFSTR(kIOMediaEjectableKey)); 1253 if (!boolean) { 1254 dwarning(("\nkIOMediaEjectableKey property missing for '%s'\n", ioBSDName)); 1255 goto Next; 1256 } 1257 assert(CFGetTypeID(boolean) == CFBooleanGetTypeID()); 1258 1259 ioEjectable = (kCFBooleanTrue == boolean); 1260 1261 dwarning(("ioEjectable = %d\t", ioEjectable)); 1262 1263 //ioSize 1264 1265 number = (CFNumberRef) CFDictionaryGetValue(properties, CFSTR(kIOMediaSizeKey)); 1266 if (!number) { 1267 dwarning(("\nkIOMediaSizeKey property missing for '%s'\n", ioBSDName)); 1268 } 1269 assert(CFGetTypeID(number) == CFNumberGetTypeID()); 1270 1271 if (!CFNumberGetValue(number, kCFNumberLongLongType, &ioSize)) { 1272 goto Next; 1273 } 1274 dwarning(("ioSize = %ld\t", (long int) ioSize)); 1275 1276 //Construct the < flags > word 1277 1278 flags = 0; 1279 1280 if (!ioWritable) 1281 flags |= kDiskArbDiskAppearedLockedMask; 1282 1283 if (ioEjectable) 1284 flags |= kDiskArbDiskAppearedEjectableMask; 1285 1286 if (!ioSize) 1287 flags |= kDiskArbDiskAppearedNoSizeMask; 1288 //blank media 1289 1290 if (diskIsInternal(entry)) { 1291 dwarning(("\nInternal disk appeared ...\n")); 1292 flags |= kDiskArbDiskAppearedInternal; 1293 } 1294 1295 //Create a disk record 1296 1297 { 1298 /* 1299 * Create a new disk 1300 */ 1301 DiskPtr disk = NewDisk(ioBSDName, 1302 entry, 1303 flags, 1304 ioSize); 1305 if (!disk) { 1306 pwarning(("%s: NewDisk() failed!\n", __FUNCTION__)); 1307 } 1308 } 1309 1310Next: 1311 1312 if (properties) 1313 CFRelease(properties); 1314 if (ioBSDName) 1315 free(ioBSDName); 1316 if (ioContent) 1317 free(ioContent); 1318 1319 IOObjectRelease(entry); 1320 1321 } /* while */ 1322 1323} /* GetDisksFromRegistry */ 1324 1325/* 1326 * Function: string_to_argv 1327 * Purpose: 1328 * The given string "str" looks like a set of command-line arguments, space-separated e.g. 1329 * "-v -d -s", or, "-y", or "". Turn that into an array of string pointers using the given 1330 * "argv" array to store up to "n" of them. 1331 * 1332 * The given string is modified, as each space is replaced by a nul. 1333 */ 1334int 1335string_to_argv(char * str, char * * argv, int n) 1336{ 1337 int count; 1338 char * scan; 1339 1340 if (str == NULL) 1341 return (0); 1342 1343 for (count = 0, scan = str; count < n; ) { 1344 char * space; 1345 1346 argv[count++] = scan; 1347 space = strchr(scan, ' '); 1348 if (space == NULL) 1349 break; 1350 *space = '\0'; 1351 scan = space + 1; 1352 } 1353 return (count); 1354} 1355 1356/* 1357 * We only want to trigger the quotacheck command 1358 * on a volume when we fsck it and mark it clean. 1359 * The quotacheck must be done post mount. 1360 */ 1361boolean_t 1362fsck_vols(DiskVolumesPtr vols) 1363{ 1364 boolean_t result = TRUE; /* mandatory initialization */ 1365 int i; 1366 1367 for (i = 0; i < DiskVolumes_count(vols); i++) { 1368 1369 DiskVolumePtr vol = (DiskVolumePtr) DiskVolumes_objectAtIndex(vols, i); 1370 if (!vol) { 1371 return FALSE; 1372 } 1373 1374 if (vol->writable && vol->dirty) { 1375#define NUM_ARGV 6 1376 const char * argv[NUM_ARGV] = { 1377 NULL, /* fsck */ 1378 NULL, /* -y */ 1379 NULL, /* /dev/rdisk0s8 */ 1380 NULL, /* termination */ 1381 NULL, /* 2 extra args in case someone wants to pass */ 1382 NULL /* extra args beyond -y */ 1383 }; 1384 int argc; 1385 char *fsckCmd = repairPathForFileSystem(vol->fs_type); 1386 char *rprCmd = repairArgsForFileSystem(vol->fs_type); 1387 char devpath[64]; 1388 int ret; 1389 1390 snprintf(devpath, sizeof(devpath), "/dev/r%s", vol->disk_dev_name); 1391 argv[0] = fsckCmd; 1392 argc = string_to_argv(rprCmd, (char * *)argv + 1, NUM_ARGV - 3); 1393 argv[1 + argc] = devpath; 1394 1395 if (do_exec(NULL, argv, &ret, NULL) == FALSE) { 1396 /* failed to get a result, assume the volume is clean */ 1397 dwarning(("*** vol dirty? ***\n")); 1398 vol->dirty = FALSE; 1399 ret = 0; 1400 } 1401 else if (ret == 0) { 1402 /* Mark the volume as clean so that it will be mounted */ 1403 vol->dirty = FALSE; 1404 } 1405 else { 1406 dwarning(("'%s' failed: %d\n", fsckCmd, ret)); 1407 } 1408 1409 /* 1410 * Result will be TRUE iff each fsck command 1411 * is successful 1412 */ 1413 dwarning(("*** result? ***\n")); 1414 result = result && (ret == 0); 1415 1416 dwarning(("*** freeing? ***\n")); 1417 1418 free(fsckCmd); 1419 free(rprCmd); 1420 1421 } //if dirty 1422 } //for each 1423 return result; 1424 1425} 1426 1427boolean_t 1428autodiskmount_findDisk(boolean_t all, const char * volume_name) 1429{ 1430 boolean_t found = TRUE; 1431 DiskVolumesPtr vols; 1432 1433 DiskVolumes_new(&vols); 1434 DiskVolumes_do_volumes(vols); 1435 1436 (void)fsck_vols(vols); 1437 found = DiskVolumes_findDisk(vols, all, volume_name); 1438 1439 DiskVolumes_delete(vols); 1440 return (found); 1441} 1442 1443int 1444findDiskInit() 1445{ 1446 kern_return_t r; 1447 io_iterator_t ioIterator; // first match 1448 1449 r = IOMasterPort(bootstrap_port, &ioMasterPort); 1450 if (r != KERN_SUCCESS) 1451 { 1452 pwarning(("(%s:%d) IOMasterPort failed: {0x%x}\n", __FILE__, __LINE__, r)); 1453 return -1; 1454 } 1455 1456 r = IOServiceGetMatchingServices(ioMasterPort, 1457 IOServiceMatching( "IOMedia" ), 1458 &ioIterator); 1459 if (r != KERN_SUCCESS) 1460 { 1461 pwarning(("(%s:%d) IOServiceGetMatching Services: {0x%x}\n", __FILE__, __LINE__, r)); 1462 return -1; 1463 } 1464 GetDisksFromRegistry(ioIterator, 1, 0); 1465 IOObjectRelease(ioIterator); 1466 cacheFileSystemDictionaries(); 1467 cacheFileSystemMatchingArray(); 1468 return (0); 1469} 1470 1471int 1472main(int argc, char * argv[]) 1473{ 1474 const char * volume_name = NULL; 1475 char * progname; 1476 char ch; 1477 boolean_t find = FALSE; 1478 boolean_t all = FALSE; 1479 1480 /* Initialize globals */ 1481 1482 g.Disks = NULL; 1483 g.NumDisks = 0; 1484 1485 g.verbose = FALSE; 1486 g.debug = FALSE; 1487 1488 /* Initialize <progname> */ 1489 1490 progname = argv[0]; 1491 1492 /* Must run as root */ 1493 if (getuid() != 0) { 1494 pwarning(("%s: must be run as root\n", progname)); 1495 exit(1); 1496 } 1497 1498 /* Parse command-line arguments */ 1499 while ((ch = getopt(argc, argv, "avdFV:")) != -1) { 1500 switch (ch) { 1501 case 'a': 1502 all = TRUE; 1503 break; 1504 case 'v': 1505 g.verbose = TRUE; 1506 break; 1507 case 'd': 1508 g.debug = TRUE; 1509 break; 1510 case 'F': 1511 find = TRUE; 1512 break; 1513 case 'V': 1514 volume_name = optarg; 1515 break; 1516 } 1517 } 1518 1519 if (find == TRUE) { 1520 extern int findDiskInit(); 1521 1522 if (findDiskInit() < 0) { 1523 exit(2); 1524 } 1525 if (autodiskmount_findDisk(all, volume_name) == FALSE) { 1526 exit(1); 1527 } 1528 exit(0); 1529 } 1530 1531 exit(0); 1532} 1533