home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d7xx / d725 / snoopdos.lha / SnoopDos / src / snoopdos.c < prev    next >
C/C++ Source or Header  |  1992-09-05  |  36KB  |  1,246 lines

  1. /*
  2.  *        SNOOPDOS.C                                    vi:ts=4
  3.  *
  4.  *        (C) Copyright Eddy Carroll, June 1992. Freely distributable.
  5.  *
  6.  *        Snoopdos patches into dos.library and outputs a message to a
  7.  *        debugging window or file whenever a process calls certain DOS
  8.  *        functions.
  9.  *
  10.  *        Type snoopdos -h for a list of available options. See the
  11.  *        documentation for further details.
  12.  *
  13.  *        Compiles under Lattice C V5.10. I use flags: -cusq -j88i -ms -v
  14.  *        Note: Source assumes tabs set every 4 columns.
  15.  *
  16.  *        Revisions
  17.  *        ---------
  18.  *        30 Oct 90:  Fixed potential deadlock problem in termination code
  19.  *                    Improved handling of NULL lock (i.e. boot device)
  20.  *
  21.  *        27 Jan 91:    Really fixed deadlock problem in termination code!
  22.  *
  23.  *       8 Feb 91:  Fixed small bug in tiny.a. Saved 2K by replacing
  24.  *                  sprintf in lc.lib with a version that uses RawDoFmt.
  25.  *
  26.  *        21 Oct 91:    Fixed silly bug with -z option whereby if a space was
  27.  *                    left between the z and the filename, SnoopDos would
  28.  *                    crash the system. I had mistyped extfilename as extfile.
  29.  *                    Silly silly silly!
  30.  *
  31.  *         7 Jul 92:    Fixed bug reported by Matthias Scheler, whereby
  32.  *                    DeleteFile() sometimes trashed the return value.
  33.  *                    This was a simple goof-up on my part (I forgot to
  34.  *                    return the result from the function!) Also made exit
  35.  *                    handling more robust to avoid lockups on exit, and
  36.  *                    added -i option to ignore Shell Lock() commands and
  37.  *                    Shell & Workbench CurrentDir() commands. 
  38.  */
  39.  
  40. #ifndef LATTICE_50
  41. #include "system.h"
  42. #endif
  43.  
  44. #define tolower(ch)    (((ch) >= 'A' && (ch) <= 'Z') ? (ch) + 0x20 : (ch))
  45.  
  46. /*
  47.  *        Assorted strings
  48.  */
  49.  
  50. #define NAME    "SnoopDos V1.5"
  51.  
  52. char *Version = "$VER: SnoopDos V1.5 (7 July 1992)";
  53.  
  54. #define TITLE \
  55. NAME ".  Copyright \251 Eddy Carroll, July 1992. Freely distributable."
  56.  
  57. char *HEADER =
  58. "Process name          Func  Filename                                Mode Res."
  59. "\r\n"
  60. "------------          ----  --------                                ---- ----"
  61. "\r\n";
  62.  
  63. #define PORTNAME    NAME
  64.  
  65. #define DEFWINDOW    "CON:0/0/640/120/"
  66.  
  67. /*
  68.  *        These defines are for use with the -i1 option; when enabled,
  69.  *        Lock() calls by the tasks called IGNORE_CLI and IGNORE_BG will
  70.  *        be ignored and CurrentDir() calls by all three tasks will also
  71.  *        be ignored. Basically, this avoids the frenzy of activity whenever
  72.  *        the Shell searches for an executable or Workbench does its once a
  73.  *        second scan of the mounted volumes.
  74.  */
  75. #define IGNORE_CLI    "Shell Process"
  76. #define IGNORE_BG    "Background CLI"
  77. #define IGNORE_WB    "Workbench"
  78.  
  79. /*
  80.  *        The following message array contains both colour and non-colour
  81.  *        versions of the various short message strings displayed.
  82.  */
  83. char *msgs[][2] = {
  84. /* Monochrome           Colour   */
  85. /* ----------           ------   */
  86.     "OLD ",                "OLD ",
  87.     "NEW ",                "\033[33mNEW\033[0m ",
  88.     "R/W ",                "\033[32mR/W\033[0m ",
  89.     "??? ",                "??? ",
  90.     "SHAR",                "SHAR",
  91.     "EXCL",                "\033[33mEXCL\033[0m",
  92.     "????",                "????",
  93.     "Okay\r\n",            "Okay\r\n",
  94.     "Fail\r\n",            "\033[33mFail\033[0m\r\n",
  95.     ">",                "\033[33m>\033[0m",
  96.     "> (Done)",            "> (Done)",
  97.     "Warning: Missed",    "\033[33mWarning:\033[0m Missed",
  98.     ">>>>\r\n",            ">>>>\r\n",
  99.     "Open",                "Open",
  100.     "Lock",                "\033[33mLock\033[0m",
  101.     "Load",                "\033[32mLoad\033[0m",
  102.     "Exec",                "\033[32mExec\033[0m",
  103.     "CD  ",                "CD  ",
  104.     "Del ",                "\033[33mDel\033[0m "
  105. };
  106.  
  107. #define TXT_OLD        msgs[ 0][colour]
  108. #define TXT_NEW        msgs[ 1][colour]
  109. #define TXT_R_W        msgs[ 2][colour]
  110. #define TXT_QM3        msgs[ 3][colour]
  111. #define TXT_SHAR    msgs[ 4][colour]
  112. #define TXT_EXCL    msgs[ 5][colour]
  113. #define TXT_QM4        msgs[ 6][colour]
  114. #define TXT_OKAY    msgs[ 7][colour]
  115. #define TXT_FAIL    msgs[ 8][colour]
  116. #define TXT_POINT    msgs[ 9][colour]
  117. #define TXT_DONE    msgs[10][colour]
  118. #define TXT_WARN    msgs[11][colour]
  119. #define TXT_NEST    msgs[12][colour]
  120. #define TXT_OPEN    msgs[13][colour]
  121. #define TXT_LOCK    msgs[14][colour]
  122. #define TXT_LOAD    msgs[15][colour]
  123. #define TXT_EXEC    msgs[16][colour]
  124. #define TXT_CURDIR    msgs[17][colour]
  125. #define TXT_DELETE    msgs[18][colour]
  126.  
  127. #define POINT(x)    ((x) ? TXT_POINT : " ")
  128.  
  129. /*
  130.  *        Now some standard system-type macros
  131.  */
  132. #define reg_d0    register __d0
  133. #define reg_d1    register __d1
  134. #define reg_d2    register __d2
  135. #define reg_d3    register __d3
  136. #define reg_a0    register __a0
  137.  
  138. #define BTOC(x)    (void *)(((ULONG)x) << 2)
  139.  
  140. #define D_S(name, type) char c_##name[sizeof(type)+3];\
  141.                         type *name = (type *)((long)(c_##name+3) & ~3)
  142.  
  143. extern __asm BPTR CallOpen(reg_d1 UBYTE *, reg_d2 int);
  144. extern __asm BPTR CallLock(reg_d1 UBYTE *, reg_d2 int);
  145. extern __asm BPTR CallLoadSeg(reg_d1 UBYTE *);
  146. extern __asm LONG CallExecute(reg_d1 UBYTE *, reg_d2 BPTR, reg_d3 BPTR);
  147. extern __asm BPTR CallCurrentDir(reg_d1 BPTR);
  148. extern __asm LONG CallDeleteFile(reg_d1 UBYTE *);
  149.  
  150. /*
  151.  *        Structure used to pass messages back and fro
  152.  */
  153. typedef struct {
  154.     struct Message msg;            /* Standard message header    */
  155.     struct Process *process;    /* Sending process id        */
  156.     int msgtype;                /* Message type, see below    */
  157.     int  data1;                    /* Data field 1                */ 
  158.     void *data2;                /* Data field 2                */
  159. } MYMSG;
  160.  
  161. /*
  162.  *        Now the various settings that can be set to affect the monitoring
  163.  */
  164. typedef struct {
  165.     int set_doopen;                /* If true, monitor Open()            */
  166.     int    set_dolock;                /* If true, monitor Lock()            */
  167.     int set_doloadseg;            /* If true, monitor LoadSeg()        */
  168.     int set_doexecute;            /* If true, monitor Execute()        */
  169.     int set_docurdir;            /* If true, monitor CurrentDir()    */
  170.     int set_dodelete;            /* If true, monitor DeleteFile()    */
  171.     int    set_showfullpath;        /* If true, display full paths        */
  172.     int set_sleepwait;            /* If true, sleep if necessary        */
  173.     int set_snoopactive;        /* If true, monitoring is active    */
  174.     int set_colour;                /* If true, use ANSI colour codes    */
  175.     int set_ignoretasks;        /* If true, ignore workbench CD        */
  176. } SETTINGS;
  177.  
  178. /*
  179.  *        Default settings
  180.  */
  181. SETTINGS settings = { 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1 };
  182.  
  183. /*
  184.  *        These defines allow the various settings to be accessed as
  185.  *        normal variables rather than structure members; this is purely
  186.  *        for convenience.
  187.  */
  188. #define doopen            settings.set_doopen
  189. #define dolock            settings.set_dolock
  190. #define doloadseg        settings.set_doloadseg
  191. #define doexecute        settings.set_doexecute
  192. #define docurdir        settings.set_docurdir
  193. #define dodelete        settings.set_dodelete
  194. #define showfullpath    settings.set_showfullpath
  195. #define sleepwait        settings.set_sleepwait
  196. #define snoopactive        settings.set_snoopactive
  197. #define colour            settings.set_colour
  198. #define ignoretasks        settings.set_ignoretasks
  199.  
  200. /*
  201.  *        Now the various message types that can be sent
  202.  */
  203. typedef enum {
  204.     MSG_QUIT,            /* Quit                     */
  205.     MSG_GETOPTIONS,        /* Read options                */
  206.     MSG_SETOPTIONS,        /* Update options            */
  207.     MSG_OPEN,            /* Open file                */
  208.     MSG_OPEN_DONE,        /* Open file completed        */
  209.     MSG_LOCK,            /* Lock file                */
  210.     MSG_LOCK_DONE,        /* Lock file completed        */
  211.     MSG_LOADSEG,        /* LoadSeg file                */
  212.     MSG_LOADSEG_DONE,    /* LoadSeg file completed    */
  213.     MSG_EXECUTE,        /* Execute command            */
  214.     MSG_CURDIR,            /* CurrentDir                */
  215.     MSG_DELETE,            /* DeleteFile                */
  216.     MSG_DELETE_DONE        /* DeleteFile completed        */
  217. } MSGTYPES;
  218.  
  219. struct SignalSemaphore sem[1];
  220. struct MsgPort   *myport;        /* Pointer to background SnoopDos msg port    */
  221. struct MsgPort   *inport;        /* Pointer to our own message port            */
  222. struct Task      *snooptask;    /* Pointer to our own task                    */
  223. BPTR debugwin;                    /* Output file or window                    */
  224. BPTR stderr;                    /* Standard CLI console                        */
  225. int  extfile;                    /* True if output directed to external file    */
  226. char extfilename[100];            /* Name of window/file to open if specified    */
  227. char outbuf[800];                /* Output buffer used by myprintf() etc.    */
  228.  
  229. int missed_open_sig;            /* Signal to indicate Open() missed            */
  230. int missed_lock_sig;            /* Signal to indicate Lock() missed            */
  231. int missed_loadseg_sig;            /* Signal to indicate LoadSeg() missed        */
  232. int missed_execute_sig;            /* Signal to indicate Execute() missed        */
  233. int missed_curdir_sig;            /* Signal to indicate CurrentDir() missed    */
  234. int missed_delete_sig;            /* Signal to indicate DeleteFile() missed    */
  235. int portsig;                    /* Signal used by our public port            */
  236.  
  237. /**************************** Start of Functions ****************************/
  238.  
  239. /*
  240.  *        cleanup()
  241.  *        ---------
  242.  *        Cleans up all active resources and exits. If err is -1, then
  243.  *        returns instead of exiting.
  244.  */
  245. void cleanup(int err)
  246. {
  247.     static int called = 0;
  248.  
  249.     if (called++)        /* Make sure not called twice by accident */
  250.         return;
  251.  
  252.     if (inport)
  253.         DeletePort(inport);
  254.  
  255.     if (debugwin)
  256.         Close(debugwin);
  257.  
  258.     if (stderr)
  259.         Close(stderr);
  260.  
  261.     if (err != -1)
  262.         exit(err);
  263. }
  264.  
  265. /*
  266.  *        myprintf(), myfprintf()
  267.  *        -----------------------
  268.  *        Two low cost alternatives to printf that go directly to AmigaDOS
  269.  *        Note we deliberately use the pre-ANSI declaration, to avoid Lattice
  270.  *        kicking up a fuss about the wrong number of parameters.
  271.  */
  272. void myprintf(format, p1, p2, p3, p4, p5, p6)
  273. UBYTE *format;
  274. ULONG p1, p2, p3, p4, p5, p6;
  275. {
  276.     sprintf(outbuf, format, p1, p2, p3, p4, p5, p6);
  277.     Write(Output(), outbuf, strlen(outbuf));
  278. }
  279.  
  280. void myfprintf(file, format, p1, p2, p3, p4, p5, p6)
  281. BPTR file;
  282. char *format;
  283. ULONG p1, p2, p3, p4, p5, p6;
  284. {
  285.     sprintf(outbuf, format, p1, p2, p3, p4, p5, p6);
  286.     Write(file, outbuf, strlen(outbuf));
  287. }
  288.  
  289. /*
  290.  *        sendmsg()
  291.  *        ---------
  292.  *        Sends a message to myport, and waits for a reply to arrive.
  293.  *        A message type and some message data are all that need be provided
  294.  *        by the caller; the callee will provide the rest. Doesn't return
  295.  *        until a reply has been received.
  296.  */
  297. void sendmsg(int type, int data1, void *data2)
  298. {
  299.     MYMSG msg;
  300.     struct Process *me = (struct Process *)FindTask(0);
  301.     struct MsgPort *replyport = &me->pr_MsgPort;
  302.  
  303.     msg.msg.mn_Node.ln_Type = NT_MESSAGE;
  304.     msg.msg.mn_Length       = sizeof(MYMSG);
  305.     msg.msg.mn_ReplyPort    = replyport;
  306.     msg.process                = me;
  307.     msg.msgtype             = type;
  308.     msg.data1               = data1;
  309.     msg.data2               = data2;
  310.  
  311.     PutMsg(myport, &msg);
  312.     WaitPort(replyport);
  313.     GetMsg(replyport);
  314. }
  315.  
  316.  
  317. /*
  318.  *        getlockpath()
  319.  *        -------------
  320.  *        Returns a pointer to a string containing the full path for the
  321.  *        specified lock. You must copy the string before calling this
  322.  *        routine again.
  323.  */
  324. char *getlockpath(BPTR lock)
  325. {
  326.     struct Process *p = (struct Process *)FindTask(0L);
  327.     APTR oldwin = p->pr_WindowPtr;
  328.     static char path[300];
  329.     int pos = 299;
  330.     BPTR mylock;
  331.     char *name;
  332.     D_S(fib, struct FileInfoBlock);
  333.     int err = 0;
  334.  
  335.     p->pr_WindowPtr = (APTR)-1;    /* Disable error requesters */
  336.     mylock = DupLock(lock);
  337.  
  338.     path[pos] = '\0';
  339.  
  340.     do {
  341.         int len;
  342.         BPTR newlock;
  343.  
  344.         if (!Examine(mylock, fib)) {
  345.             UnLock(mylock);
  346.             err++;
  347.             break;
  348.         }
  349.         name = fib->fib_FileName;
  350.         if (*name == '\0')
  351.             name = "RAM";        /* Workaround for old RAM: disk bug */
  352.         len = strlen(name);
  353.         pos = pos - len - 1;
  354.         newlock = ParentDir(mylock);
  355.         UnLock(mylock);
  356.         mylock = newlock;
  357.         strncpy(path + pos, name, len);
  358.         if (mylock)
  359.             path[pos + len] = '/';
  360.         else
  361.             path[pos + len] = ':';
  362.     } while (mylock);
  363.     p->pr_WindowPtr = oldwin;    /* Enable error requesters again */
  364.  
  365.     if (err) {
  366.         /*
  367.          *        Volume not present so have to be happy with just
  368.          *        returning the volume node instead.
  369.          */
  370.         struct FileLock *fl;
  371.         struct DeviceList *dl;
  372.         UBYTE *name;
  373.  
  374.         if (lock) {
  375.             fl = BTOC(lock);
  376.             dl = BTOC(fl->fl_Volume);
  377.             name = BTOC(dl->dl_Name);
  378.  
  379.             strncpy(path, name + 1, *name);
  380.             path[*name] = '\0';
  381.         } else {
  382.             strcpy(path, "<Boot device>");
  383.         }
  384.         strcat(path, ":.../");
  385.         return (path);
  386.     } else
  387.         return (path + pos);
  388. }
  389.  
  390. /*
  391.  *        makepath()
  392.  *        ----------
  393.  *        Builds a full path string given a process ptr and a filename.
  394.  *        If the filename includes relative references (// or :)
  395.  *        these are handled also. The point of this is to resolve relative
  396.  *        directory references.
  397.  *
  398.  *        Returns TRUE if a new string was generated, FALSE if the existing
  399.  *        string didn't depend on the current directory (this doesn't affect
  400.  *        the output stored in buf though).
  401.  */
  402. int makepath(char *buf, BPTR curdir, char *filename)
  403. {
  404.     char *origfilename = filename;
  405.     int pos;
  406.     int doneroot = 0;
  407.  
  408.     /*
  409.      *        Special check for the 'current process console' file '*'
  410.      */
  411.     if (strcmp(filename, "*") == 0) {
  412.         strcpy(buf, filename);
  413.         return (FALSE);
  414.     }
  415.  
  416.     strcpy(buf, getlockpath(curdir));
  417.     pos = strlen(buf);
  418.  
  419.     for (;;) {
  420.         if (!doneroot && *filename == ':') {
  421.             /*
  422.              *        Path is relative to root
  423.              */
  424.             doneroot = 1;
  425.             for (pos = 0; buf[pos] && buf[pos] != ':'; pos++)
  426.                 ;
  427.             if (buf[pos] == ':')
  428.                 pos++;
  429.         } else if (*filename == '/') {
  430.             /*
  431.              *        Path is relative to parent directory; if none, then
  432.              *        remains the same.
  433.              */
  434.             int newpos = pos - 2;
  435.             while (newpos >= 0 && buf[newpos] != '/' && buf[newpos] != ':')
  436.                 newpos--;
  437.             if (newpos >= 0)
  438.                 pos = newpos + 1;
  439.         } else {
  440.             /*
  441.              *        No more special characters; just append what's left of
  442.              *        the filename.
  443.              */
  444.             if (!doneroot) {
  445.                 /*
  446.                  *        If the filename wasn't relative to the root
  447.                  *        directory, then make sure there are no device/volume
  448.                  *        references contained within it. We copy the original
  449.                  *        filename rather than the currently modified version
  450.                  *        since a volume name of /A: is legal and the / would
  451.                  *        be stripped off the modified name.
  452.                  */
  453.                 char *p;
  454.                 for (p = filename; *p; p++) {
  455.                     if (*p == ':') {
  456.                         strcpy(buf, origfilename);
  457.                         return (0);
  458.                     }
  459.                 }
  460.             }
  461.             strcpy(buf + pos, filename);
  462.             return (1);
  463.         }
  464.         filename++;
  465.     }
  466. }
  467.  
  468. /*
  469.  *        mainloop()
  470.  *        ----------
  471.  *        This is the main event loop for SnoopDOS, where everything happens.
  472.  *        Control is passed here when SnoopDOS first starts up. When this
  473.  *        function returns, it terminates the background process.
  474.  */
  475. void mainloop(void)
  476. {
  477.     static char fullname[300];
  478.     int done   = 0;                    /* True if finished processing            */
  479.     int col0   = 1;                    /* True if cursor in column 0            */
  480.     int nested = 0;                    /* True if nested DOS calls                */
  481.  
  482. #define MISSED_NONE        0            /* Haven't missed anything    */
  483. #define MISSED_OPEN        (1 << 0)    /* Missed Open() call        */
  484. #define MISSED_LOCK        (1 << 1)    /* Missed Lock() call        */
  485. #define MISSED_LOADSEG    (1 << 2)    /* Missed LoadSeg() call    */
  486. #define MISSED_EXECUTE    (1 << 3)    /* Missed Execute() call    */
  487. #define MISSED_CURDIR    (1 << 4)    /* Missed CurrentDir() call    */
  488. #define MISSED_DELETE    (1 << 5)    /* Missed DeleteFile() call    */
  489.  
  490.     int missed = MISSED_NONE;        /* Was a DOS function missed? See above    */
  491.  
  492.     inport = CreatePort(PORTNAME, 0);
  493.     if (!inport) {
  494.         myfprintf(stderr, "SnoopDos: Can't allocate message port.\n");
  495.         cleanup(-1);
  496.         return;
  497.     }
  498.  
  499.     myport  = inport;
  500.     portsig = 1 << myport->mp_SigBit;
  501.  
  502.     /*
  503.      *        Allocate signals
  504.      */
  505.     missed_open_sig       = 1 << AllocSignal(-1);
  506.     missed_lock_sig       = 1 << AllocSignal(-1);
  507.     missed_loadseg_sig = 1 << AllocSignal(-1);
  508.     missed_execute_sig = 1 << AllocSignal(-1);
  509.     missed_curdir_sig  = 1 << AllocSignal(-1);
  510.     missed_delete_sig  = 1 << AllocSignal(-1);
  511.  
  512.     if (    missed_open_sig    == -1  || missed_lock_sig    == -1  ||
  513.             missed_loadseg_sig == -1  || missed_execute_sig == -1  ||
  514.             missed_curdir_sig  == -1  || missed_delete_sig  == -1) {
  515.         myfprintf(stderr, "SnoopDos: Can't allocate enough signals.\n");
  516.         cleanup(-1);
  517.         return;
  518.     }
  519.  
  520.     if (extfile) {
  521.         debugwin = Open(extfilename, MODE_NEWFILE);
  522.         if (!debugwin) {
  523.             myfprintf(stderr, "SnoopDos: Can't open file %s for output.\n",
  524.                                 extfilename);
  525.             cleanup(-1);
  526.             return;
  527.         }
  528.         myfprintf(debugwin, "\r\n" TITLE "\r\n\r\n");
  529.     } else {
  530.         debugwin = Open(DEFWINDOW TITLE, MODE_NEWFILE);
  531.         if (!debugwin) {
  532.             myfprintf(stderr, "SnoopDos: Can't open display window.\n");
  533.             cleanup(-1);
  534.             return;
  535.         }
  536.     }
  537.     Close(stderr); stderr = NULL;
  538.  
  539.     if (!extfile) {
  540.         myfprintf(debugwin, "\n"
  541.     "Type CTRL-E/CTRL-D to enable/disable snooping. Type CTRL-C to exit.\n\n");
  542.     };
  543.     myfprintf(debugwin, HEADER);
  544.  
  545.     InitSemaphore(sem);
  546.     snooptask = FindTask(0L);
  547.     installdospatch();
  548.  
  549.     /*
  550.      *        Now just sit processing messages
  551.      */
  552.     while (!done) {
  553.         int mask;
  554.  
  555. #define SIGMASK    (portsig | missed_open_sig | missed_lock_sig | \
  556.                  missed_loadseg_sig | missed_execute_sig |     \
  557.                  missed_curdir_sig | missed_delete_sig |       \
  558.                  SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E)
  559.  
  560.         mask = Wait(SIGMASK);
  561.  
  562.         if (mask & SIGBREAKF_CTRL_C)
  563.             done = 1;
  564.  
  565.         if (mask & SIGBREAKF_CTRL_D) {
  566.             if (snoopactive) {
  567.                 myfprintf(debugwin,
  568. "\nSnooping now disabled; type CTRL-E to enable it again.\r\n\r\n");
  569.                 snoopactive = 0;
  570.             }
  571.         }
  572.  
  573.         if (mask & SIGBREAKF_CTRL_E) {
  574.             if (!snoopactive) {
  575.                 myfprintf(debugwin,
  576. "Snooping now enabled; type CTRL-D to disable it again.\r\n\r\n%s", HEADER);
  577.                 snoopactive = 1;
  578.             }
  579.         }
  580.  
  581.         if (mask & missed_open_sig)
  582.             missed |= MISSED_OPEN;
  583.  
  584.         if (mask & missed_lock_sig)
  585.             missed |= MISSED_LOCK;
  586.  
  587.         if (mask & missed_loadseg_sig)
  588.             missed |= MISSED_LOADSEG;
  589.  
  590.         if (mask & missed_execute_sig)
  591.             missed |= MISSED_EXECUTE;
  592.  
  593.         if (mask & missed_curdir_sig)
  594.             missed |= MISSED_CURDIR;
  595.  
  596.         if (mask & missed_delete_sig)
  597.             missed |= MISSED_DELETE;
  598.  
  599.         if (mask & portsig) {
  600.             MYMSG *msg;
  601.  
  602.             /*
  603.              *        Note in the following, there is some slightly tricky
  604.              *        stuff to handle the case where a DOS function calls
  605.              *        another DOS function internally. Under 1.3, this doesn't
  606.              *        happen, but it may under WB 2.0 and in addition, Jim
  607.              *        Goodnow's handy Rez utility patches LoadSeg() so that
  608.              *        it calls Open(). `nested' is true when a nested call
  609.              *        like this happens, and in this case, process names are
  610.              *        printed out prefixed by `> ' to indicate the nesting.
  611.              *
  612.              *        The nesting is detected because an incoming Open/Lock/
  613.              *        LoadSeg message will arrive when the cursor is positioned
  614.              *        to print a Fail/Okay result from a previous call (i.e.
  615.              *        col0 is false; the cursor is not in column 0). When a
  616.              *        result arrives in and the cursor IS in column 0, then
  617.              *        this must be the result from an earlier call so the
  618.              *        nesting is ended. Note that the semaphores used ensures
  619.              *        that this situation can only ever occur as a result of
  620.              *        nesting; other tasks will always wait until they are
  621.              *        properly in sync before sending messages to the main
  622.              *        Snoopdos process.
  623.              *
  624.              *        The more alert among you are probably saying something
  625.              *        like "Ah, but what if SnoopDos is configured to display
  626.              *        all DOS calls, even if it means forcing some tasks to
  627.              *        sleep until SnoopDos can process them? Then, when a
  628.              *        task calls LoadSeg() (say) and LoadSeg() calls Open(),
  629.              *        Open() will sleep forever waiting for the semaphore
  630.              *        Obtain()ed by LoadSeg() to become free again." Well,
  631.              *        in fact, it won't, since exec's ObtainSemaphore() call
  632.              *        will suceed even when the semaphore is in use, IF the
  633.              *        caller is the task that owns the semaphore -- and in such
  634.              *        a case, the caller will be the same task. (It took me a
  635.              *        while to figure out exactly what things were working --
  636.              *        it looked like I should get a serious lockup in certain
  637.              *        circumstances).
  638.              *        
  639.              */
  640.             while ((msg = (MYMSG *)GetMsg(myport)) != NULL) {
  641.                 /*
  642.                  *        Get the name of the process/command for
  643.                  *        printing out if necessary.
  644.                  */
  645.                 static char namebuf[256];
  646.                 UBYTE *procname = msg->process->pr_Task.tc_Node.ln_Name;
  647.                 struct CommandLineInterface *cli = BTOC(msg->process->pr_CLI);
  648.                 BPTR curdir = msg->process->pr_CurrentDir;
  649.                 UBYTE *s;
  650.                 UBYTE *filename;
  651.                 int newname;    /* If true, a new name was generated */
  652.  
  653.                 if (!col0 && (msg->msgtype == MSG_OPEN        ||
  654.                               msg->msgtype == MSG_LOCK        ||
  655.                               msg->msgtype == MSG_LOADSEG    ||
  656.                               msg->msgtype == MSG_CURDIR    ||
  657.                               msg->msgtype == MSG_DELETE)) {
  658.                     nested = 1;
  659.                     myfprintf(debugwin, TXT_NEST);
  660.                 }
  661.                 if (cli && cli->cli_Module) {
  662.                     UBYTE *cliname = BTOC(cli->cli_CommandName);
  663.                     if (*cliname > 0) {
  664.                         /* Only use CLI name if it's not null */
  665.                         strncpy(namebuf+2, cliname + 1, *cliname);
  666.                         namebuf[*cliname+2] = '\0';
  667.                         procname = namebuf + 2;
  668.                         if (nested) {
  669.                             /*
  670.                              *        If we're not at column 0, then we're
  671.                              *        calling this DOS function from within
  672.                              *        another DOS function so indent display
  673.                              */
  674.                             procname = namebuf;
  675.                             procname[0] = '>';
  676.                             procname[1] = ' ';
  677.                         }
  678.                     }
  679.                 } else {
  680.                     if (nested) {
  681.                         sprintf(namebuf, "> %s", procname);
  682.                         procname = namebuf;
  683.                     }
  684.                 }
  685.  
  686.                 /*
  687.                  *        Now handle the message
  688.                  */
  689.                 filename = msg->data2;    /* Standard file name            */
  690.                 newname  = 0;            /* No problems expanding it        */
  691.  
  692.                 switch (msg->msgtype) {
  693.  
  694.                     case MSG_QUIT:
  695.                         done = 1;
  696.                         break;
  697.  
  698.                     case MSG_GETOPTIONS:
  699.                         memcpy(msg->data2, &settings, sizeof(SETTINGS));
  700.                         break;
  701.  
  702.                     case MSG_SETOPTIONS:
  703.                         memcpy(&settings, msg->data2, sizeof(SETTINGS));
  704.                         break;
  705.  
  706.                     case MSG_OPEN:
  707.                         if (msg->data1 == MODE_OLDFILE)
  708.                             s = TXT_OLD;
  709.                         else if (msg->data1 == MODE_NEWFILE)
  710.                             s = TXT_NEW;
  711.                         else if (msg->data1 == MODE_READWRITE)
  712.                             s = TXT_R_W;
  713.                         else
  714.                             s = TXT_QM3;
  715.  
  716.                         if (showfullpath) {
  717.                             newname = makepath(fullname, curdir, msg->data2);
  718.                             filename = fullname;
  719.                         }
  720.                         myfprintf(debugwin, "%-21s %s %s%-39s %s ", procname,
  721.                                     TXT_OPEN, POINT(newname), filename, s);
  722.                         col0 = 0;
  723.                         break;  
  724.  
  725.                     case MSG_LOCK:
  726.                         if (msg->data1 == ACCESS_READ)
  727.                             s = TXT_SHAR;
  728.                         else if (msg->data1 == ACCESS_WRITE)
  729.                             s = TXT_EXCL;
  730.                         else
  731.                             s = TXT_QM4;
  732.  
  733.                         if (showfullpath) {
  734.                             newname = makepath(fullname, curdir, msg->data2);
  735.                             filename = fullname;
  736.                         }
  737.                         myfprintf(debugwin, "%-21s %s %s%-39s %s ", procname,
  738.                                     TXT_LOCK, POINT(newname), filename, s);
  739.                         col0 = 0;
  740.                         break;
  741.  
  742.                     case MSG_LOADSEG:
  743.                         if (showfullpath) {
  744.                             newname = makepath(fullname, curdir, msg->data2);
  745.                             filename = fullname;
  746.                         }
  747.                         myfprintf(debugwin, "%-21s %s %s%-44s ", procname,
  748.                                     TXT_LOAD, POINT(newname), filename);
  749.                         col0 = 0;
  750.                         break;
  751.  
  752.                     case MSG_EXECUTE:
  753.                         myfprintf(debugwin, "%-21s %s  %s\r\n", procname,
  754.                                                     TXT_EXEC, filename);
  755.                         col0 = 1;
  756.                         break;
  757.  
  758.                     case MSG_CURDIR:
  759.                         {
  760.                             char *dirname = getlockpath(msg->data1);
  761.                             int i = strlen(dirname);
  762.  
  763.                             if (dirname[i-1] == '/')
  764.                                 dirname[i-1] = '\0';
  765.                             myfprintf(debugwin, "%-21s %s  %s\r\n", procname,
  766.                                                     TXT_CURDIR, dirname);
  767.                             col0 = 1;
  768.                         }
  769.                         break;
  770.  
  771.                     case MSG_DELETE:
  772.                         if (showfullpath) {
  773.                             newname = makepath(fullname, curdir, msg->data2);
  774.                             filename = fullname;
  775.                         }
  776.                         myfprintf(debugwin, "%-21s %s %s%-44s ", procname,
  777.                                     TXT_DELETE, POINT(newname), filename);
  778.                         col0 = 0;
  779.                         break;
  780.  
  781.                     case MSG_LOCK_DONE:
  782.                     case MSG_OPEN_DONE:
  783.                     case MSG_LOADSEG_DONE:
  784.                     case MSG_DELETE_DONE:
  785.                         if (col0 && nested) {
  786.                             myfprintf(debugwin, "%-73s", TXT_DONE);
  787.                             nested = 0;
  788.                         }
  789.                         if (msg->data1)
  790.                             myfprintf(debugwin, TXT_OKAY);
  791.                         else
  792.                             myfprintf(debugwin, TXT_FAIL);
  793.                         col0 = 1;
  794.                         break;
  795.                 }
  796.                 ReplyMsg(msg);
  797.             }
  798.         }
  799.  
  800.         /*
  801.          *        Finally, check if we missed a DOS function. If we did,
  802.          *        AND we are in column 0, print out an appropriate message.
  803.          *        Otherwise, wait until next time. This stops the display
  804.          *        getting messed up when waiting to print a 'Fail' or 'Okay'.
  805.          */
  806.         if (missed) {
  807.             if (col0) {
  808.                 if (missed & MISSED_OPEN)
  809.                     myfprintf(debugwin, "%s an Open()\r\n", TXT_WARN);
  810.                 if (missed & MISSED_LOCK)
  811.                     myfprintf(debugwin, "%s a Lock()\r\n", TXT_WARN);
  812.                 if (missed & MISSED_LOADSEG)
  813.                     myfprintf(debugwin, "%s a LoadSeg()\r\n", TXT_WARN);
  814.                 if (missed & MISSED_EXECUTE)
  815.                     myfprintf(debugwin, "%s an Execute()\r\n", TXT_WARN);
  816.                 if (missed & MISSED_CURDIR)
  817.                     myfprintf(debugwin, "%s a CurrentDir()\r\n", TXT_WARN);
  818.                 if (missed & MISSED_DELETE)
  819.                     myfprintf(debugwin, "%s a DeleteFile()\r\n", TXT_WARN);
  820.                 missed = MISSED_NONE;
  821.             }
  822.         }
  823.     }
  824.  
  825.     /*
  826.      *        Remove the port from the public ports list; this stops any
  827.      *        SnoopDos processes started up elsewhere from trying to
  828.      *        communicate with us (which may happen if this process can't
  829.      *        exit immediately).
  830.      */
  831.     RemPort(myport);
  832.     myport->mp_Node.ln_Name = NULL;
  833.     snoopactive = 0;    /* Make sure our patch stops sending msgs to us! */
  834.  
  835.     /*
  836.      *        Now try and obtain our semaphore. Until we can achieve it,
  837.      *        we may still be receiving messages from other tasks telling
  838.      *        us about DOS operations, so, we reply to these as they arrive
  839.      *        (else deadlock occurs).
  840.      */
  841.     while (!AttemptSemaphore(sem)) {
  842.         MYMSG *msg = (MYMSG *)GetMsg(myport);
  843.  
  844.         if (msg)
  845.             ReplyMsg(msg);
  846.         Delay(5);                /* Wait for 0.1 seconds */
  847.     }
  848.  
  849.     /*
  850.      *        Now remove the dospatch, and cleanup
  851.      */
  852.     if (!uninstalldospatch()) {
  853.         /*
  854.          *        Someone else has patched DOSbase so print a message for
  855.          *        the user and keep trying every 5 seconds until we succeed.
  856.          */
  857.         int count = 0;
  858.  
  859.         myfprintf(debugwin,
  860. "\r\n"
  861. "Someone else has patched dos.library so I'll have to wait until they quit."
  862. "\r\n");
  863.         if (!extfile) {
  864.             myfprintf(debugwin, 
  865.   "This window will close shortly though to stop it from annoying you.\r\n");
  866.         }
  867.  
  868.         do {
  869.             Delay(50);                    /* Wait for one second */
  870.             if (debugwin) {
  871.                 count++;
  872.                 if (count > 10) {
  873.                     Close(debugwin);
  874.                     debugwin = NULL;
  875.                 }
  876.             }
  877.         } while (!uninstalldospatch());
  878.     }
  879.  
  880.     if (debugwin)
  881.         myfprintf(debugwin, "\r\nSnoopDos terminated.\r\n");
  882.  
  883.     /*
  884.      *        We do a final wait for 2 seconds, just in case there are any
  885.      *        other tasks still running in our SetFunction'd code. We close
  886.      *        the window/file first, to avoid annoying the user.
  887.      *        (This isn't 100% bulletproof, but it's fairly safe).
  888.      */
  889.     if (debugwin) {
  890.         Close(debugwin);
  891.         debugwin = NULL;    /* Make sure cleanup code doesn't close it too */
  892.     }
  893.     Delay(50);
  894.     /*
  895.      *        Now make one final check to ensure there are no outstanding
  896.      *        messages waiting to be replied too. Note that all this delaying
  897.      *        etc. isn't really a problem since we are now "invisible" to
  898.      *        the rest of the system, having deleted our AmigaDOS patch and
  899.      *        public port earlier on. It's just a bit of extra bullet
  900.      *        proofing to reduce the risk of race conditions during exit.
  901.      */
  902.     if (myport) {
  903.         MYMSG *msg;
  904.         while ((msg = (MYMSG *)GetMsg(myport)) != NULL)
  905.             ReplyMsg(msg);
  906.     }
  907.     Delay(100);    /* And give such code time to complete */
  908.     cleanup(-1);
  909. }
  910.  
  911. /*
  912.  *        main()
  913.  *        ------
  914.  *        Mainline. Parses the command line and, if necessary, kicks off the
  915.  *        background task to do the real work.
  916.  */
  917. void main(int argc, char **argv)
  918. {
  919.     int error  = 0;            /* True if error detected in cmd line    */
  920.     int quit   = 0;            /* True if we want to quit                */
  921.     int colsel = 0;            /* True if colour option was specified    */
  922.  
  923.     /*
  924.      *        See if we are already active elsewhere; if yes, then read in
  925.      *        the default settings used by that process.
  926.      */
  927.  
  928.     myport = FindPort(PORTNAME);
  929.     if (myport)
  930.         sendmsg(MSG_GETOPTIONS, 0, &settings);
  931.  
  932.     while (argc > 1 && argv[1][0] == '-') {
  933.         int val;
  934.  
  935.         /* Make -X == -x0 and -x == -x1 */
  936.         if (argv[1][1] >= 'a' && argv[1][2] != '0')
  937.             val = 1;
  938.         else
  939.             val = 0;
  940.  
  941.         switch (tolower(argv[1][1])) {
  942.  
  943.             case 'a': colour         = val;
  944.                       colsel        = 1;   break;    /* Display ANSI colour    */
  945.             case 'c': docurdir        = val; break;    /* Monitor CurrentDir() */
  946.             case 'd': dodelete        = val; break;    /* Monitor DeleteFile()    */
  947.             case 'f': showfullpath    = val; break;    /* Show full filepath    */
  948.             case 'g': doloadseg        = val; break;    /* Monitor LoadSeg()    */
  949.             case 'h': error            = 1;   break;    /* Just print help msg    */
  950.             case 'i': ignoretasks   = val; break;    /* Ignore WBench/Shell  */
  951.             case 'l': dolock        = val; break;    /* Monitor Lock()        */
  952.             case 'm': snoopactive    = val; break;    /* Actively monitoring    */
  953.             case 'o': doopen        = val; break;    /* Monitor Open()        */
  954.             case 'q': quit            = 1;   break;    /* Ask SnoopDos to quit */
  955.             case 'r': error            = 2;   break;    /* Report settings        */
  956.             case 'w': sleepwait        = val; break;    /* Wait when necessary    */
  957.             case 'x': doexecute        = val; break;    /* Monitor Execute()    */
  958.             case 'z':
  959.                     if (argv[1][2]) {
  960.                         strcpy(extfilename, &argv[1][2]);
  961.                         extfile = 1;
  962.                     } else {
  963.                         argv++;
  964.                         argc--;
  965.                         if (argc > 1) {
  966.                             strcpy(extfilename, argv[1]);
  967.                             extfile = 1;
  968.                         }
  969.                     }
  970.                     if (!extfile) {
  971.                         myprintf(
  972.         "-z must be followed by a filename. Type SnoopDos -h for help.\n");
  973.                         exit(5);
  974.                     }
  975.                     /*
  976.                      *        If outputting to a file, make colour off
  977.                      *        by default, rather than on.
  978.                      */
  979.                     if (colsel == 0)
  980.                         colour = 0;
  981.                     break;
  982.  
  983.             default:
  984.                 myprintf("Unrecognised option %s. "
  985.                          "Type Snoopdos -h for help.\n", argv[1]);
  986.                 exit(5);
  987.         }
  988.         argv++; argc--;
  989.     }
  990.  
  991.     if (argc > 1)
  992.         error = 1;
  993.  
  994.     if (error) {
  995.         if (error == 1) {
  996.             myprintf(TITLE "\n\n"
  997. "SnoopDos monitors calls made to various AmigaDOS functions by all processes\n"
  998. "on the system. The following options are available. Use -x1 or just -x to\n"
  999. "enable an option, -x0 or -X to disable that option. Current settings in (-)."
  1000. "\n\n");
  1001.         } else
  1002.             myprintf("Current " NAME " settings:\n\n");
  1003.  
  1004. #define O(x,y) myprintf(x, y ? "(on)" : "(off)")
  1005. O("    -a  Use ANSI colour sequences                     %s\n", colour);
  1006. O("    -c  Monitor CurrentDir() calls                    %s\n", docurdir);
  1007. O("    -d  Monitor DeleteFile() calls                    %s\n", dodelete);
  1008. O("    -f  Display full filename paths                   %s\n", showfullpath);
  1009. O("    -g  Monitor LoadSeg() calls                       %s\n", doloadseg);
  1010. O("    -i  Ignore some Shell & Workbench calls           %s\n", ignoretasks);
  1011. O("    -l  Monitor Lock() calls                          %s\n", dolock);
  1012. O("    -m  Globally enable/disable monitoring            %s\n", snoopactive);
  1013. O("    -o  Monitor Open() calls                          %s\n", doopen);
  1014. O("    -w  Display all activity, sleeping if necessary   %s\n", sleepwait);
  1015. O("    -x  Monitor Execute() calls                       %s\n", doexecute);
  1016.  
  1017.         if (error == 1) {
  1018.             myprintf("\n"
  1019. "    -h  Print out this help message\n"
  1020. "    -q  Tell SnoopDos to quit\n"
  1021. "    -r  Report current SnoopDos settings\n" 
  1022. "    -z$ Output to file $ (e.g. -zCON:0/0/640/100/SnoopDos or -zSER:)\n"
  1023. "\n");
  1024.         }
  1025.         cleanup(5);
  1026.     }
  1027.  
  1028.     /*
  1029.      *        First see are we already installed. If so, send a copy of the
  1030.      *        updated settings to the background process, or send a QUIT
  1031.      *        message if the user wanted to quit.
  1032.      */
  1033.     if (myport) {
  1034.         if (quit)
  1035.             sendmsg(MSG_QUIT, 0, 0);
  1036.         else
  1037.             sendmsg(MSG_SETOPTIONS, 0, &settings);
  1038.         cleanup(0);
  1039.     }
  1040.  
  1041.     /*
  1042.      *        If user wanted to quit and we weren't already running, just
  1043.      *        quit without doing anything.
  1044.      */
  1045.     if (quit) {
  1046.         myprintf("There is no background SnoopDos process to tell to quit!\n");
  1047.         cleanup(0);
  1048.     }
  1049.  
  1050.     /*
  1051.      *        Not installed, so install ourselves. First of all though, we
  1052.      *        kick ourselves into the background and return control to the
  1053.      *        calling CLI. We need to do this before we start creating ports
  1054.      *        and opening files, to prevent Exec and AmigaDOS getting
  1055.      *        confused about which task we are.
  1056.      *
  1057.      *        Also open stderr channel for the new task to output fatal
  1058.      *        error messages to; the new task takes responsibility for closing
  1059.      *        this channel.
  1060.      */
  1061.     stderr = Open("*", MODE_NEWFILE);
  1062.     if (!res("SnoopDos", 5, mainloop, 4000)) {
  1063.         myprintf("Couldn't spawn background SnoopDos task.\n");
  1064.         cleanup(10);
  1065.     }
  1066. }
  1067.  
  1068. /*
  1069.  *        NewOpen()
  1070.  *        ---------
  1071.  *        This is the new Open() code. It checks to see if the calling task
  1072.  *        is actually the SnoopDos task; if it is, then it essentially does
  1073.  *        nothing (this stops any possible deadlock occurring). Otherwise,
  1074.  *        it sends a message to the task with the pertinent info.
  1075.  *
  1076.  *        If sleeping is disabled then if the semaphore isn't immediately
  1077.  *        available, a signal is sent to the Snoopdos task telling it that
  1078.  *        it's missed trapping a function.
  1079.  */
  1080. __asm BPTR NewOpen(reg_d1 char *filename, reg_d2 int mode)
  1081. {
  1082.     BPTR filehandle;
  1083.     geta4();
  1084.     if (snoopactive && doopen && FindTask(0) != snooptask) {
  1085.         if (sleepwait)
  1086.             ObtainSemaphore(sem);
  1087.         else if (!AttemptSemaphore(sem)) {
  1088.             Signal(snooptask, missed_open_sig);
  1089.             return (CallOpen(filename, mode));
  1090.         }
  1091.         sendmsg(MSG_OPEN, mode, filename);
  1092.         filehandle = CallOpen(filename, mode);
  1093.         sendmsg(MSG_OPEN_DONE, filehandle, 0);
  1094.         ReleaseSemaphore(sem);
  1095.         return (filehandle);
  1096.     } else {
  1097.         return (CallOpen(filename, mode));
  1098.     }
  1099. }
  1100. /*
  1101.  *        NewLock()
  1102.  *        ---------
  1103.  *        Replacement for Lock(), all the comments for NewOpen() apply
  1104.  *        equally here.
  1105.  */
  1106. __asm BPTR NewLock(reg_d1 char *filename, reg_d2 int mode)
  1107. {
  1108.     BPTR lock;
  1109.     struct Task *task;
  1110.  
  1111.     geta4();
  1112.     task = FindTask(0L);
  1113.  
  1114.     if (ignoretasks && (strcmp(task->tc_Node.ln_Name, IGNORE_CLI) == 0 ||
  1115.                         strcmp(task->tc_Node.ln_Name, IGNORE_BG)  == 0))
  1116.         return (CallLock(filename, mode));
  1117.  
  1118.     if (snoopactive && dolock && FindTask(0) != snooptask) {
  1119.         if (sleepwait)
  1120.             ObtainSemaphore(sem);
  1121.         else if (!AttemptSemaphore(sem)) {
  1122.             Signal(snooptask, missed_lock_sig);
  1123.             return (CallLock(filename, mode));
  1124.         }
  1125.         sendmsg(MSG_LOCK, mode, filename);
  1126.         lock = CallLock(filename, mode);
  1127.         sendmsg(MSG_LOCK_DONE, lock, 0);
  1128.         ReleaseSemaphore(sem);
  1129.         return (lock);
  1130.     } else {
  1131.         return (CallLock(filename, mode));
  1132.     }
  1133. }
  1134.  
  1135. /*
  1136.  *        NewLoadSeg()
  1137.  *        ------------
  1138.  *        Replacement for LoadSeg(), all the comments for NewOpen() apply
  1139.  *        equally here.
  1140.  */
  1141. __asm BPTR NewLoadSeg(reg_d1 char *filename)
  1142. {
  1143.     BPTR seglist;
  1144.     geta4();
  1145.     if (snoopactive && doloadseg && FindTask(0) != snooptask) {
  1146.         if (sleepwait)
  1147.             ObtainSemaphore(sem);
  1148.         else if (!AttemptSemaphore(sem)) {
  1149.             Signal(snooptask, missed_loadseg_sig);
  1150.             return (CallLoadSeg(filename));
  1151.         }
  1152.         sendmsg(MSG_LOADSEG, 0, filename);
  1153.         seglist = CallLoadSeg(filename);
  1154.         sendmsg(MSG_LOADSEG_DONE, seglist, 0);
  1155.         ReleaseSemaphore(sem);
  1156.         return (seglist);
  1157.     } else {
  1158.         return (CallLoadSeg(filename));
  1159.     }
  1160. }
  1161.  
  1162. /*
  1163.  *        NewExecute()
  1164.  *        ------------
  1165.  *        Replacement for Execute()
  1166.  */
  1167. __asm LONG NewExecute(reg_d1 char *command, reg_d2 BPTR in, reg_d3 BPTR out)
  1168. {
  1169.     geta4();
  1170.     if (snoopactive && doexecute && FindTask(0) != snooptask) {
  1171.         if (sleepwait)
  1172.             ObtainSemaphore(sem);
  1173.         else if (!AttemptSemaphore(sem)) {
  1174.             Signal(snooptask, missed_execute_sig);
  1175.             return (CallExecute(command, in, out));
  1176.         }
  1177.         sendmsg(MSG_EXECUTE, 0, command);
  1178.         ReleaseSemaphore(sem);
  1179.     }
  1180.     return (CallExecute(command, in, out));
  1181. }
  1182.  
  1183. /*
  1184.  *        NewCurrentDir()
  1185.  *        ---------------
  1186.  *        Replacement for CurrentDir()
  1187.  */
  1188. __asm BPTR NewCurrentDir(reg_d1 BPTR newlock)
  1189. {
  1190.     struct Task *task;
  1191.  
  1192.     geta4();
  1193.     task = FindTask(0L);
  1194.  
  1195.     /*
  1196.      *        If we are ignoring CD's from the Workbench and Shell tasks
  1197.      *        (to save lots of useless output when running under
  1198.      *        Kickstart 2.0x), then check to see if the task trying to
  1199.      *        do a CD is Workbench, or the shell itself. If it is,
  1200.      *        don't output anything. Note that we distinguish between
  1201.      *        commands running from within the shell, and the shell itself,
  1202.      *        by looking to see if a module has been loaded into the Shell.
  1203.      */
  1204.     if (ignoretasks && (strcmp(task->tc_Node.ln_Name, IGNORE_WB)  == 0 ||
  1205.                         strcmp(task->tc_Node.ln_Name, IGNORE_CLI) == 0 ||
  1206.                         strcmp(task->tc_Node.ln_Name, IGNORE_BG)  == 0))
  1207.         return (CallCurrentDir(newlock));
  1208.  
  1209.     if (snoopactive && docurdir && task != snooptask) {
  1210.         if (sleepwait)
  1211.             ObtainSemaphore(sem);
  1212.         else if (!AttemptSemaphore(sem)) {
  1213.             Signal(snooptask, missed_curdir_sig);
  1214.             return (CallCurrentDir(newlock));
  1215.         }
  1216.         sendmsg(MSG_CURDIR, newlock, 0);
  1217.         ReleaseSemaphore(sem);
  1218.     }
  1219.     return (CallCurrentDir(newlock));
  1220. }
  1221.  
  1222. /*
  1223.  *        NewDeleteFile()
  1224.  *        ---------------
  1225.  *        Replacement for DeleteFile()
  1226.  */
  1227. __asm LONG NewDeleteFile(reg_d1 char *filename)
  1228. {
  1229.     LONG success;
  1230.     geta4();
  1231.     if (snoopactive && dodelete && FindTask(0) != snooptask) {
  1232.         if (sleepwait)
  1233.             ObtainSemaphore(sem);
  1234.         else if (!AttemptSemaphore(sem)) {
  1235.             Signal(snooptask, missed_delete_sig);
  1236.             return (CallDeleteFile(filename));
  1237.         }
  1238.         sendmsg(MSG_DELETE, 0, filename);
  1239.         success = CallDeleteFile(filename);
  1240.         sendmsg(MSG_DELETE_DONE, success, 0);
  1241.         ReleaseSemaphore(sem);
  1242.         return (success);
  1243.     } else
  1244.         return (CallDeleteFile(filename));
  1245. }
  1246.