/* ** $RCSfile: UnMount.c,v $ ** $Filename: UnMount.c $ ** $Revision: 0.1 $ ** $Date: 1995/04/29 17:33:51 $ ** ** Try to Shutdown or at least Inhibit DOS-Handlers (version 1.0) ** ** (C) Copyright 1995-2001 by Etienne Vogt */ #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include struct ExecBase *SysBase; struct DosLibrary *DOSBase; static struct WBStartup *wbmsg; static struct RDArgs *myrda; static UBYTE version[] = "$VER: UnMount 1.0 (24.6.2001)"; static UBYTE template[] = "DEVICE,INHIBIT/S,RETRY/K/N,ALL/S,FREENODE/S,QUIET/S"; #define DBUFSIZE 16 #define DNAMSIZE 24 struct devBuffer { struct devBuffer *dbf_Link; UBYTE dbf_Name[DBUFSIZE][DNAMSIZE]; }; #define OPT_DEVICE 0 #define OPT_INHIBIT 1 #define OPT_RETRY 2 #define OPT_ALL 3 #define OPT_FREENODE 4 #define OPT_QUIET 5 #define OPTMAX 6 ULONG __saveds main(void); static void cleanexit(ULONG rc); static int unmount(STRPTR device, int inhibit, int retry, int quiet); static struct devBuffer *getdevices(int *nodes); static void freedbufs(struct devBuffer *dbufs); static void killdevices(struct devBuffer *dbuf, int numdevs, int inhibit, int retry, int freenode, int quiet); static void freeNode(STRPTR device); static void freeWeird(BPTR bp, ULONG size); ULONG __saveds main(void) /* No startup code */ { struct Process *myproc; LONG opts[OPTMAX]; ULONG rc = 0; SysBase = *(struct ExecBase **)4; DOSBase = NULL; wbmsg = NULL; myrda = NULL; myproc = (struct Process *)FindTask(NULL); if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",36)) == NULL) { Alert(AT_Recovery|AG_OpenLib|AO_DOSLib); return 100; } if (!(myproc->pr_CLI)) /* If started from WB, exit cleanly */ { WaitPort(&(myproc->pr_MsgPort)); wbmsg = (struct WBStartup *)GetMsg(&(myproc->pr_MsgPort)); cleanexit(20); } else { APTR oldwinptr; int retrycount = 10, error; memset((char *)opts, 0, sizeof(opts)); if ((myrda = ReadArgs(template, opts, NULL)) == NULL) { PrintFault(IoErr(),"UnMount"); cleanexit(20); } if (opts[OPT_RETRY]) retrycount = *((LONG *)opts[OPT_RETRY]); oldwinptr = myproc->pr_WindowPtr; /* Disable DOS Requesters */ myproc->pr_WindowPtr = (APTR)(-1L); if (opts[OPT_DEVICE]) { struct DosList *dol; char buffer[DNAMSIZE]; STRPTR colon; dol = LockDosList(LDF_DEVICES | LDF_READ); strncpy(buffer, (STRPTR)opts[OPT_DEVICE], sizeof(buffer)); if (colon = (UBYTE *)strchr(buffer,':')) *colon = (UBYTE)0; else buffer[DNAMSIZE-1] = (UBYTE)0; if (dol = FindDosEntry(dol, buffer, LDF_DEVICES)) { if (dol->dol_Task) /* There's a handler process running */ { UnLockDosList(LDF_DEVICES | LDF_READ); if (error = unmount((STRPTR)opts[OPT_DEVICE], opts[OPT_INHIBIT], retrycount, opts[OPT_QUIET])) { PrintFault(error, "UnMount"); rc = 10; } } else UnLockDosList(LDF_DEVICES | LDF_READ); if (opts[OPT_FREENODE]) freeNode((STRPTR)opts[OPT_DEVICE]); } else { UnLockDosList(LDF_DEVICES | LDF_READ); PrintFault(ERROR_DEVICE_NOT_MOUNTED, "UnMount"); rc = 20; } } else if (opts[OPT_ALL]) { struct devBuffer *dbuf; int numdevs; if (dbuf = getdevices(&numdevs)) killdevices(dbuf, numdevs, opts[OPT_INHIBIT], retrycount, opts[OPT_FREENODE], opts[OPT_QUIET]); else { PrintFault(ERROR_NO_FREE_STORE, "UnMount"); rc = 20; } } else { PrintFault(ERROR_REQUIRED_ARG_MISSING, "UnMount"); rc = 20; } myproc->pr_WindowPtr = oldwinptr; } cleanexit(rc); } static void cleanexit(ULONG rc) { if (myrda) FreeArgs(myrda); if (DOSBase) CloseLibrary((struct Library *)DOSBase); if (wbmsg) { Forbid(); ReplyMsg((struct Message *)wbmsg); } Exit(rc); } static int unmount(STRPTR device, int inhibit, int retry, int quiet) { struct DevProc *dvp; int count = 0, rc = 0; if (!strchr(device,':')) return ERROR_INVALID_COMPONENT_NAME; if (dvp = GetDeviceProc(device, NULL)) { if (DoPkt0(dvp->dvp_Port, ACTION_DIE) == DOSFALSE) { rc = IoErr(); if (IsFileSystem(device) && inhibit) { if (!quiet) Printf("UnMount: Couldn't kill device %s, Trying to inhibit...\n", device); do { if (Inhibit(device, DOSTRUE)) break; else if ((rc = IoErr()) == ERROR_ACTION_NOT_KNOWN) count = retry; else Delay(TICKS_PER_SECOND); } while (++count < retry); if (count < retry) rc = 0; } } FreeDeviceProc(dvp); } else rc = IoErr(); return rc; } static struct devBuffer *getdevices(int *nodes) { struct devBuffer *dbuf; if (dbuf = AllocVec(sizeof(struct devBuffer), MEMF_PUBLIC | MEMF_CLEAR)) { struct DosList *dol; struct devBuffer *db = dbuf; int i = 0; dol = LockDosList(LDF_DEVICES | LDF_READ); *nodes = 0; while (dol = NextDosEntry(dol, LDF_DEVICES)) { UBYTE namlen; UBYTE *namptr; if (dol->dol_Task == NULL) continue; namptr = BADDR(dol->dol_Name); namlen = (namptr[0] < DNAMSIZE - 1 ? namptr[0] : DNAMSIZE - 2); strncpy(db->dbf_Name[i], namptr + 1, namlen); db->dbf_Name[i][namlen] = ':'; db->dbf_Name[i][namlen+1] = '\0'; if (strcmp(db->dbf_Name[i], "RAM:") == 0) continue; (*nodes)++; if (++i == DBUFSIZE) { struct devBuffer *db1; if (db1 = AllocVec(sizeof(struct devBuffer), MEMF_PUBLIC | MEMF_CLEAR)) { db->dbf_Link = db1; db = db1; i = 0; } else { UnLockDosList(LDF_DEVICES | LDF_READ); freedbufs(dbuf); return NULL; } } } UnLockDosList(LDF_DEVICES | LDF_READ); } return dbuf; } static void freedbufs(struct devBuffer *dbufs) { struct devBuffer *nextdb; do { nextdb = dbufs->dbf_Link; FreeVec(dbufs); } while (dbufs = nextdb); } static void killdevices(struct devBuffer *dbuf, int numdevs, int inhibit, int retry, int freenode, int quiet) { struct devBuffer *db = dbuf; STRPTR devname; int j, i, error; for (j = 0, i = 0 ; j < numdevs ; j++) { devname = db->dbf_Name[i]; if (IsFileSystem(devname)) { if (!quiet) Printf("Unmounting device %s\n", db->dbf_Name[i]); if (error = unmount(devname, inhibit, retry, TRUE) && !quiet) PrintFault(error, "UnMount"); else if (freenode) freeNode(devname); } if (++i == DBUFSIZE) { db = db->dbf_Link; i = 0; } } freedbufs(dbuf); } static void freeNode(STRPTR device) { struct DosList *dol; char buffer[DNAMSIZE]; STRPTR colon; struct FileSysStartupMsg *fssm; struct DosEnvec *de; dol = LockDosList(LDF_DEVICES | LDF_WRITE); strncpy(buffer, device, sizeof(buffer)); if (colon = (UBYTE *)strchr(buffer,':')) *colon = (UBYTE)0; else buffer[DNAMSIZE-1] = (UBYTE)0; if (dol = FindDosEntry(dol, buffer, LDF_DEVICES)) { RemDosEntry(dol); if (TypeOfMem(fssm = BADDR(dol->dol_misc.dol_handler.dol_Startup)) && ((ULONG)fssm & 1) == 0) { de = BADDR(fssm->fssm_Environ); /* and now for some extremely bizarre assumptions... */ if (*(UBYTE *)fssm == 0 || *(UBYTE *)BADDR(fssm->fssm_Device) != 0 && TypeOfMem(de) != 0 && (de->de_TableSize & 0xffffff00) == 0) { if (de->de_TableSize >= DE_CONTROL) freeWeird(de->de_Control, 0); freeWeird(fssm->fssm_Device, 0); freeWeird(fssm->fssm_Environ, (de->de_TableSize + 1) * sizeof(ULONG)); freeWeird(dol->dol_misc.dol_handler.dol_Startup, sizeof(struct FileSysStartupMsg)); } else freeWeird(dol->dol_misc.dol_handler.dol_Startup, 0); /* Probably a startup string */ } freeWeird(dol->dol_misc.dol_handler.dol_Handler, 0); FreeDosEntry(dol); } UnLockDosList(LDF_DEVICES | LDF_WRITE); } /* From Ralph Babel's excellent Guru Book */ static void freeWeird(BPTR bp, ULONG size) { UBYTE *p; if (bp) { p = BADDR(bp); if (TypeOfMem(p)) /* Should point to valid memory */ { if (((ULONG)p & MEM_BLOCKMASK) == 0) FreeMem(p, size != 0 ? size : *p + 2); else FreeVec(p); /* Assume BCPL-style memory vector */ } } }