/* ** AssignWedge - AmigaDOS 2.04 utility ** ** Copyright © 1992 by Olaf `Olsen' Barthel ** All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Create the requester strings. */ #define STRINGARRAY #include "assignwedge.h" /* The requester selection IDs. */ enum { REQ_CANCEL, REQ_RETRY, REQ_ASSIGN, REQ_MOUNT, REQ_DENY }; /* Some handy signal macros. */ #define SIG_KILL SIGBREAKF_CTRL_C #define SIG_NOTIFY (1 << MainPort -> mp_SigBit) /* The MC680x0 `jump to absolute address' opcode. */ #define JMP_ABS 0x4EF9 /* A simple wedge definition which is to consist of a jmp * instruction and the destination of the jump. */ struct Wedge { UWORD Command; APTR Address; }; /* Process and command names which are no longer allowed to * access certain paths will be identified by information * to be found in a list. The following structure definition * holds the necessary data (name and process base address). */ struct DenyNode { struct MinNode Node; struct Process *Process; UBYTE Name[40], ProgramName[40]; }; /* The library vector offset of the intuition.library routine to patch. */ extern ULONG __far LVOEasyRequestArgs; /* The version ID tag. */ STATIC UBYTE Version[] = "\0$VER: AssignWedge 1.1 (12.4.92)"; /* Global and shared library identifiers. */ struct IntuitionBase *IntuitionBase; struct ExecBase *SysBase; struct DosLibrary *DOSBase; struct Library *UtilityBase; struct Library *AslBase; /* Locale support. */ struct LocaleBase *LocaleBase; struct Catalog *Catalog; /* Registration of programs which are not allowed to * access certain devices. */ struct SignalSemaphore DenySemaphore; struct MinList DenyList; /* The following counter and the associated access semaphore help * to keep track of the number of programs currently using the * patched EasyRequestArgs() routine. */ struct SignalSemaphore RunSemaphore; LONG RunCount; /* Handshake data. */ struct Process *MainProcess; struct MsgPort *MainPort; BYTE Removed; /* To compensate for possible incompatibilities introduced by internationalized * requester texts, we will try to determine the text to turn up when an * `please insert volume' requester is opened. The `SearchName' will receive * the string to look for. */ UBYTE SearchName[256]; /* Function prototypes. */ LONG __saveds Main(VOID); STRPTR __regargs GetString(LONG ID); LONG __saveds __asm NewEasyRequestArgs(register __a0 struct Window *Window,register __a1 struct EasyStruct *EasyStruct,register __a2 ULONG *IDCMPPtr,register __a3 APTR *Args); LONG (* __asm OldEasyRequestArgs)(register __a0 struct Window *,register __a1 struct EasyStruct *,register __a2 ULONG *,register __a3 APTR *,register __a6 struct IntuitionBase *); LONG __saveds Main() { struct WBStartup *WBenchMsg = NULL; LONG ReturnCode = RETURN_FAIL; /* Set up ExecBase */ SysBase = *(struct ExecBase **)4; /* Determine current process identifier. */ MainProcess = (struct Process *)SysBase -> ThisTask; /* Are we running from CLI? If so, wait for Workbench * startup message. */ if(!MainProcess -> pr_CLI) { WaitPort(&MainProcess -> pr_MsgPort); WBenchMsg = (struct WBStartup *)GetMsg(&MainProcess -> pr_MsgPort); } /* Try to find the global handshake port and if present * send a termination signal. */ if(MainPort = FindPort("AssignWedge Rendezvous")) { Signal(MainPort -> mp_SigTask,SIG_KILL); ReturnCode = RETURN_OK; } else { /* Are we running under Kickstart version 37 or higher? */ if(SysBase -> LibNode . lib_Version > 36) { /* Create the global handshake port. */ if(MainPort = CreateMsgPort()) { /* Give it a name and add it to the public list. */ MainPort -> mp_Node . ln_Name = "AssignWedge Rendezvous"; AddPort(MainPort); /* Open the required libraries. */ if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)) { if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)) { if(UtilityBase = OpenLibrary("utility.library",37)) { if(AslBase = OpenLibrary(AslName,37)) { struct Wedge *Wedge; /* Try to open locale.library, but don't panic * if it's not available. */ if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38)) { if(!(Catalog = OpenCatalog(NULL,"assignwedge.catalog", OC_BuiltInLanguage, "english", OC_BuiltInCodeSet, 0, TAG_DONE))) { CloseLibrary(LocaleBase); LocaleBase = NULL; } } /* Initialize the access semaphore. */ InitSemaphore(&RunSemaphore); RunCount = 0; /* Initialize the access semaphore and * the list of programs to which access * to certain devices has been denied. */ InitSemaphore(&DenySemaphore); NewList((struct List *)&DenyList); /* Allocate a system library function wedge. */ if(Wedge = AllocMem(sizeof(struct Wedge),MEMF_PUBLIC)) { struct DenyNode *NextNode, *DenyNode; /* Initialize the wedge. */ Wedge -> Command = JMP_ABS; Wedge -> Address = (APTR)NewEasyRequestArgs; Removed = FALSE; /* Install the wedge. */ Forbid(); OldEasyRequestArgs = (APTR)SetFunction(IntuitionBase,(LONG)&LVOEasyRequestArgs,(APTR)Wedge); /* Make sure the data gets written to memory. */ CacheClearU(); /* Put up an example requester. Note: this requester * will be trapped by the wedge routine, giving us * the string to look for in the future. */ ErrorReport(ERROR_DEVICE_NOT_MOUNTED,REPORT_INSERT,(ULONG)"Test:",NULL); /* We're up and running now. Note that the * Forbid() will be broken by the Wait() for * a ^C signal. */ Wait(SIG_KILL); /* We are no longer running, * tell the wedge routine to * skip the `access denied' * part which requires the * list to be initialized. */ Removed = TRUE; /* Redirect the wedge pointer to * the original routine. */ Wedge -> Address = OldEasyRequestArgs; /* Make sure that the data * gets written to memory. */ CacheClearU(); /* Turn the multitasking back on. */ Permit(); /* Clear pending signals. */ SetSignal(0,SIG_NOTIFY); /* Wait until our wedge routine * is no longer in use. */ while(RunCount) Wait(SIG_NOTIFY); /* Clear the `access denied' list. */ DenyNode = (struct DenyNode *)DenyList . mlh_Head; while(NextNode = (struct DenyNode *)DenyNode -> Node . mln_Succ) { FreeVec(DenyNode); DenyNode = NextNode; } /* Successful termination. */ ReturnCode = RETURN_OK; } /* Close the resources * we had allocated, * but *not* the wedge * memory. */ if(Catalog) CloseCatalog(Catalog); if(LocaleBase) CloseLibrary(LocaleBase); CloseLibrary(AslBase); } CloseLibrary(UtilityBase); } CloseLibrary(IntuitionBase); } CloseLibrary(DOSBase); } /* Remove the global handshake port. */ RemPort(MainPort); DeleteMsgPort(MainPort); } } } /* If run from Workbench, reply the startup message. */ if(WBenchMsg) { Forbid(); ReplyMsg(&WBenchMsg -> sm_Message); } /* That's all folks. */ return(ReturnCode); } /* GetString(LONG ID): * * Fetch a text from the database. */ STRPTR __regargs GetString(LONG ID) { STRPTR Builtin = NULL; WORD i; /* Try to find the builtin string to match the ID we received. */ if(AppStrings[ID] . as_ID != ID) { for(i = 0 ; i < (sizeof(AppStrings) / sizeof(struct AppString)) ; i++) { if(AppStrings[i] . as_ID == ID) { Builtin = AppStrings[i] . as_Str; break; } } } else Builtin = AppStrings[ID] . as_Str; /* If locale.library is installed and the database catalog was * successfully opened, query the library's idea of the corresponding * text string. Otherwise, return the builtin string. */ if(LocaleBase) return(GetCatalogStr(Catalog,ID,Builtin)); else return(Builtin); } /* NewEasyRequestArgs(): * * A custom version of the original EasyRequest() routine which * is to provide enhanced options whenever a DOS handler puts * up a `REPORT_INSERT' style requester. */ LONG __saveds __asm NewEasyRequestArgs(register __a0 struct Window *Window,register __a1 struct EasyStruct *EasyStruct,register __a2 ULONG *IDCMPPtr,register __a3 APTR *Args) { struct Process *ThisProcess = (struct Process *)SysBase -> ThisTask; LONG Result; /* This may be the first call to the new routine, made by the * main program trying to determine the text to look for in * future requesters. */ if(!SearchName[0] && ThisProcess == MainProcess) { strcpy(SearchName,Args[0]); return(REQ_CANCEL); } /* Increment the use count. */ ObtainSemaphore(&RunSemaphore); RunCount++; ReleaseSemaphore(&RunSemaphore); /* Is the caller a process, i.e. will it be able to use all * DOS routines? */ if(ThisProcess -> pr_Task . tc_Node . ln_Type == NT_PROCESS) { /* Do the arguments match the pattern we had expected and * are DOS requesters enabled? */ if(!Strnicmp(EasyStruct -> es_TextFormat,"%s",2) && Args && ThisProcess -> pr_WindowPtr != (APTR)-1) { /* Did we get any calling parameters? */ if(Args[0]) { /* Does the first argument match the `please insert volume...' title? */ if(!Stricmp(Args[0],SearchName)) { UBYTE *DirBuffer; /* Allocate a temporary storage buffer * required by a number of routines * lateron. */ if(DirBuffer = (UBYTE *)AllocVec(512 + 60,MEMF_ANY)) { UBYTE *HailBuffer; struct EasyStruct __aligned Easy = *EasyStruct; struct DenyNode *DenyNode; struct FileRequester *AslFileRequest; struct Screen *FirstScreen; ULONG IntuiLock; BPTR In,Out; /* Gain access to the list of * programs to which access to * some devices has been denied. */ ObtainSemaphore(&DenySemaphore); DenyNode = (struct DenyNode *)DenyList . mlh_Head; /* If this process has a CLI structure * attached, look for a command name * to match a list entry. */ if(ThisProcess -> pr_CLI) { /* Process the list... */ while(DenyNode -> Node . mln_Succ) { /* Does this entry refer to * a command name? */ if(DenyNode -> ProgramName[0]) { /* Does the name of the device * in question match the name * in the list entry? */ if(!Stricmp(DenyNode -> Name,Args[1])) { /* Obtain the name of the program * currently running. */ if(GetProgramName(DirBuffer,512)) { /* Does the name match the one * in the list entry? */ if(!Stricmp(FilePart(DirBuffer),DenyNode -> ProgramName)) { /* Release the access semaphore. */ ReleaseSemaphore(&DenySemaphore); /* Free the temporary storage buffer. */ FreeVec(DirBuffer); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Return failure. */ return(REQ_CANCEL); } } } } /* Proceed to the next list entry. */ DenyNode = (struct DenyNode *)DenyNode -> Node . mln_Succ; } } else { /* Run down the list. */ while(DenyNode -> Node . mln_Succ) { /* Does the process identifier match the * one in the list entry? */ if(DenyNode -> Process == ThisProcess) { /* Does the name of the device in * question match the one in the * list entry? */ if(!Stricmp(DenyNode -> Name,Args[1])) { /* Release the access semaphore. */ ReleaseSemaphore(&DenySemaphore); /* Free the temporary storage buffer. */ FreeVec(DirBuffer); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Return failure. */ return(REQ_CANCEL); } } /* Proceed to the next entry. */ DenyNode = (struct DenyNode *)DenyNode -> Node . mln_Succ; } } /* Release the access semaphore. */ ReleaseSemaphore(&DenySemaphore); /* Split the buffer to create the directory * requester title string. */ HailBuffer = DirBuffer + 512; /* Fill in the `Retry|Assign|Mount|Deny|Cancel' buttons. */ Easy . es_GadgetFormat = GetString(MSG_PROMPT_GAD); /* Put up the requester and decide what to do. */ switch(Result = OldEasyRequestArgs(Window,&Easy,IDCMPPtr,Args,IntuitionBase)) { case REQ_ASSIGN: /* Try to obtain the name of the current directory, * most programs to look for assignments or volume * names will be happy if assignments are made * referring to their home directories. */ if(!GetCurrentDirName(DirBuffer,512)) DirBuffer[0] = 0; /* Set up the window title. */ sprintf(HailBuffer,GetString(MSG_HAIL_GAD),Args[1]); /* create the directory requester. */ if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, ASL_Dir, DirBuffer, ASL_Hail, HailBuffer, ASL_OKText, GetString(MSG_ASSIGN_GAD), ASL_Window, Window, ASL_FuncFlags, FILF_NEWIDCMP, ASL_ExtFlags1, FIL1F_NOFILES, TAG_DONE)) { /* Remember the first screen ID. */ IntuiLock = LockIBase(NULL); FirstScreen = IntuitionBase -> FirstScreen; UnlockIBase(IntuiLock); /* Move the screen the requester is to appear on * up if necessary. */ if(Window -> WScreen -> TopEdge > 0) MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge); /* Move the screen to the front. */ ScreenToFront(Window -> WScreen); /* Display the requester. */ while(AslRequestTags(AslFileRequest,TAG_DONE)) { APTR OldWindowPtr = ThisProcess -> pr_WindowPtr; BPTR FileLock; /* Disable the system requesters. */ ThisProcess -> pr_WindowPtr = (APTR)-1; /* Try to access the directory the * user has just selected. */ if(FileLock = Lock(AslFileRequest -> rf_Dir,ACCESS_READ)) { /* Try to create the assignment. */ if(!AssignLock(Args[1],FileLock)) { /* Oops, something went wrong. */ DisplayBeep(Window -> WScreen); UnLock(FileLock); } else { /* Restore the window pointer. */ ThisProcess -> pr_WindowPtr = OldWindowPtr; break; } } else DisplayBeep(Window -> WScreen); /* Restore the window pointer. */ ThisProcess -> pr_WindowPtr = OldWindowPtr; } /* Free the requester data. */ FreeAslRequest(AslFileRequest); /* Pop the screen which was frontmost * before the requester was displayed * back to the front. */ IntuiLock = LockIBase(0); if(FirstScreen == IntuitionBase -> FirstScreen) UnlockIBase(IntuiLock); else { struct Screen *Screen = IntuitionBase -> FirstScreen; BYTE IsValid = FALSE; /* Try to determine if the screen ID we * remembered is still valid. */ while(Screen && !IsValid) { if(Screen == FirstScreen) IsValid = TRUE; else Screen = Screen -> NextScreen; } Forbid(); UnlockIBase(IntuiLock); /* Push the screen to the front. */ if(IsValid) ScreenToFront(FirstScreen); Permit(); } } /* Free the directory buffer. */ FreeVec(DirBuffer); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Tell AmigaDOS to take a second look at the * device list. */ return(REQ_RETRY); case REQ_MOUNT: /* Open input stream. */ if(In = Open("NIL:",MODE_OLDFILE)) { /* Open output stream. */ if(Out = Open("NIL:",MODE_OLDFILE)) { APTR OldPtr = ThisProcess -> pr_WindowPtr; /* Enter the mount command string. */ sprintf(DirBuffer,"Mount >NIL: pr_WindowPtr = (APTR)-1; /* Execute the mount command. */ SystemTags(DirBuffer, SYS_Input, In, SYS_Output, Out, TAG_DONE); /* Restore window pointer. */ ThisProcess -> pr_WindowPtr = OldPtr; /* Close output stream. */ Close(Out); } /* Close input stream. */ Close(In); } /* Free the directory buffer. */ FreeVec(DirBuffer); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Tell AmigaDOS to take a second look at the * device list. */ return(REQ_RETRY); case REQ_DENY: /* If not about to be removed, allocate an `access denied' node. */ if(!Removed) { if(DenyNode = (struct DenyNode *)AllocVec(sizeof(struct DenyNode),MEMF_CLEAR)) { /* Fill in the current process ID. */ DenyNode -> Process = ThisProcess; /* Copy the name of the device in question. */ strcpy(DenyNode -> Name,Args[1]); /* If this process has a CLI structure attached, * try to remember the program name. */ if(ThisProcess -> pr_CLI) { if(GetProgramName(DirBuffer,512)) strcpy(DenyNode -> ProgramName,FilePart(DirBuffer)); } /* Gain access to the list. */ ObtainSemaphore(&DenySemaphore); /* Add the entry to the list. */ AddTail((struct List *)&DenyList,(struct Node *)DenyNode); /* Release the semaphore again. */ ReleaseSemaphore(&DenySemaphore); } } /* Free the directory buffer. */ FreeVec(DirBuffer); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Return failure. */ return(REQ_CANCEL); default: /* Free the directory buffer. */ FreeVec(DirBuffer); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Return the result (can be either `retry' or `cancel'). */ return(Result); } } } } } } /* In any other case, use the standard call. */ Result = OldEasyRequestArgs(Window,EasyStruct,IDCMPPtr,Args,IntuitionBase); /* Decrement use count. */ ObtainSemaphore(&RunSemaphore); RunCount--; ReleaseSemaphore(&RunSemaphore); /* Tell the main process to take a * look at the use count. */ Signal(MainProcess,SIG_NOTIFY); /* Return the result. */ return(Result); }