home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume2 / remote / rmtlib.c < prev    next >
C/C++ Source or Header  |  1986-11-30  |  14KB  |  834 lines

  1. /*
  2.  *    rmt --- remote tape emulator subroutines
  3.  *
  4.  *    Originally written by Jeff Lee, modified some by Arnold Robbins
  5.  *
  6.  *    WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
  7.  *    tape protocol which rdump and rrestore use.  Unfortunately, the man
  8.  *    page is *WRONG*.  The author of the routines I'm including originally
  9.  *    wrote his code just based on the man page, and it didn't work, so he
  10.  *    went to the rdump source to figure out why.  The only thing he had to
  11.  *    change was to check for the 'F' return code in addition to the 'E',
  12.  *    and to separate the various arguments with \n instead of a space.  I
  13.  *    personally don't think that this is much of a problem, but I wanted to
  14.  *    point it out.
  15.  *    -- Arnold Robbins
  16.  *
  17.  *    Redone as a library that can replace open, read, write, etc, by
  18.  *    Fred Fish, with some additional work by Arnold Robbins.
  19.  */
  20.  
  21. /*
  22.  *    MAXUNIT --- Maximum number of remote tape file units
  23.  *
  24.  *    READ --- Return the number of the read side file descriptor
  25.  *    WRITE --- Return the number of the write side file descriptor
  26.  */
  27.  
  28. #define RMTIOCTL    1
  29.  
  30. #include <stdio.h>
  31. #include <signal.h>
  32. #include <sys/types.h>
  33.  
  34. #ifdef RMTIOCTL
  35. #include <sys/ioctl.h>
  36. #include <sys/mtio.h>
  37. #endif
  38.  
  39. #include <errno.h>
  40. #include <setjmp.h>
  41. #include <sys/stat.h>
  42.  
  43. #define BUFMAGIC    64    /* a magic number for buffer sizes */
  44. #define MAXUNIT    4
  45.  
  46. #define READ(fd)    (Ctp[fd][0])
  47. #define WRITE(fd)    (Ptc[fd][1])
  48.  
  49. static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  50. static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  51.  
  52. static jmp_buf Jmpbuf;
  53. extern int errno;
  54.  
  55. /*
  56.  *    abort --- close off a remote tape connection
  57.  */
  58.  
  59. static void abort(fildes)
  60. int fildes;
  61. {
  62.     close(READ(fildes));
  63.     close(WRITE(fildes));
  64.     READ(fildes) = -1;
  65.     WRITE(fildes) = -1;
  66. }
  67.  
  68.  
  69.  
  70. /*
  71.  *    command --- attempt to perform a remote tape command
  72.  */
  73.  
  74. static int command(fildes, buf)
  75. int fildes;
  76. char *buf;
  77. {
  78.     register int blen;
  79.     int (*pstat)();
  80.  
  81. /*
  82.  *    save current pipe status and try to make the request
  83.  */
  84.  
  85.     blen = strlen(buf);
  86.     pstat = signal(SIGPIPE, SIG_IGN);
  87.     if (write(WRITE(fildes), buf, blen) == blen)
  88.     {
  89.         signal(SIGPIPE, pstat);
  90.         return(0);
  91.     }
  92.  
  93. /*
  94.  *    something went wrong. close down and go home
  95.  */
  96.  
  97.     signal(SIGPIPE, pstat);
  98.     abort(fildes);
  99.  
  100.     errno = EIO;
  101.     return(-1);
  102. }
  103.  
  104.  
  105.  
  106. /*
  107.  *    status --- retrieve the status from the pipe
  108.  */
  109.  
  110. static int status(fildes)
  111. int fildes;
  112. {
  113.     int i;
  114.     char c, *cp;
  115.     char buffer[BUFMAGIC];
  116.  
  117. /*
  118.  *    read the reply command line
  119.  */
  120.  
  121.     for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
  122.     {
  123.         if (read(READ(fildes), cp, 1) != 1)
  124.         {
  125.             abort(fildes);
  126.             errno = EIO;
  127.             return(-1);
  128.         }
  129.         if (*cp == '\n')
  130.         {
  131.             *cp = 0;
  132.             break;
  133.         }
  134.     }
  135.  
  136.     if (i == BUFMAGIC)
  137.     {
  138.         abort(fildes);
  139.         errno = EIO;
  140.         return(-1);
  141.     }
  142.  
  143. /*
  144.  *    check the return status
  145.  */
  146.  
  147.     for (cp = buffer; *cp; cp++)
  148.         if (*cp != ' ')
  149.             break;
  150.  
  151.     if (*cp == 'E' || *cp == 'F')
  152.     {
  153.         errno = atoi(cp + 1);
  154.         while (read(READ(fildes), &c, 1) == 1)
  155.             if (c == '\n')
  156.                 break;
  157.  
  158.         if (*cp == 'F')
  159.             abort(fildes);
  160.  
  161.         return(-1);
  162.     }
  163.  
  164. /*
  165.  *    check for mis-synced pipes
  166.  */
  167.  
  168.     if (*cp != 'A')
  169.     {
  170.         abort(fildes);
  171.         errno = EIO;
  172.         return(-1);
  173.     }
  174.  
  175.     return(atoi(cp + 1));
  176. }
  177.  
  178.  
  179.  
  180. /*
  181.  *    _rmt_open --- open a magtape device on system specified, as given user
  182.  *
  183.  *    file name has the form system[.user]:/dev/????
  184.  */
  185.  
  186. #define MAXHOSTLEN    257    /* BSD allows very long host names... */
  187.  
  188. static int _rmt_open (path, oflag, mode)
  189. char *path;
  190. int oflag;
  191. int mode;
  192. {
  193.     int i, rc;
  194.     char buffer[BUFMAGIC];
  195.     char system[MAXHOSTLEN];
  196.     char device[BUFMAGIC];
  197.     char login[BUFMAGIC];
  198.     char *sys, *dev, *user;
  199.  
  200.     sys = system;
  201.     dev = device;
  202.     user = login;
  203.  
  204. /*
  205.  *    first, find an open pair of file descriptors
  206.  */
  207.  
  208.     for (i = 0; i < MAXUNIT; i++)
  209.         if (READ(i) == -1 && WRITE(i) == -1)
  210.             break;
  211.  
  212.     if (i == MAXUNIT)
  213.     {
  214.         errno = EMFILE;
  215.         return(-1);
  216.     }
  217.  
  218. /*
  219.  *    pull apart system and device, and optional user
  220.  *    don't munge original string
  221.  */
  222.     while (*path != '.' && *path != ':') {
  223.         *sys++ = *path++;
  224.     }
  225.     *sys = '\0';
  226.     path++;
  227.  
  228.     if (*(path - 1) == '.')
  229.     {
  230.         while (*path != ':') {
  231.             *user++ = *path++;
  232.         }
  233.         *user = '\0';
  234.         path++;
  235.     }
  236.     else
  237.         *user = '\0';
  238.  
  239.     while (*path) {
  240.         *dev++ = *path++;
  241.     }
  242.     *dev = '\0';
  243.  
  244. /*
  245.  *    setup the pipes for the 'rsh' command and fork
  246.  */
  247.  
  248.     if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
  249.         return(-1);
  250.  
  251.     if ((rc = fork()) == -1)
  252.         return(-1);
  253.  
  254.     if (rc == 0)
  255.     {
  256.         close(0);
  257.         dup(Ptc[i][0]);
  258.         close(Ptc[i][0]); close(Ptc[i][1]);
  259.         close(1);
  260.         dup(Ctp[i][1]);
  261.         close(Ctp[i][0]); close(Ctp[i][1]);
  262.         (void) setuid (getuid ());
  263.         (void) setgid (getgid ());
  264.         if (*user)
  265.         {
  266.             execl("/usr/ucb/rsh", "rsh", system, "-l", login,
  267.                 "/etc/rmt", (char *) 0);
  268.             execl("/usr/bin/remsh", "remsh", system, "-l", login,
  269.                 "/etc/rmt", (char *) 0);
  270.         }
  271.         else
  272.         {
  273.             execl("/usr/ucb/rsh", "rsh", system,
  274.                 "/etc/rmt", (char *) 0);
  275.             execl("/usr/bin/remsh", "remsh", system,
  276.                 "/etc/rmt", (char *) 0);
  277.         }
  278.  
  279. /*
  280.  *    bad problems if we get here
  281.  */
  282.  
  283.         perror("exec");
  284.         exit(1);
  285.     }
  286.  
  287.     close(Ptc[i][0]); close(Ctp[i][1]);
  288.  
  289. /*
  290.  *    now attempt to open the tape device
  291.  */
  292.  
  293.     sprintf(buffer, "O%s\n%d\n", device, oflag);
  294.     if (command(i, buffer) == -1 || status(i) == -1)
  295.         return(-1);
  296.  
  297.     return(i);
  298. }
  299.  
  300.  
  301.  
  302. /*
  303.  *    _rmt_close --- close a remote magtape unit and shut down
  304.  */
  305.  
  306. static int _rmt_close(fildes)
  307. int fildes;
  308. {
  309.     int rc;
  310.  
  311.     if (command(fildes, "C\n") != -1)
  312.     {
  313.         rc = status(fildes);
  314.  
  315.         abort(fildes);
  316.         return(rc);
  317.     }
  318.  
  319.     return(-1);
  320. }
  321.  
  322.  
  323.  
  324. /*
  325.  *    _rmt_read --- read a buffer from a remote tape
  326.  */
  327.  
  328. static int _rmt_read(fildes, buf, nbyte)
  329. int fildes;
  330. char *buf;
  331. unsigned int nbyte;
  332. {
  333.     int rc, i;
  334.     char buffer[BUFMAGIC];
  335.  
  336.     sprintf(buffer, "R%d\n", nbyte);
  337.     if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
  338.         return(-1);
  339.  
  340.     for (i = 0; i < rc; i += nbyte, buf += nbyte)
  341.     {
  342.         nbyte = read(READ(fildes), buf, rc);
  343.         if (nbyte <= 0)
  344.         {
  345.             abort(fildes);
  346.             errno = EIO;
  347.             return(-1);
  348.         }
  349.     }
  350.  
  351.     return(rc);
  352. }
  353.  
  354.  
  355.  
  356. /*
  357.  *    _rmt_write --- write a buffer to the remote tape
  358.  */
  359.  
  360. static int _rmt_write(fildes, buf, nbyte)
  361. int fildes;
  362. char *buf;
  363. unsigned int nbyte;
  364. {
  365.     int rc;
  366.     char buffer[BUFMAGIC];
  367.     int (*pstat)();
  368.  
  369.     sprintf(buffer, "W%d\n", nbyte);
  370.     if (command(fildes, buffer) == -1)
  371.         return(-1);
  372.  
  373.     pstat = signal(SIGPIPE, SIG_IGN);
  374.     if (write(WRITE(fildes), buf, nbyte) == nbyte)
  375.     {
  376.         signal (SIGPIPE, pstat);
  377.         return(status(fildes));
  378.     }
  379.  
  380.     signal (SIGPIPE, pstat);
  381.     abort(fildes);
  382.     errno = EIO;
  383.     return(-1);
  384. }
  385.  
  386.  
  387.  
  388. /*
  389.  *    _rmt_lseek --- perform an imitation lseek operation remotely
  390.  */
  391.  
  392. static long _rmt_lseek(fildes, offset, whence)
  393. int fildes;
  394. long offset;
  395. int whence;
  396. {
  397.     char buffer[BUFMAGIC];
  398.  
  399.     sprintf(buffer, "L%d\n%d\n", offset, whence);
  400.     if (command(fildes, buffer) == -1)
  401.         return(-1);
  402.  
  403.     return(status(fildes));
  404. }
  405.  
  406.  
  407. #ifdef RMTIOCTL
  408. /*
  409.  *    _rmt_ioctl --- perform raw tape operations remotely
  410.  */
  411.  
  412. static _rmt_ioctl(fildes, op, arg)
  413. int fildes, op;
  414. char *arg;
  415. {
  416.     char c;
  417.     int rc, cnt;
  418.     char buffer[BUFMAGIC];
  419.  
  420. /*
  421.  *    MTIOCOP is the easy one. nothing is transfered in binary
  422.  */
  423.  
  424.     if (op == MTIOCTOP)
  425.     {
  426.         sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  427.             ((struct mtop *) arg)->mt_count);
  428.         if (command(fildes, buffer) == -1)
  429.             return(-1);
  430.         return(status(fildes));
  431.     }
  432.  
  433. /*
  434.  *    we can only handle 2 ops, if not the other one, punt
  435.  */
  436.  
  437.     if (op != MTIOCGET)
  438.     {
  439.         errno = EINVAL;
  440.         return(-1);
  441.     }
  442.  
  443. /*
  444.  *    grab the status and read it directly into the structure
  445.  *    this assumes that the status buffer is (hopefully) not
  446.  *    padded and that 2 shorts fit in a long without any word
  447.  *    alignment problems, ie - the whole struct is contiguous
  448.  *    NOTE - this is probably NOT a good assumption.
  449.  */
  450.  
  451.     if (command(fildes, "S\n") == -1 || (rc = status(fildes)) == -1)
  452.         return(-1);
  453.  
  454.     for (; rc > 0; rc -= cnt, arg += cnt)
  455.     {
  456.         cnt = read(READ(fildes), arg, rc);
  457.         if (cnt <= 0)
  458.         {
  459.             abort(fildes);
  460.             errno = EIO;
  461.             return(-1);
  462.         }
  463.     }
  464.  
  465. /*
  466.  *    now we check for byte position. mt_type is a small integer field
  467.  *    (normally) so we will check its magnitude. if it is larger than
  468.  *    256, we will assume that the bytes are swapped and go through
  469.  *    and reverse all the bytes
  470.  */
  471.  
  472.     if (((struct mtget *) arg)->mt_type < 256)
  473.         return(0);
  474.  
  475.     for (cnt = 0; cnt < rc; cnt += 2)
  476.     {
  477.         c = arg[cnt];
  478.         arg[cnt] = arg[cnt+1];
  479.         arg[cnt+1] = c;
  480.     }
  481.  
  482.     return(0);
  483.   }
  484. #endif /* RMTIOCTL */
  485.  
  486. /*
  487.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  488.  *    The preprocessor can be used to remap these the rmtopen(), etc
  489.  *    thus minimizing source changes:
  490.  *
  491.  *        #ifdef REMOTETAPE
  492.  *        #  define access rmtaccess
  493.  *        #  define close rmtclose
  494.  *        #  define creat rmtcreat
  495.  *        #  define dup rmtdup
  496.  *        #  define fcntl rmtfcntl
  497.  *        #  define fstat rmtfstat
  498.  *        #  define ioctl rmtioctl
  499.  *        #  define isatty rmtisatty
  500.  *        #  define lseek rmtlseek
  501.  *        #  define lstat rmtlstat
  502.  *        #  define open rmtopen
  503.  *        #  define read rmtread
  504.  *        #  define stat rmtstat
  505.  *        #  define write rmtwrite
  506.  *        #  define access rmtaccess
  507.  *        #  define close rmtclose
  508.  *        #  define creat rmtcreat
  509.  *        #  define dup rmtdup
  510.  *        #  define fcntl rmtfcntl
  511.  *        #  define fstat rmtfstat
  512.  *        #  define ioctl rmtioctl
  513.  *        #  define lseek rmtlseek
  514.  *        #  define open rmtopen
  515.  *        #  define read rmtread
  516.  *        #  define stat rmtstat
  517.  *        #  define write rmtwrite
  518.  *        #endif
  519.  *
  520.  *    -- Fred Fish
  521.  *
  522.  *    ADR --- I set up a <rmt.h> include file for this
  523.  *
  524.  */
  525.  
  526. /*
  527.  *    Note that local vs remote file descriptors are distinquished
  528.  *    by adding a bias to the remote descriptors.  This is a quick
  529.  *    and dirty trick that may not be portable to some systems.
  530.  */
  531.  
  532. #define REM_BIAS 128
  533.  
  534.  
  535. /*
  536.  *    Test pathname to see if it is local or remote.  A remote device
  537.  *    is any string that contains ":/dev/".  Returns 1 if remote,
  538.  *    0 otherwise.
  539.  */
  540.  
  541. static int remdev (path)
  542. register char *path;
  543. {
  544. #define strchr    index
  545.     extern char *strchr ();
  546.  
  547.     if ((path = strchr (path, ':')) != NULL)
  548.     {
  549.         if (strncmp (path + 1, "/dev/", 5) == 0)
  550.         {
  551.             return (1);
  552.         }
  553.     }
  554.     return (0);
  555. }
  556.  
  557.  
  558. /*
  559.  *    Open a local or remote file.  Looks just like open(2) to
  560.  *    caller.
  561.  */
  562.  
  563. int rmtopen (path, oflag, mode)
  564. char *path;
  565. int oflag;
  566. int mode;
  567. {
  568.     if (remdev (path))
  569.     {
  570.         return (_rmt_open (path, oflag, mode) + REM_BIAS);
  571.     }
  572.     else
  573.     {
  574.         return (open (path, oflag, mode));
  575.     }
  576. }
  577.  
  578. /*
  579.  *    Test pathname for specified access.  Looks just like access(2)
  580.  *    to caller.
  581.  */
  582.  
  583. int rmtaccess (path, amode)
  584. char *path;
  585. int amode;
  586. {
  587.     if (remdev (path))
  588.     {
  589.         return (0);        /* Let /etc/rmt find out */
  590.     }
  591.     else
  592.     {
  593.         return (access (path, amode));
  594.     }
  595. }
  596.  
  597.  
  598. /*
  599.  *    Read from stream.  Looks just like read(2) to caller.
  600.  */
  601.   
  602. int rmtread (fildes, buf, nbyte)
  603. int fildes;
  604. char *buf;
  605. unsigned int nbyte;
  606. {
  607.     if (isrmt (fildes))
  608.     {
  609.         return (_rmt_read (fildes - REM_BIAS, buf, nbyte));
  610.     }
  611.     else
  612.     {
  613.         return (read (fildes, buf, nbyte));
  614.     }
  615. }
  616.  
  617.  
  618. /*
  619.  *    Write to stream.  Looks just like write(2) to caller.
  620.  */
  621.  
  622. int rmtwrite (fildes, buf, nbyte)
  623. int fildes;
  624. char *buf;
  625. unsigned int nbyte;
  626. {
  627.     if (isrmt (fildes))
  628.     {
  629.         return (_rmt_write (fildes - REM_BIAS, buf, nbyte));
  630.     }
  631.     else
  632.     {
  633.         return (write (fildes, buf, nbyte));
  634.     }
  635. }
  636.  
  637. /*
  638.  *    Perform lseek on file.  Looks just like lseek(2) to caller.
  639.  */
  640.  
  641. long rmtlseek (fildes, offset, whence)
  642. int fildes;
  643. long offset;
  644. int whence;
  645. {
  646.     if (isrmt (fildes))
  647.     {
  648.         return (_rmt_lseek (fildes - REM_BIAS, offset, whence));
  649.     }
  650.     else
  651.     {
  652.         return (lseek (fildes, offset, whence));
  653.     }
  654. }
  655.  
  656.  
  657. /*
  658.  *    Close a file.  Looks just like close(2) to caller.
  659.  */
  660.  
  661. int rmtclose (fildes)
  662. int fildes;
  663. {
  664.     if (isrmt (fildes))
  665.     {
  666.         return (_rmt_close (fildes - REM_BIAS));
  667.     }
  668.     else
  669.     {
  670.         return (close (fildes));
  671.     }
  672. }
  673.  
  674. /*
  675.  *    Do ioctl on file.  Looks just like ioctl(2) to caller.
  676.  */
  677.  
  678. int rmtioctl (fildes, request, arg)
  679. int fildes, request, arg;
  680. {
  681.     if (isrmt (fildes))
  682.     {
  683.         errno = EOPNOTSUPP;
  684.         return (-1);        /* For now  (fnf) */
  685.     }
  686.     else
  687.     {
  688.         return (ioctl (fildes, request, arg));
  689.     }
  690. }
  691.  
  692.  
  693. /*
  694.  *    Duplicate an open file descriptor.  Looks just like dup(2)
  695.  *    to caller.
  696.  */
  697.  
  698. int rmtdup (fildes)
  699. int fildes;
  700. {
  701.     if (isrmt (fildes))
  702.     {
  703.         errno = EOPNOTSUPP;
  704.         return (-1);        /* For now (fnf) */
  705.     }
  706.     else
  707.     {
  708.         return (dup (fildes));
  709.     }
  710. }
  711.  
  712. /*
  713.  *    Get file status.  Looks just like fstat(2) to caller.
  714.  */
  715.  
  716. int rmtfstat (fildes, buf)
  717. int fildes;
  718. struct stat *buf;
  719. {
  720.     if (isrmt (fildes))
  721.     {
  722.         errno = EOPNOTSUPP;
  723.         return (-1);        /* For now (fnf) */
  724.     }
  725.     else
  726.     {
  727.         return (fstat (fildes, buf));
  728.     }
  729. }
  730.  
  731.  
  732. /*
  733.  *    Get file status.  Looks just like stat(2) to caller.
  734.  */
  735.  
  736. int rmtstat (path, buf)
  737. char *path;
  738. struct stat *buf;
  739. {
  740.     if (remdev (path))
  741.     {
  742.         errno = EOPNOTSUPP;
  743.         return (-1);        /* For now (fnf) */
  744.     }
  745.     else
  746.     {
  747.         return (stat (path, buf));
  748.     }
  749. }
  750.  
  751.  
  752.  
  753. /*
  754.  *    Create a file from scratch.  Looks just like creat(2) to the caller.
  755.  */
  756.  
  757. #include <sys/file.h>        /* BSD DEPENDANT!!! */
  758. /* #include <fcntl.h>        /* use this one for S5 with remote stuff */
  759.  
  760. int rmtcreat (path, mode)
  761. char *path;
  762. int mode;
  763. {
  764.     if (remdev (path))
  765.     {
  766.         return (rmtopen (path, 1 | O_CREAT, mode));
  767.     }
  768.     else
  769.     {
  770.         return (creat (path, mode));
  771.     }
  772. }
  773.  
  774. /*
  775.  *    Isrmt. Let a programmer know he has a remote device.
  776.  */
  777.  
  778. int isrmt (fd)
  779. int fd;
  780. {
  781.     return (fd >= REM_BIAS);
  782. }
  783.  
  784. /*
  785.  *    Rmtfcntl. Do a remote fcntl operation.
  786.  */
  787.  
  788. int rmtfcntl (fd, cmd, arg)
  789. int fd, cmd, arg;
  790. {
  791.     if (isrmt (fd))
  792.     {
  793.         errno = EOPNOTSUPP;
  794.         return (-1);
  795.     }
  796.     else
  797.     {
  798.         return (fcntl (fd, cmd, arg));
  799.     }
  800. }
  801.  
  802. /*
  803.  *    Rmtisatty.  Do the isatty function.
  804.  */
  805.  
  806. int rmtisatty (fd)
  807. int fd;
  808. {
  809.     if (isrmt (fd))
  810.         return (0);
  811.     else
  812.         return (isatty (fd));
  813. }
  814.  
  815.  
  816. /*
  817.  *    Get file status, even if symlink.  Looks just like lstat(2) to caller.
  818.  */
  819.  
  820. int rmtlstat (path, buf)
  821. char *path;
  822. struct stat *buf;
  823. {
  824.     if (remdev (path))
  825.     {
  826.         errno = EOPNOTSUPP;
  827.         return (-1);        /* For now (fnf) */
  828.     }
  829.     else
  830.     {
  831.         return (lstat (path, buf));
  832.     }
  833. }
  834.