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