#include <libc.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <bsd/dev/disk.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <unistd.h>
#include <fts.h>
#include <mach/boolean.h>
#include "DiskArbitrationTypes.h"
#include "DiskVolume.h"
#include "DiskArbitrationServerMain.h"
#include "FSParticular.h"
extern void DiskArbRefresh_rpc(mach_port_t server);
static void
handleSIGHUP(int signal)
{
dwarning(("Recieved Sighup - Refreshing autodiskmount\n"));
DiskArbRefresh_rpc(0);
}
void CleanupDirectory( char *dir )
{
FTS *ftsp;
FTSENT *chp;
const char *rootDir[] = {dir,0};
char cookieFile[MAXPATHLEN];
char path[MAXPATHLEN];
struct stat sb;
ftsp = fts_open(rootDir, FTS_PHYSICAL, NULL);
fts_read(ftsp);
chp = fts_children(ftsp, 0);
if (chp) {
do {
sprintf(cookieFile, "%s/%s/%s", dir, chp->fts_accpath, ADM_COOKIE_FILE);
sprintf(path, "%s/%s", dir, chp->fts_accpath);
if (chp->fts_info & FTS_D) {
if (stat(cookieFile, &sb) == 0) {
if (remove(cookieFile) == 0) {
if (rmdir(path) == 0) {
dwarning(("*** The directory %s was cleaned up and removed by autodiskmount prior to mounting ***\n", chp->fts_name));
continue;
}
}
}
}
} while((chp = chp->fts_link));
}
fts_close(ftsp);
}
boolean_t
fsck_vols(DiskVolumesPtr vols)
{
boolean_t result = TRUE;
char command[1024];
char fsck_command_line[1024];
int i;
struct stat sb;
for (i = 0; i < DiskVolumes_count(vols); i++)
{
DiskVolumePtr vol;
vol = (DiskVolumePtr)DiskVolumes_objectAtIndex(vols,i);
if (vol->writable && vol->dirty && vol->mount_point == NULL)
{
char *fsckCmd = repairPathForFileSystem(vol->fs_type);
char *rprCmd = repairArgsForFileSystem(vol->fs_type);
sprintf(command, "%s %s /dev/r%s", fsckCmd, rprCmd,vol->disk_dev_name);
sprintf(fsck_command_line, fsckCmd);
{
if (stat(fsck_command_line, &sb) != 0) {
vol->dirty = FALSE;
dwarning(("%s: '%s' not found...\n", __FUNCTION__, fsck_command_line));
continue;
}
}
{
FILE * f;
int ret;
dwarning(("%s: '%s'...\n", __FUNCTION__, command));
f = popen(command, "w");
if (f == NULL)
{
dwarning(("popen('%s') failed", command));
vol->dirty = FALSE;
continue;
}
fflush(f);
ret = pclose(f);
dwarning(("%s: '%s' => %d\n", __FUNCTION__, command, ret));
if ( ret <= 0 )
{
vol->dirty = FALSE;
}
else
{
dwarning(("'%s' failed: %d\n", command, ret));
}
result = result && (ret == 0);
}
free(fsckCmd);
free(rprCmd);
}
}
return result;
}
boolean_t
mount_vols(DiskVolumesPtr vols, int takeOwnership)
{
int i;
for (i = 0; i < DiskVolumes_count(vols); i++)
{
DiskVolumePtr d = (DiskVolumePtr)DiskVolumes_objectAtIndex(vols,i);
DiskPtr dp = LookupDiskByIOBSDName( d->disk_dev_name );
if (d->mounted)
{
if (dp)
{
DiskSetMountpoint(dp, d->mount_point);
if (takeOwnership) {
if (dp->mountedUser != -1) {
dwarning(("*** Someone should own the disks now %d, %s ***\n", dp->mountedUser, d->mount_point));
chown(d->mount_point, dp->mountedUser, 99);
}
}
DiskVolume_SetTrashes(d);
}
continue;
}
if (d->dirty)
{
continue;
}
if ( DiskVolumes_setVolumeMountPoint(vols,d) == FALSE)
{
continue;
}
if (DiskVolume_mount(d))
{
if (dp)
{
DiskSetMountpoint( dp, d->mount_point );
if (takeOwnership) {
if (dp->mountedUser != -1) {
dwarning(("*** Someone should own the disks now %d, %s ***\n", dp->mountedUser, d->mount_point));
chown(d->mount_point, dp->mountedUser, 99);
}
}
DiskVolume_SetTrashes(d);
}
}
}
return (TRUE);
}
void autodiskmount(int takeOwnership)
{
DiskVolumesPtr vols;
DiskPtr diskPtr;
DiskVolumes_new(&vols);
CleanupDirectory("/");
CleanupDirectory(mountPath());
DiskVolumes_do_removable(vols,g.do_removable,g.eject_removable);
if (g.do_mount)
{
if (fsck_vols(vols) == FALSE)
{
pwarning(("Some fsck failed!\n"));
}
if (mount_vols(vols, takeOwnership) == FALSE)
{
pwarning(("Some mount() failed!\n"));
}
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next )
{
if (diskPtr->mountpoint != NULL && strlen(diskPtr->mountpoint)) {
DiskPtr wholePtr = LookupWholeDiskForThisPartition(diskPtr);
if (wholePtr) {
wholePtr->flags = wholePtr->flags | kDiskArbDiskAppearedRecognizableSectionMounted;
}
}
}
for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next )
{
int isWhole = ( diskPtr->flags & kDiskArbDiskAppearedWholeDiskMask );
int dialogPreviouslyDisplayed = ( diskPtr->flags & kDiskArbDiskAppearedDialogDisplayed );
int neverMount = ( diskPtr->flags & kDiskArbDiskAppearedNoMountMask );
if (isWhole && !dialogPreviouslyDisplayed && !neverMount) {
int recognizablePartitionsAppeared = ( diskPtr->flags & kDiskArbDiskAppearedRecognizableSectionMounted );
if (!recognizablePartitionsAppeared) {
if (DiskArbIsHandlingUnrecognizedDisks()) {
StartUnrecognizedDiskDialogThread(diskPtr);
diskPtr->flags |= kDiskArbDiskAppearedDialogDisplayed;
}
}
}
}
}
if (g.verbose)
{
DiskVolumes_print(vols);
}
DiskVolumes_delete(vols);
}
GlobalStruct g;
int
main(int argc, char * argv[])
{
char * progname;
char ch;
g.Clients = NULL;
g.NumClients = 0;
g.Disks = NULL;
g.NumDisks = 0;
g.NumDisksAddedOrDeleted = 1;
g.eject_removable = FALSE;
g.do_removable = FALSE;
g.verbose = FALSE;
g.do_mount = TRUE;
g.debug = FALSE;
progname = argv[0];
if (getuid() != 0)
{
pwarning(("%s: must be run as root\n", progname));
exit(1);
}
signal(SIGHUP, handleSIGHUP);
while ((ch = getopt(argc, argv, "avned")) != -1)
{
switch (ch)
{
case 'a':
g.do_removable = TRUE;
break;
case 'v':
g.verbose = TRUE;
break;
case 'n':
g.do_mount = FALSE;
break;
case 'e':
g.eject_removable = TRUE;
break;
case 'd':
g.debug = TRUE;
break;
}
}
if (g.eject_removable)
{
g.do_removable = FALSE;
}
{
char * argv2[] = { argv[0], "-d" };
int argc2 = ( g.debug ? 2 : 1 );
(void) DiskArbitrationServerMain(argc2, argv2);
}
exit(0);
}