home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 19 / AACD19.BIN / AACD / System / SnoopDos / SnoopDos_Src / SnoopDos_Source / patches.c < prev    next >
C/C++ Source or Header  |  2001-02-04  |  213KB  |  4,936 lines

  1. /*
  2.  *              PATCHES.C                                                                       vi:ts=4
  3.  *
  4.  *      Copyright (c) Eddy Carroll, September 1994.
  5.  *      Updated by Thomas Richter, THOR, 5.3.2000.
  6.  *
  7.  *              Controls the patching of dos.library and other functions in a
  8.  *              reliable manner.
  9.  */
  10.  
  11. #define DEBUG_PATTERN           0
  12.  
  13. #define MONITOR_SEMAPHORE       0
  14. #define STACK_CHECK                     0               /* Not currently used */
  15.  
  16. #pragma libcall SysBase RawPutChar 204 001
  17.  
  18. #include "system.h"
  19. #include "snoopdos.h"
  20. #include "patches.h"
  21.  
  22. /*
  23.  *              These four pointers are imported from PATCHCODE.S, which is
  24.  *              also where the real code size is determined.
  25.  */
  26. #define CODESIZE                88      /* Must equal PatchCode_End - PatchCode_Start   */
  27. #define STACKADJUST             14      /* Must equal pc_JumpOrigFunc - pc_NormalReturn */
  28.  
  29. #define PatchCode_Size            (PatchCode_End - PatchCode_Start)
  30. #define PatchCode_StackAdjust (PatchCode_JumpOrigFunc - PatchCode_NormalReturn)
  31.  
  32. extern char far PatchCode_Start[];
  33. extern char far PatchCode_NormalReturn[];
  34. extern char far PatchCode_JumpOrigFunc[];
  35. extern char far PatchCode_End[];
  36.  
  37. #define ASM     __asm __saveds
  38.  
  39. #if MONITOR_SEMAPHORE
  40. Task *LoadTask;                         /* Indicates we're inside LoadSeg() */
  41. #endif
  42.  
  43. /*
  44.  *              Now some packet IDs not defined by Commodore in dos/dosextens.h
  45.  */
  46. #define ACTION_DOUBLE             2000  /* Conman: create pipe filehandle       */
  47. #define ACTION_FORCE              2001  /* Conman: Force input into handler     */
  48. #define ACTION_DROP                       2004  /* Conman: Discard all queued input     */
  49.  
  50. #define ACTION_GET_DISK_FSSM  4201      /* Get disk startup message                     */
  51. #define ACTION_FREE_DISK_FSSM 4202      /* Free disk startup message            */
  52.  
  53. /*
  54.  *              Next, our three message types for the background process. These
  55.  *              correspond to pattern and pathname expansion messages.
  56.  */
  57. #define QUIT_MSG                0
  58. #define PATTERN_MSG             1
  59. #define PATHEXPAND_MSG  2
  60.  
  61. /*
  62.  *              Some miscellaneous strings
  63.  */
  64. char LinkPointerString[] = " --> ";
  65.  
  66. /*
  67.  *              I needed a quick way to hook into ReleaseSemaphore() to try and
  68.  *              figure out why ramlib would sometimes crash on calling it. What
  69.  *              better way to do this than by re-using one of our existing
  70.  *              patched functions (one which takes a parameter in A0). OpenDevice
  71.  *              fits the bill nicely (we just ignore the additional parameters).
  72.  */
  73. #if MONITOR_SEMAPHORE
  74. #undef LVO_OpenDevice
  75. #define LVO_OpenDevice          -570 // ReleaseSemaphore() LVO vector
  76. #endif
  77.  
  78. /*
  79.  *              This structure is used to communicate between the PutMsg() patch
  80.  *              and the background SnoopDos process when doing path expansion
  81.  *              for ACTION_MAKE_LINK or ShowFullPaths (when we're monitoring packets,
  82.  *              we can't guarantee that the calling processes' message port is free).
  83.  */
  84. typedef struct NameFromLockMsg {
  85.         struct Message  msg;            /* Standard exec message                                */
  86.         int                             type;           /* Type of this message                                 */
  87.         BPTR                    lock;           /* Lock to calculate path relative to   */
  88.         char                    *filename;      /* Filename relative to lock                    */
  89.         char                    *buf;           /* Buffer to store result in                    */
  90.         int                             maxlen;         /* Maximum length of buffer                             */
  91.         char                    *newbuf;        /* On return, points to path in buffer  */
  92.         int                             sigmask;        /* Signal number to signal when done    */
  93.         Task                    *task;          /* Task to signal when done                             */
  94. } NameFromLockMsg;
  95.  
  96. /*
  97.  *              This structure is used to communicate between the patches and
  98.  *              the background SnoopDos process when doing pattern matching.
  99.  */
  100. typedef struct PatternMsg {
  101.         struct Message  msg;            /* Standard exec message                                */
  102.         int                             type;           /* Type of this message                                 */
  103.         char                    *name;          /* Name of task to check                                */
  104.         int                             match;          /* Result of pattern match (1 == okay)  */
  105.         int                             sigmask;        /* Signal number to signal when done    */
  106.         Task                    *task;          /* Task to signal when done                             */
  107. } PatternMsg;
  108.  
  109. /*
  110.  *              This structure is used to cache the results of pattern comparisons
  111.  *              for various tasks.
  112.  */
  113. typedef struct PatternCache {
  114.         struct MinNode  node;           /* Used to link items together                          */
  115.         Task                    *task;          /* ID of task stored in this entry                      */
  116.         char                    name[PC_NAMELEN];/* Name of task stored in this entry   */
  117.         int                             match;          /* True=monitor this task, false=don't          */
  118. } PatternCache;
  119.  
  120. PatternCache    PCacheEntries[NUM_PCACHE_ENTRIES];      /* Entries on list              */
  121. MsgPort                 BackgroundPort; /* Where to send pattern match requests to      */
  122. List                    PatternList;    /* List of cached patterns                                      */
  123. Semaphore               PatternCacheSem;/* Sem to control access to pattern cache       */
  124. Semaphore               PatternBufSem;  /* Sem to control access to pattern buffer      */
  125. Semaphore               TaskCacheSem;   /* Sem used to arbitrate cache access           */
  126. Semaphore               DosDeviceSem;   /* Sem used to control access to dev list       */
  127. Process                 *BackgroundProc;/* Process used to do pattern matching          */
  128. ULONG                   PatternEnabled;         /* If true, pattern matching is enabled */
  129. ULONG                   PatternWildcard;        /* If true, pattern contains a wildcard */
  130. Task                    *SnoopTask;                     /* Pointer to our own task                              */
  131. Task                    *RamLibTask;            /* Pointer to RamLib process                    */
  132. Task                    *RealRamLibTask;        /* Pointer to Ramlib process (always!)  */
  133. Task                    *InputTask;                     /* Pointer to input.device's task               */
  134. ULONG                   NewEventSig    = -1;/* Signal bit used when new event ready     */
  135. ULONG                   ScanDosListSig = -1;/* Signal bit used to say rescan list       */
  136. ULONG                   TaskCacheIndex = 1; /* Index into task cache array                      */
  137.  
  138. #define PAT_MAX_LEN     (MAX_STR_LEN   + 50)
  139. #define PAT_BUF_LEN     (PAT_MAX_LEN*2 + 3)
  140.  
  141. char                    PatternString[PAT_MAX_LEN];                     /* Holds source pattern */
  142. char                    PatternBuf[PAT_BUF_LEN];                        /* Holds parsed pattern */
  143. Task                    *CachedTask[NUM_CACHED_TASKS];          /* Holds cached tasks   */
  144. Task                    *DeviceTaskList[MAX_DOS_DEVICES];       /* Holds device IDs             */
  145.  
  146. /*
  147.  *              This structure records outstanding packets (for direct packet i/o
  148.  *              that bypasses AmigaDOS) which we are watching out for a reply to.
  149.  *              We keep all the additional info because it's likely that any given
  150.  *              task will re-use a packet structure when sending packets to different
  151.  *              DOS processes, and we want to be able to distinguish these cases.
  152.  */
  153. typedef struct WaitPacket {
  154.         struct  MinNode         node;                   /* Used to link items together  */
  155.         struct  DosPacket       *dp;                    /* Packet that was dispatched   */
  156.         struct  Task            *sendtask;              /* Task that sent it                    */
  157.         struct  MsgPort         *destport;              /* Port it was sent to                  */
  158.         LONG    eventnum;                                       /* Associated event number              */
  159.         Event   *event;                                         /* Associated event pointer             */
  160.         ULONG   arg1;                                           /* ARG1 of the packet                   */
  161.         ULONG   arg2;                                           /* ARG2 of the packet                   */
  162.         ULONG   arg3;                                           /* ARG3 of the packet                   */
  163.         char    *resmsg;                                        /* Message to use for result    */
  164.         UWORD   flags;                                          /* Flags associated with result */
  165. } WaitPacket;
  166.  
  167. Semaphore       PacketSem;                                                      /* Arbitrates list access       */
  168. struct List PacketWaitList;                                             /* List of waiting packets      */
  169. struct List     PacketFreeList;                                         /* List of free nodes           */
  170. WaitPacket      PacketEntries[NUM_PACKET_ENTRIES];      /* The nodes on the list        */
  171.  
  172. /*
  173.  *              Prototypes for all our replacement patched functions
  174.  */
  175.  
  176. void BackgroundProcCode(void);
  177. char *MyNameFromLock(BPTR lock, char *filename, char *buf, int maxlen);
  178.  
  179. typedef unsigned long (*FuncPtr)();
  180.  
  181. #define FPROTO(name)    ULONG ASM New_##name(){return (0);}
  182. #define DPROTO(name)    ULONG ASM New_##name();
  183.  
  184. DPROTO(AddDosEntry)
  185. DPROTO(CurrentDir)
  186. DPROTO(DeleteFile)
  187. DPROTO(Execute)
  188. DPROTO(GetVar)
  189. DPROTO(FindVar)
  190. DPROTO(LoadSeg)
  191. DPROTO(NewLoadSeg)
  192. DPROTO(Lock)
  193. DPROTO(CreateDir)
  194. DPROTO(MakeLink)
  195. DPROTO(Open)
  196. DPROTO(Rename)
  197. DPROTO(RunCommand)
  198. DPROTO(SetVar)
  199. DPROTO(DeleteVar)
  200. DPROTO(SystemTagList)
  201.  
  202. DPROTO(FindPort)
  203. DPROTO(FindResident)
  204. DPROTO(FindSemaphore)
  205. DPROTO(FindTask)
  206. DPROTO(OpenDevice)
  207. DPROTO(OpenLibrary)
  208. DPROTO(OpenResource)
  209. DPROTO(PutMsg)
  210.  
  211. DPROTO(OpenFont)
  212. DPROTO(LockPubScreen)
  213. DPROTO(FindToolType)
  214. DPROTO(MatchToolValue)
  215.  
  216. /*
  217.  *              These two defines control whether or not a patch is enabled. It's
  218.  *              vital that PATCH_ENABLED be -1 rather than simply any non-zero
  219.  *              value -- see the comments in patchcode.s for more details.
  220.  */
  221. #define PATCH_ENABLED           ((ULONG)(-1))
  222. #define PATCH_DISABLED          0
  223.  
  224. /*
  225.  *              MarkCallAddr
  226.  *              CallAddr
  227.  *
  228.  *              These two macros allow us to determine what address we were called
  229.  *              from in a patch function. MarkCallAddr should be the first
  230.  *              declaration at the start of the patch function, and then CallAddr
  231.  *              will correspond to the caller's address throughout that function.
  232.  *              callmarker[0] is the place marker itself, callmarker[1] is the
  233.  *              immediate return address, and callmarker[3] takes into the
  234.  *              account the assembly language patch stub as well.
  235.  */
  236. #define MarkCallAddr            ULONG volatile callmarker[1]
  237. #define CallAddr                        (callmarker[6])
  238.  
  239. /*
  240.  *              JumpOrigFunc(retval)
  241.  *
  242.  *              This macro lets us return and call the original function from the
  243.  *              resident patch code rather than from our C code. The passed
  244.  *              parameter can be 0 in most cases, but if the function we're using
  245.  *              this in had a formal parameter passed in reg_d0, then that
  246.  *              formal parameter must be used as the return value.
  247.  *
  248.  *              We implement this by patching the stack directly to adjust the
  249.  *              return address so that we arrive back at a second bit of code
  250.  *              instead of the first bit.
  251.  */
  252. #define JumpOrigFunc(retval) \
  253.         { callmarker[1] += STACKADJUST; \
  254.           return (ULONG)(retval); }
  255.  
  256. /*
  257.  *              The patch structure itself. Don't change the order of the first
  258.  *              four fields without updating the code in PATCHCODE.S as well!
  259.  *
  260.  *              Note that we use a library number rather than a pointer to an
  261.  *              actual library, for convenience.
  262.  */
  263. typedef struct Patch {
  264.         UWORD   code[CODESIZE/2];               /* Assembly code to handle patch        */
  265.         FuncPtr origfunc;                               /* Original function pointer            */
  266.         FuncPtr newfunc;                                /* Replacement function pointer         */
  267.         ULONG   enabled;                                /* If -1, patch currently active        */
  268.         void    *sysbase;                               /* Points to ExecBase                           */
  269.         ULONG   stackneeded;                    /* #bytes free stack required           */
  270.         UWORD   usecount;                               /* No. of tasks currently in code       */
  271.         UWORD   library;                                /* Library to patch                                     */
  272.         WORD    offset;                                 /* Offset into library                          */
  273.         WORD    pad;                                    /* Keep structure longword-aligned      */
  274. } Patch;
  275.  
  276. #define PATCH_DEF(lib,func)     { lib, LVO_##func, (FuncPtr)New_##func }
  277. #define PATCH_END                       { 0, 0, 0 }
  278.  
  279. /*
  280.  *              This structure is used to initialise the main Patch array in memory.
  281.  *
  282.  *              IMPORTANT -- these patches MUST be defined in exactly the same
  283.  *              order as the first entries in the GID_* defines in snoopdos.h
  284.  *              since those same GID_* values are used to toggle the patches
  285.  *              on and off.
  286.  */
  287. struct PatchInitTable {
  288.         UWORD   library;                                /* Library number to patch                      */
  289.         WORD    offset;                                 /* Offset in that library                       */
  290.         FuncPtr newfunc;                                /* Replacement function to call         */
  291. } PatchInit[] = {
  292.         PATCH_END,
  293.         PATCH_DEF(      EXEC_LIB,               FindPort                ),      /* GID_FINDPORT                 */
  294.         PATCH_DEF(      EXEC_LIB,               FindResident    ),      /* GID_FINDRESIDENT             */
  295.         PATCH_DEF(      EXEC_LIB,               FindSemaphore   ),      /* GID_FINDSEMAPHORE    */
  296.         PATCH_DEF(      EXEC_LIB,               FindTask                ),      /* GID_FINDTASK                 */
  297.         PATCH_DEF(      INTUITION_LIB,          LockPubScreen   ),      /* GID_LOCKSCREEN               */
  298.         PATCH_DEF(      EXEC_LIB,               OpenDevice              ),      /* GID_OPENDEVICE               */
  299.         PATCH_DEF(      GRAPHICS_LIB,           OpenFont                ),      /* GID_OPENFONT                 */
  300.         PATCH_DEF(      EXEC_LIB,               OpenLibrary             ),      /* GID_OPENLIBRARY              */
  301.         PATCH_DEF(      EXEC_LIB,               OpenResource    ),      /* GID_OPENRESOURCE             */
  302.         PATCH_DEF(      ICON_LIB,               FindToolType    ),      /* GID_READTOOLTYPES    */
  303.         PATCH_DEF(      EXEC_LIB,               PutMsg          ),      /* GID_SENDREXX         */
  304.  
  305.         PATCH_DEF(      DOS_LIB,                CurrentDir              ),      /* GID_CHANGEDIR                */
  306.         PATCH_DEF(      DOS_LIB,                DeleteFile              ),      /* GID_DELETE                   */
  307.         PATCH_DEF(      DOS_LIB,                Execute                 ),      /* GID_EXECUTE                  */
  308.         PATCH_DEF(      DOS_LIB,                GetVar                  ),      /* GID_GETVAR                   */
  309.         PATCH_DEF(      DOS_LIB,                LoadSeg                 ),      /* GID_LOADSEG                  */
  310.         PATCH_DEF(      DOS_LIB,                Lock                    ),      /* GID_LOCKFILE                 */
  311.         PATCH_DEF(      DOS_LIB,                CreateDir               ),      /* GID_MAKEDIR                  */
  312.         PATCH_DEF(      DOS_LIB,                MakeLink                ),      /* GID_MAKELINK                 */
  313.         PATCH_DEF(      DOS_LIB,                Open                    ),      /* GID_OPENFILE                 */
  314.         PATCH_DEF(      DOS_LIB,                Rename                  ),      /* GID_RENAME                   */
  315.         PATCH_DEF(      DOS_LIB,                RunCommand              ),      /* GID_RUNCOMMAND               */
  316.         PATCH_DEF(      DOS_LIB,                SetVar                  ),      /* GID_SETVAR                   */
  317.         PATCH_DEF(      DOS_LIB,                SystemTagList   ),      /* GID_SYSTEM                   */
  318.  
  319.         /*
  320.          *              Now the paired functions that track their partner's state
  321.          */
  322.         PATCH_DEF(      ICON_LIB,               MatchToolValue  ),      /* GID_READTOOLTYPES2   */
  323.         PATCH_DEF(      DOS_LIB,                NewLoadSeg              ),      /* GID_LOADSEG2                 */
  324.         PATCH_DEF(      DOS_LIB,                FindVar                 ),      /* GID_GETVAR2                  */
  325.         PATCH_DEF(      DOS_LIB,                DeleteVar               ),      /* GID_SETVAR2                  */
  326.         PATCH_DEF(  DOS_LIB,            AddDosEntry         ),  /* GID_ADDDOSENTRY              */
  327.  
  328.         PATCH_END
  329. };
  330.  
  331. #define PatchInitCount  (sizeof(PatchInit) / sizeof(PatchInit[0]))
  332. #define PatchInitSize   (PatchInitCount * sizeof(Patch))
  333.  
  334. /*
  335.  *              This anchor structure is used to let us locate the patches if we
  336.  *              quit SnoopDos and then rerun it -- the patches themselves always
  337.  *              stay in memory once loaded.
  338.  */
  339. typedef struct {
  340.         Semaphore       sem;                    /* Semaphore to arbitrate access to patches     */
  341.         char            name[30];               /* Somewhere permanent to store sem name        */
  342.         Patch           patchdata[1];   /* This is an open-ended array                          */
  343. } PatchAnchorData;
  344.  
  345. PatchAnchorData *PatchAnchor;   /* Points to the current patch anchor           */
  346.  
  347. /*
  348.  *              If SAS/C allowed us to examine the value of Enum types from
  349.  *              within the preprocessor, the following check would actually work
  350.  */
  351. #if SASC_ALLOWS_ENUM_CHECKS
  352. #if (sizeof(PatchInit)/sizeof(PatchInit[0])) < (GID_NUMPATCHES+1)
  353. #error "PatchInit[] table has too few entries for patches"
  354. #else
  355. #if (sizeof(PatchInit)/sizeof(PatchInit[0])) > (GID_NUMPATCHES+1)
  356. #error "PatchInit[] table has too many entries for patches"
  357. #endif
  358. #endif
  359. #endif
  360.  
  361. void *LibList[NUM_LIBS];
  362.  
  363. Patch *PatchList;
  364.  
  365. /*
  366.  *              Now we have a big table of DOS packets that we recognise while
  367.  *              monitoring. For each packet, we record the internal AmigaDOS ID
  368.  *              we use to recognise it, the message ID of its name, the number
  369.  *              of dp_Args to display, and the number of results to display.
  370.  */
  371.  
  372. /*              The following constants define how many parameters are returned
  373.  *              by the handler when it receives this packet. PK_0 means there is
  374.  *              no return value, PK_1 means 1 return value, PK_2 means there are
  375.  *              two return values (with the second being the error code if the
  376.  *              first one indicates failure) and PK_2OK means there are two actual
  377.  *              returned values, both of which are legitimate.
  378.  */
  379. #define PK_0                    0                       /* No return value from this packet             */
  380. #define PK_1                    1                       /* One return value from this packet    */
  381. #define PK_2                    2                       /* Two return values from this packet   */
  382. #define PK_2OK                  3                       /* Two return values even when okay             */
  383. #define PK_MASK                 3                       /* Used to extract PK_CODE                              */
  384.  
  385. /*
  386.  *              How to detect when an event failed. Selecting none of these means
  387.  *              that the packet can never fail.
  388.  */
  389. #define PKF_BOOL                0x08            /* True if zero result == fail                  */
  390. #define PKF_NEG                 0x10            /* True if -1 result == fail                    */
  391.  
  392. /*
  393.  *              We want to completely ignore some packets, namely all those sent
  394.  *              by the handler to lower level devices like timer.device or scsi.device
  395.  *              for its own needs. We use PK_IGNORE to identify all such packets
  396.  *              so we can discard them.
  397.  *
  398.  *              PK_COMMON packets are those which are monitored when the
  399.  *              "Monitor Packets" option is enabled. These are connected
  400.  *              with the associated DOS functions Open(), Lock() etc. and
  401.  *              are output as such by SnoopDos, rather than as raw packets.
  402.  *
  403.  *              PK_RAW is used for our sentinel packet which indicates that
  404.  *              even the packet type should be output since it's not recognised.
  405.  */
  406. #define PK_COMMON               0x20            /* Common packet (Open, Lock, etc.)             */
  407. #define PK_RAW                  0x40            /* Completely raw packet                                */
  408. #define PK_IGNORE               0x80            /* Ignore this packet completely                */
  409.  
  410. /*
  411.  *              Most packets return a value in dp_Res1 and if that value is
  412.  *              zero or -1, then the error code is in dp_Res2. We define
  413.  *              two constants to handle these common case.
  414.  */
  415. #define PK_BOOLEAN              (PKF_BOOL | PK_2)
  416. #define PK_NEGATIVE             (PKF_NEG  | PK_2)
  417.  
  418. /*
  419.  *              Warning: this table MUST be sorted by packet ID in ascending order,
  420.  *              since a binary search is used to locate packet types
  421.  */
  422. #define LAST_PACK_MSG           0
  423.  
  424. struct PacketRef {
  425.         UWORD   packetid;                               /* The ID we watch out for                              */
  426.         UWORD   msgid;                                  /* The name of the action to print              */
  427.         UBYTE   numparams;                              /* Number of parameters to display              */
  428.         UBYTE   flags;                                  /* How to interpret the result                  */
  429. } PacketTable[] = {
  430.         ACTION_STARTUP,                 MSG_ACT_STARTUP,                 1, PK_1,
  431.         ACTION_GET_BLOCK,               MSG_ACT_GET_BLOCK,               1, PK_IGNORE,
  432.         ACTION_SET_MAP,                 MSG_ACT_SET_MAP,                 1, PK_IGNORE,
  433.         ACTION_DIE,                             MSG_ACT_DIE,                     0, PK_BOOLEAN,
  434.         ACTION_EVENT,                   MSG_ACT_EVENT,                   1, PK_IGNORE,
  435.         ACTION_CURRENT_VOLUME,  MSG_ACT_CURRENT_VOLUME,  1, PK_2OK,
  436.         ACTION_LOCATE_OBJECT,   MSG_ACT_LOCATE_OBJECT,   3, PK_BOOLEAN | PK_COMMON,
  437.         ACTION_RENAME_DISK,             MSG_ACT_RENAME_DISK,     1, PK_BOOLEAN,
  438.         ACTION_FREE_LOCK,               MSG_ACT_FREE_LOCK,               1, PK_BOOLEAN,
  439.         ACTION_DELETE_OBJECT,   MSG_ACT_DELETE_OBJECT,   2, PK_BOOLEAN | PK_COMMON,
  440.         ACTION_RENAME_OBJECT,   MSG_ACT_RENAME_OBJECT,   4, PK_BOOLEAN | PK_COMMON,
  441.         ACTION_MORE_CACHE,              MSG_ACT_MORE_CACHE,              1, PKF_BOOL   | PK_2OK,
  442.         ACTION_COPY_DIR,                MSG_ACT_COPY_DIR,                1, PK_BOOLEAN,
  443.         ACTION_WAIT_CHAR,               MSG_ACT_WAIT_CHAR,               1, PKF_BOOL   | PK_2OK,
  444.         ACTION_SET_PROTECT,             MSG_ACT_SET_PROTECT,     4, PK_BOOLEAN,
  445.         ACTION_CREATE_DIR,              MSG_ACT_CREATE_DIR,              2, PK_BOOLEAN | PK_COMMON,
  446.         ACTION_EXAMINE_OBJECT,  MSG_ACT_EXAMINE_OBJECT,  2, PK_BOOLEAN,
  447.         ACTION_EXAMINE_NEXT,    MSG_ACT_EXAMINE_NEXT,    2, PK_BOOLEAN,
  448.         ACTION_DISK_INFO,               MSG_ACT_DISK_INFO,               1, PK_BOOLEAN,
  449.         ACTION_INFO,                    MSG_ACT_INFO,                    2, PK_BOOLEAN,
  450.         ACTION_FLUSH,                   MSG_ACT_FLUSH,                   0, PK_BOOLEAN,
  451.         ACTION_SET_COMMENT,             MSG_ACT_SET_COMMENT,     4, PK_BOOLEAN,
  452.         ACTION_PARENT,                  MSG_ACT_PARENT,                  1, PK_BOOLEAN,
  453.         ACTION_TIMER,                   MSG_ACT_TIMER,                   1, PK_IGNORE,
  454.         ACTION_INHIBIT,                 MSG_ACT_INHIBIT,                 1, PK_BOOLEAN,
  455.         ACTION_DISK_TYPE,               MSG_ACT_DISK_TYPE,               1, PK_IGNORE,
  456.         ACTION_DISK_CHANGE,             MSG_ACT_DISK_CHANGE,     1, PK_1,
  457.         ACTION_SET_DATE,                MSG_ACT_SET_DATE,                4, PK_BOOLEAN,
  458.         ACTION_SAME_LOCK,               MSG_ACT_SAME_LOCK,               2, PK_BOOLEAN,
  459.         ACTION_READ,                    MSG_ACT_READ,                    3, PK_NEGATIVE,
  460.         ACTION_WRITE,                   MSG_ACT_WRITE,                   3, PK_NEGATIVE,
  461.         ACTION_SCREEN_MODE,             MSG_ACT_SCREEN_MODE,     1, PK_BOOLEAN,
  462.         ACTION_CHANGE_SIGNAL,   MSG_ACT_CHANGE_SIGNAL,   3, PKF_BOOL   | PK_2OK,
  463.         ACTION_READ_RETURN,             MSG_ACT_READ_RETURN,     1, PK_IGNORE,
  464.         ACTION_WRITE_RETURN,    MSG_ACT_WRITE_RETURN,    1, PK_IGNORE,
  465.         ACTION_FINDUPDATE,              MSG_ACT_FINDUPDATE,              3, PK_BOOLEAN | PK_COMMON,
  466.         ACTION_FINDINPUT,               MSG_ACT_FINDINPUT,               3, PK_BOOLEAN | PK_COMMON,
  467.         ACTION_FINDOUTPUT,              MSG_ACT_FINDOUTPUT,              3, PK_BOOLEAN | PK_COMMON,
  468.         ACTION_END,                             MSG_ACT_END,                     1, PK_BOOLEAN,
  469.         ACTION_SEEK,                    MSG_ACT_SEEK,                    3, PK_NEGATIVE,
  470.         ACTION_FORMAT,                  MSG_ACT_FORMAT,                  2, PK_BOOLEAN,
  471.         ACTION_MAKE_LINK,               MSG_ACT_MAKE_LINK,               4, PK_BOOLEAN | PK_COMMON,
  472.         ACTION_SET_FILE_SIZE,   MSG_ACT_SET_FILE_SIZE,   3, PK_NEGATIVE,
  473.         ACTION_WRITE_PROTECT,   MSG_ACT_WRITE_PROTECT,   2, PK_BOOLEAN,
  474.         ACTION_READ_LINK,               MSG_ACT_READ_LINK,               4, PK_BOOLEAN,
  475.         ACTION_FH_FROM_LOCK,    MSG_ACT_FH_FROM_LOCK,    2, PK_BOOLEAN,
  476.         ACTION_IS_FILESYSTEM,   MSG_ACT_IS_FILESYSTEM,   0, PK_BOOLEAN,
  477.         ACTION_CHANGE_MODE,             MSG_ACT_CHANGE_MODE,     3, PK_BOOLEAN,
  478.         ACTION_COPY_DIR_FH,             MSG_ACT_COPY_DIR_FH,     1, PK_BOOLEAN,
  479.         ACTION_PARENT_FH,               MSG_ACT_PARENT_FH,               1, PK_BOOLEAN,
  480.         ACTION_EXAMINE_ALL,             MSG_ACT_EXAMINE_ALL,     5, PK_BOOLEAN,
  481.         ACTION_EXAMINE_FH,              MSG_ACT_EXAMINE_FH,              2, PK_BOOLEAN,
  482.         ACTION_EXAMINE_ALL_END, MSG_ACT_EXAMINE_ALL_END, 5, PK_BOOLEAN,
  483.         ACTION_SET_OWNER,               MSG_ACT_SET_OWNER,               4, PK_BOOLEAN,
  484.         ACTION_DOUBLE,                  MSG_ACT_DOUBLE,                  3, PK_BOOLEAN,
  485.         ACTION_FORCE,                   MSG_ACT_FORCE,                   3, PK_BOOLEAN,
  486.         ACTION_STACK,                   MSG_ACT_STACK,                   3, PK_BOOLEAN,
  487.         ACTION_QUEUE,                   MSG_ACT_QUEUE,                   3, PK_BOOLEAN,
  488.         ACTION_DROP,                    MSG_ACT_DROP,                    1, PK_BOOLEAN,
  489.         ACTION_LOCK_RECORD,             MSG_ACT_LOCK_RECORD,     5, PK_BOOLEAN,
  490.         ACTION_FREE_RECORD,             MSG_ACT_FREE_RECORD,     3, PK_BOOLEAN,
  491.         ACTION_ADD_NOTIFY,              MSG_ACT_ADD_NOTIFY,              1, PK_BOOLEAN,
  492.         ACTION_REMOVE_NOTIFY,   MSG_ACT_REMOVE_NOTIFY,   1, PK_BOOLEAN,
  493.         ACTION_SERIALIZE_DISK,  MSG_ACT_SERIALIZE_DISK,  0, PK_BOOLEAN,
  494.         ACTION_GET_DISK_FSSM,   MSG_ACT_GET_DISK_FSSM,   0, PK_BOOLEAN,
  495.         ACTION_FREE_DISK_FSSM,  MSG_ACT_FREE_DISK_FSSM,  0, PK_BOOLEAN,
  496.         /*
  497.          *              Our final table entry is used as a sentinel -- we key off the
  498.          *              final packet message as an indication that we're finished
  499.          *              searching the table.
  500.          */
  501.         0,                                              LAST_PACK_MSG,                   4, PK_2OK | PK_RAW
  502. };
  503.  
  504. #define NUM_PACKETS             (sizeof(PacketTable) / sizeof(PacketTable[0]))
  505.  
  506. /*****************************************************************************
  507.  *
  508.  *              Start of functions!
  509.  *
  510.  *****************************************************************************/
  511.  
  512. /*
  513.  *              InitPatches()
  514.  *
  515.  *              Sets up the library pointers and makes sure all the patch
  516.  *              code vectors are initialised properly.
  517.  *
  518.  *              Also allocates memory for the patches (if necessary)
  519.  *
  520.  *              Returns TRUE for success, FALSE for failure.
  521.  */
  522. int InitPatches(void)
  523. {
  524.         struct PatchInitTable *pi;
  525.         Patch *p;
  526.         int i;
  527.  
  528.         /*
  529.          *              Before doing anything else, do a quick check to ensure that
  530.          *              the patch code in PATCHCODE.S agrees with the equivalent patch
  531.          *              structure defined in this file.
  532.          */
  533.         if (CODESIZE != PatchCode_Size || STACKADJUST != PatchCode_StackAdjust) {
  534.                 Printf("In patches.c, adjust CODESIZE by %ld and STACKADJUST by %ld\n",
  535.                                 PatchCode_Size-CODESIZE, PatchCode_StackAdjust-STACKADJUST);
  536.                 return (FALSE);
  537.         }
  538.  
  539.         LibList[DOS_LIB]                = DOSBase;
  540.         LibList[EXEC_LIB]               = SysBase;
  541.         LibList[INTUITION_LIB]  = IntuitionBase;
  542.         LibList[GRAPHICS_LIB]   = GfxBase;
  543.         LibList[ICON_LIB]               = IconBase;
  544.  
  545.         /*
  546.          *              First, let's calculate our ROM start and end address.
  547.          *              We do this by getting the address pointed to by the
  548.          *              Open LVO vector in exec.library and rounding it down
  549.          *              to the nearest 512K
  550.          */
  551.         RomStart = (*((ULONG *)(((char *)SysBase) + LIB_OPEN + 2))) & 0xFFF80000;
  552.         RomEnd   = RomStart + 0x7FFFF;
  553.  
  554.         /*
  555.          *              Now see if the patches were already installed by an earlier
  556.          *              version of SnoopDos.
  557.          */
  558.         Forbid();
  559.         PatchAnchor = (PatchAnchorData *)FindSemaphore(PATCHES_NAME);
  560.         if (!PatchAnchor) {
  561.                 /*
  562.                  *              Patches weren't found, so allocate a new set and initialise
  563.                  *              it with our patch code.
  564.                  */
  565.                 PatchAnchor = AllocMem(sizeof(PatchAnchorData) + PatchInitSize,
  566.                                                            MEMF_ANY | MEMF_CLEAR);
  567.                 if (!PatchAnchor) {
  568.                         Permit();
  569.                         return (FALSE);
  570.                 }
  571.                 strcpy(PatchAnchor->name, PATCHES_NAME);
  572.                 PatchAnchor->sem.ss_Link.ln_Name = PatchAnchor->name;
  573.                 PatchAnchor->sem.ss_Link.ln_Pri  = 0;
  574.                 AddSemaphore(&PatchAnchor->sem);
  575.         }
  576.         /*
  577.          *              Now PatchAnchor points to our patch list in memory -- copy over
  578.          *              our patch code and initialised data accordingly.
  579.          */
  580.         PatchList = PatchAnchor->patchdata;
  581.         for (pi = PatchInit+1, p = PatchList+1; pi->offset; p++, pi++) {
  582.                 memcpy(p->code, PatchCode_Start, CODESIZE);
  583.                 p->library              = pi->library;
  584.                 p->offset               = pi->offset;
  585.                 p->newfunc              = pi->newfunc;
  586.                 p->stackneeded  = CurSettings.StackLimit;
  587.                 p->sysbase              = SysBase;
  588.         }
  589.         CacheClearU();  /* Invalidate cache for code we just built */
  590.         Permit();
  591.  
  592.         /*
  593.          *              Now initialise other variables associated with the patch code
  594.          */
  595.         SnoopTask       = SysBase->ThisTask;
  596.         InputTask       = FindTask("input.device");
  597.         InitRamLibPatch();
  598.         InitSemaphore(&PatternBufSem);
  599.         InitSemaphore(&PatternCacheSem);
  600.         InitSemaphore(&TaskCacheSem);
  601.         InitSemaphore(&DosDeviceSem);
  602.         InitSemaphore(&PauseSem);
  603.         InitSemaphore(&PacketSem);
  604.  
  605.         UpdateDeviceList(SCANDEV_IMMEDIATE);
  606.  
  607.         NewList(&PatternList);
  608.         for (i = 0; i < NUM_PCACHE_ENTRIES; i++)
  609.                 AddHead(&PatternList, (Node *)&PCacheEntries[i]);
  610.  
  611.         NewList(&PacketWaitList);
  612.         NewList(&PacketFreeList);
  613.         for (i = 0; i < NUM_PACKET_ENTRIES; i++)
  614.                 AddHead(&PacketFreeList, (Node *)&PacketEntries[i]);
  615.  
  616.         NewEventSig = AllocSignal(-1);
  617.         if (NewEventSig == -1)
  618.                 return (FALSE);
  619.         NewEventMask = 1 << NewEventSig;
  620.  
  621.         /*
  622.          *              Signal bit used to tell main task to rescan device list because
  623.          *              a device was added (or removed?)
  624.          */
  625.         ScanDosListSig = AllocSignal(-1);
  626.         if (ScanDosListSig == -1)
  627.                 return (FALSE);
  628.         ScanDosListMask = 1 << ScanDosListSig;
  629.  
  630.         /*
  631.          *              Now create a background process to handle process matching.
  632.          *              We run this at a high priority to ensure quick response.
  633.          *
  634.          *              We first of all initialise our pattern port, and set it
  635.          *              to NOT signal our task when a message arrives. This ensures
  636.          *              that if, for some reason, our new process doesn't run
  637.          *              until after someone tries to send it a message, nothing
  638.          *              bad will happen (e.g. signalling a task at 0x0000)
  639.          *
  640.          *              The background process itself will replace this with
  641.          *              PA_SIGNAL to make things work normally again.
  642.          */
  643.         NewList(&BackgroundPort.mp_MsgList);
  644.         BackgroundPort.mp_Flags = PA_IGNORE;
  645.         BackgroundProc = CreateNewProcTags(NP_Entry,     BackgroundProcCode,
  646.                                                                            NP_Name,      BACKGROUND_NAME,
  647.                                                                            NP_Priority,  5,
  648.                                                                            TAG_DONE);
  649.  
  650.         return (BackgroundProc != NULL);
  651. }
  652.  
  653. /*
  654.  *              UpdatePatches()
  655.  *
  656.  *              Scans the list of patches, updating our behaviour as follows.
  657.  *              This means:
  658.  *
  659.  *                      - Any patch that's currently active and which has been flagged
  660.  *                        as inactive should be disabled if possible (i.e. origfunc
  661.  *                        set to NULL).
  662.  *
  663.  *                      - Any patch that's currently inactive and which has been flagged
  664.  *                        as active should be enabled if possible (i.e. origfunc set
  665.  *                        to point to the original function).
  666.  *
  667.  *              If we are currently Disabled, then all patches are made inactive.
  668.  *
  669.  */
  670. void UpdatePatches(void)
  671. {
  672.         Patch *p;
  673.  
  674.         if (!PatchList)
  675.                 return;
  676.  
  677.         if (MonPackets || ShowAllPackets)
  678.                 UpdateDeviceList(SCANDEV_IMMEDIATE); /* Keep device list up to date */
  679.  
  680.         Forbid();                       /* Don't even think about letting anyone else run! */
  681.  
  682.         /*
  683.          *              Update status of pair functions to reflect the master
  684.          *              function's status
  685.          */
  686.         PatchList[GID_READTOOLTYPES2].enabled   =
  687.                                                         PatchList[GID_READTOOLTYPES].enabled;
  688.         PatchList[GID_LOADSEG2].enabled                 =
  689.                                                         PatchList[GID_LOADSEG].enabled;
  690.         PatchList[GID_GETVAR2].enabled                  =
  691.                                                         PatchList[GID_GETVAR].enabled;
  692.         PatchList[GID_SETVAR2].enabled                  =
  693.                                                         PatchList[GID_SETVAR].enabled;
  694.  
  695.         for (p = PatchList+1; p->offset; p++) {
  696.                 void *lib        = LibList[p->library];
  697.                 int func_enabled = (Disabled ? PATCH_DISABLED : p->enabled);
  698.  
  699.                 p->stackneeded   = CurSettings.StackLimit;      /* Update this */
  700.  
  701.                 if (!lib)                       /* Skip over any libraries we couldn't open */
  702.                         continue;
  703.  
  704.                 if (p->origfunc == NULL && func_enabled != PATCH_DISABLED) {
  705.                         /*
  706.                          *              Okay, we want to enable this function.
  707.                          */
  708.                         p->origfunc = (FuncPtr)SetFunction(lib, p->offset, (FuncPtr)p);
  709.                 } else if (p->origfunc && func_enabled == PATCH_DISABLED) {
  710.                         /*
  711.                          *              Okay, we want to disable this function. However, we
  712.                          *              may not be able to do this cleanly, if it's been
  713.                          *              since patched by someone else. Thus, if our attempt
  714.                          *              to unpatch it doesn't return a pointer to our replacement
  715.                          *              code, we have to leave the patch installed. However, it
  716.                          *              will be re-tried automatically the next time someone
  717.                          *              calls this function.
  718.                          */
  719.                         FuncPtr curfunc = (FuncPtr)SetFunction(lib, p->offset, p->origfunc);
  720.  
  721.                         if (curfunc != (FuncPtr)p) {
  722.                                 /*
  723.                                  *              Uhoh -- someone else patched us!
  724.                                  */
  725.                                 SetFunction(lib, p->offset, (FuncPtr)curfunc);
  726.                         } else {
  727.                                 /*
  728.                                  *              We unpatched successfully, so zero pointer
  729.                                  */
  730.                                 p->origfunc = NULL;
  731.                         }
  732.                 }
  733.         }
  734.         /*
  735.          *              We disable stack monitoring for the PutMsg() patch because
  736.          *              we need to catch the return packet from small-stack processes
  737.          *              like RAM: etc. Instead, that patch does its own stack checking.
  738.          */
  739.         PatchList[GID_SENDREXX].stackneeded = 0;
  740.  
  741.         CacheClearU();  /* Just to be safe */
  742.         Permit();
  743.         /*
  744.          *              Finally, check if we've disabled packet monitoring and
  745.          *              there are some outstanding packets that have not yet had
  746.          *              return values assigned. Free them all as appropriate
  747.          */
  748.         if (!MonPackets && !ShowAllPackets)
  749.         {
  750.                 for (;;) {
  751.                         WaitPacket *wp;
  752.                         Event *ev;
  753.                         LONG  seqnum;
  754.  
  755.                         ObtainSemaphore(&PacketSem);
  756.                         if (IsListEmpty(&PacketWaitList)) {
  757.                                 ReleaseSemaphore(&PacketSem);
  758.                                 break;
  759.                         }
  760.                         wp         = (WaitPacket *)RemHead(&PacketWaitList);
  761.                         AddHead(&PacketFreeList, (Node *)wp);
  762.                         ev         = wp->event;
  763.                         seqnum = wp->eventnum;
  764.                         ReleaseSemaphore(&PacketSem);
  765.  
  766.                         if (AttemptSemaphoreHeavely(&BufSem)) {
  767.                                 if (seqnum >= RealFirstSeq) {
  768.                                         ev->status = ES_READY;
  769.                                         Signal(SnoopTask, NewEventMask);
  770.                                 }
  771.                                 ReleaseSemaphore(&BufSem);
  772.                         }
  773.                 }
  774.         }
  775. }
  776.  
  777. /*
  778.  *              CleanupPatches()
  779.  *
  780.  *              Frees any resources allocated when initialising this module. Also
  781.  *              disable any patches that are still active.
  782.  */
  783. void CleanupPatches(void)
  784. {
  785.         static int unpatchtries = 0;
  786.  
  787.         if (PatchList) {
  788.                 struct PatchInitTable *pi;
  789.                 Patch *p;
  790.  
  791.                 for (p = PatchList+1; p->offset; p++)
  792.                         p->enabled = PATCH_DISABLED;
  793.                 UpdatePatches();
  794.  
  795.                 /*
  796.                  *              Now our patches have been disabled, and it's time to
  797.                  *              ensure nobody got left inside our code. We do this by
  798.                  *              checking that all the usecounts are set to zero, and if
  799.                  *              they're not, giving the user the option of continuing
  800.                  *              to try, or exiting.
  801.                  *
  802.                  *              Before we do this, however, we record all the functions
  803.                  *              which still have a usecount > 0 -- this way, if someone
  804.                  *              else runs SnoopDos while we are checking and installs
  805.                  *              a new set of patches in the patchtable, and enables
  806.                  *              some additional functions, we don't have to check that
  807.                  *              ALL usage counts are zero, only those which were non-zero
  808.                  *              at the start of the loop.
  809.                  *
  810.                  *              (That is, we ignore any usage counts which are results of
  811.                  *              functions being re-enabled by the new SnoopDos -- typically,
  812.                  *              there will only be one or two functions at most to be
  813.                  *              checked.)
  814.                  *
  815.                  *              For convenience, we re-use the PatchInit list to hold the
  816.                  *              exit "usage" states for each function -- we won't be needing
  817.                  *              it any more.
  818.                  */
  819.                 for (p = (PatchList+1), pi = (PatchInit+1); p->offset; p++, pi++)
  820.                         pi->offset = p->usecount;
  821.  
  822.                 for (;;) {
  823.                         for (p = (PatchList+1), pi = (PatchInit+1); p->offset; p++, pi++) {
  824.                                 if (pi->offset > 0) {
  825.                                         if (p->usecount > 0)
  826.                                                 break;
  827.                                         pi->offset = 0; /* No longer active, so mark as done */
  828.                                 }
  829.                         }
  830.                         if (p->offset) {
  831.                                 /*
  832.                                  *              Couldn't unpatch, so go around the loop and try
  833.                                  *              again. After about 8-10 seconds, we warn the user
  834.                                  *              that we're still trying.
  835.                                  */
  836.                                 unpatchtries++;
  837.                                 if (unpatchtries == 5) {
  838.                                         char errorbuf[400];
  839.  
  840.                                         mysprintf(errorbuf, MSG(MSG_ERROR_UNPATCH),
  841.                                                           GetFuncName(p - PatchList));
  842.                                         ShowError(errorbuf);
  843.                                 }
  844.                                 Delay(2*50);            /* Wait 2 seconds before next try */
  845.                         } else
  846.                                 break;
  847.                 }
  848.         }
  849.         if (BackgroundProc) {
  850.                 /*
  851.                  *              Send a terminate message to the pattern process and wait
  852.                  *              for it to respond
  853.                  */
  854.                 PatternMsg pmsg;
  855.  
  856.                 pmsg.type                = QUIT_MSG;
  857.                 pmsg.sigmask                     = SIGF_SINGLE;
  858.                 pmsg.task                                = SysBase->ThisTask;
  859.                 pmsg.msg.mn_Node.ln_Name = NULL;
  860.  
  861.                 SetSignal(0, SIGF_SINGLE);              /* Ensure signal is clear first */
  862.                 PutMsg(&BackgroundPort, &pmsg); /* Send quit message to process */
  863.                 Wait(SIGF_SINGLE);                              /* Wait for acknowledgement             */
  864.         }
  865.         if (NewEventSig    != -1) FreeSignal(NewEventSig),    NewEventSig    = -1;
  866.         if (ScanDosListSig != -1) FreeSignal(ScanDosListSig), ScanDosListSig = -1;
  867. }
  868.  
  869. /*
  870.  *              InitRamLibPatch()
  871.  *
  872.  *              Attempts to patch the ramlib process so that it no longer uses
  873.  *              a message port with the signal bit set to SIGB_SINGLE (which
  874.  *              is asking for trouble if you call any functions that use
  875.  *              semaphores, since a SIGB_SINGLE can be generated by a message
  876.  *              arriving at the message port while waiting for the semaphore,
  877.  *              causing all hell to break loose -- the semaphore appears to be
  878.  *              obtained while in fact it's still in use by someone else).
  879.  */
  880. void InitRamLibPatch(void)
  881. {
  882.         unsigned char *ramdata;
  883.         int i;
  884.  
  885.         RealRamLibTask = FindTask("ramlib");
  886.         if (NoPatchRamLib || !RealRamLibTask) {
  887.                 /*
  888.                  *              Not patching ramlib, so instead, install our bypass patch
  889.                  *              that stops us from monitoring any ramlib tasks so that
  890.                  *              we won't get crashed.
  891.                  */
  892.                 RamLibTask = RealRamLibTask;
  893.         } else {
  894.                 /*
  895.                  *              Patch ramlib itself so that it doesn't use SIGF_SINGLE
  896.                  *              any more.
  897.                  */
  898.                 ramdata = (void *)SysBase->ex_RamLibPrivate;
  899.                 if (!ramdata) {
  900.                         /*
  901.                          *              You never know ... this field may no longer exist. If
  902.                          *              it doesn't, then assume the bug no longer exists either
  903.                          *              and exit.
  904.                          */
  905.                         return;
  906.                 }
  907.                 for (i = 0x20; i < 0x50; i += 2) {
  908.                         struct MsgPort *ramport = (struct MsgPort *)(ramdata + i);
  909.  
  910.                         /*
  911.                          *              Depending on the Kickstart version (V37 through V40)
  912.                          *              the ramlib message port lies somewhere in the range
  913.                          *              0x30 to 0x50 of the ramlib's private area. We do
  914.                          *              some integrity checks on the port to make sure it's
  915.                          *              not just a lucky hit. If some future SetPatch fixes
  916.                          *              this, then we will never find a match, which suits
  917.                          *              us fine.
  918.                          */
  919.                         if (ramport->mp_Flags   == 0                    &&
  920.                                 ramport->mp_SigBit  == SIGB_SINGLE      &&
  921.                                 ramport->mp_SigTask == RealRamLibTask)
  922.                         {
  923.                                 /*
  924.                                  *              Now patch ramlib's message port so it won't use
  925.                                  *              SIGB_SINGLE any more. This is a little tricky, since
  926.                                  *              ramlib process will be in the middle of WaitPort()
  927.                                  *              and WaitPort() won't return until a message arrives at
  928.                                  *              the port. Essentially, we can only change the port's
  929.                                  *              message bit while we are sure that the ramlib process
  930.                                  *              is NOT in a WaitPort(). We do this by bumping our
  931.                                  *              process priority up to 127 temporarily, making the
  932.                                  *              call, and then restoring it.
  933.                                  *
  934.                                  *              Since we're at a higher priority than ramlib, then
  935.                                  *              as soon as ramlib responds to the message, it will
  936.                                  *              be switched out (in the Ready state) before it has a
  937.                                  *              chance to call WaitPort() and go back to sleep again.
  938.                                  */
  939.                                 ULONG oldpri;
  940.  
  941.                                 Forbid();
  942.                                 oldpri = SetTaskPri(SysBase->ThisTask, 127);
  943.                                 OpenLibrary("ramlib-patch.library", 0); /* Wake-up ramlib */
  944.                                 ramport->mp_SigBit = SIGBREAKB_CTRL_E;
  945.                                 SetTaskPri(SysBase->ThisTask, oldpri);
  946.                                 Permit();
  947.                                 break;
  948.                         }
  949.                 }
  950.         }
  951. }
  952.  
  953. /*
  954.  *              UpdateDeviceList(method)
  955.  *
  956.  *              Updates the DOS device list. This is used to keep an internal list
  957.  *              of all the task IDs of DOS handlers so we can quickly determine
  958.  *              if a given ID belongs to a handler or not.
  959.  *
  960.  *              This should be called at least once, and ideally every now and
  961.  *              again, so that new devices added to the DOS list can be detected
  962.  *              and old ones ignored.
  963.  *
  964.  *              The method can be SCANDEV_IMMEDIATE, to immediately scan the device
  965.  *              list, or SCANDEV_DELAY to wait for a second before updating. The
  966.  *              delay is because the patch that signals us to rescan (AddDosEntry)
  967.  *              happens before the device is actually fully initialised, so we need
  968.  *              to give it a little extra time to get going.
  969.  *
  970.  *              It's not critical if we don't give it enough time, it just means
  971.  *              that the new device won't appear in the list after all -- a bit
  972.  *              annoying for people using the packet debugger to help debug a
  973.  *              device they keep mounting interactively.
  974.  */
  975. void UpdateDeviceList(int method)
  976. {
  977.         struct DosList *dlist;
  978.         int i = 0;
  979.  
  980.         if (method == SCANDEV_DELAY)
  981.                 Delay(50);
  982.  
  983.         ObtainSemaphore(&DosDeviceSem);
  984.         dlist = LockDosList(LDF_DEVICES | LDF_READ);
  985.         while ((dlist = NextDosEntry(dlist, LDF_DEVICES))
  986.                          && i < (MAX_DOS_DEVICES-1))
  987.         {
  988.                 if (dlist->dol_Task)
  989.                         DeviceTaskList[i++] = dlist->dol_Task->mp_SigTask;
  990.         }
  991.         UnLockDosList(LDF_DEVICES | LDF_READ);
  992.         DeviceTaskList[i] = 0;
  993. #if 0
  994.         Printf("New device list:\n");
  995.         for (i = 0; DeviceTaskList[i]; i++)
  996.                 Printf("    %2ld = %s\n", i, DeviceTaskList[i]->tc_Node.ln_Name);
  997. #endif
  998.         ReleaseSemaphore(&DosDeviceSem);
  999. }
  1000.  
  1001. /*
  1002.  *              SetPattern(string, ignorewb)
  1003.  *
  1004.  *              Sets the current pattern to the given string (possibly containing
  1005.  *              wildcards). If ignorewb is true, then the pattern is modified to
  1006.  *              also exclude any processes with the names Workbench, Shell Process
  1007.  *              or Background CLI.
  1008.  */
  1009. void SetPattern(char *pattern, int ignorewb)
  1010. {
  1011.         PatternCache *pc;
  1012.         char *p;
  1013.  
  1014.         if (*pattern == '\0' && !ignorewb) {
  1015.                 PatternEnabled = 0;
  1016.                 return;
  1017.         }
  1018.         ObtainSemaphore(&PatternCacheSem);
  1019.         ObtainSemaphore(&PatternBufSem);
  1020.         PatternEnabled = 0;
  1021.  
  1022.         /*
  1023.          *              Now, update our pattern string. If the pattern string is empty,
  1024.          *              we disable patterns. If the pattern string contains no wildcards,
  1025.          *              we enable patterns but disable wildcard patching (this is much
  1026.          *              faster, since it can be done in the patch's task, rather than
  1027.          *              having to call back to the main routine).
  1028.          *
  1029.          *              We allocate both pattern semaphores: the Cache semaphore to
  1030.          *              ensure that no pattern code can execute when PatternEnabled
  1031.          *              is zero, and the buffer semaphore to ensure that the pattern
  1032.          *              process doesn't try to do pattern matching while we are
  1033.          *              building the new pattern string.
  1034.          *
  1035.          *              We need to be careful to get the cache semaphore BEFORE we get
  1036.          *              the pattern buffer semaphore, otherwise we could deadlock if
  1037.          *              a patch decided to check a pattern at just the wrong time.
  1038.          */
  1039.         if (ignorewb) {
  1040.                 if (*pattern == '\0')
  1041.                         strcpy(PatternString, PAT_EASY_EXCLUDE);
  1042.                 else
  1043.                         mysprintf(PatternString, PAT_COMPLEX_EXCLUDE, pattern);
  1044.         } else
  1045.                 strcpy(PatternString, pattern);
  1046.  
  1047.         /*
  1048.          *              Now, due to a bug in AmigaDOS's ParsePatternNoCase, we
  1049.          *              have to convert the string to upper case first. (The bug
  1050.          *              is that character classes like [a-z] will never match anything,
  1051.          *              only [A-Z] will work. Since it's case insensitive for
  1052.          *              everything else, we simply convert everything to upper case.)
  1053.          */
  1054.         for (p = PatternString; *p; p++) {
  1055.                 if (*p >= 'a' && *p <= 'z')
  1056.                         *p &= 0x5F;
  1057.         }
  1058.         PatternWildcard = ParsePatternNoCase(PatternString,
  1059.                                                                                  PatternBuf, PAT_BUF_LEN);
  1060.  
  1061.         if (PatternWildcard != -1)      /* Only enable patterns if successful */
  1062.                 PatternEnabled = 1;
  1063.  
  1064.         /*
  1065.          *              Regardless of what happened, invalidate the pattern cache
  1066.          *              to force a new match for each task name.
  1067.          */
  1068.         FORLIST(&PatternList, pc)
  1069.                 pc->task = NULL;
  1070.  
  1071.         ReleaseSemaphore(&PatternBufSem);
  1072.         ReleaseSemaphore(&PatternCacheSem);
  1073. }
  1074.  
  1075. /*
  1076.  *              FlushWaitingPackets(void)
  1077.  *
  1078.  *              Flushes any packets currently in the waiting packets queue
  1079.  *              (marking them as missed). Usually called after packet monitoring
  1080.  *              has been disabled, in case there were any half-completed packets
  1081.  *              in the queue.
  1082.  */
  1083. void FlushWaitingPackets(void)
  1084. {
  1085.         WaitPacket *wp;
  1086.         int flushed = 0;
  1087.  
  1088.         ObtainSemaphore(&PacketSem);
  1089.         wp = HeadNode(&PacketWaitList);
  1090.         while (NextNode(wp)) {
  1091.                 ULONG seqnum = wp->eventnum;
  1092.                 Event *ev    = wp->event;
  1093.  
  1094.                 Remove((Node *)wp);
  1095.                 AddHead(&PacketFreeList, (Node *)wp);
  1096.                 ReleaseSemaphore(&PacketSem);   /* Never lock two sem's at once! */
  1097.                 if (AttemptSemaphoreHeavely(&BufSem)) {
  1098.                         if (seqnum >= RealFirstSeq) {
  1099.                                 ev->result = MSG(MSG_RES_MISSED);
  1100.                                 ev->status = ES_READY;
  1101.                                 flushed    = 1;
  1102.                         }
  1103.                         ReleaseSemaphore(&BufSem);
  1104.                 }
  1105.                 ObtainSemaphore(&PacketSem);
  1106.                 wp = HeadNode(&PacketWaitList);
  1107.         }
  1108.         ReleaseSemaphore(&PacketSem);
  1109.  
  1110.         if (flushed)
  1111.                 Signal(SnoopTask, NewEventMask);
  1112. }
  1113.  
  1114. /*
  1115.  *              LoadFuncSettings(FuncSets)
  1116.  *
  1117.  *              Downloads the values in the passed-in FuncSettings array to the
  1118.  *              various local structures that require them.
  1119.  */
  1120. void LoadFuncSettings(FuncSettings *func)
  1121. {
  1122.         Patch *p;
  1123.         int i;
  1124.  
  1125.         if (!PatchList)
  1126.                 return;
  1127.  
  1128.         Forbid();
  1129.         for (p = PatchList+1, i = 1; p->offset; p++, i++)
  1130.                 p->enabled = ((func->Opts[i] && !Disabled) ?
  1131.                                                         PATCH_ENABLED : PATCH_DISABLED);
  1132.         /*
  1133.          *              A bit of a hack -- the PutMsg() function is needed to monitor
  1134.          *              three individual patches: SendRexx, Monitor Packets, and
  1135.          *              Packet Debugger. We do the check for the last two here.
  1136.          */
  1137.         if ((func->Opts[GID_MONPACKETS] || func->Opts[GID_MONALLPACKETS]) &&
  1138.              !Disabled)
  1139.         {
  1140.                 PatchList[GID_SENDREXX].enabled    = PATCH_ENABLED;
  1141.                 PatchList[GID_ADDDOSENTRY].enabled = PATCH_ENABLED;
  1142.         } else {
  1143.                 PatchList[GID_ADDDOSENTRY].enabled = PATCH_DISABLED;
  1144.                 FlushWaitingPackets();
  1145.         }
  1146.         UpdatePatches();
  1147.         Permit();
  1148.         SetPattern(func->Pattern, func->Opts[GID_IGNOREWB]);
  1149. }
  1150.  
  1151. /*
  1152.  *              BackgroundProcCode()
  1153.  *
  1154.  *              This function is called as a separate process. It is used
  1155.  *              to service requests for pattern matching by patched code.
  1156.  *              We do this in a separate process to ensure we have enough
  1157.  *              stack to perform the pattern matching (pattern matching can
  1158.  *              be very stack-intensive.)
  1159.  *
  1160.  *              This process is also used to do pathname expansion when we
  1161.  *              are monitoring packets -- this is needed for both the
  1162.  *              ShowAllPaths option and monitoring of the ACTION_MAKE_LINK packet.
  1163.  *
  1164.  *              We keep going until we get a QUIT_MSG from the main task,
  1165.  *              at which point we exit.
  1166.  */
  1167. void __saveds BackgroundProcCode(void)
  1168. {
  1169. #if DEBUG_PATTERN
  1170.         BPTR dbfile = Open("CON:100/100/400/100/Pattern/WAIT/AUTO/CLOSE",
  1171.                                            MODE_OLDFILE);
  1172. #define DBP(s)  FPrintf s
  1173. #else
  1174. #define DBP(s)
  1175. #endif
  1176.  
  1177.         Task  *quittask;
  1178.         ULONG  quitsig;
  1179.         int    done = 0;
  1180.  
  1181.         /*
  1182.          *              Our first task is to re-route the message port allocated
  1183.          *              on our behalf by the main process so that it points to us.
  1184.          *              We also re-enable signals on incoming messages to ensure
  1185.          *              we are correctly interrupted.
  1186.          */
  1187.         BackgroundPort.mp_SigTask = SysBase->ThisTask;
  1188.         BackgroundPort.mp_SigBit  = AllocSignal(-1);    /* Better not fail!             */
  1189.         BackgroundPort.mp_Flags   = PA_SIGNAL;                  /* Allow signalling now */
  1190.         DBP((dbfile, "Started pattern debug code\n"));
  1191.  
  1192.         while (!done) {
  1193.                 /*              Now handle all pattern messages queue on the pattern port.
  1194.                  *              Unlike normal messages, we don't simply reply to these
  1195.                  *              with ReplyMsg(); instead, we signal the indicated task
  1196.                  *              using the signal bit specified in the message.
  1197.                  *
  1198.                  *              This is because the sender may not have an available
  1199.                  *              signal bit to use to receive the reply so it uses a
  1200.                  *              system bit which is guaranteed to be unused.
  1201.                  *
  1202.                  *              Note that we grab the pattern semapore while we process
  1203.                  *              the messages; this stops the mainline code from updating
  1204.                  *              the middle of the buffer while we are doing a comparison.
  1205.                  */
  1206.                 PatternMsg      *pmsg;
  1207.                 NameFromLockMsg *lmsg;
  1208.  
  1209.                 WaitPort(&BackgroundPort);
  1210.  
  1211.                 ObtainSemaphore(&PatternBufSem);
  1212.                 while ((pmsg = (void *)GetMsg(&BackgroundPort)) != NULL) {
  1213.                         DBP((dbfile, "Got a message, type = %ld!\n", pmsg->type));
  1214.                         switch (pmsg->type) {
  1215.  
  1216.                                 case QUIT_MSG:
  1217.                                         /*
  1218.                                          *              We've been told to quit by the main task, so
  1219.                                          *              set some variables appropriately. We flush
  1220.                                          *              the remaining messages in the queue first
  1221.                                          *              just to be safe (we wouldn't want to leave
  1222.                                          *              anyone hanging, now, would we?)
  1223.                                          */
  1224.                                         PatternEnabled  = 0;    /* Safety first */
  1225.                                         done                    = 1;
  1226.                                         quittask                = pmsg->task;
  1227.                                         quitsig                 = pmsg->sigmask;
  1228.                                         break;
  1229.  
  1230.                                 case PATTERN_MSG:
  1231.                                         DBP((dbfile, "Got a pmatch from %s\n", pmsg->name));
  1232.                                         if (PatternEnabled)
  1233.                                                 pmsg->match = MatchPatternNoCase(PatternBuf,
  1234.                                                                                                                  pmsg->name);
  1235.                                         else
  1236.                                                 pmsg->match = 1; /* If disabled, everything matches */
  1237.  
  1238.                                         Signal(pmsg->task, pmsg->sigmask);
  1239.                                         break;
  1240.  
  1241.                                 case PATHEXPAND_MSG:
  1242.                                         lmsg         = (NameFromLockMsg *)pmsg;
  1243.                                         lmsg->newbuf = MyNameFromLock(lmsg->lock, lmsg->filename,
  1244.                                                                                                   lmsg->buf,  lmsg->maxlen);
  1245.                                         Signal(lmsg->task, lmsg->sigmask);
  1246.                                         break;
  1247.                         }
  1248.                 }
  1249.                 ReleaseSemaphore(&PatternBufSem);
  1250.         }
  1251.  
  1252. #if DEBUG_PATTERN
  1253.         DBP((dbfile, "Quitting...\n"));
  1254.         Close(dbfile);
  1255. #endif
  1256.  
  1257.         /*
  1258.          *              Now cleanup and exit from this task. We need to Forbid()
  1259.          *              before we signal the main task that we're ready to quit,
  1260.          *              since otherwise the main task might go ahead and unload
  1261.          *              us before we have a chance to execute the last few lines
  1262.          *              in the function (e.g. if the main task is running at a
  1263.          *              higher priority than we are).
  1264.          */
  1265.         Forbid();
  1266.         FreeSignal(BackgroundPort.mp_SigBit);
  1267.         Signal(quittask, quitsig);
  1268. }
  1269.  
  1270. /*
  1271.  *              CheckPattern(name, namelen)
  1272.  *
  1273.  *              Checks if our task's name has been masked out by the
  1274.  *              user, using our current AmigaDOS pattern string.
  1275.  *
  1276.  *              We can't call the DOS pattern match function directly, due to
  1277.  *              stack limitations (the caller may not have a very big stack).
  1278.  *              So, we maintain a cache of recently used tasks -- the first
  1279.  *              task on the list is always the most recently monitored task.
  1280.  *
  1281.  *              If a task doesn't appear on the list, or if it appears on the
  1282.  *              list but its name has changed, then we send a message to the
  1283.  *              main SnoopDos task asking it to check the pattern. We also
  1284.  *              add the result of this check to our cache for future calls.
  1285.  *
  1286.  *              Sending a message to another task from within a patch is tricky;
  1287.  *              more specifically, receiving the acknowledgement back from the
  1288.  *              main task is tricky. This is because we don't know what signal
  1289.  *              bits the caller might be using, and so we can't just grab one.
  1290.  *              We could use AllocSignal(), but then what if the caller has no
  1291.  *              free signal bits?
  1292.  *
  1293.  *              Our solution (not necessarily the best) is to use the reserved
  1294.  *              exec signal bit SIGB_SINGLE. This is used for semaphore operations,
  1295.  *              among others, and is only ever used while waiting for a single
  1296.  *              event to happen. Thus, when our code is reached, we know this
  1297.  *              bit is not in use and thus we can use it ourselves.
  1298.  *
  1299.  *              Returns true if no pattern is set, or if the pattern matches
  1300.  *              the current task name. Returns false otherwise.
  1301.  *
  1302.  */
  1303. int CheckPattern(char *taskname, int namelen)
  1304. {
  1305.         PatternCache *pc;
  1306.         Task *thistask = SysBase->ThisTask;
  1307.         PatternMsg pmsg;
  1308.  
  1309.         if (!PatternEnabled)
  1310.                 return (TRUE);
  1311.  
  1312.         if (!PatternWildcard)
  1313.                 return (stricmp(taskname, PatternString) == 0);
  1314.  
  1315.         namelen = MIN(namelen, PC_NAMELEN-1);
  1316.  
  1317.         /*
  1318.          *              Got a pattern, so search our cache list
  1319.          */
  1320.         ObtainSemaphore(&PatternCacheSem);
  1321.         FORLIST(&PatternList, pc)
  1322.                 if (pc->task == thistask)
  1323.                         break;
  1324.  
  1325.         /*
  1326.          *              Okay, now pc is either the matching task, or else a pointer
  1327.          *              to the end of our list.
  1328.          */
  1329.         if (NextNode(pc) && pc->task == thistask) {
  1330.                 /*
  1331.                  *              We broke out of the loop since we matched the task.
  1332.                  *              Now check if the name matches too.
  1333.                  */
  1334.                 if (strncmp(pc->name, taskname, namelen) == 0) {
  1335.                         /*
  1336.                          *              We're the same. Move this node to the start of
  1337.                          *              the list, and return the appropriate state.
  1338.                          */
  1339.                         Remove((Node *)pc);
  1340.                         AddHead(&PatternList, (Node *)pc);
  1341.                         ReleaseSemaphore(&PatternCacheSem);
  1342.                         return (pc->match);
  1343.                 }
  1344.                 /*
  1345.                  *              The name is different but the Task ID is the same --
  1346.                  *              most likely, someone ran a new CLI command. Thus, use
  1347.                  *              this cache entry for our new task name and fall through.
  1348.                  */
  1349.         } else {
  1350.                 /*
  1351.                  *              We didn't match a task so grab one from the end of the
  1352.                  *              list and use that instead.
  1353.                  */
  1354.                 pc               = TailNode(&PatternList);
  1355.                 pc->task = thistask;
  1356.         }
  1357.  
  1358.         /*
  1359.          *              Move the node to the start of the list to stop it being flushed
  1360.          *              any time soon, and update the name to match our own name.
  1361.          */
  1362.         Remove((Node *)pc);
  1363.         AddHead(&PatternList, (Node *)pc);
  1364.         strncpy(pc->name, taskname, namelen);
  1365.         pc->name[namelen] = 0;
  1366.         ReleaseSemaphore(&PatternCacheSem);
  1367.  
  1368.         /*
  1369.          *              Now send a message to the main task asking it to perform a name
  1370.          *              match for us. We need to be careful to make sure our pmsg won't
  1371.          *              be confused with a DOS packet by our PutMsg() patch -- we do
  1372.          *              this by NULLing out the name field.
  1373.          */
  1374.         pmsg.type                = PATTERN_MSG;
  1375.         pmsg.name                                = taskname;
  1376.         pmsg.sigmask                     = SIGF_SINGLE;
  1377.         pmsg.task                                = thistask;
  1378.         pmsg.msg.mn_Node.ln_Name = NULL;
  1379.  
  1380.         SetSignal(0, SIGF_SINGLE);              /* Ensure signal is clear first         */
  1381.         PutMsg(&BackgroundPort, &pmsg); /* Send request to background task      */
  1382.         Wait(SIGF_SINGLE);                              /* Wait for acknowledgement                     */
  1383.         pc->match = pmsg.match;                 /* And save result in cache                     */
  1384.  
  1385.         return (pmsg.match);
  1386. }
  1387.  
  1388. /*
  1389.  *              GetVolName(lock, buf, maxlen)
  1390.  *
  1391.  *              Copies the volume name associated with lock into the buffer,
  1392.  *              with terminating ':'. If lock is NULL, the volume address is
  1393.  *              taken directly from volume.
  1394.  *
  1395.  *              If UseDevNames is true, the device list is searched looking
  1396.  *              for the device node associated with the volume node (i.e. two
  1397.  *              nodes sharing the same task address).
  1398.  *
  1399.  *              WARNING: This function must not be called from within a DOS
  1400.  *                               device handler due to potential deadlock errors!
  1401.  *
  1402.  */
  1403. void GetVolName(BPTR lock, char *buf, int maxlen)
  1404. {
  1405.         struct DeviceList *vol;
  1406.         struct DosList *dl;
  1407.         int gotdev = 0;
  1408.  
  1409.         if (lock == NULL) {
  1410.                 NameFromLock(lock, buf, maxlen);
  1411.                 return;
  1412.         }
  1413.         vol = BTOC(((struct FileLock *)BTOC(lock))->fl_Volume);
  1414.  
  1415.         if (UseDevNames == 0 || vol->dl_Task == NULL) {
  1416.                 /*
  1417.                  *              Use volume name, especially if the volume isn't currently
  1418.                  *              mounted!
  1419.                  */
  1420.                 UBYTE *volname = BTOC(vol->dl_Name);
  1421.                 int len = MIN(maxlen-2, *volname);
  1422.  
  1423.                 memcpy(buf, volname+1, len);
  1424.                 buf[len++] = ':';
  1425.                 buf[len] = '\0';
  1426.                 return;
  1427.         }
  1428.  
  1429.         /*
  1430.          *              The user wants the device name. The only way to obtain this
  1431.          *              is to search the device list looking for the device node with
  1432.          *              the same task address as this volume.
  1433.          */
  1434.         dl = LockDosList(LDF_DEVICES | LDF_READ);
  1435.         while (dl = NextDosEntry(dl, LDF_DEVICES)) {
  1436.                 if (dl->dol_Task == vol->dl_Task) {
  1437.                         /*
  1438.                          *              Found our task, so now copy device name
  1439.                          */
  1440.                         UBYTE *devname = BTOC(dl->dol_Name);
  1441.                         int len = MIN(maxlen-2, *devname);
  1442.  
  1443.                         memcpy(buf, devname+1, len);
  1444.                         buf[len++] = ':';
  1445.                         buf[len] = '\0';
  1446.                         gotdev = 1;
  1447.                         break;
  1448.                 }
  1449.         }
  1450.         UnLockDosList(LDF_DEVICES | LDF_READ);
  1451.         if (!gotdev)
  1452.                 strcpy(buf, "???:");
  1453. }
  1454.  
  1455. /*
  1456.  *              MyNameFromLock(lock, filename, buf, maxlen)
  1457.  *
  1458.  *              This is a custom version of the DOS function NameFromLock()
  1459.  *              which expands a disk lock into a full path.
  1460.  *
  1461.  *              Our version adds the following features. The device name will be
  1462.  *              given as either the physical device (like DH0:) if UseDevNames
  1463.  *              is true, or the volume name (like System3.0:) if UseDevNames is
  1464.  *              false.
  1465.  *
  1466.  *              If filename is non-NULL, then it will be appended to the lock
  1467.  *              path. If filename contains path info, then this will be taken
  1468.  *              into account when generating the lock, so that an absolute path
  1469.  *              in filename will not have any effect, and a relative filename
  1470.  *              (like //directory) will cause the original lock to be ParentDir()'d
  1471.  *              twice before being resolved.
  1472.  *
  1473.  *              This function can't fail. In the event of an error (string too
  1474.  *              long, or something like that), the buffer will be filled accordingly.
  1475.  *              It is assumed that the buffer will always be big enough to hold short
  1476.  *              error messages or a volume name.
  1477.  *
  1478.  *              Returns a pointer to the path (which will not necessarily be at
  1479.  *              the start of the buffer, but is guaranteed null-terminated.)
  1480.  *              Note that it's even possible that the pointer returned will be
  1481.  *              to the original filename if no path expansion was required.
  1482.  *
  1483.  *              New: We now preserve the IoErr() that was present on entry, since
  1484.  *              it may have been set by the calling function if OnlyShowFails is
  1485.  *              true. Otherwise, IoErr() will be screwed up by the operations we
  1486.  *              do here (e.g. SAS/C deleting a non-existent file when OnlyShowFails
  1487.  *              is true).
  1488.  *
  1489.  *              WARNING: This function must not be called from within a DOS
  1490.  *                               device handler due to potential deadlock errors!
  1491.  */
  1492. char *MyNameFromLock(BPTR lock, char *filename, char *buf, int maxlen)
  1493. {
  1494.         Process *myproc = (Process *)SysBase->ThisTask;
  1495.         int pos = maxlen - 1;
  1496.         D_S(fib, struct FileInfoBlock);
  1497.         LONG savedioerr = IoErr();
  1498.         BPTR curlock;
  1499.         BPTR newlock;
  1500.         void *savewinptr;
  1501.         char *p;
  1502.         int len;
  1503.         int skipfirstslash = 0; /* If true, skip first slash when building name */
  1504.         int err = 0;
  1505.  
  1506.         /*
  1507.          *              Check for special magic filehandle
  1508.          */
  1509.         if (filename && *filename) {
  1510.                 if (strcmp(filename, "*") == 0)
  1511.                         return (filename);
  1512.  
  1513.                 /*
  1514.                  *              First determine if we have any work to do.
  1515.                  */
  1516.                 if (*filename == ':') {
  1517.                         /*
  1518.                          *              Got a reference relative to the root directory. Simply
  1519.                          *              grab the volume (or device) name from the lock and go
  1520.                          *              with that.
  1521.                          */
  1522.                         int len;
  1523.  
  1524.                         GetVolName(lock, buf, maxlen);
  1525.                         len = strlen(buf);
  1526.                         strncat(buf+len, filename+1, maxlen-len);
  1527.                         buf[maxlen-1] = '\0';
  1528.                         SetIoErr(savedioerr);
  1529.                         return (buf);
  1530.                 }
  1531.                 for (p = filename; *p; p++) {
  1532.                         if (*p == ':')                  /* If absolute path name, leave it alone */
  1533.                                 return (filename);
  1534.                 }
  1535.         } else {
  1536.                 /*
  1537.                  *              Filename is null, so indicate we want to skip the first
  1538.                  *              slash when building the directory path
  1539.                  */
  1540.                 skipfirstslash = 1;
  1541.         }
  1542.  
  1543.         savewinptr = myproc->pr_WindowPtr;
  1544.         myproc->pr_WindowPtr = (APTR)-1;                /* Disable error requesters       */
  1545.  
  1546.         newlock = DupLock(lock);
  1547.         if (lock && !newlock) {
  1548.                 GetVolName(lock, buf, 20);
  1549.                 if (filename) {
  1550.                         strcat(buf, ".../");
  1551.                         strcat(buf, filename);
  1552.                 }
  1553.                 myproc->pr_WindowPtr = savewinptr;      /* Re-enable error requesters */
  1554.                 SetIoErr(savedioerr);
  1555.                 return (buf);
  1556.         }
  1557.         buf[pos] = '\0';
  1558.         curlock = newlock;
  1559.         if (filename) {
  1560.                 while (newlock && *filename == '/') {
  1561.                         /*
  1562.                          *              Handle leading /'s by moving back a directory level
  1563.                          *              but nothing else
  1564.                          */
  1565.                         newlock = ParentDir(curlock);
  1566.                         if (newlock) {
  1567.                                 UnLock(curlock);
  1568.                                 curlock = newlock;
  1569.                                 filename++;
  1570.                         }
  1571.                 }
  1572.                 len = strlen(filename);
  1573.                 if (len > (pos-2)) {
  1574.                         memcpy(buf+2, filename+len-pos, pos-2);
  1575.                         buf[0] = buf[1] = '.';
  1576.                         pos = 0;
  1577.                         UnLock(curlock);
  1578.                 } else {
  1579.                         pos -= len;
  1580.                         memcpy(buf+pos, filename, len);
  1581.                 }
  1582.         }
  1583.  
  1584.         /*
  1585.          *              At this point, we have buf containing the filename (minus any
  1586.          *              leading /'s), starting at the index given by pos. If filename
  1587.          *              was NULL or empty, then pos indexes to a \0 terminator.
  1588.          *
  1589.          *              Next, we want to pre-pend directory names to the front of
  1590.          *              the filename (assuming there _is_ a filename) until we get
  1591.          *              to the device root.
  1592.          */
  1593.         newlock = curlock;
  1594.         while (newlock) {
  1595.  
  1596.                 if (!Examine(curlock, fib)) {
  1597.                         err++;
  1598.                         break;
  1599.                 }
  1600.                 len = strlen(fib->fib_FileName);
  1601.                 if (len > (pos-3)) {
  1602.                         /*
  1603.                          *              Not enough room: prefix dots at start to indicate
  1604.                          *              an overrun. We use pos-3 since we need one char
  1605.                          *              for a possible slash and two more to accomodate a
  1606.                          *              leading ".."
  1607.                          */
  1608.                         memcpy(buf+2, fib->fib_FileName+len-pos+3, pos-2);
  1609.                         buf[0] = buf[1] = '.';
  1610.                         buf[pos-1] = '/';
  1611.                         pos = 0;
  1612.                         break;
  1613.                 }
  1614.                 newlock = ParentDir(curlock);
  1615.                 if (newlock) {
  1616.                         UnLock(curlock);
  1617.                         curlock = newlock;
  1618.                         pos -= len + 1;
  1619.                         memcpy(buf + pos, fib->fib_FileName, len);
  1620.                         if (skipfirstslash) {
  1621.                                 skipfirstslash = 0;
  1622.                                 buf[pos+len] = '\0';
  1623.                         } else
  1624.                                 buf[pos+len] = '/';
  1625.                 }
  1626.         }
  1627.         /*
  1628.          *              Now we've built the path components; add the volume node
  1629.          *              to the beginning if possible.
  1630.          */
  1631.         if (err) {
  1632.                 /*
  1633.                  *              If an error occurred, the volume is probably not mounted,
  1634.                  *              so we include a ".../" component in the path to show
  1635.                  *              we couldn't get all the info
  1636.                  */
  1637.                 pos -= 4;
  1638.                 memcpy(buf + pos, ".../", 4);
  1639.         }
  1640.         if (pos > 0) {
  1641.                 char volname[20];
  1642.                 int len;
  1643.                 char *p;
  1644.  
  1645.                 GetVolName(curlock, volname, 20);
  1646.                 len = strlen(volname);
  1647.                 if (len > pos) {
  1648.                         p = volname + len - pos;
  1649.                         len = pos;
  1650.                 } else {
  1651.                         p = volname;
  1652.                 }
  1653.                 pos -= len;
  1654.                 memcpy(buf + pos, p, len);
  1655.         }
  1656.         if (curlock)
  1657.                 UnLock(curlock);
  1658.  
  1659.         myproc->pr_WindowPtr = savewinptr;              /* Re-enable error requesters */
  1660.         SetIoErr(savedioerr);
  1661.         return (buf+pos);
  1662. }
  1663.  
  1664. /*
  1665.  *              AsyncNameFromLock(volname, lock, filename, dest, maxlen)
  1666.  *
  1667.  *              This is identical to the MyNameFromLock() function except that
  1668.  *              it gets the background SnoopDos process to do the path expansion
  1669.  *              instead of doinng it from within the caller's process. This is
  1670.  *              necessary if we need to expand paths and we are not sure if the
  1671.  *              caller's process mesage port is free.
  1672.  *
  1673.  *              Volname is the volume on which the lock resides. If the lock itself
  1674.  *              is NULL, then the root of the volume will be assumed and this
  1675.  *              string will be copied into the buffer as the volume name.
  1676.  *
  1677.  *              WARNING: This function must not be called from within a DOS
  1678.  *                               device handler due to potential deadlock errors!
  1679.  */
  1680. char *AsyncNameFromLock(char *volname, BPTR lock, char *filename,
  1681.                                                 char *buf, int maxlen)
  1682. {
  1683.         NameFromLockMsg lmsg;
  1684.  
  1685.         if (lock == NULL) {
  1686.                 /*
  1687.                  *              Do a quick scan on the filename itself to see
  1688.                  *              if it contains a colon prefixed by some text;
  1689.                  *              if it does, then we already have a full path.
  1690.                  *              If it's just a colon, prefix it with the
  1691.                  *              volume name. If it has no colon, prefix it
  1692.                  *              with the volume name and a colon.
  1693.                  */
  1694.                 char *p;
  1695.  
  1696.                 strcpy(buf, volname);
  1697.                 if (filename) {
  1698.                         if (*filename == ':') {
  1699.                                 strcat(buf, filename);
  1700.                         } else {
  1701.                                 for (p = filename; *p && *p != ':'; p++)
  1702.                                         ;
  1703.                                 if (*p)
  1704.                                         strcpy(buf, filename);
  1705.                                 else
  1706.                                         mysprintf(buf, "%s:%s", volname, filename);
  1707.                         }
  1708.                 }
  1709.                 return (buf);
  1710.         }
  1711.         lmsg.type               = PATHEXPAND_MSG;
  1712.         lmsg.lock               = lock;
  1713.         lmsg.filename   = filename;
  1714.         lmsg.buf                = buf;
  1715.         lmsg.maxlen             = maxlen;
  1716.         lmsg.sigmask    = SIGF_SINGLE;
  1717.         lmsg.task               = SysBase->ThisTask;
  1718.         lmsg.msg.mn_Node.ln_Name = NULL;
  1719.  
  1720.         SetSignal(0, SIGF_SINGLE);              /* Ensure signal is clear first         */
  1721.         PutMsg(&BackgroundPort, &lmsg); /* Send request to background task      */
  1722.         Wait(SIGF_SINGLE);                              /* Wait for acknowledgement                     */
  1723.         return (lmsg.newbuf);
  1724. }
  1725.  
  1726. #if STACK_CHECK
  1727. /*
  1728.  *              GetFreeStack()
  1729.  *
  1730.  *              Returns the amount of free space available on the calling task's
  1731.  *              stack (thanks to Ralph Babel for this).
  1732.  */
  1733. ULONG GetFreeStack(void)
  1734. {
  1735.         Process *pr = (Process *)SysBase->ThisTask;
  1736.         char *upper;
  1737.         char *lower;
  1738.         ULONG total;
  1739.         ULONG avail;
  1740.  
  1741.         if (pr->pr_Task.tc_Node.ln_Type == NT_PROCESS && pr->pr_CLI != NULL) {
  1742.                 upper = (char *)pr->pr_ReturnAddr + sizeof(ULONG);
  1743.                 total = *(ULONG *)pr->pr_ReturnAddr;
  1744.                 lower = upper - total;
  1745.         } else {
  1746.                 upper = (char *)pr->pr_Task.tc_SPUpper;
  1747.                 lower = (char *)pr->pr_Task.tc_SPLower;
  1748.                 total = upper - lower;
  1749.         }
  1750.         avail = (char *)getreg(REG_A7) - lower;
  1751.         return (avail);
  1752. }
  1753. #endif
  1754.  
  1755. /*
  1756.  *              CreateEvent(calladdr, seqnum, action, filename,
  1757.  *                                      options, expandname [, lock] )
  1758.  *
  1759.  *              Allocates a new event for the current task and initialises
  1760.  *              almost all the fields in it accordingly.
  1761.  *
  1762.  *              seqnum is initialised to the sequence number of the new event. This
  1763.  *              is used to allow later detection of events which have scrolled off
  1764.  *              the top of the buffer.
  1765.  *
  1766.  *              filename and options are text strings, and actionid is a message ID.
  1767.  *              The storage for these will be allocated in the event buffer.
  1768.  *
  1769.  *              If expandname is EXPAND_NAME, then 'filename' is assumed to represent
  1770.  *              a real disk filename, and it will be expanded to a full path if that
  1771.  *              option is set. If expandname is NO_EXPAND, then the name is passed
  1772.  *              unchanged.
  1773.  *
  1774.  *              If expandname is neither EXPAND_NAME or NO_EXPAND, then it is
  1775.  *              interpreted as a volume name, and one additional parameter
  1776.  *              following it will be expected -- this additional parameter will
  1777.  *              be a lock on that volume. The filename will then be expanded
  1778.  *              to a full pathname on that volume. If the lock is null, then it
  1779.  *              is assumed to represent the root of the volume. The filename
  1780.  *              expansion is done by the background process, making it safe to
  1781.  *              call from within the PutMsg() patch which monitors raw packets.
  1782.  *
  1783.  *              If you pass in a NULL value for any of the three pointers, it will
  1784.  *              be made to point to a blank string.
  1785.  *
  1786.  *              If for some reason the event could not be created, returns NULL,
  1787.  *              else returns a pointer to the initialised event.
  1788.  *
  1789.  *              Possible reasons for failure include:
  1790.  *
  1791.  *                      - Calling task is main SnoopDos task (!)
  1792.  *                      - Calling task is not included in the match pattern
  1793.  *                      - Calling task was called by a ROM function
  1794.  *                      - Disk error occurred expanding filename
  1795.  *                      - Out of memory allocating new event
  1796.  */
  1797. struct Event *CreateEvent(ULONG calladdr, LONG *seqnum, ULONG actionid,
  1798.                           char *filename, char *options, int expandname, ...)
  1799. {
  1800.         Task *thistask = SysBase->ThisTask;
  1801.         struct CommandLineInterface *cli;
  1802.         Event *ev;
  1803.         char *procname;
  1804.         char *strptr;
  1805.         char *action;
  1806.         char namebuf[MAX_SHORT_LEN+1];
  1807.         char pathbuf[MAX_STR_LEN+1];
  1808.         int plen = 0;
  1809.         int flen = 0;
  1810.         int olen = 0;
  1811.         int alen = 0;
  1812.         int slen = 0;
  1813.         int clinum;
  1814.  
  1815.         /*
  1816.          *              We ignore all calls from the main SnoopDOS process and
  1817.          *              background process, and also any nested calls made while
  1818.          *              we have the semaphore locked (which might otherwise lead
  1819.          *              to nasty trashing of the list!)
  1820.          *
  1821.          *              Also, any calls from input.device are ignored since these
  1822.          *              typically call us with layers locked, and the slightest
  1823.          *              delay could be fatal.
  1824.          */
  1825.         if (thistask == SnoopTask || thistask == (Task *)BackgroundProc
  1826.                                                           || thistask == BufSem.ss_Owner
  1827.                                                           /*
  1828.                                                           || thistask == RamLibTask
  1829.                                                           || thistask == InputTask
  1830.                                                           */
  1831.                                                           )
  1832.                 return (NULL);
  1833.  
  1834.         /*
  1835.          *              We also ignore any calls made from ROM addresses (if this
  1836.          *              option is enabled), since this cuts down the amount of
  1837.          *              superfluos output considerably.
  1838.          *
  1839.          *              We specifically DO allow calls from within ramlib, since
  1840.          *              it's very easy to disable ramlib directly if need be (by
  1841.          *              putting ~ramlib in the match name) and ramlib does
  1842.          *              many useful operations that are convenient to monitor.
  1843.          */
  1844.         if (thistask != RealRamLibTask && !MonROMCalls &&
  1845.             calladdr >= RomStart && calladdr <= RomEnd)
  1846.                 return (NULL);
  1847.  
  1848.         /*
  1849.          *              Work out the correct name for our task. This will either be
  1850.          *              the task name, the process name, or the current CLI command
  1851.          *              (if the process is a CLI, _and_ is currently running a command.)
  1852.          *
  1853.          *              In addition, for CLIs, we set clinum to the CLI number. For
  1854.          *              tasks and non-CLI processes, clinum becomes zero.
  1855.          */
  1856.         procname = thistask->tc_Node.ln_Name;
  1857.         plen     = strlen(procname);
  1858.         cli              = BTOC(((Process *)thistask)->pr_CLI);
  1859.         clinum   = 0;
  1860.  
  1861.         if (thistask->tc_Node.ln_Type == NT_PROCESS && cli) {
  1862.                 /*
  1863.                  *              If we have a CLI command, we have to convert the name
  1864.                  *              from a BSTR into a C string
  1865.                  */
  1866.                 clinum = ((Process *)thistask)->pr_TaskNum;
  1867.                 if (cli->cli_Module) {
  1868.                         UBYTE *cliname = BTOC(cli->cli_CommandName);
  1869.                         plen = *cliname;
  1870.  
  1871.                         if (plen) {
  1872.                                 if (plen > MAX_SHORT_LEN)
  1873.                                         plen = MAX_SHORT_LEN;
  1874.                                 memcpy(namebuf, cliname+1, plen);
  1875.                                 namebuf[plen] = 0;
  1876.                         } else {
  1877.                                 strcpy(namebuf, "<Unknown>");
  1878.                                 plen = strlen(namebuf);
  1879.                         }
  1880.                         procname = namebuf;
  1881.                 }
  1882.         }
  1883.  
  1884. #if 0
  1885.         if (stricmp(procname, "ramlib") == 0) {
  1886.                 KPrintF("Ramlib: Stacksize is %ld\n", GetFreeStack());
  1887.         }
  1888. #endif
  1889.  
  1890.         if (!CheckPattern(procname, plen))              /* Perform pattern check */
  1891.                 return (FALSE);
  1892.  
  1893.         /*
  1894.          *              Now deal with our three strings
  1895.          */
  1896.         if (ShowPaths && filename != NULL) {
  1897.                 if (expandname == EXPAND_NAME) {
  1898.                         /*
  1899.                          *              Expand filename to full path
  1900.                          */
  1901.                         filename = MyNameFromLock(((Process *)thistask)->pr_CurrentDir,
  1902.                                                                           filename, pathbuf, MAX_STR_LEN);
  1903.                 } else if (expandname != NO_EXPAND) {
  1904.                         /*
  1905.                          *              Expand filename to full path using background process
  1906.                          *              and the lock specified in expandname.
  1907.                          */
  1908.                         BPTR lock = *(ULONG *)(&expandname+1);
  1909.  
  1910.                         filename = AsyncNameFromLock((char *)expandname, lock, filename,
  1911.                                                                              pathbuf, MAX_STR_LEN);
  1912.                 }
  1913.         }
  1914.         plen++;
  1915.         if (ShowCLINum && clinum)
  1916.                 plen += 8;                                              /* Leave room for CLI display */
  1917.  
  1918.         action = MSG(actionid);
  1919.         alen   = strlen(action) + 1;
  1920.  
  1921.         if (filename)   flen = strlen(filename) + 1;
  1922.         if (options)    olen = strlen(options)  + 1;
  1923.  
  1924.         if (SegTrackerActive)
  1925.                 slen = MAX_SEGTRACKER_LEN;
  1926.  
  1927.         /*
  1928.          *              If the calling task has locked the layers of the SnoopDos
  1929.          *              screen, then we ignore all calls by that task. This prevents
  1930.          *              us deadlocking when we wait for the semaphore (while meanwhile,
  1931.          *              the SnoopDos mainline code could own the semaphore, and be
  1932.          *              waiting for the layers to be unlocked by our caller so it can
  1933.          *              render some output).
  1934.          *
  1935.          *              We Forbid() to make sure the window doesn't get closed from
  1936.          *              under our feet while we're checking it. We have to try and
  1937.          *              allocate the event while still Forbid'd since otherwise, there
  1938.          *              is a small window where the main window could open, lock the
  1939.          *              layers, and lock the semaphore, in between our check. It's
  1940.          *              unlikely, but not _that_ unlikely (especially since the main
  1941.          *              window always does an immediate redraw when it opens)
  1942.          *
  1943.          *              THOR: RPort->Layer is set to NULL by some rendering calls
  1944.          *              and hence the code might find a NULL here. Handle this as if
  1945.          *              the layer is locked.
  1946.          */
  1947.  
  1948.         /*
  1949.          *
  1950.          *
  1951.         Forbid();
  1952.         if (MainWindow &&
  1953.                         (MainWindow->RPort->Layer                     == NULL     ||
  1954.                          MainWindow->RPort->Layer->Lock.ss_Owner      == thistask ||
  1955.                          MainWindow->WScreen->LayerInfo.Lock.ss_Owner == thistask)) {
  1956.                 Permit();
  1957.                 return (NULL);
  1958.         }
  1959.         */
  1960.         ev = GetNewEvent(plen + alen + flen + olen + slen);
  1961.         /*
  1962.         Permit();
  1963.          *
  1964.          *
  1965.          */
  1966.  
  1967.         if (!ev)
  1968.                 return (NULL);
  1969.  
  1970.         ev->action = ev->filename = ev->options = ev->result = "";
  1971.  
  1972.         strptr = (char *)(ev+1);
  1973.  
  1974.         if (ShowCLINum && clinum)
  1975.                 mysprintf(strptr, "[%ld] %s", clinum, procname);
  1976.         else
  1977.                 strcpy(strptr, procname);
  1978.         ev->procname  = strptr;
  1979.         strptr       += plen;
  1980.  
  1981. //      KPrintF("New event: %ld, %s, %s\n", ev->seqnum, procname, action); /* DB */
  1982.         if (alen) {
  1983.                 strcpy(strptr, action);
  1984.                 ev->action   = strptr;
  1985.                 strptr          += alen;
  1986.         }
  1987.         if (flen) {
  1988.                 strcpy(strptr, filename);
  1989.                 ev->filename  = strptr;
  1990.                 strptr           += flen;
  1991.         }
  1992.         if (olen) {
  1993.                 strcpy(strptr, options);
  1994.                 ev->options   = strptr;
  1995.                 strptr       += olen;
  1996.         }
  1997.         if (slen) {
  1998.                 ev->segname       = strptr;
  1999.                 strptr       += slen;
  2000.         } else {
  2001.                 ev->segname   = NULL;   /* Say no segtracker storage allocated */
  2002.         }
  2003.         // DateStamp(&ev->datestamp);
  2004.         ev->calladdr    = calladdr;
  2005.         ev->processid   = (ULONG)thistask;
  2006.         // ev->processid        = GetFreeStack();
  2007.  
  2008.         if (seqnum)
  2009.                 *seqnum = ev->seqnum;
  2010.         return (ev);
  2011. }
  2012.  
  2013. /*
  2014.  *              CheckTaskRecursion()
  2015.  *
  2016.  *              Checks if the current task is already listed as being on the
  2017.  *              recursion list. If so, returns FALSE, indicating that the
  2018.  *              caller should immediately pass control back to the original
  2019.  *              function and not try and do anything else.
  2020.  *
  2021.  *              Otherwise, records the task's address in a recursion list
  2022.  *              and returns a handle. This handle should be passed back to
  2023.  *              EndTaskRecursion() when the function is complete, which will
  2024.  *              cause it to be removed from the list.
  2025.  *
  2026.  *              OpenLibrary() needs to surround its call to CreateEvent() with
  2027.  *              CheckTaskRecursion()/EndTaskRecursion. Also, GetMsg()/PutMsg() need
  2028.  *              this to check if any of the DOS packets it monitors have been
  2029.  *              generated by AmigaDOS functions we monitor.
  2030.  */
  2031. ULONG CheckTaskRecursion(void)
  2032. {
  2033.         Task *taskid = SysBase->ThisTask;
  2034.         ULONG taskhandle;
  2035.         int i;
  2036.  
  2037.         for (i = 1; i < NUM_CACHED_TASKS; i++)
  2038.                 if (CachedTask[i] == taskid)
  2039.                         return (0);
  2040.  
  2041.         ObtainSemaphore(&TaskCacheSem);
  2042.         taskhandle = TaskCacheIndex++;
  2043.         if (TaskCacheIndex >= NUM_CACHED_TASKS)
  2044.                 TaskCacheIndex = 1;
  2045.         CachedTask[taskhandle] = taskid;
  2046.         ReleaseSemaphore(&TaskCacheSem);
  2047.  
  2048.         return (taskhandle);
  2049. }
  2050.  
  2051. /*
  2052.  *              EndTaskRecursion(taskhandle)
  2053.  *
  2054.  *              Called to remove a task from the recursion list.
  2055.  *              See CheckTaskRecursion() above.
  2056.  */
  2057. void EndTaskRecursion(ULONG taskhandle)
  2058. {
  2059.         CachedTask[taskhandle] = 0;
  2060. }
  2061.  
  2062. #if 0
  2063. /*
  2064.  *              TestPatch()
  2065.  *
  2066.  *              Patches a single function to try it out
  2067.  */
  2068. void TestPatch(void)
  2069. {
  2070.         extern List                     EventList;                      /* List of events               */
  2071.         static EventFormat evformat[50];
  2072.         static char outstr[500];
  2073.         char *formatstr = "%d %t %c %n %s %h %a %40f %o %r";
  2074.         int formatlen;
  2075.  
  2076.         OnlyShowFails    = 0;
  2077.         SegTrackerActive = 1;
  2078.         formatlen = ParseFormatString(formatstr, evformat, 50);
  2079.  
  2080.         if (!InitPatches()) {
  2081.                 printf("Patch initialisation failed!\n");
  2082.                 return;
  2083.         }
  2084.  
  2085.         PatchList[GID_OPENFILE].enabled = 1;
  2086.         UpdatePatches();
  2087.         printf("Patch now enabled!\n\n");
  2088.  
  2089.         FormatEvent(evformat, NULL, outstr, 0, formatlen-1);
  2090.         printf("%s\n", outstr);
  2091.         printf("%s\n", UnderlineTitles(evformat, outstr, '-'));
  2092.  
  2093.         for (;;) {
  2094.                 ULONG mask;
  2095.  
  2096.                 mask = Wait(SIGBREAKF_CTRL_C | NewEventMask);
  2097.                 if (mask & SIGBREAKF_CTRL_C)
  2098.                         break;
  2099.  
  2100.                 if (mask & NewEventMask) {
  2101.                         Event *ev;
  2102.  
  2103.                         SetSignal(0, NewEventMask);     /* Clear signal for next time */
  2104.                         FORLIST(&EventList, ev) {
  2105.                                 int stat = ev->status;
  2106.  
  2107.                                 if (stat == ES_UPDATING || stat == ES_READY) {
  2108.                                         FormatEvent(evformat, ev, outstr, 0, formatlen-1);
  2109.                                         printf("%s\n", outstr);
  2110.                                         if (stat == ES_READY)
  2111.                                                 ev->status = ES_ACCEPTED;
  2112.                                 }
  2113.                         }
  2114.                 }
  2115.         }
  2116.         PatchList[GID_OPENFILE].enabled = 0;
  2117.         UpdatePatches();
  2118.         printf("Patch disabled\n");
  2119.         CleanupPatches();
  2120. }
  2121. #endif
  2122.  
  2123. /*
  2124.  *              HandlePaused(event, seqnum)
  2125.  *
  2126.  *              Should be called when pausing is enabled -- it sets the
  2127.  *              event Result code to "...." to indicate the event is about
  2128.  *              to be executed, then waits for the pausing to be turned off.
  2129.  *              If you pass in NULL as the event code, then this isn't done.
  2130.  *
  2131.  *              seqnum is the actual event number remembered by the caller,
  2132.  *              not (necessarily) the event number stored in the event. This
  2133.  *              is so that the code can check if the event has rolled off the
  2134.  *              top of the buffer or not before modifying it.
  2135.  *
  2136.  *              There are some circumstances where it is dangerous for
  2137.  *              us to pause because we are being called by a system task
  2138.  *              that is needed by the main SnoopDos program.
  2139.  *
  2140.  *              We work around this as follows. Firstly, if the caller happens
  2141.  *              to own the semaphore associated with the layer info for the
  2142.  *              window or screen containing the SnoopDos window, then we
  2143.  *              don't try and pause it since otherwise we might deadlock
  2144.  *              (the user wouldn't be able to unpause SnoopDos because that
  2145.  *              requires clicking on a button.)
  2146.  *
  2147.  *              Secondly, whenever SnoopDos itself does something that might
  2148.  *              stop it processing the main messages (e.g. show a requester,
  2149.  *              open a file, check for ASL, etc.) then pausing is temporarily
  2150.  *              turned off since we have no way of knowing whether a third
  2151.  *              party patch might be spinning off a background task to do it
  2152.  *              and the background task might try and wait on this. Bummer, eh?
  2153.  */
  2154. void HandlePaused(Event *ev, LONG seqnum)
  2155. {
  2156.         if (Paused) {
  2157.                 /*
  2158.                  *              Need to forbid when checking layers since otherwise the
  2159.                  *              main window might close while we're reading its pointers.
  2160.                  */
  2161.                 int gotlock = 0;
  2162.                 char *oldresmsg;
  2163.  
  2164.                 Forbid();
  2165.                 if (MainWindow) {
  2166.                         struct Layer *layer;
  2167.                         struct Layer_Info *li;
  2168.                         Task *thistask = SysBase->ThisTask;
  2169.  
  2170.                         layer = MainWindow->RPort->Layer;
  2171.                         li    = &MainWindow->WScreen->LayerInfo;
  2172.  
  2173.                         /*
  2174.                          * THOR: Check whether the layer is available. Some Gfx rendering
  2175.                          * calls clear the layer temporarely.
  2176.                          * In that case, do not proceed since we do not really
  2177.                          * know who owns the layer.
  2178.                          */
  2179.  
  2180.                         if (layer) {
  2181.                                 gotlock = (li->Lock.ss_Owner    == thistask) ||
  2182.                                           (layer->Lock.ss_Owner == thistask);
  2183.                         } else  gotlock = TRUE;
  2184.                 }
  2185.                 Permit();
  2186.                 if (gotlock)
  2187.                         return;
  2188.  
  2189.                 /*
  2190.                  *              Okay, safe to proceed with pausing. We simply set the
  2191.                  *              result message to indicate we're paused, signal
  2192.                  *              the main task, wait for the pausing to finish, restore
  2193.                  *              the result message, and return.
  2194.                  */
  2195.                 if (ev) {
  2196.                         if (AttemptSemaphoreHeavely(&BufSem)) {
  2197.                                 if (seqnum >= RealFirstSeq) {
  2198.                                         oldresmsg  = ev->result;
  2199.                                         ev->result = MSG(MSG_RES_PAUSE);
  2200.                                 }
  2201.                                 ReleaseSemaphore(&BufSem);
  2202.                         }
  2203.                 }
  2204.                 Signal(SnoopTask, NewEventMask);        /* Make sure main task updates */
  2205.                 ObtainSemaphore(&PauseSem);
  2206.                 ReleaseSemaphore(&PauseSem);
  2207.                 if (ev) {
  2208.                         if (AttemptSemaphoreHeavely(&BufSem)) {
  2209.                                 if (seqnum >= RealFirstSeq)
  2210.                                         ev->result = oldresmsg;
  2211.                                 ReleaseSemaphore(&BufSem);
  2212.                         }
  2213.                 }
  2214.         }
  2215. }
  2216.  
  2217. #define CheckForPause(ev,seqnum)        if (Paused)     { HandlePaused(ev, seqnum); }
  2218.  
  2219. /*****************************************************************************
  2220.  *
  2221.  *              Now here are all the patches for the 25 or so functions that we
  2222.  *              patch into. Most of the patches follow a similar template, and
  2223.  *              share similar lower-level functions, but are different enough to
  2224.  *              prevent us from using the same patch for several functions.
  2225.  *
  2226.  *              We always signal both before and after a particular call, so that
  2227.  *              in the event of a call causing a crash, it will still show up in
  2228.  *              the SnoopDos window.
  2229.  *
  2230.  *              The OnlyShowFails flag is used to say whether we want to monitor
  2231.  *              all calls to a function, or only those which return a failure code.
  2232.  *              If the latter, we need to call the function first before deciding
  2233.  *              whether or not to create an event to record it -- in this case, the
  2234.  *              result code remains cached for the remainder of the function. The
  2235.  *              rest of the time, we create the event and signal the main task,
  2236.  *              then call the function to get the result, and finally update the
  2237.  *              event with the result and signal the main task again.
  2238.  *
  2239.  *              Each patch that calls a function and then updates the buffer on its
  2240.  *              return must ensure that the buffer entry is has a pointer to is still
  2241.  *              valid before it updates it. It does this by remembering the sequence
  2242.  *              number of the buffer entry, and then checking that the sequence
  2243.  *              number of the first buffer entry is still <= that (i.e. the entry
  2244.  *              is still somewhere in the buffer). This is vital to ensure that
  2245.  *              innocent buffer memory isn't trashed by old events.
  2246.  *
  2247.  *****************************************************************************/
  2248.  
  2249. /*
  2250.  *              New_FindPort(name)
  2251.  *
  2252.  *              Searches the system port list looking for a port name
  2253.  */
  2254. ULONG ASM New_FindPort(reg_a1 char *name, reg_a6 void *libbase)
  2255. {
  2256.         MarkCallAddr;
  2257.         FP_FindPort origfunc = (FP_FindPort)PatchList[GID_FINDPORT].origfunc;
  2258.         int onlyfails = OnlyShowFails;
  2259.         ULONG result;
  2260.         Event *ev;
  2261.         LONG  seqnum;
  2262.  
  2263.         if (onlyfails) {
  2264.                 result = origfunc(name, libbase);
  2265.                 if (result)
  2266.                         return (result);
  2267.         }
  2268.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_FINDPORT,
  2269.                                          name, NULL, NO_EXPAND);
  2270.         if (!ev) {
  2271.                 if (onlyfails)
  2272.                         return (result);
  2273.                 JumpOrigFunc(0);
  2274.         }
  2275.  
  2276.         /*
  2277.          *              Allocated event safely, now tell SnoopDos task to wake up
  2278.          */
  2279.         if (onlyfails) {
  2280.                 CheckForPause(NULL, 0);
  2281.         } else {
  2282.                 ev->status = ES_UPDATING;
  2283.                 CheckForPause(ev, seqnum);
  2284.                 Signal(SnoopTask, NewEventMask);
  2285.                 result = origfunc(name, libbase);
  2286.         }
  2287.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2288.                 if (seqnum >= RealFirstSeq) {
  2289.                         if (result)
  2290.                                 ev->result = MSG(MSG_RES_OKAY);
  2291.                         else
  2292.                                 ev->result = MSG(MSG_RES_FAIL);
  2293.                         ev->status = ES_READY;
  2294.                         Signal(SnoopTask, NewEventMask);
  2295.                 }
  2296.                 ReleaseSemaphore(&BufSem);
  2297.         }
  2298.         return (result);
  2299. }
  2300.  
  2301. /*
  2302.  *              New_FindResident(name)
  2303.  *
  2304.  *              Searches the system resident list looking for a resident module
  2305.  */
  2306. ULONG ASM New_FindResident(reg_a1 char *name, reg_a6 void *libbase)
  2307. {
  2308.         MarkCallAddr;
  2309.         FP_FindResident origfunc = (FP_FindResident)
  2310.                                                                 PatchList[GID_FINDRESIDENT].origfunc;
  2311.         int onlyfails = OnlyShowFails;
  2312.         ULONG result;
  2313.         Event *ev;
  2314.         LONG  seqnum;
  2315.  
  2316.         if (SysBase->ThisTask == RealRamLibTask)
  2317.                 JumpOrigFunc(0);
  2318.  
  2319.         if (onlyfails) {
  2320.                 result = origfunc(name, libbase);
  2321.                 if (result)
  2322.                         return (result);
  2323.         }
  2324.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_FINDRESIDENT,
  2325.                                          name, NULL, NO_EXPAND);
  2326.         if (!ev) {
  2327.                 if (onlyfails)
  2328.                         return (result);
  2329.                 JumpOrigFunc(0);
  2330.         }
  2331.  
  2332.         /*
  2333.          *              Allocated event safely, now tell SnoopDos task to wake up
  2334.          */
  2335.         if (onlyfails) {
  2336.                 CheckForPause(NULL, 0);
  2337.         } else {
  2338.                 ev->status = ES_UPDATING;
  2339.                 CheckForPause(ev, seqnum);
  2340.                 Signal(SnoopTask, NewEventMask);
  2341.                 result = origfunc(name, libbase);
  2342.         }
  2343.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2344.                 if (seqnum >= RealFirstSeq) {
  2345.                         if (result)
  2346.                                 ev->result = MSG(MSG_RES_OKAY);
  2347.                         else
  2348.                                 ev->result = MSG(MSG_RES_FAIL);
  2349.                         ev->status = ES_READY;
  2350.                         Signal(SnoopTask, NewEventMask);
  2351.                 }
  2352.                 ReleaseSemaphore(&BufSem);
  2353.         }
  2354.         return (result);
  2355. }
  2356.  
  2357. /*
  2358.  *              New_FindSemaphore(name)
  2359.  *
  2360.  *              Searches the system semaphore list looking for the named semaphore
  2361.  */
  2362. ULONG ASM New_FindSemaphore(reg_a1 char *name, reg_a6 void *libbase)
  2363. {
  2364.         MarkCallAddr;
  2365.         FP_FindSemaphore origfunc = (FP_FindSemaphore)
  2366.                                                                  PatchList[GID_FINDSEMAPHORE].origfunc;
  2367.         int onlyfails = OnlyShowFails;
  2368.         ULONG result;
  2369.         Event *ev;
  2370.         LONG  seqnum;
  2371.  
  2372.         if (onlyfails) {
  2373.                 result = origfunc(name, libbase);
  2374.                 if (result)
  2375.                         return (result);
  2376.         }
  2377.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_FINDSEM,
  2378.                                          name, NULL, NO_EXPAND);
  2379.         if (!ev) {
  2380.                 if (onlyfails)
  2381.                         return (result);
  2382.                 JumpOrigFunc(0);
  2383.         }
  2384.  
  2385.         /*
  2386.          *              Allocated event safely, now tell SnoopDos task to wake up
  2387.          */
  2388.         if (onlyfails) {
  2389.                 CheckForPause(NULL, 0);
  2390.         } else {
  2391.                 ev->status = ES_UPDATING;
  2392.                 CheckForPause(ev, seqnum);
  2393.                 Signal(SnoopTask, NewEventMask);
  2394.                 result = origfunc(name, libbase);
  2395.         }
  2396.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2397.                 if (seqnum >= RealFirstSeq) {
  2398.                         if (result)
  2399.                                 ev->result = MSG(MSG_RES_OKAY);
  2400.                         else
  2401.                                 ev->result = MSG(MSG_RES_FAIL);
  2402.                         ev->status = ES_READY;
  2403.                         Signal(SnoopTask, NewEventMask);
  2404.                 }
  2405.                 ReleaseSemaphore(&BufSem);
  2406.         }
  2407.         return (result);
  2408. }
  2409.  
  2410. /*
  2411.  *              New_FindTask(name)
  2412.  *
  2413.  *              Searches the system task list looking for the named task.
  2414.  *              We ignore calls to FindTask(0) since this is just
  2415.  *              looking for a pointer to the current task.
  2416.  */
  2417. ULONG ASM New_FindTask(reg_a1 char *name, reg_a6 void *libbase)
  2418. {
  2419.         MarkCallAddr;
  2420.         FP_FindTask origfunc = (FP_FindTask)PatchList[GID_FINDTASK].origfunc;
  2421.         int onlyfails = OnlyShowFails;
  2422.         ULONG result;
  2423.         Event *ev;
  2424.         LONG  seqnum;
  2425.  
  2426.         if (name == NULL)
  2427.                 return (origfunc(name, libbase));
  2428.  
  2429.         if (onlyfails) {
  2430.                 result = origfunc(name, libbase);
  2431.                 if (result)
  2432.                         return (result);
  2433.         }
  2434.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_FINDTASK,
  2435.                                          name, NULL, NO_EXPAND);
  2436.         if (!ev) {
  2437.                 if (onlyfails)
  2438.                         return (result);
  2439.                 JumpOrigFunc(0);
  2440.         }
  2441.  
  2442.         /*
  2443.          *              Allocated event safely, now tell SnoopDos task to wake up
  2444.          */
  2445.         if (onlyfails) {
  2446.                 CheckForPause(NULL, 0);
  2447.         } else {
  2448.                 ev->status = ES_UPDATING;
  2449.                 CheckForPause(ev, seqnum);
  2450.                 Signal(SnoopTask, NewEventMask);
  2451.                 result = origfunc(name, libbase);
  2452.         }
  2453.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2454.                 if (seqnum >= RealFirstSeq) {
  2455.                         if (result)
  2456.                                 ev->result = MSG(MSG_RES_OKAY);
  2457.                         else
  2458.                                 ev->result = MSG(MSG_RES_FAIL);
  2459.                         ev->status = ES_READY;
  2460.                         Signal(SnoopTask, NewEventMask);
  2461.                 }
  2462.                 ReleaseSemaphore(&BufSem);
  2463.         }
  2464.         return (result);
  2465. }
  2466.  
  2467. /*
  2468.  *              New_LockPubScreen(name)
  2469.  *
  2470.  *              Obtains a lock on the named public screen. If the name is NULL,
  2471.  *              then the caller is looking for a Lock() on the default screen,
  2472.  *              and we ignore it (otherwise we'd get loads of output).
  2473.  */
  2474. ULONG ASM New_LockPubScreen(reg_a0 char *name, reg_a6 void *libbase)
  2475. {
  2476.         MarkCallAddr;
  2477.         FP_LockPubScreen origfunc = (FP_LockPubScreen)
  2478.                                                                 PatchList[GID_LOCKSCREEN].origfunc;
  2479.         int onlyfails = OnlyShowFails;
  2480.         ULONG result;
  2481.         Event *ev;
  2482.         LONG  seqnum;
  2483.  
  2484.         if (!name)
  2485.                 JumpOrigFunc(0);
  2486.  
  2487.         if (onlyfails) {
  2488.                 result = origfunc(name, libbase);
  2489.                 if (result)
  2490.                         return (result);
  2491.         }
  2492.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_LOCKSCREEN,
  2493.                                          name, NULL, NO_EXPAND);
  2494.         if (!ev) {
  2495.                 if (onlyfails)
  2496.                         return (result);
  2497.                 JumpOrigFunc(0);
  2498.         }
  2499.  
  2500.         /*
  2501.          *              Allocated event safely, now tell SnoopDos task to wake up
  2502.          */
  2503.         if (onlyfails) {
  2504.                 CheckForPause(NULL, 0);
  2505.         } else {
  2506.                 ev->status = ES_UPDATING;
  2507.                 Signal(SnoopTask, NewEventMask);
  2508.                 CheckForPause(ev, seqnum);
  2509.                 result = origfunc(name, libbase);
  2510.         }
  2511.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2512.                 if (seqnum >= RealFirstSeq) {
  2513.                         if (result)
  2514.                                 ev->result = MSG(MSG_RES_OKAY);
  2515.                         else
  2516.                                 ev->result = MSG(MSG_RES_FAIL);
  2517.                         ev->status = ES_READY;
  2518.                         Signal(SnoopTask, NewEventMask);
  2519.                 }
  2520.                 ReleaseSemaphore(&BufSem);
  2521.         }
  2522.         return (result);
  2523. }
  2524.  
  2525. /*
  2526.  *              New_OpenDevice(name, unit, ioreq, flags)
  2527.  *
  2528.  *              Opens a new device. We need to be careful with the error return
  2529.  *              for this function, since success is indicated by a return of 0!
  2530.  *
  2531.  *              N.b. Kickstart 3.1 has a space-saving hack which allows a NULL
  2532.  *              device name to be interpreted as a magic cookie indicating a
  2533.  *              particular ROM devices. We ignore such calls (especially from CON,
  2534.  *              which does it a lot!) but flag other occurrances of NULL device
  2535.  *              names as an error.
  2536.  */
  2537. ULONG ASM New_OpenDevice(reg_a0 char *name, reg_d0 long unit,
  2538.                                              reg_a1 struct IORequest *ioreq,
  2539.                                                  reg_d1 long flags, reg_a6 void *libbase)
  2540. {
  2541.         MarkCallAddr;
  2542.         FP_OpenDevice origfunc = (FP_OpenDevice)PatchList[GID_OPENDEVICE].origfunc;
  2543.         int onlyfails = OnlyShowFails;
  2544.         ULONG result;
  2545.         Event *ev;
  2546.         char unitstr[20];
  2547.         char *devname = name;
  2548.         LONG  seqnum;
  2549.  
  2550. /*
  2551.  *              Release Semaphore replacement code for debugging patch
  2552.  */
  2553. #if MONITOR_SEMAPHORE
  2554.         Semaphore *sem = (Semaphore *)name;
  2555.  
  2556.         if (LoadTask == SysBase->ThisTask)
  2557.                 KPrintF("ReleaseSemaphore in LoadSeg: retaddr = %08lx\n", CallAddr);
  2558.         return origfunc(name, unit, ioreq, flags, libbase);
  2559. #endif
  2560.  
  2561.         if (onlyfails) {
  2562.                 result = origfunc(name, unit, ioreq, flags, libbase);
  2563.                 if (!result)
  2564.                         return (result);
  2565.         }
  2566.         /*
  2567.          *              Now a workaround for a bug in CON that makes it call
  2568.          *              OpenDevice("timer.device" | NULL) very frequently.
  2569.          *              (The NULL is a space-saving shorthand which the 3.1 Kickstart
  2570.          *              interprets as a magic cookie for "timer.device" to save some
  2571.          *              ROM space).
  2572.          */
  2573.         if ((CallAddr >= RomStart && CallAddr <= RomEnd) ||
  2574.                                         strcmp(SysBase->ThisTask->tc_Node.ln_Name, "CON") == 0) {
  2575.                 if (onlyfails)
  2576.                         return (result);
  2577.                 JumpOrigFunc(unit);
  2578.         }
  2579.         if (!devname)
  2580.                 devname = MSG(MSG_NULLSTR);
  2581.  
  2582.         mysprintf(unitstr, MSG(MSG_OPT_DEVUNIT), unit);
  2583.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_OPENDEV,
  2584.                                          devname, unitstr, NO_EXPAND);
  2585.         if (!ev) {
  2586.                 if (onlyfails)
  2587.                         return (result);
  2588.                 JumpOrigFunc(unit);
  2589.         }
  2590.  
  2591.         /*
  2592.          *              Allocated event safely, now tell SnoopDos task to wake up
  2593.          */
  2594.         if (onlyfails) {
  2595.                 CheckForPause(NULL, 0);
  2596.         } else {
  2597.                 ev->status = ES_UPDATING;
  2598.                 CheckForPause(ev, seqnum);
  2599.                 Signal(SnoopTask, NewEventMask);
  2600.                 result = origfunc(name, unit, ioreq, flags, libbase);
  2601.         }
  2602.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2603.                 if (seqnum >= RealFirstSeq) {
  2604.                         if (!result)
  2605.                                 ev->result = MSG(MSG_RES_OKAY);
  2606.                         else
  2607.                                 ev->result = MSG(MSG_RES_FAIL);
  2608.                         ev->status = ES_READY;
  2609.                         Signal(SnoopTask, NewEventMask);
  2610.                 }
  2611.                 ReleaseSemaphore(&BufSem);
  2612.         }
  2613.         return (result);
  2614. }
  2615.  
  2616. /*
  2617.  *              New_OpenFont(textattr)
  2618.  *
  2619.  *              Opens a new font that's currently in memory. OpenDiskFont will
  2620.  *              call this function first before checking the disk, so patching
  2621.  *              this function catches all accesses.
  2622.  */
  2623. ULONG ASM New_OpenFont(reg_a0 struct TextAttr *textattr, reg_a6 void *libbase)
  2624. {
  2625.         MarkCallAddr;
  2626.         FP_OpenFont origfunc = (FP_OpenFont)PatchList[GID_OPENFONT].origfunc;
  2627.         int onlyfails = OnlyShowFails;
  2628.         ULONG result;
  2629.         Event *ev;
  2630.         char *name;
  2631.         char sizestr[20];
  2632.         LONG  seqnum;
  2633.  
  2634.         if (onlyfails) {
  2635.                 result = origfunc(textattr, libbase);
  2636.                 if (result)
  2637.                         return (result);
  2638.         }
  2639.         if (textattr) {
  2640.                 mysprintf(sizestr, MSG(MSG_OPT_FONTSIZE), textattr->ta_YSize);
  2641.                 name = textattr->ta_Name;
  2642.         } else {
  2643.                 *sizestr = '\0';
  2644.                 name = MSG(MSG_NULLSTR);
  2645.         }
  2646.  
  2647.         /*
  2648.          * THOR: Do not monitor input.device OpenFont().
  2649.          * This is only annoying...
  2650.          */
  2651.  
  2652.         if (SysBase->ThisTask == InputTask) {
  2653.                 ev = NULL;
  2654.         } else {
  2655.                 ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_OPENFONT,
  2656.                                          name, sizestr, NO_EXPAND);
  2657.         }
  2658.  
  2659.         if (!ev) {
  2660.                 if (onlyfails)
  2661.                         return (result);
  2662.                 JumpOrigFunc(0);
  2663.         }
  2664.  
  2665.         /*
  2666.          *              Allocated event safely, now tell SnoopDos task to wake up
  2667.          */
  2668.         if (onlyfails) {
  2669.                 CheckForPause(NULL, 0);
  2670.         } else {
  2671.                 ev->status = ES_UPDATING;
  2672.                 CheckForPause(ev, seqnum);
  2673.                 Signal(SnoopTask, NewEventMask);
  2674.                 result = origfunc(textattr, libbase);
  2675.         }
  2676.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2677.                 if (seqnum >= RealFirstSeq) {
  2678.                         if (result)
  2679.                                 ev->result = MSG(MSG_RES_OKAY);
  2680.                         else
  2681.                                 ev->result = MSG(MSG_RES_FAIL);
  2682.                         ev->status = ES_READY;
  2683.                         Signal(SnoopTask, NewEventMask);
  2684.                 }
  2685.                 ReleaseSemaphore(&BufSem);
  2686.         }
  2687.         return (result);
  2688. }
  2689.  
  2690. /*
  2691.  *              New_OpenLibrary(name, version)
  2692.  *
  2693.  *              Opens the named library with the specified version number.
  2694.  *
  2695.  *              We have a nasty potential for deadlock here -- CreateEvent()
  2696.  *              which we call, in turns calls DateStamp(), and DateStamp()
  2697.  *              itself calls OpenLibrary(....). So, we need to protect
  2698.  *              ourselves against a recursive call.
  2699.  *
  2700.  *              We do this by ignoring any call to open dos.library made
  2701.  *              by a call originating in ROM.
  2702.  */
  2703. ULONG ASM New_OpenLibrary(reg_a1 char *name, reg_d0 long version,
  2704.                                                   reg_a6 void *libbase)
  2705. {
  2706.         MarkCallAddr;
  2707.         FP_OpenLibrary origfunc = (FP_OpenLibrary)
  2708.                                                            PatchList[GID_OPENLIBRARY].origfunc;
  2709.         int onlyfails = OnlyShowFails;
  2710.         ULONG result;
  2711.         Event *ev;
  2712.         char verstr[20];
  2713.         ULONG taskhandle;
  2714.         LONG  seqnum;
  2715.  
  2716.         /*
  2717.          *              Check for re-entrant calling (usually caused by the
  2718.          *              DateStamp call in the GetNewEvent() code).
  2719.          *
  2720.          *              In theory, we should only need to check if the semaphore
  2721.          *              is owned by the current task. In practise, we need
  2722.          *              the additional checks to be really sure (otherwise
  2723.          *              we seem to get unexplained crashes very frequently --
  2724.          *              very mysterious and worrying).
  2725.          *
  2726.          *              We also ignore calls to open dos.library -- this is partly
  2727.          *              because it gets called by DateStamp() inside dos.library
  2728.          *              itself (so things that call DateStamp once a second, like
  2729.          *              Enforcer(), will generate loads of calls to it) and partly
  2730.          *              to avoid problems with our own CreateEvent() code calling it.
  2731.          */
  2732.         if (BufSem.ss_Owner == SysBase->ThisTask ||
  2733.                 strcmp(name, "dos.library") == 0)
  2734.         {
  2735.                 JumpOrigFunc(version);
  2736.         }
  2737.  
  2738.         if (onlyfails) {
  2739.                 result = origfunc(name, version, libbase);
  2740.                 if (result)
  2741.                         return (result);
  2742.         }
  2743.         taskhandle = CheckTaskRecursion();
  2744.         if (!taskhandle) {
  2745.                 if (!onlyfails)
  2746.                         result = origfunc(name, version, libbase);
  2747.                 return (result);
  2748.         }
  2749.         mysprintf(verstr, MSG(MSG_OPT_LIBVER), version);
  2750.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_OPENLIB,
  2751.                                          name, verstr, NO_EXPAND);
  2752.         EndTaskRecursion(taskhandle);
  2753.  
  2754.         if (!ev) {
  2755.                 if (onlyfails)
  2756.                         return (result);
  2757.                 JumpOrigFunc(version);
  2758.         }
  2759.  
  2760.         /*
  2761.          *              Allocated event safely, now tell SnoopDos task to wake up
  2762.          */
  2763.         if (onlyfails) {
  2764.                 CheckForPause(NULL, 0);
  2765.         } else {
  2766.                 ev->status = ES_UPDATING;
  2767.                 CheckForPause(ev, seqnum);
  2768.                 Signal(SnoopTask, NewEventMask);
  2769.                 result = origfunc(name, version, libbase);
  2770.         }
  2771.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2772.                 if (seqnum >= RealFirstSeq) {
  2773.                         if (result)
  2774.                                 ev->result = MSG(MSG_RES_OKAY);
  2775.                         else
  2776.                                 ev->result = MSG(MSG_RES_FAIL);
  2777.                         ev->status = ES_READY;
  2778.                         Signal(SnoopTask, NewEventMask);
  2779.                 }
  2780.                 ReleaseSemaphore(&BufSem);
  2781.         }
  2782.         return (result);
  2783. }
  2784.  
  2785. /*
  2786.  *              New_OpenResource(name)
  2787.  *
  2788.  *              Opens the named resource
  2789.  */
  2790. ULONG ASM New_OpenResource(reg_a1 char *name, reg_a6 void *libbase)
  2791. {
  2792.         MarkCallAddr;
  2793.         FP_OpenResource origfunc = (FP_OpenResource)
  2794.                                                             PatchList[GID_OPENRESOURCE].origfunc;
  2795.         int onlyfails = OnlyShowFails;
  2796.         ULONG result;
  2797.         Event *ev;
  2798.         LONG  seqnum;
  2799.  
  2800.         if (onlyfails) {
  2801.                 result = origfunc(name, libbase);
  2802.                 if (result)
  2803.                         return (result);
  2804.         }
  2805.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_OPENRES,
  2806.                                          name, NULL, NO_EXPAND);
  2807.         if (!ev) {
  2808.                 if (onlyfails)
  2809.                         return (result);
  2810.                 JumpOrigFunc(0);
  2811.         }
  2812.  
  2813.         /*
  2814.          *              Allocated event safely, now tell SnoopDos task to wake up
  2815.          */
  2816.         if (onlyfails) {
  2817.                 CheckForPause(NULL, 0);
  2818.         } else {
  2819.                 ev->status = ES_UPDATING;
  2820.                 CheckForPause(ev, seqnum);
  2821.                 Signal(SnoopTask, NewEventMask);
  2822.                 result = origfunc(name, libbase);
  2823.         }
  2824.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2825.                 if (seqnum >= RealFirstSeq) {
  2826.                         if (result)
  2827.                                 ev->result = MSG(MSG_RES_OKAY);
  2828.                         else
  2829.                                 ev->result = MSG(MSG_RES_FAIL);
  2830.                         ev->status = ES_READY;
  2831.                         Signal(SnoopTask, NewEventMask);
  2832.                 }
  2833.                 ReleaseSemaphore(&BufSem);
  2834.         }
  2835.         return (result);
  2836. }
  2837.  
  2838. /*
  2839.  *              New_FindToolType(array, tooltype)
  2840.  *
  2841.  *              Searches the tooltype array for a particular tooltype
  2842.  */
  2843. ULONG ASM New_FindToolType(reg_a0 char **array, reg_a1 char *tooltype,
  2844.                                                    reg_a6 void *libbase)
  2845. {
  2846.         MarkCallAddr;
  2847.         FP_FindToolType origfunc = (FP_FindToolType)
  2848.                                                             PatchList[GID_READTOOLTYPES].origfunc;
  2849.         int onlyfails = OnlyShowFails;
  2850.         ULONG result;
  2851.         Event *ev;
  2852.         char *toolname = tooltype;
  2853.         LONG  seqnum;
  2854.  
  2855.         if (onlyfails) {
  2856.                 result = origfunc(array, tooltype, libbase);
  2857.                 if (result)
  2858.                         return (result);
  2859.         }
  2860.         if (toolname == NULL)
  2861.                 toolname = MSG(MSG_NULLSTR);
  2862.  
  2863.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_FINDTOOL,
  2864.                                          toolname, NULL, NO_EXPAND);
  2865.         if (!ev) {
  2866.                 if (onlyfails)
  2867.                         return (result);
  2868.                 JumpOrigFunc(0);
  2869.         }
  2870.  
  2871.         /*
  2872.          *              Allocated event safely, now tell SnoopDos task to wake up
  2873.          */
  2874.         if (onlyfails) {
  2875.                 CheckForPause(NULL, 0);
  2876.         } else {
  2877.                 ev->status = ES_UPDATING;
  2878.                 CheckForPause(ev, seqnum);
  2879.                 Signal(SnoopTask, NewEventMask);
  2880.                 result = origfunc(array, tooltype, libbase);
  2881.         }
  2882.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2883.                 if (seqnum >= RealFirstSeq) {
  2884.                         if (result)
  2885.                                 ev->result = MSG(MSG_RES_OKAY);
  2886.                         else
  2887.                                 ev->result = MSG(MSG_RES_FAIL);
  2888.                         ev->status = ES_READY;
  2889.                         Signal(SnoopTask, NewEventMask);
  2890.                 }
  2891.                 ReleaseSemaphore(&BufSem);
  2892.         }
  2893.         return (result);
  2894. }
  2895.  
  2896. /*
  2897.  *              New_MatchToolValue(tooltype, value)
  2898.  *
  2899.  *              Checks if a specified tooltype contains a given value
  2900.  */
  2901. ULONG ASM New_MatchToolValue(reg_a0 char *tooltype, reg_a1 char *value,
  2902.                                                      reg_a6 void *libbase)
  2903. {
  2904.         MarkCallAddr;
  2905.         FP_MatchToolValue origfunc = (FP_MatchToolValue)
  2906.                                                               PatchList[GID_READTOOLTYPES2].origfunc;
  2907.         int onlyfails = OnlyShowFails;
  2908.         ULONG result;
  2909.         Event *ev;
  2910.         char *toolname = tooltype;
  2911.         LONG  seqnum;
  2912.  
  2913.         if (onlyfails) {
  2914.                 result = origfunc(tooltype, value, libbase);
  2915.                 if (result)
  2916.                         return (result);
  2917.         }
  2918.         if (toolname == NULL)
  2919.                 toolname = MSG(MSG_NULLSTR);
  2920.  
  2921.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_MATCHTOOL,
  2922.                                          toolname, value, NO_EXPAND);
  2923.         if (!ev) {
  2924.                 if (onlyfails)
  2925.                         return (result);
  2926.                 JumpOrigFunc(0);
  2927.         }
  2928.  
  2929.         /*
  2930.          *              Allocated event safely, now tell SnoopDos task to wake up
  2931.          */
  2932.         if (onlyfails) {
  2933.                 CheckForPause(NULL, 0);
  2934.         } else {
  2935.                 ev->status = ES_UPDATING;
  2936.                 CheckForPause(ev, seqnum);
  2937.                 Signal(SnoopTask, NewEventMask);
  2938.                 result = origfunc(tooltype, value, libbase);
  2939.         }
  2940.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2941.                 if (seqnum >= RealFirstSeq) {
  2942.                         if (result)
  2943.                                 ev->result = MSG(MSG_RES_OKAY);
  2944.                         else
  2945.                                 ev->result = MSG(MSG_RES_FAIL);
  2946.                         ev->status = ES_READY;
  2947.                         Signal(SnoopTask, NewEventMask);
  2948.                 }
  2949.                 ReleaseSemaphore(&BufSem);
  2950.         }
  2951.         return (result);
  2952. }
  2953.  
  2954. /*
  2955.  *              New_CurrentDir()
  2956.  *
  2957.  *              Changes current directory to somewhere else
  2958.  */
  2959. ULONG ASM New_CurrentDir(reg_d1 BPTR lock, reg_a6 void *libbase)
  2960. {
  2961.         MarkCallAddr;
  2962.         FP_CurrentDir origfunc = (FP_CurrentDir)PatchList[GID_CHANGEDIR].origfunc;
  2963.         int onlyfails = OnlyShowFails;
  2964.         Event *ev;
  2965.         char lockbuf[MAX_LOCK_LEN+1];
  2966.         char *lockpath;
  2967.         LONG  seqnum;
  2968.  
  2969.         if (onlyfails)
  2970.                 return origfunc(lock, libbase);         /* CurrentDir never fails */
  2971.  
  2972.         lockpath = MyNameFromLock(lock, NULL, lockbuf, MAX_LOCK_LEN);
  2973.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_CHANGEDIR,
  2974.                                          lockpath, NULL, NO_EXPAND);
  2975.         if (!ev)
  2976.                 JumpOrigFunc(0);
  2977.  
  2978.         /*
  2979.          *              Allocated event safely, now tell SnoopDos task to wake up
  2980.          */
  2981.         ev->status = ES_UPDATING;
  2982.         CheckForPause(ev, seqnum);
  2983.         if (AttemptSemaphoreHeavely(&BufSem)) {
  2984.                 if (seqnum >= RealFirstSeq) {
  2985.                         ev->status = ES_READY;
  2986.                         Signal(SnoopTask, NewEventMask);
  2987.                 }
  2988.                 ReleaseSemaphore(&BufSem);
  2989.         }
  2990.         return origfunc(lock, libbase);
  2991. }
  2992.  
  2993. /*
  2994.  *              New_DeleteFile()
  2995.  *
  2996.  *              Deletes a file from disk
  2997.  */
  2998. ULONG ASM New_DeleteFile(reg_d1 char *name, reg_a6 void *libbase)
  2999. {
  3000.         MarkCallAddr;
  3001.         FP_DeleteFile origfunc = (FP_DeleteFile)PatchList[GID_DELETE].origfunc;
  3002.         int onlyfails = OnlyShowFails;
  3003.         Event *ev;
  3004.         ULONG result;
  3005.         LONG  seqnum;
  3006.  
  3007.         if (onlyfails) {
  3008.                 result = origfunc(name, libbase);
  3009.                 if (result)
  3010.                         return (result);
  3011.         }
  3012.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_DELETE,
  3013.                                          name, NULL, EXPAND_NAME);
  3014.         if (!ev) {
  3015.                 if (onlyfails)
  3016.                         return (result);
  3017.                 JumpOrigFunc(0);
  3018.         }
  3019.  
  3020.         /*
  3021.          *              Allocated event safely, now tell SnoopDos task to wake up
  3022.          */
  3023.         if (onlyfails) {
  3024.                 CheckForPause(NULL, 0);
  3025.         } else {
  3026.                 ev->status = ES_UPDATING;
  3027.                 CheckForPause(ev, seqnum);
  3028.                 Signal(SnoopTask, NewEventMask);
  3029.                 result = origfunc(name, libbase);
  3030.         }
  3031.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3032.                 if (seqnum >= RealFirstSeq) {
  3033.                         if (result)
  3034.                                 ev->result = MSG(MSG_RES_OKAY);
  3035.                         else
  3036.                                 ev->result = MSG(MSG_RES_FAIL);
  3037.                         ev->status = ES_READY;
  3038.                         Signal(SnoopTask, NewEventMask);
  3039.                 }
  3040.                 ReleaseSemaphore(&BufSem);
  3041.         }
  3042.         return (result);
  3043. }
  3044.  
  3045. /*
  3046.  *              New_Execute()
  3047.  *
  3048.  *              Executes a command from disk. Now superceded by System and RunCommand
  3049.  */
  3050. ULONG ASM New_Execute(reg_d1 char *cmdline, reg_d2 BPTR fin, reg_d3 BPTR fout,
  3051.                                           reg_a6 void *libbase)
  3052. {
  3053.         MarkCallAddr;
  3054.         FP_Execute origfunc = (FP_Execute)PatchList[GID_EXECUTE].origfunc;
  3055.         int onlyfails = OnlyShowFails;
  3056.         Event *ev;
  3057.         ULONG result;
  3058.         char *optstr;
  3059.         LONG  seqnum;
  3060.  
  3061.         /*
  3062.          *              For functions that may potentially take a long time to complete,
  3063.          *              we check if they're being called from ROM straight away, so
  3064.          *              that we can exit and not hang around waiting for them if they
  3065.          *              are, even in the OnlyShowFails case.
  3066.          */
  3067.         if (!MonROMCalls && CallAddr >= RomStart && CallAddr <= RomEnd)
  3068.                 JumpOrigFunc(0);
  3069.  
  3070.         if (onlyfails) {
  3071.                 result = origfunc(cmdline, fin, fout, libbase);
  3072.                 if (result)
  3073.                         return (result);
  3074.         }
  3075.         if (fin == NULL)
  3076.                 optstr = MSG(MSG_OPT_EXECSINGLE);
  3077.         else
  3078.                 optstr = MSG(MSG_OPT_EXECBATCH);
  3079.  
  3080.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_EXECUTE,
  3081.                                          cmdline, optstr, NO_EXPAND);
  3082.         if (!ev) {
  3083.                 if (onlyfails)
  3084.                         return (result);
  3085.                 JumpOrigFunc(0);
  3086.         }
  3087.  
  3088.         /*
  3089.          *              Allocated event safely, now tell SnoopDos task to wake up
  3090.          */
  3091.         if (onlyfails) {
  3092.                 CheckForPause(NULL, 0);
  3093.         } else {
  3094.                 ev->status = ES_UPDATING;
  3095.                 CheckForPause(ev, seqnum);
  3096.                 Signal(SnoopTask, NewEventMask);
  3097.                 result = origfunc(cmdline, fin, fout, libbase);
  3098.         }
  3099.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3100.                 if (seqnum >= RealFirstSeq) {
  3101.                         if (result)
  3102.                                 ev->result = MSG(MSG_RES_OKAY);
  3103.                         else
  3104.                                 ev->result = MSG(MSG_RES_FAIL);
  3105.                         ev->status = ES_READY;
  3106.                         Signal(SnoopTask, NewEventMask);
  3107.                 }
  3108.                 ReleaseSemaphore(&BufSem);
  3109.         }
  3110.         return (result);
  3111. }
  3112.  
  3113. /*
  3114.  *              New_GetVar()
  3115.  *
  3116.  *              Inquires about the value of an environment variable
  3117.  */
  3118. ULONG ASM New_GetVar(reg_d1 char *name, reg_d2 char *buffer,
  3119.                                          reg_d3 size, reg_d4 flags, reg_a6 void *libbase)
  3120. {
  3121.         MarkCallAddr;
  3122.         FP_GetVar origfunc = (FP_GetVar)PatchList[GID_GETVAR].origfunc;
  3123.         int onlyfails = OnlyShowFails;
  3124.         Event *ev;
  3125.         ULONG result;
  3126.         char optstr[20];
  3127.         ULONG optid;
  3128.         LONG  seqnum;
  3129.  
  3130.         if (onlyfails) {
  3131.                 result = origfunc(name, buffer, size, flags, libbase);
  3132.                 if (result != -1)
  3133.                         return (result);
  3134.         }
  3135.         /*
  3136.          *              Now determine our flags. We recognise global, local
  3137.          *              or either types of variable. Binary variables are
  3138.          *              flagged with a trailing asterisk.
  3139.          */
  3140.         if              (flags & GVF_GLOBAL_ONLY)       optid = MSG_OPT_GLOBAL;
  3141.         else if ((flags & 7) == LV_ALIAS)       optid = MSG_OPT_ALIAS;
  3142.         else if (flags & GVF_LOCAL_ONLY)        optid = MSG_OPT_LOCAL;
  3143.         else                                                            optid = MSG_OPT_ANY;
  3144.         strcpy(optstr, MSG(optid));
  3145.  
  3146.         if (flags & GVF_BINARY_VAR)                     strcat(optstr, "*");
  3147.  
  3148.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_GETVAR,
  3149.                                          name, optstr, NO_EXPAND);
  3150.         if (!ev) {
  3151.                 if (onlyfails)
  3152.                         return (result);
  3153.                 JumpOrigFunc(0);
  3154.         }
  3155.  
  3156.         /*
  3157.          *              Allocated event safely, now tell SnoopDos task to wake up
  3158.          */
  3159.         if (onlyfails) {
  3160.                 CheckForPause(NULL, 0);
  3161.         } else {
  3162.                 ev->status = ES_UPDATING;
  3163.                 CheckForPause(ev, seqnum);
  3164.                 Signal(SnoopTask, NewEventMask);
  3165.                 result = origfunc(name, buffer, size, flags, libbase);
  3166.         }
  3167.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3168.                 if (seqnum >= RealFirstSeq) {
  3169.                         if (result != -1)
  3170.                                 ev->result = MSG(MSG_RES_OKAY);
  3171.                         else
  3172.                                 ev->result = MSG(MSG_RES_FAIL);
  3173.                         ev->status = ES_READY;
  3174.                         Signal(SnoopTask, NewEventMask);
  3175.                 }
  3176.                 ReleaseSemaphore(&BufSem);
  3177.         }
  3178.         return (result);
  3179. }
  3180.  
  3181. /*
  3182.  *              New_FindVar()
  3183.  *
  3184.  *              Inquires about the value of a local environment variable
  3185.  */
  3186. ULONG ASM New_FindVar(reg_d1 char *name, reg_d2 ULONG type,
  3187.                                           reg_a6 void *libbase)
  3188. {
  3189.         MarkCallAddr;
  3190.         FP_FindVar origfunc = (FP_FindVar)PatchList[GID_GETVAR2].origfunc;
  3191.         int onlyfails = OnlyShowFails;
  3192.         Event *ev;
  3193.         ULONG result;
  3194.         ULONG optid;
  3195.         LONG  seqnum;
  3196.  
  3197.         if (onlyfails) {
  3198.                 result = origfunc(name, type, libbase);
  3199.                 if (result)
  3200.                         return (result);
  3201.         }
  3202.  
  3203.         if              ((type & 7) == LV_VAR)          optid = MSG_OPT_LOCAL;
  3204.         else if ((type & 7) == LV_ALIAS)        optid = MSG_OPT_ALIAS;
  3205.         else                                                            optid = MSG_OPT_UNKNOWN;
  3206.  
  3207.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_FINDVAR,
  3208.                                          name, MSG(optid), NO_EXPAND);
  3209.         if (!ev) {
  3210.                 if (onlyfails)
  3211.                         return (result);
  3212.                 JumpOrigFunc(0);
  3213.         }
  3214.  
  3215.         /*
  3216.          *              Allocated event safely, now tell SnoopDos task to wake up
  3217.          */
  3218.         if (onlyfails) {
  3219.                 CheckForPause(NULL, 0);
  3220.         } else {
  3221.                 ev->status = ES_UPDATING;
  3222.                 Signal(SnoopTask, NewEventMask);
  3223.                 CheckForPause(ev, seqnum);
  3224.                 result = origfunc(name, type, libbase);
  3225.         }
  3226.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3227.                 if (seqnum >= RealFirstSeq) {
  3228.                         if (result)
  3229.                                 ev->result = MSG(MSG_RES_OKAY);
  3230.                         else
  3231.                                 ev->result = MSG(MSG_RES_FAIL);
  3232.                         ev->status = ES_READY;
  3233.                         Signal(SnoopTask, NewEventMask);
  3234.                 }
  3235.                 ReleaseSemaphore(&BufSem);
  3236.         }
  3237.         return (result);
  3238. }
  3239.  
  3240. /*
  3241.  *              New_SetVar()
  3242.  *
  3243.  *              Sets a (possibly new) variable to a particular value
  3244.  */
  3245. ULONG ASM New_SetVar(reg_d1 char *name, reg_d2 char *buffer,
  3246.                                          reg_d3 size, reg_d4 flags, reg_a6 void *libbase)
  3247. {
  3248.         MarkCallAddr;
  3249.         FP_SetVar origfunc = (FP_SetVar)PatchList[GID_SETVAR].origfunc;
  3250.         int onlyfails = OnlyShowFails;
  3251.         Event *ev;
  3252.         ULONG result;
  3253.         char varstr[MAX_STR_LEN+1];
  3254.         int vlen;
  3255.         ULONG optid;
  3256.         LONG  seqnum;
  3257.  
  3258.         if (onlyfails) {
  3259.                 result = origfunc(name, buffer, size, flags, libbase);
  3260.                 if (result)
  3261.                         return (result);
  3262.         }
  3263.         /*
  3264.          *              Now determine our flags. We recognise global, local
  3265.          *              or alias variables.
  3266.          */
  3267.         if              (flags & GVF_GLOBAL_ONLY)       optid = MSG_OPT_GLOBAL;
  3268.         else if ((flags & 7) == LV_VAR)         optid = MSG_OPT_LOCAL;
  3269.         else if ((flags & 7) == LV_ALIAS)       optid = MSG_OPT_ALIAS;
  3270.         else                                                            optid = MSG_OPT_UNKNOWN;
  3271.  
  3272.         /*
  3273.          *              Now create a string that looks like "Variable=Value"
  3274.          *
  3275.          *              We go to some pains to ensure we don't overwrite our
  3276.          *              string length
  3277.          */
  3278.         vlen = strlen(name);
  3279.         if (vlen > (MAX_STR_LEN-1)) {
  3280.                 strncpy(varstr, name, MAX_STR_LEN);
  3281.                 varstr[MAX_STR_LEN] = 0;
  3282.         } else {
  3283.                 strcpy(varstr, name);
  3284.                 strcat(varstr, "=");
  3285.                 vlen = 98 - vlen;
  3286.                 if (size != -1)
  3287.                         vlen = MIN(vlen, size);
  3288.  
  3289.                 strncat(varstr, buffer, vlen);
  3290.                 varstr[MAX_STR_LEN] = 0;
  3291.         }
  3292.  
  3293.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_SETVAR,
  3294.                                          varstr, MSG(optid), NO_EXPAND);
  3295.         if (!ev) {
  3296.                 if (onlyfails)
  3297.                         return (result);
  3298.                 JumpOrigFunc(0);
  3299.         }
  3300.  
  3301.         /*
  3302.          *              Allocated event safely, now tell SnoopDos task to wake up
  3303.          */
  3304.         if (onlyfails) {
  3305.                 CheckForPause(NULL, 0);
  3306.         } else {
  3307.                 ev->status = ES_UPDATING;
  3308.                 CheckForPause(ev, seqnum);
  3309.                 Signal(SnoopTask, NewEventMask);
  3310.                 result = origfunc(name, buffer, size, flags, libbase);
  3311.         }
  3312.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3313.                 if (seqnum >= RealFirstSeq) {
  3314.                         if (result)
  3315.                                 ev->result = MSG(MSG_RES_OKAY);
  3316.                         else
  3317.                                 ev->result = MSG(MSG_RES_FAIL);
  3318.                         ev->status = ES_READY;
  3319.                         Signal(SnoopTask, NewEventMask);
  3320.                 }
  3321.                 ReleaseSemaphore(&BufSem);
  3322.         }
  3323.         return (result);
  3324. }
  3325.  
  3326. /*
  3327.  *              New_DeleteVar()
  3328.  *
  3329.  *              Deletes an environment variable from the environment
  3330.  */
  3331. ULONG ASM New_DeleteVar(reg_d1 char *name, reg_d2 ULONG flags,
  3332.                                                 reg_a6 void *libbase)
  3333. {
  3334.         MarkCallAddr;
  3335.         FP_DeleteVar origfunc = (FP_DeleteVar)PatchList[GID_SETVAR2].origfunc;
  3336.         int onlyfails = OnlyShowFails;
  3337.         Event *ev;
  3338.         ULONG result;
  3339.         ULONG optid;
  3340.         LONG  seqnum;
  3341.  
  3342.         if (onlyfails) {
  3343.                 result = origfunc(name, flags, libbase);
  3344.                 if (result)
  3345.                         return (result);
  3346.         }
  3347.         /*
  3348.          *              Now determine our flags. We recognise global, local
  3349.          *              or alias variables.
  3350.          */
  3351.         if              (flags & GVF_GLOBAL_ONLY)       optid = MSG_OPT_GLOBAL;
  3352.         else if ((flags & 7) == LV_VAR)         optid = MSG_OPT_LOCAL;
  3353.         else if ((flags & 7) == LV_ALIAS)       optid = MSG_OPT_ALIAS;
  3354.         else                                                            optid = MSG_OPT_UNKNOWN;
  3355.  
  3356.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_KILLVAR,
  3357.                                          name, MSG(optid), NO_EXPAND);
  3358.         if (!ev) {
  3359.                 if (onlyfails)
  3360.                         return (result);
  3361.                 JumpOrigFunc(0);
  3362.         }
  3363.  
  3364.         /*
  3365.          *              Allocated event safely, now tell SnoopDos task to wake up
  3366.          */
  3367.         if (onlyfails) {
  3368.                 CheckForPause(NULL, 0);
  3369.         } else {
  3370.                 ev->status = ES_UPDATING;
  3371.                 CheckForPause(ev, seqnum);
  3372.                 Signal(SnoopTask, NewEventMask);
  3373.                 result = origfunc(name, flags, libbase);
  3374.         }
  3375.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3376.                 if (seqnum >= RealFirstSeq) {
  3377.                         if (result)
  3378.                                 ev->result = MSG(MSG_RES_OKAY);
  3379.                         else
  3380.                                 ev->result = MSG(MSG_RES_FAIL);
  3381.                         ev->status = ES_READY;
  3382.                         Signal(SnoopTask, NewEventMask);
  3383.                 }
  3384.                 ReleaseSemaphore(&BufSem);
  3385.         }
  3386.         return (result);
  3387. }
  3388.  
  3389. /*
  3390.  *              New_LoadSeg()
  3391.  *
  3392.  *              Tries to load in a module from disk
  3393.  */
  3394. ULONG ASM New_LoadSeg(reg_d1 char *name, reg_d2 BPTR hunk, reg_d3 BPTR file,reg_a6 void *libbase)
  3395. {
  3396.         MarkCallAddr;
  3397.         FP_LoadSeg origfunc = (FP_LoadSeg)PatchList[GID_LOADSEG].origfunc;
  3398.         int onlyfails = OnlyShowFails;
  3399.         Event *ev;
  3400.         ULONG result;
  3401.         LONG  seqnum;
  3402.  
  3403.         /*
  3404.          * THOR: Fix overlay loading here.
  3405.          */
  3406.         if (name == NULL) {
  3407.                 return origfunc(NULL,hunk,file,libbase);
  3408.         }
  3409.  
  3410.         if (onlyfails) {
  3411.                 result = origfunc(name, NULL, NULL, libbase);
  3412.                 if (result)
  3413.                         return (result);
  3414.         }
  3415.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_LOADSEG,
  3416.                                          name, NULL, EXPAND_NAME);
  3417.         if (!ev) {
  3418.                 if (onlyfails)
  3419.                         return (result);
  3420.                 JumpOrigFunc(0);
  3421.         }
  3422.  
  3423.         /*
  3424.          *              Allocated event safely, now tell SnoopDos task to wake up
  3425.          */
  3426.         if (onlyfails) {
  3427.                 CheckForPause(NULL, 0);
  3428.         } else {
  3429.                 ev->status = ES_UPDATING;
  3430.                 CheckForPause(ev, seqnum);
  3431.  
  3432. #if MONITOR_SEMAPHORE
  3433.                 LoadTask = SysBase->ThisTask;
  3434.                 result = origfunc(name, NULL, NULL, libbase);
  3435.                 LoadTask = 0;
  3436. #else
  3437.                 result = origfunc(name, NULL, NULL, libbase);
  3438. #endif
  3439.         }
  3440.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3441.                 if (seqnum >= RealFirstSeq) {
  3442.                         if (result)
  3443.                                 ev->result = MSG(MSG_RES_OKAY);
  3444.                         else
  3445.                                 ev->result = MSG(MSG_RES_FAIL);
  3446.                         ev->status = ES_READY;
  3447.                         Signal(SnoopTask, NewEventMask);
  3448.                 }
  3449.                 ReleaseSemaphore(&BufSem);
  3450.         }
  3451.         return (result);
  3452. }
  3453.  
  3454. /*
  3455.  *              New_NewLoadSeg()
  3456.  *
  3457.  *              Tries to load in a module from disk
  3458.  */
  3459. ULONG ASM New_NewLoadSeg(reg_d1 char *name, reg_d2 TAGPTR tags,
  3460.                                                  reg_a6 void *libbase)
  3461. {
  3462.         MarkCallAddr;
  3463.         FP_NewLoadSeg origfunc = (FP_NewLoadSeg)PatchList[GID_LOADSEG2].origfunc;
  3464.         int onlyfails = OnlyShowFails;
  3465.         Event *ev;
  3466.         ULONG result;
  3467.         LONG  seqnum;
  3468.  
  3469.         if (onlyfails) {
  3470.                 result = origfunc(name, tags, libbase);
  3471.                 if (result)
  3472.                         return (result);
  3473.         }
  3474.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_NEWLOADSEG,
  3475.                                          name, NULL, EXPAND_NAME);
  3476.         if (!ev) {
  3477.                 if (onlyfails)
  3478.                         return (result);
  3479.                 JumpOrigFunc(0);
  3480.         }
  3481.  
  3482.         /*
  3483.          *              Allocated event safely, now tell SnoopDos task to wake up
  3484.          */
  3485.         if (onlyfails) {
  3486.                 CheckForPause(NULL, 0);
  3487.         } else {
  3488.                 ev->status = ES_UPDATING;
  3489.                 CheckForPause(ev, seqnum);
  3490.                 Signal(SnoopTask, NewEventMask);
  3491.                 result = origfunc(name, tags, libbase);
  3492.         }
  3493.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3494.                 if (seqnum >= RealFirstSeq) {
  3495.                         if (result)
  3496.                                 ev->result = MSG(MSG_RES_OKAY);
  3497.                         else
  3498.                                 ev->result = MSG(MSG_RES_FAIL);
  3499.                         ev->status = ES_READY;
  3500.                         Signal(SnoopTask, NewEventMask);
  3501.                 }
  3502.                 ReleaseSemaphore(&BufSem);
  3503.         }
  3504.         return (result);
  3505. }
  3506.  
  3507. /*
  3508.  *              New_NewLoadSeg()
  3509.  *
  3510.  *              Tries to load in a module from disk
  3511.  */
  3512. ULONG ASM New_Lock(reg_d1 char *name, reg_d2 LONG mode, reg_a6 void *libbase)
  3513. {
  3514.         MarkCallAddr;
  3515.         FP_Lock origfunc = (FP_Lock)PatchList[GID_LOCKFILE].origfunc;
  3516.         int onlyfails = OnlyShowFails;
  3517.         Event *ev;
  3518.         ULONG result;
  3519.         LONG optid;
  3520.         char *curname;
  3521.         LONG  seqnum;
  3522.  
  3523.         if (onlyfails) {
  3524.                 result = origfunc(name, mode, libbase);
  3525.                 if (result)
  3526.                         return (result);
  3527.         }
  3528.         if              (mode == ACCESS_READ)           optid = MSG_OPT_READ;
  3529.         else if (mode == ACCESS_WRITE)          optid = MSG_OPT_WRITE;
  3530.         else                                                            optid = MSG_OPT_READBAD;
  3531.  
  3532.         curname = name;
  3533.         if (!ShowPaths && *curname == '\0')
  3534.                 curname = "\"\"";
  3535.  
  3536.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_LOCK,
  3537.                                          curname, MSG(optid), EXPAND_NAME);
  3538.         if (!ev) {
  3539.                 if (onlyfails)
  3540.                         return (result);
  3541.                 JumpOrigFunc(0);
  3542.         }
  3543.  
  3544.         /*
  3545.          *              Allocated event safely, now tell SnoopDos task to wake up
  3546.          */
  3547.         if (onlyfails) {
  3548.                 CheckForPause(NULL, 0);
  3549.         } else {
  3550.                 ev->status = ES_UPDATING;
  3551.                 CheckForPause(ev, seqnum);
  3552.                 Signal(SnoopTask, NewEventMask);
  3553.                 result = origfunc(name, mode, libbase);
  3554.         }
  3555.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3556.                 if (seqnum >= RealFirstSeq) {
  3557.                         if (result)
  3558.                                 ev->result = MSG(MSG_RES_OKAY);
  3559.                         else
  3560.                                 ev->result = MSG(MSG_RES_FAIL);
  3561.                         ev->status = ES_READY;
  3562.                         Signal(SnoopTask, NewEventMask);
  3563.                 }
  3564.                 ReleaseSemaphore(&BufSem);
  3565.         }
  3566.         return (result);
  3567. }
  3568.  
  3569. /*
  3570.  *              New_CreateDir()
  3571.  *
  3572.  *              Creates a new directory on disk
  3573.  */
  3574. ULONG ASM New_CreateDir(reg_d1 char *name, reg_a6 void *libbase)
  3575. {
  3576.         MarkCallAddr;
  3577.         FP_CreateDir origfunc = (FP_CreateDir)PatchList[GID_MAKEDIR].origfunc;
  3578.         int onlyfails = OnlyShowFails;
  3579.         Event *ev;
  3580.         ULONG result;
  3581.         LONG  seqnum;
  3582.  
  3583.         if (onlyfails) {
  3584.                 result = origfunc(name, libbase);
  3585.                 if (result)
  3586.                         return (result);
  3587.         }
  3588.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_MAKEDIR,
  3589.                                          name, NULL, EXPAND_NAME);
  3590.         if (!ev) {
  3591.                 if (onlyfails)
  3592.                         return (result);
  3593.                 JumpOrigFunc(0);
  3594.         }
  3595.  
  3596.         /*
  3597.          *              Allocated event safely, now tell SnoopDos task to wake up
  3598.          */
  3599.         if (onlyfails) {
  3600.                 CheckForPause(NULL, 0);
  3601.         } else {
  3602.                 ev->status = ES_UPDATING;
  3603.                 CheckForPause(ev, seqnum);
  3604.                 Signal(SnoopTask, NewEventMask);
  3605.                 result = origfunc(name, libbase);
  3606.         }
  3607.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3608.                 if (seqnum >= RealFirstSeq) {
  3609.                         if (result)
  3610.                                 ev->result = MSG(MSG_RES_OKAY);
  3611.                         else
  3612.                                 ev->result = MSG(MSG_RES_FAIL);
  3613.                         ev->status = ES_READY;
  3614.                         Signal(SnoopTask, NewEventMask);
  3615.                 }
  3616.                 ReleaseSemaphore(&BufSem);
  3617.         }
  3618.         return (result);
  3619. }
  3620.  
  3621. /*
  3622.  *              New_MakeLink()
  3623.  *
  3624.  *              Creates a new hard or soft link
  3625.  */
  3626. ULONG ASM New_MakeLink(reg_d1 char *name, reg_d2 LONG dest, reg_d3 LONG soft,
  3627.                                            reg_a6 void *libbase)
  3628. {
  3629.         MarkCallAddr;
  3630.         struct Process *myproc = (struct Process *)SysBase->ThisTask;
  3631.         FP_MakeLink origfunc   = (FP_MakeLink)PatchList[GID_MAKELINK].origfunc;
  3632.         int onlyfails          = OnlyShowFails;
  3633.         Event *ev;
  3634.         ULONG result;
  3635.         LONG optid;
  3636.         char namestr[MAX_STR_LEN+1];
  3637.         LONG seqnum;
  3638.         int  len;
  3639.  
  3640.         if (onlyfails) {
  3641.                 result = origfunc(name, dest, soft, libbase);
  3642.                 if (result)
  3643.                         return (result);
  3644.         }
  3645.         if (soft)       optid = MSG_OPT_SOFTLINK;
  3646.         else            optid = MSG_OPT_HARDLINK;
  3647.  
  3648.         /*
  3649.          *              Now build a string that looks like "name --> <dest>" to display
  3650.          *              as our link. For soft links, we just concatenate the two
  3651.          *              strings. For hard links, we have to generate a filename
  3652.          *              from the lock also.
  3653.          */
  3654.         len = strlen(name);
  3655.         if (len >= MAX_STR_LEN) {
  3656.                 strncpy(namestr, name, MAX_STR_LEN);
  3657.                 namestr[MAX_STR_LEN] = 0;
  3658.         } else {
  3659.                 if (ShowPaths) {
  3660.                         strcpy(namestr, MyNameFromLock(myproc->pr_CurrentDir,
  3661.                                                                                    name, namestr, MAX_STR_LEN-2));
  3662.                         len = strlen(namestr);
  3663.                 } else
  3664.                         strcpy(namestr, name);
  3665.  
  3666.                 strcat(namestr, LinkPointerString);             /* Usually ' --> ' */
  3667.                 if (soft) {
  3668.                         strncat(namestr, (char *)dest, MAX_STR_LEN - len - 1);
  3669.                         namestr[MAX_STR_LEN] = 0;
  3670.                 } else {
  3671.                         strcat(namestr, MyNameFromLock(dest, NULL, namestr+len+1,
  3672.                                                                                                  MAX_STR_LEN-len-1));
  3673.                 }
  3674.         }
  3675.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_MAKELINK,
  3676.                                          namestr, MSG(optid), NO_EXPAND);
  3677.         if (!ev) {
  3678.                 if (onlyfails)
  3679.                         return (result);
  3680.                 JumpOrigFunc(0);
  3681.         }
  3682.  
  3683.         /*
  3684.          *              Allocated event safely, now tell SnoopDos task to wake up
  3685.          */
  3686.         if (onlyfails) {
  3687.                 CheckForPause(NULL, 0);
  3688.         } else {
  3689.                 ev->status = ES_UPDATING;
  3690.                 CheckForPause(ev, seqnum);
  3691.                 Signal(SnoopTask, NewEventMask);
  3692.                 result = origfunc(name, dest, soft, libbase);
  3693.         }
  3694.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3695.                 if (seqnum >= RealFirstSeq) {
  3696.                         if (result)
  3697.                                 ev->result = MSG(MSG_RES_OKAY);
  3698.                         else
  3699.                                 ev->result = MSG(MSG_RES_FAIL);
  3700.                         ev->status = ES_READY;
  3701.                         Signal(SnoopTask, NewEventMask);
  3702.                 }
  3703.                 ReleaseSemaphore(&BufSem);
  3704.         }
  3705.         return (result);
  3706. }
  3707.  
  3708. /*
  3709.  *              New_Open()
  3710.  *
  3711.  *              Opens a new file on disk
  3712.  */
  3713. ULONG ASM New_Open(reg_d1 char *name, reg_d2 LONG accessMode,
  3714.                                   reg_a6 void *libbase)
  3715. {
  3716.         MarkCallAddr;
  3717.         FP_Open origfunc = (FP_Open)PatchList[GID_OPENFILE].origfunc;
  3718.         int onlyfails = OnlyShowFails;
  3719.         Event *ev;
  3720.         ULONG result;
  3721.         char *optstr;
  3722.         LONG  seqnum;
  3723.  
  3724.         if              (accessMode == MODE_OLDFILE)    optstr = MSG(MSG_OPT_READ);
  3725.         else if (accessMode == MODE_NEWFILE)    optstr = MSG(MSG_OPT_WRITE);
  3726.         else if (accessMode == MODE_READWRITE)  optstr = MSG(MSG_OPT_MODIFY);
  3727.         else                                                                    optstr = MSG(MSG_OPT_UNKNOWN);
  3728.  
  3729.         if (onlyfails) {
  3730.                 result = origfunc(name, accessMode, libbase);
  3731.                 if (result)
  3732.                         return (result);
  3733.         }
  3734.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_OPEN,
  3735.                                          name, optstr, EXPAND_NAME);
  3736.         if (!ev) {
  3737.                 if (onlyfails)
  3738.                         return (result);
  3739.                 JumpOrigFunc(0);
  3740.         }
  3741.  
  3742.         /*
  3743.          *              Allocated event safely, now tell SnoopDos task to wake up
  3744.          */
  3745.         if (onlyfails) {
  3746.                 CheckForPause(NULL, 0);
  3747.         } else {
  3748.                 ev->status = ES_UPDATING;
  3749.                 CheckForPause(ev, seqnum);
  3750.                 Signal(SnoopTask, NewEventMask);
  3751.                 result = origfunc(name, accessMode, libbase);
  3752.         }
  3753.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3754.                 if (seqnum >= RealFirstSeq) {
  3755.                         if (result)
  3756.                                 ev->result = MSG(MSG_RES_OKAY);
  3757.                         else
  3758.                                 ev->result = MSG(MSG_RES_FAIL);
  3759.                         ev->status = ES_READY;
  3760.                         Signal(SnoopTask, NewEventMask);
  3761.                 }
  3762.                 ReleaseSemaphore(&BufSem);
  3763.         }
  3764.         return (result);
  3765. }
  3766.  
  3767. /*
  3768.  *              New_Rename()
  3769.  *
  3770.  *              Renames a file on disk. This is a little tricky, since we have
  3771.  *              to generate two events: one containing the source name and
  3772.  *              one containing the destination name.
  3773.  */
  3774. ULONG ASM New_Rename(reg_d1 char *oldname, reg_d2 char *newname,
  3775.                                      reg_a6 void *libbase)
  3776. {
  3777.         MarkCallAddr;
  3778.         FP_Rename origfunc = (FP_Rename)PatchList[GID_RENAME].origfunc;
  3779.         int onlyfails = OnlyShowFails;
  3780.         Event *ev;
  3781.         ULONG result;
  3782.         LONG  seqnum;
  3783.  
  3784.         if (onlyfails) {
  3785.                 result = origfunc(oldname, newname, libbase);
  3786.                 if (result)
  3787.                         return (result);
  3788.         }
  3789.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_RENAME,
  3790.                                          oldname, NULL, EXPAND_NAME);
  3791.         if (!ev) {
  3792.                 if (onlyfails)
  3793.                         return (result);
  3794.                 JumpOrigFunc(0);
  3795.         }
  3796.         ev->status = ES_READY;
  3797.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_RENAME2,
  3798.                                          newname, NULL, EXPAND_NAME);
  3799.         if (!ev) {
  3800.                 if (onlyfails)
  3801.                         return (result);
  3802.                 JumpOrigFunc(0);
  3803.         }
  3804.  
  3805.         /*
  3806.          *              Allocated event safely, now tell SnoopDos task to wake up
  3807.          */
  3808.         if (onlyfails) {
  3809.                 CheckForPause(NULL, 0);
  3810.         } else {
  3811.                 ev->status = ES_UPDATING;
  3812.                 CheckForPause(ev, seqnum);
  3813.                 Signal(SnoopTask, NewEventMask);
  3814.                 result = origfunc(oldname, newname, libbase);
  3815.         }
  3816.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3817.                 if (seqnum >= RealFirstSeq) {
  3818.                         if (result)
  3819.                                 ev->result = MSG(MSG_RES_OKAY);
  3820.                         else
  3821.                                 ev->result = MSG(MSG_RES_FAIL);
  3822.                         ev->status = ES_READY;
  3823.                         Signal(SnoopTask, NewEventMask);
  3824.                 }
  3825.                 ReleaseSemaphore(&BufSem);
  3826.         }
  3827.         return (result);
  3828. }
  3829.  
  3830. /*
  3831.  *              New_RunCommand()
  3832.  *
  3833.  *              Runs a command from disk. Like Execute() only with more control.
  3834.  */
  3835. ULONG ASM New_RunCommand(reg_d1 BPTR seglist,  reg_d2 ULONG stack,
  3836.                                                  reg_d3 char *cmdline, reg_d4 cmdlen,
  3837.                                          reg_a6 void *libbase)
  3838. {
  3839.         MarkCallAddr;
  3840.         FP_RunCommand origfunc = (FP_RunCommand)PatchList[GID_RUNCOMMAND].origfunc;
  3841.         int onlyfails = OnlyShowFails;
  3842.         Event *ev;
  3843.         ULONG result;
  3844.         char  stacksize[40];    /* Reserve additional space for return code! */
  3845.         LONG  seqnum;
  3846.         int       stklen;
  3847.         char  *p;
  3848.  
  3849.         /*
  3850.          *              For functions that may potentially take a long time to complete,
  3851.          *              we check if they're being called from ROM straight away, so
  3852.          *              that we can exit and not hang around waiting for them if they
  3853.          *              are, even in the OnlyShowFails case.
  3854.          */
  3855.         if (!MonROMCalls && CallAddr >= RomStart && CallAddr <= RomEnd)
  3856.                 JumpOrigFunc(0);
  3857.  
  3858.         if (onlyfails) {
  3859.                 result = origfunc(seglist, stack, cmdline, cmdlen, libbase);
  3860.                 if (result != -1)
  3861.                         return (result);
  3862.         }
  3863.  
  3864.         /*
  3865.          *              This is kind of nasty but it works. We need somewhere to store
  3866.          *              the return code string, but when we call CreateEvent(), we
  3867.          *              don't know what it will be yet. So, we allocate additional
  3868.          *              space at the end of our stacksize to hold this info, and
  3869.          *              overwrite it later on.
  3870.          */
  3871.         mysprintf(stacksize, "%ld", stack);
  3872.         stklen = strlen(stacksize);
  3873.         strcat(stacksize, "................");  /* Storage for return code */
  3874.  
  3875.         /*
  3876.          *              Next, a quick hack to get rid of that nasty CR at the end
  3877.          *              of the string (purely for visual purposes -- we put it back
  3878.          *              afterwards, of course!)
  3879.          */
  3880.         for (p = cmdline; *p; p++) {
  3881.                 if (*p == '\n') {
  3882.                         *p = ' ';
  3883.                         break;
  3884.                 }
  3885.         }
  3886.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_RUNCOMMAND,
  3887.                                          cmdline, stacksize, NO_EXPAND);
  3888.         if (*p)
  3889.                 *p = '\n';
  3890.  
  3891.         if (!ev) {
  3892.                 if (onlyfails)
  3893.                         return (result);
  3894.                 JumpOrigFunc(0);
  3895.         }
  3896.         ev->options[stklen] = 0;
  3897.  
  3898.         /*
  3899.          *              Allocated event safely, now tell SnoopDos task to wake up
  3900.          */
  3901.         if (onlyfails) {
  3902.                 CheckForPause(NULL, 0);
  3903.         } else {
  3904.                 ev->result = "----";
  3905.                 ev->status = ES_UPDATING;
  3906.                 CheckForPause(ev, seqnum);
  3907.                 Signal(SnoopTask, NewEventMask);
  3908.                 result = origfunc(seglist, stack, cmdline, cmdlen, libbase);
  3909.         }
  3910.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3911.                 if (seqnum >= RealFirstSeq) {
  3912.                         if (result != -1) {
  3913.                                 ev->result = ev->options + stklen + 1;
  3914.                                 mysprintf(ev->result, "%ld", result);
  3915.                         } else {
  3916.                                 ev->result = MSG(MSG_RES_FAIL);
  3917.                         }
  3918.                         ev->status = ES_READY;
  3919.                         Signal(SnoopTask, NewEventMask);
  3920.                 }
  3921.                 ReleaseSemaphore(&BufSem);
  3922.         }
  3923.         return (result);
  3924. }
  3925.  
  3926. /*
  3927.  *              New_SystemTagList()
  3928.  *
  3929.  *              Executes a command line. Like Execute() only more powerful.
  3930.  */
  3931. ULONG ASM New_SystemTagList(reg_d1 char *cmdline, reg_d2 TAGPTR tags,
  3932.                                                 reg_a6 void *libbase)
  3933. {
  3934.         MarkCallAddr;
  3935.         FP_SystemTagList origfunc = (FP_SystemTagList)
  3936.                                                                  PatchList[GID_SYSTEM].origfunc;
  3937.         int onlyfails = OnlyShowFails;
  3938.         Event *ev;
  3939.         ULONG result;
  3940.         char  optstr[20];       /* Reserve additional space for return code! */
  3941.         LONG  seqnum;
  3942.  
  3943.         /*
  3944.          *              For functions that may potentially take a long time to complete,
  3945.          *              we check if they're being called from ROM straight away, so
  3946.          *              that we can exit and not hang around waiting for them if they
  3947.          *              are, even in the OnlyShowFails case.
  3948.          */
  3949.         if (!MonROMCalls && CallAddr >= RomStart && CallAddr <= RomEnd)
  3950.                 JumpOrigFunc(0);
  3951.  
  3952.         if (onlyfails) {
  3953.                 result = origfunc(cmdline, tags, libbase);
  3954.                 if (result != -1)
  3955.                         return (result);
  3956.         }
  3957.         /*
  3958.          *              This is kind of nasty but it works. We need somewhere to store
  3959.          *              the return code string, but when we call CreateEvent(), we
  3960.          *              don't know what it will be yet. So, we allocate space for our
  3961.          *              option string instead and then replace it with our result
  3962.          *              string later on.
  3963.          */
  3964.         strcpy(optstr, "............"); /* Storage for result string */
  3965.  
  3966.         ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_SYSTEM, cmdline,
  3967.                                          optstr, NO_EXPAND);
  3968.         if (!ev) {
  3969.                 if (onlyfails)
  3970.                         return (result);
  3971.                 JumpOrigFunc(0);
  3972.         }
  3973.         *ev->options = '\0';
  3974.  
  3975.         /*
  3976.          *              Allocated event safely, now tell SnoopDos task to wake up
  3977.          */
  3978.         if (onlyfails) {
  3979.                 CheckForPause(NULL, 0);
  3980.         } else {
  3981.                 ev->result = "----";
  3982.                 ev->status = ES_UPDATING;
  3983.                 CheckForPause(ev, seqnum);
  3984.                 Signal(SnoopTask, NewEventMask);
  3985.                 result = origfunc(cmdline, tags, libbase);
  3986.         }
  3987.         if (AttemptSemaphoreHeavely(&BufSem)) {
  3988.                 if (seqnum >= RealFirstSeq) {
  3989.                         if (result != -1) {
  3990.                                 ev->result  = ev->options;
  3991.                                 ev->options = "";
  3992.                                 mysprintf(ev->result, "%ld", result);
  3993.                         } else {
  3994.                                 ev->result = MSG(MSG_RES_FAIL);
  3995.                         }
  3996.                         ev->status = ES_READY;
  3997.                         Signal(SnoopTask, NewEventMask);
  3998.                 }
  3999.                 ReleaseSemaphore(&BufSem);
  4000.         }
  4001.         return (result);
  4002. }
  4003.  
  4004. /*****************************************************************************
  4005.  *
  4006.  *        Now the Mother of all patches -- the PutMsg() packet monitor/Rexx patch
  4007.  *
  4008.  *        (There are quite a few sub-functions associated with this.)
  4009.  *
  4010.  *****************************************************************************/
  4011.  
  4012. /*
  4013.  *              New_AddDosEntry(dlist)
  4014.  *
  4015.  *              This is a very simple patch which is only enabled when we are
  4016.  *              monitoring DOS packets. It simply signals the main task to update
  4017.  *              the device list whenever a new device is added to the DOS device
  4018.  *              list.
  4019.  */
  4020. ULONG ASM New_AddDosEntry(reg_d1 struct DosList *dlist, reg_a6 void *libbase)
  4021. {
  4022.         FP_AddDosEntry origfunc = (FP_AddDosEntry)
  4023.                                                            PatchList[GID_ADDDOSENTRY].origfunc;
  4024.         ULONG result;
  4025.  
  4026.         /*
  4027.          *              Note that we better remember to actually add the new device
  4028.          *              before telling SnoopDos to update its list, otherwise it
  4029.          *              might miss it if it's too quick (e.g. priority > 0).
  4030.          *
  4031.          *              New: Even though we DO add it before signalling SnoopDos, the
  4032.          *              device itself won't be fully initialised for a little bit longer.
  4033.          *              Therefore, the main SnoopDos code
  4034.          */
  4035.         result = origfunc(dlist, libbase);
  4036.  
  4037.         if (dlist && dlist->dol_Type == DLT_DEVICE)
  4038.                 Signal(SnoopTask, ScanDosListMask);
  4039.  
  4040.         return (result);
  4041. }
  4042.  
  4043. /*
  4044.  *              AddWaitingPacket(ev, seqnum, failmsg, dp, port, pt)
  4045.  *
  4046.  *              Adds a new entry to the list of waiting packets containing enough
  4047.  *              information to allow us to identify the reply to the packet when
  4048.  *              it is processed later on (in the main PutMsg() patch).
  4049.  *
  4050.  *              If there isn't a spare waiting packet, we will steal one and mark
  4051.  *              the event it represented as "Miss" to indicate the return code
  4052.  *              was missed.
  4053.  */
  4054. void AddWaitingPacket(Event *ev, LONG seqnum, char *failmsg,
  4055.                                           struct DosPacket *dp, struct MsgPort *port,
  4056.                                           struct PacketRef *pt)
  4057. {
  4058.         WaitPacket *wp;
  4059.         Event *oldev;
  4060.         ULONG oldseq;
  4061.  
  4062.         /*
  4063.          *              Add details about this packet to our list of waiting
  4064.          *              packets, so that when we spot the packet being returned
  4065.          *              by PutMsg() later on, we can fill in the result code.
  4066.          *
  4067.          *              Note that we must not obtain both the buffer and packet
  4068.          *              semaphores simultaneously, or a deadlock could occur.
  4069.          */
  4070.         ObtainSemaphore(&PacketSem);
  4071.         if (IsListEmpty(&PacketFreeList)) {
  4072.                 /*
  4073.                  *              Removing an existing node which is already in use. We need
  4074.                  *              to signal our main task to tell it not to continue waiting
  4075.                  *              for this event to complete. We have to wait until we unlock
  4076.                  *              the packetsem so we just note the details for now.
  4077.                  */
  4078.                 wp     = (WaitPacket *)RemTail(&PacketWaitList);
  4079.                 oldseq = wp->eventnum;
  4080.                 oldev  = wp->event;
  4081.                 //      if (!wp)
  4082.                 //              KPrintF("Warning!! No packet available on WaitList!\n");
  4083.         } else {
  4084.                 wp     = (WaitPacket *)RemHead(&PacketFreeList);
  4085.                 oldseq = 0;
  4086.         }
  4087.         wp->dp           = dp;
  4088.         wp->sendtask = SysBase->ThisTask;
  4089.         wp->destport = port;
  4090.         wp->event    = ev;
  4091.         wp->eventnum = seqnum;
  4092.         wp->arg1         = dp->dp_Arg1;
  4093.         wp->arg2         = dp->dp_Arg2;
  4094.         wp->arg3         = dp->dp_Arg3;
  4095.         wp->resmsg       = failmsg;
  4096.         wp->flags    = pt->flags;
  4097.         AddHead(&PacketWaitList, (Node *)wp);
  4098.         ReleaseSemaphore(&PacketSem);
  4099.  
  4100.         /*
  4101.          *              Finally, check if we had to flush out an old packet from
  4102.          *              our list of waiting packets when we allocated the new
  4103.          *              packet. If so, mark the packet as missed (if it hasn't
  4104.          *              already scrolled off the top of the buffer)
  4105.          */
  4106.         if (oldseq) {
  4107.                 if (AttemptSemaphoreHeavely(&BufSem)) {
  4108.                         if (oldseq >= RealFirstSeq) {
  4109.                                 oldev->result = MSG(MSG_RES_MISSED);
  4110.                                 oldev->status = ES_READY;
  4111.                                 Signal(SnoopTask, NewEventMask);
  4112.                         }
  4113.                         ReleaseSemaphore(&BufSem);
  4114.                 }
  4115.         }
  4116. }
  4117.  
  4118. /*
  4119.  *              HandleSimplePacket(calladdr, packet, port, packetref)
  4120.  *
  4121.  *              Handles the given packet by creating an event that matches the
  4122.  *              packet type (if we support it) and creating a new entry on the
  4123.  *              waiting packet list so we can match it up later.
  4124.  *
  4125.  *              This function handles only simple packets (i.e. those with the
  4126.  *              PK_COMMON flag set in the packet table). If the corresponding
  4127.  *              AmigaDOS option (Open, Lock, MakeDir etc.) is not currently
  4128.  *              enabled, then no entry is made for this packet.
  4129.  */
  4130. void HandleSimplePacket(ULONG calladdr, struct DosPacket *dp,
  4131.                                         struct MsgPort *port, struct PacketRef *pt)
  4132. {
  4133.         /*
  4134.          *              Now create our new simple event to represent the packet.
  4135.          *              The contents of this will vary depending on the packet
  4136.          *              itself, but in general, is an exact match with the format
  4137.          *              of the AmigaDOS function associated with the packet.
  4138.          *
  4139.          *              (If that function is not being monitored, then we do nothing.)
  4140.          */
  4141.         Event *ev;
  4142.         LONG  seqnum;
  4143.         ULONG gadid;
  4144.         ULONG actid = 0;
  4145.         char  *volname = ((Task *)(port->mp_SigTask))->tc_Node.ln_Name;
  4146.         BPTR  lock = NULL;
  4147.         BSTR  name;
  4148.         char  *optstr;
  4149.         char  namebuf[MAX_STR_LEN+1];
  4150.         char  optbuf[20];
  4151.  
  4152.         namebuf[0] = '\0';
  4153.  
  4154.         /*
  4155.          *              First, determine the format to use, based on the packet type
  4156.          */
  4157.         switch (dp->dp_Type) {
  4158.                 case ACTION_FINDINPUT:
  4159.                         gadid   = GID_OPENFILE;
  4160.                         actid   = MSG_ACT_POPEN;
  4161.                         lock    = dp->dp_Arg2;
  4162.                         name    = dp->dp_Arg3;
  4163.                         optstr  = MSG(MSG_OPT_READ);
  4164.                         break;
  4165.  
  4166.                 case ACTION_FINDOUTPUT:
  4167.                         gadid   = GID_OPENFILE;
  4168.                         actid   = MSG_ACT_POPEN;
  4169.                         lock    = dp->dp_Arg2;
  4170.                         name    = dp->dp_Arg3;
  4171.                         optstr  = MSG(MSG_OPT_WRITE);
  4172.                         break;
  4173.  
  4174.                 case ACTION_FINDUPDATE:
  4175.                         gadid   = GID_OPENFILE;
  4176.                         actid   = MSG_ACT_POPEN;
  4177.                         lock    = dp->dp_Arg2;
  4178.                         name    = dp->dp_Arg3;
  4179.                         optstr  = MSG(MSG_OPT_MODIFY);
  4180.                         break;
  4181.  
  4182.                 case ACTION_DELETE_OBJECT:
  4183.                         gadid   = GID_DELETE;
  4184.                         actid   = MSG_ACT_PDELETE;
  4185.                         lock    = dp->dp_Arg1;
  4186.                         name    = dp->dp_Arg2;
  4187.                         optstr  = NULL;
  4188.                         break;
  4189.  
  4190.                 case ACTION_CREATE_DIR:
  4191.                         gadid   = GID_MAKEDIR;
  4192.                         actid   = MSG_ACT_PMAKEDIR;
  4193.                         lock    = dp->dp_Arg1;
  4194.                         name    = dp->dp_Arg2;
  4195.                         optstr  = NULL;
  4196.                         break;
  4197.  
  4198.                 case ACTION_LOCATE_OBJECT:
  4199.                         gadid   = GID_LOCKFILE;
  4200.                         actid   = MSG_ACT_PLOCK;
  4201.                         lock    = dp->dp_Arg1;
  4202.                         name    = dp->dp_Arg2;
  4203.                         switch (dp->dp_Arg3) {
  4204.                                 case ACCESS_READ:       optstr = MSG(MSG_OPT_READ);             break;
  4205.                                 case ACCESS_WRITE:      optstr = MSG(MSG_OPT_WRITE);    break;
  4206.                                 default:                        optstr = MSG(MSG_OPT_READBAD);  break;
  4207.                         }
  4208.                         break;
  4209.  
  4210.                 case ACTION_MAKE_LINK:
  4211.                 {
  4212.                         int len;
  4213.                         char *cname;
  4214.  
  4215.                         gadid   = GID_MAKELINK;
  4216.                         actid   = MSG_ACT_PMAKELINK;
  4217.                         lock    = dp->dp_Arg1;
  4218.                         cname   = BTOC(dp->dp_Arg2);
  4219.  
  4220.                         /*
  4221.                          *              Now build a string that looks like "name --> <dest>" to
  4222.                          *              display as our link. For soft links, we just concatenate
  4223.                          *              the two strings. For hard links, we have to generate a
  4224.                          *              filename from the lock also.
  4225.                          */
  4226.                         len = *cname;
  4227.                         if (len >= MAX_STR_LEN) {
  4228.                                 strncpy(namebuf, cname+1, MAX_STR_LEN);
  4229.                                 namebuf[MAX_STR_LEN] = 0;
  4230.                         } else {
  4231.                                 if (ShowPaths) {
  4232.                                         char *tempbuf = namebuf + MAX_STR_LEN-9 - len;
  4233.  
  4234.                                         memcpy(tempbuf, cname+1, len);
  4235.                                         tempbuf[len] = '\0';
  4236.                                         strcpy(namebuf, AsyncNameFromLock(volname, lock, tempbuf,
  4237.                                                                                                   namebuf, MAX_STR_LEN-8));
  4238.                                         len = strlen(namebuf);
  4239.                                 } else {
  4240.                                         memcpy(namebuf, cname+1, len);
  4241.                                         namebuf[len] = '\0';
  4242.                                 }
  4243.                                 strcat(namebuf, LinkPointerString);             /* Usually ' --> ' */
  4244.                                 len += strlen(LinkPointerString);
  4245.  
  4246.                                 if (dp->dp_Arg4 == LINK_HARD) {
  4247.                                         /*
  4248.                                          *              Hard link: interpret dp->dp_Arg3 as the lock
  4249.                                          *              being linked to
  4250.                                          */
  4251.                                         strcat(namebuf, AsyncNameFromLock(volname, dp->dp_Arg3,
  4252.                                                                                                           NULL, namebuf+len+1,
  4253.                                                                                                           MAX_STR_LEN-len-1));
  4254.                                         optstr = MSG(MSG_OPT_HARDLINK);
  4255.                                 } else {
  4256.                                         /*
  4257.                                          *              Soft link: interpret dp->dp_Arg3 as the name of
  4258.                                          *              the path to the link
  4259.                                          */
  4260.                                         strncat(namebuf, (char *)dp->dp_Arg3, MAX_STR_LEN-len-1);
  4261.                                         namebuf[MAX_STR_LEN] = 0;
  4262.                                         optstr = MSG(MSG_OPT_SOFTLINK);
  4263.                                 }
  4264.                         }
  4265.                         volname = (char *)NO_EXPAND; /* Don't try and expand filename */
  4266.                         name    = NULL;
  4267.                         break;
  4268.                 }
  4269.  
  4270.                 case ACTION_RENAME_OBJECT:
  4271.                         lock    = dp->dp_Arg1;
  4272.                         name    = dp->dp_Arg2;
  4273.                         optstr  = NULL;
  4274.  
  4275.                         /*
  4276.                          *              This is a bit cheeky. The Rename action comes in
  4277.                          *              two parts, the first line with the original name and
  4278.                          *              the second part with the new name. We create the
  4279.                          *              first part here, and then fall through to let the
  4280.                          *              rest of the code handle the second part.
  4281.                          */
  4282.                         if (CurSettings.Func.Opts[GID_RENAME]) {
  4283.                                 char *cname = BTOC(name);
  4284.  
  4285.                                 lock            = dp->dp_Arg3;
  4286.                                 name            = dp->dp_Arg4;
  4287.                                 if (*cname) {
  4288.                                         memcpy(namebuf, cname+1, *cname);
  4289.                                         namebuf[*cname] = '\0';
  4290.                                 } else {
  4291.                                         /*
  4292.                                          *              If we have an empty string, we replace it with ""
  4293.                                          *              since we may be renaming the current directory (?)
  4294.                                          */
  4295.                                         strcpy(namebuf, "\"\"");
  4296.                                 }
  4297.                                 ev = CreateEvent(calladdr, &seqnum, MSG_ACT_PRENAME,
  4298.                                                                  namebuf, NULL, (int)volname, lock);
  4299.                                 if (!ev)
  4300.                                         return;
  4301.  
  4302.                                 ev->status      = ES_READY;
  4303.                                 gadid           = GID_RENAME;
  4304.                                 actid           = MSG_ACT_PRENAME2;
  4305.                         }
  4306.                         break;
  4307.         }
  4308.  
  4309.         /*
  4310.          *              Now, if we recognised the packet type, create a new event
  4311.          *              with the info stored accordingly. We ignore any packets
  4312.          *              for which monitoring is disabled.
  4313.          */
  4314.         if (actid && CurSettings.Func.Opts[gadid]) {
  4315.                 /*
  4316.                  *              We reserve 8 bytes at the start of the options string to
  4317.                  *              hold the result message (Ok or Fail) that is filled in
  4318.                  *              by the PutMsg() code when the packet is returned.
  4319.                  */
  4320. #define RES_LEN         8
  4321.  
  4322.                 strcpy(optbuf, "........");
  4323.                 if (optstr)
  4324.                         strcat(optbuf, optstr);
  4325.  
  4326.                 if (name) {
  4327.                         char *cname = BTOC(name);
  4328.  
  4329.                         namebuf[0] = '\0';
  4330.                         if (*cname) {
  4331.                                 memcpy(namebuf, cname+1, *cname);
  4332.                                 namebuf[*cname] = '\0';
  4333.                         } else {
  4334.                                 /*
  4335.                                  *              If we have an empty string, we replace it with ""
  4336.                                  *              since it will typically be a Lock("").
  4337.                                  */
  4338.                                 strcpy(namebuf, "\"\"");
  4339.                         }
  4340.                 }
  4341.                 ev = CreateEvent(calladdr, &seqnum, actid, namebuf, optbuf,
  4342.                                                  (int)volname, lock);
  4343.                 if (!ev)
  4344.                         return;
  4345.  
  4346.                 ev->result    = ev->options;
  4347.                 ev->options  += RES_LEN;
  4348.                 *ev->result   = '\0';
  4349.                 ev->status    = ES_UPDATING;
  4350.                 /*
  4351.                  *              We add the event to the waiting list BEFORE checking for Pause
  4352.                  *              so that if while paused, the user decides to disable packet
  4353.                  *              monitoring, the packet will be in the wait queue already and
  4354.                  *              thus will be safely flushed; otherwise, it would hang around
  4355.                  *              for ever (not doing any damage but wasting resources).
  4356.                  */
  4357.                 AddWaitingPacket(ev, seqnum, "%s", dp, port, pt);
  4358.                 CheckForPause(ev, seqnum);
  4359.                 Signal(SnoopTask, NewEventMask);
  4360.         }
  4361. #undef RES_LEN
  4362. }
  4363.  
  4364. /*
  4365.  *              HandleRawPacket(calladdr, packet, port, packetref)
  4366.  *
  4367.  *              Handles the given packet by creating an event that matches the
  4368.  *              packet type (if we support it) and creating a new entry on the
  4369.  *              waiting packet list so we can match it up later.
  4370.  *
  4371.  *              This function handles all packets and produces a raw hex dump
  4372.  *              (with the name of the packet) rather than the more english-like
  4373.  *              "Open", "Lock", etc.
  4374.  */
  4375. void HandleRawPacket(ULONG calladdr, struct DosPacket *dp,
  4376.                                      struct MsgPort *port, struct PacketRef *pt)
  4377. {
  4378.         /*
  4379.          *              Building this event is a little tricky, since the result
  4380.          *              string will not be a static string but will contain the
  4381.          *              actual return value. Thus, we allocate enough room in the
  4382.          *              filename portion to hold the result string as well, and
  4383.          *              adjust our variables accordingly after the event has
  4384.          *              been created.
  4385.          *
  4386.          *              The same is true for raw packet types (i.e. those that we
  4387.          *              don't recognise at all).
  4388.          */
  4389. #define RAW_LEN         20              /* Length of possible raw packet type   */
  4390. #define RES_LEN         26              /* Length of longest result code                */
  4391. #define ARG_LEN         50              /* Length of longest argument list              */
  4392.  
  4393.         static char *fmt[] = {
  4394.                 "(None)", "%8lx", "%8lx, %8lx", "%8lx, %8lx, %8lx",
  4395.                 "%8lx, %8lx, %8lx, %8lx", "%8lx, %8lx, %8lx, %8lx, %8lx"
  4396.         };
  4397.         static char *failmsg[] = {
  4398.                 "%s", "%-4s %8lx", "%-4s %8lx", "%-4s %8lx, %8lx"
  4399.         };
  4400.         char args[RAW_LEN+RES_LEN+ARG_LEN];
  4401.         char *tname = args;
  4402.         Event *ev;
  4403.         LONG  seqnum;
  4404.  
  4405.         if (pt->flags & PK_RAW)
  4406.                 tname += RAW_LEN;
  4407.  
  4408.         tname += RES_LEN;
  4409.         memset(args, ' ', tname - args);
  4410.         mysprintf(tname, fmt[pt->numparams], dp->dp_Arg1, dp->dp_Arg2,
  4411.                                                         dp->dp_Arg3, dp->dp_Arg4, dp->dp_Arg5);
  4412.  
  4413.         ev = CreateEvent(calladdr, &seqnum, pt->msgid, args,
  4414.                                          ((Task *)(port->mp_SigTask))->tc_Node.ln_Name,
  4415.                                          NO_EXPAND);
  4416.         if (!ev)
  4417.                 return;
  4418.  
  4419.         if (pt->flags & PK_RAW) {
  4420.                 /*
  4421.                  *              Now fix up action name and target name
  4422.                  */
  4423.                 ev->action    = ev->filename;
  4424.                 ev->filename += RAW_LEN;
  4425.                 mysprintf(ev->action, MSG(MSG_ACT_RAWPACKET), dp->dp_Type);
  4426.         }
  4427.         ev->result    = ev->filename;   /* Point to storage for later result */
  4428.         ev->filename += RES_LEN;
  4429.         *ev->result   = 0;                              /* Make result field empty initially */
  4430.         ev->status        = ES_UPDATING;
  4431.         /*
  4432.          *              We add the event to the waiting list BEFORE checking for Pause
  4433.          *              so that if while paused, the user decides to disable packet
  4434.          *              monitoring, the packet will be in the wait queue already and
  4435.          *              thus will be safely flushed; otherwise, it would hang around
  4436.          *              for ever (not doing any damage but wasting resources).
  4437.          */
  4438.         AddWaitingPacket(ev, seqnum, failmsg[pt->flags & PK_MASK], dp, port, pt);
  4439.         CheckForPause(ev, seqnum);
  4440.         Signal(SnoopTask, NewEventMask);
  4441. }
  4442.  
  4443. /*
  4444.  *              New_PutMsg()
  4445.  *
  4446.  *              This function is used frequently by the system to send a message
  4447.  *              from one task to another. It is also used by applications wishing
  4448.  *              to send ARexx messages, which is what we want to monitor.
  4449.  *
  4450.  *              The problem is: how do we distinguish system messages (of which
  4451.  *              there are lots!) from ARexx messages (which are relatively
  4452.  *              infrequent).
  4453.  *
  4454.  *              It's almost impossible to get a perfect solution to this, but we
  4455.  *              can get fairly close by checking the following:
  4456.  *
  4457.  *                - The destination port must have a name
  4458.  *                - The host name associated with the supposed Rexx message must
  4459.  *                      point to valid memory
  4460.  *        - The action type for the Rexx message is RXCOMM
  4461.  *        - The Rexx system library must be up and running
  4462.  *        - The library base must be word aligned (else we fault on a 68000)
  4463.  *        - The Close() vector in the Rexx private system library must
  4464.  *                      match the Close() vector in the Rexx library base that we
  4465.  *                      opened ourselves (the library bases themselves can be different).
  4466.  *
  4467.  *              If all these hold true, then we can assume it is a valid ARexx
  4468.  *              message and display it accordingly.
  4469.  *
  4470.  *              For DOS packets, things are a little simpler since DOS packets contain
  4471.  *              cross-links that can be easily checked for validity. To keep things
  4472.  *              moving at a reasonable speed, we only consider StandardPackets, where
  4473.  *              the DosPacket structure immediately follows the exec message structure.
  4474.  *              This is not universally true, but it covers all the cases we want to
  4475.  *              monitor.
  4476.  *
  4477.  *              We need to intercept DOS packets twice -- once on the initial PutMsg
  4478.  *              to the target device, and once when the target device PutMsg's the
  4479.  *              reply. Thus, we maintain a list of outstanding packets so we can
  4480.  *              detect which is which.
  4481.  *
  4482.  *              To identify DOS packets, we use the following criterion:
  4483.  *
  4484.  *                      - Task is a process
  4485.  *                      - Message node's name points to valid longword-aligned memory
  4486.  *                      - DOS packet (from name ptr) points back to message header
  4487.  *                      - Either current task is on the list of devices we're monitoring
  4488.  *                        or the destination message port's owner is on the list of
  4489.  *                        devices we're monitoring.
  4490.  *
  4491.  *              If any of these conditions fail, we ignore the message.
  4492.  *
  4493.  */
  4494. ULONG ASM New_PutMsg(reg_a0 struct MsgPort *port, reg_a1 struct Message *msg,
  4495.                                          reg_a6 void *libbase)
  4496. {
  4497.         MarkCallAddr;
  4498.  
  4499.         FP_PutMsg origfunc   = (FP_PutMsg)PatchList[GID_SENDREXX].origfunc;
  4500.         Task *thistask           = SysBase->ThisTask;
  4501.  
  4502. /*
  4503.  *              Save a little stack space and time by making these non-local
  4504.  */
  4505. #define rmsg                    ((struct RexxMsg *)msg)
  4506. #define rexxclosevect   (ULONG *)(((ULONG)RexxSysBase) - 10)
  4507. #define thisclosevect   (ULONG *)(((ULONG)rmsg->rm_LibBase) - 10)
  4508.  
  4509.         struct DosPacket *dp;
  4510.         Task  *desttask;
  4511.         Event *ev;
  4512.         LONG  seqnum;
  4513.         ULONG taskhandle;
  4514.  
  4515.         /*
  4516.          *              Before doing anything else, check if we're being called from
  4517.          *              within an interrupt. If so, get the heck out of here since
  4518.          *              trying to obtain a semaphore from within an interrupt is
  4519.          *              definitely a bad idea!
  4520.          *
  4521.          *              To quickly check if we're within an interrupt, we simply see
  4522.          *              if our stack pointer is within the range of the supervisor stack.
  4523.          *              If it is, then we're probably in an interrupt, or at least in
  4524.          *              Supervisor mode, and either way we don't want to continue.
  4525.          *
  4526.          *              We also ignore ramlib, for the usual reasons, and our own
  4527.          *              background task (since it is used to expand locks from within
  4528.          *              of this patch and an infinite loop would be easy!)
  4529.          */
  4530.         if (thistask == RamLibTask || thistask == (Task *)BackgroundProc ||
  4531.                 (getreg(REG_A7) >= (ULONG)SysBase->SysStkLower &&
  4532.                  getreg(REG_A7) <= (ULONG)SysBase->SysStkUpper))
  4533.         {
  4534.                 JumpOrigFunc(0);
  4535.         }
  4536.  
  4537.         /*
  4538.          *              See if we have a valid ARexx message. See the function
  4539.          *              header for an explanation of all the checks
  4540.          */
  4541.         if (CurSettings.Func.Opts[GID_SENDREXX]                 &&
  4542.                 port->mp_Node.ln_Name                                           &&
  4543.                 (!TypeOfMem(port->mp_Node.ln_Name) || (*port->mp_Node.ln_Name)) &&
  4544.                 rmsg->rm_CommAddr                                                       &&
  4545.                 TypeOfMem(rmsg->rm_CommAddr)                            &&
  4546.                 (rmsg->rm_Action & RXCODEMASK) == RXCOMM        &&
  4547.                 RexxSysBase                                                                     &&
  4548.                 TypeOfMem(thisclosevect)                                        &&
  4549.                 ((ULONG)thisclosevect & 1) == 0             &&
  4550.                 *thisclosevect == *rexxclosevect)
  4551.         {
  4552.                 /*
  4553.                  *              Okay, we know we've got a valid Rexx message so now enter
  4554.                  *              it into the event buffer. First, however, check that we
  4555.                  *              are within our stack bounds (since the normal check done
  4556.                  *              in the assembly patch code is bypassed for this function
  4557.                  *              to accomodate RAM returning DOS packets).
  4558.                  */
  4559.                 if (getreg(REG_A7) >= (ULONG)thistask->tc_SPLower &&
  4560.                         getreg(REG_A7) <= (ULONG)thistask->tc_SPUpper &&
  4561.                         getreg(REG_A7) <=
  4562.                                                 ((ULONG)thistask->tc_SPLower+CurSettings.StackLimit))
  4563.                 {
  4564.                         JumpOrigFunc(0);
  4565.                 }
  4566.                 ev = CreateEvent(CallAddr, &seqnum, MSG_ACT_SENDREXX, rmsg->rm_Args[0],
  4567.                                                  port->mp_Node.ln_Name, NO_EXPAND);
  4568.                 if (!ev)
  4569.                         return origfunc(port, msg, libbase);
  4570.  
  4571.                 ev->status = ES_UPDATING;
  4572.                 CheckForPause(ev, seqnum);
  4573.                 if (AttemptSemaphoreHeavely(&BufSem)) {
  4574.                         if (seqnum >= RealFirstSeq) {
  4575.                                 ev->status = ES_READY;
  4576.                                 Signal(SnoopTask, NewEventMask);
  4577.                         }
  4578.                         ReleaseSemaphore(&BufSem);
  4579.                 }
  4580.                 return origfunc(port, msg, libbase);
  4581.         }
  4582.  
  4583.         /*
  4584.          *              Not an ARexx message, now check if it's a DOS packet.
  4585.          *              First though, we must check to see if we're already in
  4586.          *              the middle of a SnoopDos patch -- if so, we could end up
  4587.          *              recursing forever unless we don't try and monitor this one.
  4588.          *
  4589.          *              See above for the criteria we use to spot packet messages.
  4590.          */
  4591.         taskhandle = CheckTaskRecursion();
  4592.         if (!taskhandle)
  4593.                 return origfunc(port, msg, libbase);
  4594.  
  4595.         dp               = (struct DosPacket *)(msg->mn_Node.ln_Name);
  4596.         desttask = port->mp_SigTask;
  4597.  
  4598.         if ((ShowAllPackets | MonPackets)                                                       &&
  4599.                 thistask->tc_Node.ln_Type == NT_PROCESS                                 &&
  4600.                 ((ULONG)dp & 1) == 0                                                                    &&
  4601.                 TypeOfMem(dp)                                                                                   &&
  4602.                 dp->dp_Link == msg                                                                              &&
  4603.                 ((ULONG)(dp->dp_Port) & 3) == 0                                                 &&
  4604.                 TypeOfMem(dp->dp_Port))
  4605.         {
  4606.                 /*
  4607.                  *              Looks like we're going to monitor the packet.
  4608.                  *
  4609.                  *              First, check if the packet is already on our list of
  4610.                  *              outstanding packets. If so, we can handle it immediately.
  4611.                  */
  4612.                 struct PacketRef *pt;
  4613.                 WaitPacket *wp;
  4614.                 Task **ptask;
  4615.                 char *p = NULL;
  4616.  
  4617.                 /*
  4618.                  *              Now some slightly tricky stuff. We can have up to TWO
  4619.                  *              entries on the waiting packet list which match the current
  4620.                  *              packet (one for the Packet Debugger and one for the
  4621.                  *              Monitor Packets option) and we need to acknowledge them
  4622.                  *              both. However, we also need to ensure we never try and
  4623.                  *              lock both the PacketSem and BufferSem at the same time
  4624.                  *              (since otherwise we could deadlock).
  4625.                  *
  4626.                  *              This effectively means we have to restart our list scan
  4627.                  *              after each packet has been acknowledged, until we have
  4628.                  *              no more left -- a small speed hit, but actually not too
  4629.                  *              bad since most times, we will be the only packet on the
  4630.                  *              wait list anyway. (We use 'p' as a flag to indicate
  4631.                  *              whether or not we found a packet, so we know to return
  4632.                  *              at the end of it all.)
  4633.                  */
  4634.                 ObtainSemaphore(&PacketSem);
  4635.                 wp = HeadNode(&PacketWaitList);
  4636.                 while (NextNode(wp)) {
  4637.                         if (wp->dp               == dp                          &&
  4638.                                 wp->sendtask     != thistask                    &&
  4639.                                 wp->destport     != port                        &&
  4640.                                 wp->arg1         == dp->dp_Arg1                 &&
  4641.                                 wp->arg2         == dp->dp_Arg2                 &&
  4642.                                 wp->arg3         == dp->dp_Arg3)
  4643.                         {
  4644.                                 /*
  4645.                                  *              Found the packet on our list, so go ahead and fill in
  4646.                                  *              the result code for the associated event (assuming it
  4647.                                  *              hasn't scrolled off the buffer, of course!)
  4648.                                  */
  4649.                                 Event *ev         = wp->event;
  4650.                                 LONG   seqnum = wp->eventnum;
  4651.                                 char  *fmsg   = wp->resmsg;
  4652.                                 char   flags  = wp->flags;
  4653.  
  4654.                                 Remove((Node *)wp);
  4655.                                 AddHead(&PacketFreeList, (Node *)wp);
  4656.                                 ReleaseSemaphore(&PacketSem);
  4657.                                 ObtainSemaphore(&BufSem);
  4658.                                 if (seqnum >= RealFirstSeq) {
  4659.                                         /*
  4660.                                          *              Okay, now fill in the result string. The space for
  4661.                                          *              this was allocated when the event was defined.
  4662.                                          *
  4663.                                          *              For events that succeed, we can print "Okay",
  4664.                                          *              "Okay <result>", and "Okay <result1> <result2>".
  4665.                                          *
  4666.                                          *              For events which fail, we can print
  4667.                                          *              "Fail <result2>" or "Fail <result1> <result2>"
  4668.                                          */
  4669.                                         UWORD fail;
  4670.                                         ULONG param;
  4671.                                         char  *q, *r;
  4672.  
  4673. #define                                   evresmsg      MSG(fail ? MSG_RES_FAIL : MSG_RES_OKAY)
  4674.  
  4675.                                         fail = ((flags & PKF_BOOL) && dp->dp_Res1 == 0)  ||
  4676.                                                    ((flags & PKF_NEG)  && dp->dp_Res1 == (ULONG)-1);
  4677.  
  4678. #if NOT_WORRIED_ABOUT_STACK_SIZE
  4679.                                         /*
  4680.                                          *              Unfortunately, we can't use this nice simple
  4681.                                          *              code because calling mysprintf() uses too much
  4682.                                          *              stack space if we're being called from certain
  4683.                                          *              handlers with minimal stack space (e.g. RAM).
  4684.                                          *              Instead, we must do the same effect ourselves.
  4685.                                          *              This code is left here so you can see what the
  4686.                                          *              original intention was.
  4687.                                          */
  4688.                                         if ((flags & PK_MASK) == PK_2OK) {
  4689.                                                 mysprintf(ev->result, fmsg, evresmsg,
  4690.                                                                   dp->dp_Res1, dp->dp_Res2);
  4691.                                         } else {
  4692.                                                 mysprintf(ev->result, fmsg, evresmsg,
  4693.                                                                   (fail ? dp->dp_Res2 : dp->dp_Res1));
  4694.                                         }
  4695.                                         p = (char *)-1; /* Non-zero means we did something */
  4696.  
  4697. #else /* Extremely worried about stack size */
  4698.  
  4699.                                         /*
  4700.                                          *              Here we roll our own sprintf() (inline!) to keep
  4701.                                          *              stack usage to an absolute minimum. It's a rather
  4702.                                          *              small subset and somewhat hacked, you'll notice.
  4703.                                          *
  4704.                                          *              We make P non-null to indicate we did some work
  4705.                                          */
  4706.                                         p = fmsg;
  4707.                                         q = ev->result;
  4708.  
  4709.                                         /*
  4710.                                          *              First, skip over string formatter at start which
  4711.                                          *              always holds either 'Ok' or 'Fail'
  4712.                                          */
  4713.                                         strcpy(q, evresmsg);
  4714.                                         q += strlen(q);
  4715.                                         while (q < (ev->result + 4))
  4716.                                                 *q++ = ' ';
  4717.                                         while (*p && *p != 's')
  4718.                                                 p++;
  4719.                                         if (*p)
  4720.                                                 p++;
  4721.  
  4722.                                         /*
  4723.                                          *              Now parse remainder of string. The first parameter
  4724.                                          *              encountered gets replaced with either dp_Res1 or
  4725.                                          *              dp_Res2, depending on circumstances. The second
  4726.                                          *              parameter always gets replaced with dp_Res2.
  4727.                                          */
  4728.                                         if ((flags & PK_MASK) == PK_2OK || !fail)
  4729.                                                 param = dp->dp_Res1;
  4730.                                         else
  4731.                                                 param = dp->dp_Res2;
  4732.  
  4733.                                         while (*p) {
  4734.                                                 if (*p != '%') {
  4735.                                                         *q++ = *p++;
  4736.                                                         continue;
  4737.                                                 }
  4738.                                                 while (*p && *p != 'x' && *p != 'X')
  4739.                                                         p++;
  4740.                                                 p++;
  4741.                                                 if (param == 0) {
  4742.                                                         strcpy(q, "       0");
  4743.                                                 } else if (param == (ULONG)-1) {
  4744.                                                         strcpy(q, "      -1");
  4745.                                                 } else {
  4746.                                                         /*
  4747.                                                          *              Expand param to 8 hex digits, right-aligned
  4748.                                                          */
  4749.                                                         r = q + 7;
  4750.                                                         while (param > 0) {
  4751.                                                                 *r-- = "0123456789ABCDEF"[param & 15];
  4752.                                                                 param >>= 4;
  4753.                                                         }
  4754.                                                         while (r >= q)
  4755.                                                                 *r-- = ' ';
  4756.                                                 }
  4757.                                                 q += 8;
  4758.                                                 param = dp->dp_Res2; /* Second parm always dp_Res2 */
  4759.                                         }
  4760.                                         *q = '\0';
  4761. #endif
  4762.                                         /*
  4763.                                          *              Unlike most times, we don't signal SnoopDos that
  4764.                                          *              an event has been updated (yet) since there may
  4765.                                          *              be another event to update too, and it's best
  4766.                                          *              to do a single signal at the end (fewer context
  4767.                                          *              switches are required.) So, we just mark the
  4768.                                          *              event as ready.
  4769.                                          */
  4770.                                         ev->status = ES_READY;
  4771.                                 }
  4772.                                 ReleaseSemaphore(&BufSem);
  4773.                                 ObtainSemaphore(&PacketSem);
  4774.                                 /*
  4775.                                  *              Now restart the search from the beginning of the
  4776.                                  *              list (since wp is no longer valid)
  4777.                                  */
  4778.                                 wp = HeadNode(&PacketWaitList);
  4779.                         } else {
  4780.                                 /*
  4781.                                  *              Just advance to next element on list
  4782.                                  */
  4783.                                 wp = NextNode(wp);
  4784.                         }
  4785.                 }
  4786.                 ReleaseSemaphore(&PacketSem);
  4787.                 if (p) {
  4788.                         /*
  4789.                          *              Found a matching packet, so wake up the main task
  4790.                          *              and finish up. (We only signal the main snoop task
  4791.                          *              now, so that both events get printed simultaneously,
  4792.                          *              rather than one after another, which would be a little
  4793.                          *              messy). This also avoids us getting pre-empted inside
  4794.                          *              our loop above if SnoopDos is running at a higher priority
  4795.                          *              than this task, which is convenient (though not essential).
  4796.                          */
  4797.                         Signal(SnoopTask, NewEventMask);
  4798.                         goto done_putmsg;
  4799.                 }
  4800.  
  4801.                 /*
  4802.                  *              If we didn't find a match on our list of waiting packets,
  4803.                  *              then check to see if we're ignoring ROM calls. If so,
  4804.                  *              and if we were called from ROM, then immediately abort
  4805.                  *              (this would be done later anyway, but by checking now,
  4806.                  *              we save quite a bit of time.)
  4807.                  *
  4808.                  *              (We can't do this checking any earlier, or we'd miss
  4809.                  *              returned packets from ROM filesystems like RAM: and FFS).
  4810.                  *
  4811.                  *              We also exit if we're under the stack limit. (We can't
  4812.                  *              check this earlier because otherwise we'd miss the
  4813.                  *              return packet from RAM which only has a tiny stack.)
  4814.                  */
  4815.                 if (((!MonROMCalls && CallAddr >= RomStart && CallAddr <= RomEnd)) ||
  4816.                         (getreg(REG_A7) >= (ULONG)thistask->tc_SPLower &&
  4817.                          getreg(REG_A7) <= (ULONG)thistask->tc_SPUpper &&
  4818.                          getreg(REG_A7) <=
  4819.                                                 ((ULONG)thistask->tc_SPLower+CurSettings.StackLimit)))
  4820.                 {
  4821.                         goto done_putmsg;
  4822.                 }
  4823.  
  4824.                 /*
  4825.                  *              Okay, didn't match the packet with a previous outgoing one.
  4826.                  *              Now search the device list to see if we can match either
  4827.                  *              the owner of the port (a new outgoing packet) or the task ID
  4828.                  *              of the sender (a returning packet).
  4829.                  *
  4830.                  *              In the case of a returning packet, we just ignore it since
  4831.                  *              we missed it on the way out.
  4832.                  */
  4833.                 for (ptask = DeviceTaskList; *ptask && *ptask != desttask; ptask++) {
  4834.                         if (*ptask == thistask)
  4835.                                 goto done_putmsg;       /* Sender was a DOS device so ignore */
  4836.                 }
  4837.                 if (!*ptask) {
  4838.                         /*
  4839.                          *              Couldn't find dest task on device list so it must
  4840.                          *              be a message to somewhere else -- hence, ignore it.
  4841.                          */
  4842.                         goto done_putmsg;
  4843.                 }
  4844.  
  4845.                 /*
  4846.                  *              Okay, got ourselves a bona fida packet. Next, look it up
  4847.                  *              in our packet table to decide what to do with it.
  4848.                  *              Unrecognised packets come out as LAST_PACK_MSG which is
  4849.                  *              specifically initialised to handle them properly.
  4850.                  */
  4851.                 for (pt = &PacketTable[0]; pt->msgid != LAST_PACK_MSG; pt++)
  4852.                         if (pt->packetid == dp->dp_Type)
  4853.                                 break;
  4854.  
  4855.                 if (pt->flags & PK_IGNORE)      /* Certain packet types are ignored */
  4856.                         goto done_putmsg;
  4857.  
  4858.                 /*
  4859.                  *              Okay, we finally (finally!) get to create a new entry
  4860.                  *              in our event buffer. Actually, we get to create two
  4861.                  *              entries, since if we have both the Packet Debugger
  4862.                  *              AND the Monitor Packets option turned on, we want to
  4863.                  *              see the output from both of them (even if they're both
  4864.                  *              the same event!).
  4865.                  *
  4866.                  *              Why? Well, if you're debugging a device driver and you
  4867.                  *              have Open packets etc. coming back and forth, then
  4868.                  *              as well as the raw packet data, it's also kind of nice
  4869.                  *              to see actual filenames etc. in english instead of hex.
  4870.                  */
  4871.                 if (MonPackets && (pt->flags & PK_COMMON))
  4872.                         HandleSimplePacket(CallAddr, dp, port, pt);
  4873.  
  4874.                 if (ShowAllPackets)
  4875.                         HandleRawPacket(CallAddr, dp, port, pt);
  4876.         }
  4877.  
  4878. done_putmsg:
  4879.         EndTaskRecursion(taskhandle);
  4880.         return origfunc(port, msg, libbase);
  4881. }
  4882.  
  4883. /*
  4884.  * AttemptSemaphoreHeavely
  4885.  *
  4886.  * Try to get a semaphore, try by waiting a certain amount of time,
  4887.  * but give up if the semaphore is really not free.
  4888.  */
  4889. LONG AttemptSemaphoreHeavely(struct SignalSemaphore *ss)
  4890. {
  4891. LONG rnd;
  4892. struct MsgPort          myport;
  4893. struct timerequest      treq;
  4894.  
  4895.         if (AttemptSemaphore(ss))
  4896.                 return TRUE;
  4897.  
  4898.         /*
  4899.          * rand is not multi-threadable....
  4900.          */
  4901.         Forbid();
  4902.         rnd = rand();
  4903.         Permit();
  4904.  
  4905.         /*
  4906.          * Now initialize the port and the timer for waiting...
  4907.          */
  4908.  
  4909.         myport.mp_Node.ln_Type  = NT_MSGPORT;
  4910.         myport.mp_Node.ln_Pri   = 0;
  4911.         myport.mp_Flags         = PA_SIGNAL;
  4912.         myport.mp_SigBit        = SIGB_SINGLE;
  4913.         myport.mp_SigTask       = SysBase->ThisTask;
  4914.         NewList(&myport.mp_MsgList);
  4915.         treq                    = *TimerRequest;
  4916.         treq.tr_node.io_Message.mn_ReplyPort    =       &myport;
  4917.  
  4918.  
  4919.         rnd >>= 27;             /* at most about two seconds... */
  4920.         rnd++;
  4921.         do {
  4922.                 treq.tr_node.io_Command = TR_ADDREQUEST;
  4923.                 treq.tr_time.tv_secs    = 0;
  4924.                 treq.tr_time.tv_micro   = 100000;       /* one tenth of a second */
  4925.                 DoIO(&treq);
  4926.  
  4927.                 if (AttemptSemaphore(ss))
  4928.                         return TRUE;
  4929.  
  4930.                 rnd--;
  4931.         } while(rnd);
  4932.  
  4933.         return FALSE;
  4934. }
  4935.  
  4936.