#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 "Configuration.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 = (DiskVolumePtr)DiskVolumes_objectAtIndex(vols,i);
if (!vol) {
return FALSE;
}
if ((vol->writable || shouldFsckReadOnlyMedia()) && vol->dirty && vol->mount_point == NULL)
{
DiskPtr dp = LookupDiskByIOBSDName( vol->disk_dev_name );
char *fsckCmd = repairPathForFileSystem(vol->fs_type);
char *rprCmd = repairArgsForFileSystem(vol->fs_type);
dwarning(("sending checking messages\n"));
SendDiskWillBeCheckedMessages(dp);
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 )
{
dwarning(("*** vol dirty? ***\n"));
vol->dirty = FALSE;
}
else
{
dwarning(("'%s' failed: %d\n", command, ret));
StartUnmountableDiskThread(dp);
dp->flags |= kDiskArbDiskAppearedCheckFailed;
}
dwarning(("*** result? ***\n"));
result = result && (ret == 0);
}
dwarning(("*** freeing? ***\n"));
free(fsckCmd);
free(rprCmd);
}
}
return result;
}
boolean_t
mount_vols(DiskVolumesPtr vols, int takeOwnership)
{
int i;
dwarning(("*** mount_vols ***\n"));
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 && currentConsoleUser != -1) {
dp->mountedUser = currentConsoleUser;
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 && currentConsoleUser != -1) {
dp->mountedUser = currentConsoleUser;
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 DiskArbDiskAppearedRecognizableSectionMountedApplier(DiskPtr wholePtr)
{
wholePtr->flags = wholePtr->flags | kDiskArbDiskAppearedRecognizableSectionMounted;
}
void autodiskmount(int takeOwnership)
{
DiskVolumesPtr vols;
DiskPtr diskPtr;
DiskVolumes_new(&vols);
CleanupDirectory("/");
CleanupDirectory(mountPath());
DiskVolumes_do_volumes(vols);
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)) {
LookupWholeDisksForThisPartition(diskPtr->service, DiskArbDiskAppearedRecognizableSectionMountedApplier);
}
}
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.verbose = FALSE;
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, "avd")) != -1)
{
switch (ch)
{
case 'a':
break;
case 'v':
g.verbose = TRUE;
break;
case 'd':
g.debug = TRUE;
break;
}
}
{
char * argv2[] = { argv[0], "-d" };
int argc2 = ( g.debug ? 2 : 1 );
(void) DiskArbitrationServerMain(argc2, argv2);
}
exit(0);
}