home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / gcc / ixemulsrc.lha / ixemul / utils / ixpipe-handler.c < prev    next >
C/C++ Source or Header  |  1996-12-11  |  12KB  |  418 lines

  1. #include <exec/types.h>
  2. #include <exec/lists.h>
  3. #include <exec/ports.h>
  4. #include <exec/execbase.h>
  5. #include <dos/dosextens.h>
  6. #include <dos/filehandler.h>
  7. #include <packets.h>
  8. #include <inline/exec.h>
  9.  
  10. #include <sys/types.h>
  11. #include <sys/file.h>
  12. #include <sys/signal.h>
  13. #include <sys/stat.h>
  14. #include <errno.h>
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <string.h>
  18. #include <setjmp.h>
  19. #include <stdio.h>
  20.  
  21. #ifdef DEBUG
  22. #define dprintf(fmt, args...) kprintf(fmt, ##args)
  23. #else
  24. #define dprintf(fmt, args...)
  25. #endif
  26.  
  27. /* this is our custom packet, which passes along an ixemul-private file
  28.    id, which we then use to clone that file into our file-table space.
  29.    All later operations are then performed on file-descriptors as usual ;-)) */
  30. #define ACTION_IXEMUL_MAGIC    0x4242    /* *very* magic ;-)) */
  31.  
  32. #define DOS_TRUE        -1
  33. #define DOS_FALSE         0
  34.  
  35. /* we require at least ixemul.library v39.41 */
  36. #define NEEDED_IX_VERSION    39    /* or better */
  37. #define NEEDED_IX_REVISION    41    /* or better */
  38.  
  39. int handler_mainloop (struct DeviceNode *dev_node, struct Process *me,
  40.               int *errno);
  41.  
  42. static int __errno_to_ioerr (int err);
  43.  
  44. int ix_exec_entry (struct DeviceNode *argc, struct Process *argv,
  45.                    int *environ, int *real_errno, 
  46.                int (*main)(struct DeviceNode *, struct Process *, int *));
  47.  
  48. /* guarantee that the first location in the code hunk is a jump to where
  49.    we start, and not some shared string that just happend to land at
  50.    location 0... */
  51. asm (".text; jmp _ENTRY;");
  52.  
  53. static const char version_id[] = "\000$VER: ixpipe-handler 1.1 (30.8.95)";
  54.  
  55. struct Library *ixemulbase = 0;
  56. struct ExecBase *SysBase;
  57.  
  58. /* returnpkt() - packet support routine
  59.  * here is the guy who sends the packet back to the sender...
  60.  *
  61.  * (I modeled this just like the BCPL routine [so its a little redundant] )
  62.  */
  63.  
  64. static void returnpkt(struct DosPacket *packet, struct Process *myproc, 
  65.        ULONG res1, ULONG res2)
  66. {
  67.   struct Message *mess;
  68.   struct MsgPort *replyport;
  69.  
  70.   packet->dp_Res1          = res1;
  71.   packet->dp_Res2          = res2;
  72.   replyport                = packet->dp_Port;
  73.   mess                     = packet->dp_Link;
  74.   packet->dp_Port          = &myproc->pr_MsgPort;
  75.   mess->mn_Node.ln_Name    = (char *) packet;
  76.   mess->mn_Node.ln_Succ    =
  77.     mess->mn_Node.ln_Pred  = 0;
  78.   PutMsg (replyport, mess);
  79. }
  80.  
  81.  
  82. static void returnpktplain(struct DosPacket *packet, struct Process *myproc)
  83. {
  84.   returnpkt(packet, myproc, packet->dp_Res1, packet->dp_Res2);
  85. }
  86.  
  87.  
  88. /*
  89.  * taskwait() ... Waits for a message to arrive at your port and
  90.  *   extracts the packet address which is returned to you.
  91.  */
  92.  
  93. static struct DosPacket *taskwait(struct Process *myproc)
  94. {
  95.   struct MsgPort *myport;
  96.   struct Message *mymess;
  97.  
  98.   myport = &myproc->pr_MsgPort;
  99.   WaitPort (myport);
  100.   mymess = GetMsg (myport);
  101.   return ((struct DosPacket *)mymess->mn_Node.ln_Name);
  102. }
  103.  
  104. int
  105. ENTRY (void)
  106. {
  107.   struct Library *ixbase;
  108.   struct Process *me;
  109.   struct DosPacket *startup_packet;
  110.   struct DeviceNode *dev_node;
  111.   int errno;
  112.  
  113.   SysBase = *(struct ExecBase **) 4;
  114.   me = (struct Process *) FindTask (0);
  115.  
  116.   dprintf("ixp-$%lx: waiting for startup-packet\n", me);
  117.  
  118.   /* wait for the startup packet */
  119.   startup_packet = taskwait (me);
  120.  
  121.   dprintf("ixp-$%lx: got startup packet\n", me);
  122.  
  123.   ixbase = OpenLibrary ("ixemul.library", NEEDED_IX_VERSION);
  124.   if (ixbase)
  125.     {
  126.       if (ixbase->lib_Version == NEEDED_IX_VERSION &&
  127.           ixbase->lib_Revision < NEEDED_IX_REVISION)
  128.     CloseLibrary (ixbase);
  129.       else
  130.     {
  131.       /* make the external library glue work */
  132.       ixemulbase = ixbase;
  133.       dev_node = BTOCPTR (startup_packet->dp_Arg3);
  134.       dev_node->dn_Task = &me->pr_MsgPort;
  135.       returnpkt (startup_packet, me, DOS_TRUE, 0);
  136.       
  137.       dprintf ("ixp-$%lx: init ok, entering handler mainloop\n", me);
  138.       /* ignore the result _exit() might pass to us.
  139.              pass our device node as `argc' to handler_mainloop() */
  140.       ix_exec_entry (dev_node, me, &errno, &errno, handler_mainloop);
  141.       CloseLibrary (ixbase);
  142.       return 0;
  143.     }
  144.     }
  145.     
  146.   dprintf ("ixp-$%lx: init-error\n", me);
  147.   returnpkt (startup_packet, me, DOS_FALSE, ERROR_BAD_STREAM_NAME);
  148.   return 0;
  149. }
  150.  
  151.  
  152. void
  153. dummy_sighandler ()
  154. {
  155. }
  156.  
  157. jmp_buf jmpbuf;
  158.  
  159. void
  160. panic_sighandler (int sig)
  161. {
  162.   longjmp (jmpbuf, sig);
  163. }
  164.  
  165. int 
  166. handler_mainloop (struct DeviceNode *dev_node, struct Process *me, int *errno)
  167. {
  168.   struct DosPacket *volatile dp = NULL;
  169.   struct MsgPort *our_mp = &me->pr_MsgPort;
  170.   int i;
  171.  
  172.   for (i = 1; i < SIGMSG; i++)
  173.     signal (i, panic_sighandler);
  174.   /* disable ^C propagation as good as we can... */
  175.   signal (SIGMSG, dummy_sighandler);
  176.      
  177.   /* terminated by ACTION_END, Close() that is */
  178.   for (;;)
  179.     {
  180.       if ((i = setjmp (jmpbuf)))
  181.         {
  182.       dprintf ("ixp-$%lx: SIGNAL %ld\n", me, i);
  183.       if (dp->dp_Type == ACTION_WRITE && i == SIGPIPE)
  184.         {
  185.           Signal (dp->dp_Port->mp_SigTask, SIGBREAKF_CTRL_C);
  186.           returnpkt (dp, me, -1, 0); /* return EOF */
  187.           continue;
  188.         }
  189.      
  190.  
  191.       /* should look like `SIG' plus number ;-) */
  192.       returnpkt (dp, me, DOS_FALSE, 516000 + i);
  193.       continue;
  194.     }
  195.  
  196.       dprintf ("ixp-$%lx: Waiting for packet...\n", me);
  197.       while (!(dp = taskwait (me))) ;
  198.  
  199.       /* find out what they want us to do.... */
  200.       switch (dp->dp_Type)
  201.         {
  202.         case ACTION_IXEMUL_MAGIC:
  203.       {
  204.         /* this is sort of an `Open', that is, we fill out a struct
  205.            FileHandle. The reason I didn't chose to `abuse' the various
  206.            ACTION_FIND{INPUT,OUTPUT} packets is simple: I want an
  207.            ordinary Open() call to fail! The semantics are, that you
  208.                pass a hex string describing the id as name. */
  209.             int fd;
  210.             char name[255];    /* a BSTR can't address more ;-) */
  211.         u_char *cp;
  212.             unsigned int id;
  213.             struct FileHandle *fh;
  214.             
  215.             fh = BTOCPTR (dp->dp_Arg1);
  216.          cp = BTOCPTR (dp->dp_Arg3);
  217.          if (cp && fh)
  218.            {
  219.          bcopy (cp + 1, name, *cp);
  220.           name[*cp] = 0;
  221.         /* in case the device-qualifier is still contained in the name */
  222.         cp = index (name, ':');
  223.         if (cp)
  224.           cp++;
  225.         else
  226.           cp = name;
  227.         if (sscanf (cp, "%x", &id) == 1)
  228.           {
  229.             /* this fcntl() command does not require a valid 
  230.                descriptor. It's quite unique in this behavior... */
  231.             fd = fcntl (-1, F_INTERNALIZE, id);
  232.             if (fd >= 0)
  233.               {
  234.                 fh->fh_Arg1 = fd;
  235.                 fh->fh_Type = our_mp;
  236.                 fh->fh_Port = 0; /* we're not interactive, are we? */
  237.  
  238.             dprintf ("ixp-$%lx: successful open, fd = %ld\n", me, fd);
  239.             /* Setting the dn_Task field back to 0 makes each 
  240.                successive opening of IXPIPE: spawn a new handler.
  241.                This is essential, or opening would block, if the
  242.                handler is inside a read/write wait */
  243.                 dev_node->dn_Task = 0;
  244.                 returnpkt (dp, me, DOS_TRUE, 0);
  245.                 break;
  246.               }
  247.           }
  248.           }
  249.         dprintf ("ixp-$%lx: open failed somehow.. \n", me);
  250.         /* default is to return object-not-found.. */
  251.         returnpkt (dp, me, DOS_FALSE, ERROR_OBJECT_NOT_FOUND);
  252.         break;
  253.       }
  254.  
  255.  
  256.     /* all the following packets operate on file descriptors obtained
  257.        in ACTION_IXEMUL_MAGIC. */
  258.        
  259.     case ACTION_READ:
  260.       dprintf ("ixp-$%lx: read (%ld, $%lx, %ld)\n", me, dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  261.       dp->dp_Res1 = read (dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  262.       if (dp->dp_Res1 < 0)
  263.         dp->dp_Res2 = __errno_to_ioerr (*errno);
  264.       else
  265.         dp->dp_Res2 = 0;
  266.       returnpktplain (dp, me);
  267.       break;
  268.  
  269.     case ACTION_WRITE:
  270.       dprintf ("ixp-$%lx: write (%ld, $%lx, %ld)\n", me, dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  271.       dp->dp_Res1 = write (dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  272.       if (dp->dp_Res1 < 0)
  273.         dp->dp_Res2 = __errno_to_ioerr (*errno);
  274.       else
  275.         dp->dp_Res2 = 0;
  276.       returnpktplain (dp, me);
  277.       break;
  278.  
  279.     case ACTION_SEEK:
  280.       dprintf ("ixp-$%lx: lseek (%ld, %ld, %ld)\n", me, dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  281.       /* we have to return the previous offset, contrary to Unix which
  282.          returns the offset after seek operation */
  283.       dp->dp_Res1 = lseek (dp->dp_Arg1, 0, SEEK_CUR);
  284.       if (dp->dp_Res1 >= 0)
  285.         {
  286.           lseek (dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3 + 1);
  287.           dp->dp_Res2 = 0;
  288.         }
  289.       else
  290.         dp->dp_Res2 = __errno_to_ioerr (*errno);
  291.       returnpktplain (dp, me);
  292.       break;
  293.  
  294.     /* a little present for the growing number of >1.3 users out there */
  295.     case ACTION_EXAMINE_FH:
  296.       {
  297.          struct FileInfoBlock *fib = BTOCPTR (dp->dp_Arg2);
  298.         struct stat stb;
  299.         long time;
  300.         
  301.         dprintf ("ixp-$%lx: fstat (%ld, )\n", me, dp->dp_Arg1);
  302.         dp->dp_Res1 = fstat (dp->dp_Arg1, &stb) == 0 ? DOS_TRUE : DOS_FALSE;
  303.         dp->dp_Res2 = (dp->dp_Res1 == DOS_FALSE) ? __errno_to_ioerr (*errno) : 0;
  304.         if (dp->dp_Res1 == DOS_TRUE)
  305.           {
  306.         fib->fib_DiskKey = stb.st_ino;
  307.         /* on the packet level, fib's contain the name as a BSTR */
  308.         strcpy (fib->fib_FileName + 1, "you won't be able to reopen me anyway");
  309.         fib->fib_FileName[0] = strlen (fib->fib_FileName + 1);
  310.             fib->fib_Protection = stb.st_amode; /* nice we kept it ;-)) */
  311.         fib->fib_Size = stb.st_size;
  312.         fib->fib_NumBlocks = stb.st_blocks;
  313.         time = stb.st_mtime - (8*365+2)*24*3600; /* offset to unix-timesystem */
  314.         fib->fib_Date.ds_Tick = (time % 60) * TICKS_PER_SECOND;
  315.         time /= 60;
  316.         /* minutes per day, not minutes per hour! */
  317.         fib->fib_Date.ds_Minute = time % (60 * 24);
  318.         time /= 60 * 24;
  319.         fib->fib_Date.ds_Days = time;
  320.         fib->fib_Comment[0] = 0;
  321.         /* reserved stuff should normally be zero'd, so do right this */
  322.         bzero (fib->fib_Reserved, sizeof (fib->fib_Reserved));
  323.  
  324.         /* this is a bit tricky ;-)) 
  325.            Wondering what AmigaOS programs might do when they're faced
  326.            with a directory type when examining a filehandle.... */
  327.         if (S_ISDIR (stb.st_mode))
  328.           fib->fib_DirEntryType = ST_USERDIR;
  329.         else if (S_ISCHR (stb.st_mode))
  330.           fib->fib_DirEntryType = ST_PIPEFILE;
  331.         else if (S_ISLNK (stb.st_mode))
  332.           fib->fib_DirEntryType = ST_SOFTLINK;
  333.         else
  334.           fib->fib_DirEntryType = ST_FILE;
  335.  
  336.         fib->fib_EntryType = fib->fib_DirEntryType;
  337.           }
  338.         returnpktplain (dp, me);
  339.         break;
  340.       }
  341.  
  342.     case ACTION_END:
  343.       dprintf ("ixp-$%lx: close (%ld)\n", me, dp->dp_Arg1);
  344.       close (dp->dp_Arg1);
  345.       returnpkt (dp, me, DOS_TRUE, 0);
  346.       /* terminates the handler */
  347.       Forbid ();
  348.       return 0;
  349.       
  350.     default:
  351.       dprintf ("ixp-$%lx: returning unknown packet %ld\n", me, dp->dp_Type);
  352.       returnpkt (dp, me, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
  353.       break;
  354.     }
  355.     }
  356. }
  357.  
  358.  
  359. static int
  360. __errno_to_ioerr (int err)
  361. {
  362.   switch (err)
  363.     {
  364.     case EAGAIN:
  365.       return ERROR_TASK_TABLE_FULL;
  366.       
  367.     case ENOMEM:
  368.       return ERROR_NO_FREE_STORE;
  369.  
  370.     case E2BIG:
  371.       return ERROR_LINE_TOO_LONG;
  372.       
  373.     case ENOEXEC:
  374.       return ERROR_FILE_NOT_OBJECT;
  375.       
  376.     case EEXIST:
  377.       return ERROR_OBJECT_EXISTS;
  378.       
  379.     case ENOENT:
  380.       return ERROR_OBJECT_NOT_FOUND;
  381.       
  382.     default:
  383.     case ENODEV:
  384.     case EIO:
  385.       return ERROR_ACTION_NOT_KNOWN;
  386.       
  387.     case EINVAL:
  388.       return ERROR_OBJECT_WRONG_TYPE;
  389.       
  390.     case EROFS:
  391.       return ERROR_DISK_WRITE_PROTECTED;
  392.       
  393.     case EXDEV:
  394.       return ERROR_RENAME_ACROSS_DEVICES;
  395.       
  396.     case ENOTEMPTY:
  397.       return ERROR_DIRECTORY_NOT_EMPTY;
  398.       
  399.     case ELOOP:
  400.       return ERROR_TOO_MANY_LEVELS;
  401.       
  402.     case ENXIO:
  403.       return ERROR_DEVICE_NOT_MOUNTED;
  404.       
  405.     case ESPIPE:
  406.       return ERROR_SEEK_ERROR;
  407.       
  408.     case ENAMETOOLONG:
  409.       return ERROR_COMMENT_TOO_BIG;
  410.       
  411.     case ENOSPC:
  412.       return ERROR_DISK_FULL;
  413.       
  414.     case EACCES:
  415.       return ERROR_READ_PROTECTED;    /* could as well be one of the others... */
  416.     }
  417. }
  418.