home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / AmiGNUtar.lha / AmiGNUtar / src.lha / src / rtape_lib.c < prev    next >
C/C++ Source or Header  |  1991-07-04  |  12KB  |  621 lines

  1. /* Remote tape emulator subroutines.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* JF: modified to make all rmtXXX calls into macros for speed */
  21.  
  22. #ifndef lint
  23. static char *RCSid = "$Header: /usr/src/local/usr.lib/librmt/RCS/rmtlib.c,v 1.7 89/03/23 14:09:51 root Exp Locker: root $";
  24. #endif
  25.  
  26. /*
  27.  * $Log:    rmtlib.c,v $
  28.  * Revision 1.7  89/03/23  14:09:51  root
  29.  * Fix from haynes@ucscc.ucsc.edu for use w/compat. ADR.
  30.  *
  31.  * Revision 1.6  88/10/25  17:04:29  root
  32.  * rexec code and a bug fix from srs!dan, miscellanious cleanup. ADR.
  33.  *
  34.  * Revision 1.5  88/10/25  16:30:17  root
  35.  * Fix from jeff@gatech.edu for getting user@host:dev right. ADR.
  36.  *
  37.  * Revision 1.4  87/10/30  10:36:12  root
  38.  * Made 4.2 syntax a compile time option. ADR.
  39.  *
  40.  * Revision 1.3  87/04/22  11:16:48  root
  41.  * Two fixes from parmelee@wayback.cs.cornell.edu to correctly
  42.  * do fd biasing and rmt protocol on 'S' command. ADR.
  43.  *
  44.  * Revision 1.2  86/10/09  16:38:53  root
  45.  * Changed to reflect 4.3BSD rcp syntax. ADR.
  46.  *
  47.  * Revision 1.1  86/10/09  16:17:35  root
  48.  * Initial revision
  49.  *
  50.  */
  51.  
  52. /*
  53.  *    rmt --- remote tape emulator subroutines
  54.  *
  55.  *    Originally written by Jeff Lee, modified some by Arnold Robbins
  56.  *
  57.  *    WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
  58.  *    tape protocol which rdump and rrestore use.  Unfortunately, the man
  59.  *    page is *WRONG*.  The author of the routines I'm including originally
  60.  *    wrote his code just based on the man page, and it didn't work, so he
  61.  *    went to the rdump source to figure out why.  The only thing he had to
  62.  *    change was to check for the 'F' return code in addition to the 'E',
  63.  *    and to separate the various arguments with \n instead of a space.  I
  64.  *    personally don't think that this is much of a problem, but I wanted to
  65.  *    point it out.
  66.  *    -- Arnold Robbins
  67.  *
  68.  *    Redone as a library that can replace open, read, write, etc, by
  69.  *    Fred Fish, with some additional work by Arnold Robbins.
  70.  */
  71.  
  72. /*
  73.  *    MAXUNIT --- Maximum number of remote tape file units
  74.  *
  75.  *    READ --- Return the number of the read side file descriptor
  76.  *    WRITE --- Return the number of the write side file descriptor
  77.  */
  78.  
  79. #define RMTIOCTL    1
  80. /* #define USE_REXEC    1    /* rexec code courtesy of Dan Kegel, srs!dan */
  81.  
  82. #include <stdio.h>
  83. #include <signal.h>
  84. #include <sys/types.h>
  85.  
  86. #ifdef RMTIOCTL
  87. #include <sys/ioctl.h>
  88. #include <sys/mtio.h>
  89. #endif
  90.  
  91. #ifdef USE_REXEC
  92. #include <netdb.h>
  93. #endif
  94.  
  95. #include <errno.h>
  96. #include <setjmp.h>
  97. #include <sys/stat.h>
  98.  
  99. #define BUFMAGIC    64    /* a magic number for buffer sizes */
  100. #define MAXUNIT 4
  101.  
  102. #define READ(fd)        (Ctp[fd][0])
  103. #define WRITE(fd)       (Ptc[fd][1])
  104.  
  105. static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  106. static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  107.  
  108. extern int errno;
  109.  
  110. char *__rmt_path;
  111.  
  112. /*
  113.  *    _rmt_panic --- close off a remote tape connection
  114.  */
  115.  
  116. static void _rmt_panic(fildes)
  117. int fildes;
  118. {
  119.     close(READ(fildes));
  120.     close(WRITE(fildes));
  121.     READ(fildes) = -1;
  122.     WRITE(fildes) = -1;
  123. }
  124.  
  125.  
  126.  
  127. /*
  128.  *    command --- attempt to perform a remote tape command
  129.  */
  130.  
  131. static int command(fildes, buf)
  132. int fildes;
  133. char *buf;
  134. {
  135.     register int blen;
  136. #ifdef USG
  137.     void (*pstat)();
  138. #else
  139.     int (*pstat)();
  140. #endif
  141.  
  142. /*
  143.  *    save current pipe status and try to make the request
  144.  */
  145.  
  146.     blen = strlen(buf);
  147.     pstat = signal(SIGPIPE, SIG_IGN);
  148.     if (write(WRITE(fildes), buf, blen) == blen)
  149.     {
  150.         signal(SIGPIPE, pstat);
  151.         return(0);
  152.     }
  153.  
  154. /*
  155.  *    something went wrong. close down and go home
  156.  */
  157.  
  158.     signal(SIGPIPE, pstat);
  159.     _rmt_panic(fildes);
  160.  
  161.     errno = EIO;
  162.     return(-1);
  163. }
  164.  
  165.  
  166.  
  167. /*
  168.  *    status --- retrieve the status from the pipe
  169.  */
  170.  
  171. static int status(fildes)
  172. int fildes;
  173. {
  174.     int i;
  175.     char c, *cp;
  176.     char buffer[BUFMAGIC];
  177.  
  178. /*
  179.  *    read the reply command line
  180.  */
  181.  
  182.     for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
  183.     {
  184.         if (read(READ(fildes), cp, 1) != 1)
  185.         {
  186.             _rmt_panic(fildes);
  187.             errno = EIO;
  188.             return(-1);
  189.         }
  190.         if (*cp == '\n')
  191.         {
  192.             *cp = 0;
  193.             break;
  194.         }
  195.     }
  196.  
  197.     if (i == BUFMAGIC)
  198.     {
  199.         _rmt_panic(fildes);
  200.         errno = EIO;
  201.         return(-1);
  202.     }
  203.  
  204. /*
  205.  *    check the return status
  206.  */
  207.  
  208.     for (cp = buffer; *cp; cp++)
  209.         if (*cp != ' ')
  210.             break;
  211.  
  212.     if (*cp == 'E' || *cp == 'F')
  213.     {
  214.         errno = atoi(cp + 1);
  215.         while (read(READ(fildes), &c, 1) == 1)
  216.             if (c == '\n')
  217.                 break;
  218.  
  219.         if (*cp == 'F')
  220.             _rmt_panic(fildes);
  221.  
  222.         return(-1);
  223.     }
  224.  
  225. /*
  226.  *    check for mis-synced pipes
  227.  */
  228.  
  229.     if (*cp != 'A')
  230.     {
  231.         _rmt_panic(fildes);
  232.         errno = EIO;
  233.         return(-1);
  234.     }
  235.  
  236.     return(atoi(cp + 1));
  237. }
  238.  
  239. #ifdef USE_REXEC
  240.  
  241. /*
  242.  * _rmt_rexec
  243.  *
  244.  * execute /etc/rmt on a remote system using rexec().
  245.  * Return file descriptor of bidirectional socket for stdin and stdout
  246.  * If username is NULL, or an empty string, uses current username.
  247.  *
  248.  * ADR: By default, this code is not used, since it requires that
  249.  * the user have a .netrc file in his/her home directory, or that the
  250.  * application designer be willing to have rexec prompt for login and
  251.  * password info. This may be unacceptable, and .rhosts files for use
  252.  * with rsh are much more common on BSD systems.
  253.  */
  254.  
  255. static int
  256. _rmt_rexec(host, user)
  257. char *host;
  258. char *user;        /* may be NULL */
  259. {
  260.     struct servent *rexecserv;
  261.  
  262.     rexecserv = getservbyname("exec", "tcp");
  263.     if (NULL == rexecserv) {
  264.         fprintf (stderr, "? exec/tcp: service not available.");
  265.         exit (-1);
  266.     }
  267.     if ((user != NULL) && *user == '\0')
  268.         user = (char *) NULL;
  269.     return rexec (&host, rexecserv->s_port, user, NULL,
  270.             "/etc/rmt", (int *)NULL);
  271. }
  272. #endif /* USE_REXEC */
  273.  
  274. /*
  275.  *    _rmt_open --- open a magtape device on system specified, as given user
  276.  *
  277.  *    file name has the form [user@]system:/dev/????
  278. #ifdef COMPAT
  279.  *    file name has the form system[.user]:/dev/????
  280. #endif
  281.  */
  282.  
  283. #define MAXHOSTLEN    257    /* BSD allows very long host names... */
  284.  
  285. int __rmt_open (path, oflag, mode, bias)
  286. char *path;
  287. int oflag;
  288. int mode;
  289. int bias;
  290. {
  291.     int i, rc;
  292.     static char buffer[BUFMAGIC];
  293.     static char system[MAXHOSTLEN];
  294.     static char device[BUFMAGIC];
  295.     static char login[BUFMAGIC];
  296.     char *sys, *dev, *user;
  297.  
  298.     sys = system;
  299.     dev = device;
  300.     user = login;
  301.  
  302. /*
  303.  *    first, find an open pair of file descriptors
  304.  */
  305.  
  306.     for (i = 0; i < MAXUNIT; i++)
  307.         if (READ(i) == -1 && WRITE(i) == -1)
  308.             break;
  309.  
  310.     if (i == MAXUNIT)
  311.     {
  312.         errno = EMFILE;
  313.         return(-1);
  314.     }
  315.  
  316. /*
  317.  *    pull apart system and device, and optional user
  318.  *    don't munge original string
  319.  *    if COMPAT is defined, also handle old (4.2) style person.site notation.
  320.  */
  321.  
  322.     while (*path != '@'
  323. #ifdef COMPAT
  324.             && *path != '.'
  325. #endif
  326.             && *path != ':') {
  327.         *sys++ = *path++;
  328.     }
  329.     *sys = '\0';
  330.     path++;
  331.  
  332.     if (*(path - 1) == '@')
  333.     {
  334.         (void) strcpy (user, system);   /* saw user part of user@host */
  335.         sys = system;            /* start over */
  336.         while (*path != ':') {
  337.             *sys++ = *path++;
  338.         }
  339.         *sys = '\0';
  340.         path++;
  341.     }
  342. #ifdef COMPAT
  343.     else if (*(path - 1) == '.')
  344.     {
  345.         while (*path != ':') {
  346.             *user++ = *path++;
  347.         }
  348.         *user = '\0';
  349.         path++;
  350.     }
  351. #endif
  352.     else
  353.         *user = '\0';
  354.  
  355.     while (*path) {
  356.         *dev++ = *path++;
  357.     }
  358.     *dev = '\0';
  359.  
  360. #ifdef USE_REXEC
  361. /*
  362.  *    Execute the remote command using rexec
  363.  */
  364.     READ(i) = WRITE(i) = _rmt_rexec(system, login);
  365.     if (READ(i) < 0)
  366.         return -1;
  367. #else
  368. /*
  369.  *    setup the pipes for the 'rsh' command and fork
  370.  */
  371.  
  372.     if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
  373.         return(-1);
  374.  
  375.     if ((rc = fork()) == -1)
  376.         return(-1);
  377.  
  378.     if (rc == 0)
  379.     {
  380.         close(0);
  381.         dup(Ptc[i][0]);
  382.         close(Ptc[i][0]); close(Ptc[i][1]);
  383.         close(1);
  384.         dup(Ctp[i][1]);
  385.         close(Ctp[i][0]); close(Ctp[i][1]);
  386.         (void) setuid (getuid ());
  387.         (void) setgid (getgid ());
  388.         if (*login)
  389.         {
  390.             execl("/usr/ucb/rsh", "rsh", system, "-l", login,
  391.                 "/etc/rmt", (char *) 0);
  392.             execl("/usr/bin/remsh", "remsh", system, "-l", login,
  393.                 "/etc/rmt", (char *) 0);
  394.             execl("/usr/bin/rsh", "rsh", system, "-l", login,
  395.                 "/etc/rmt", (char *) 0);
  396.             execl("/usr/bsd/rsh", "rsh", system, "-l", login,
  397.                 "/etc/rmt", (char *)0);
  398.         }
  399.         else
  400.         {
  401.             execl("/usr/ucb/rsh", "rsh", system,
  402.                 "/etc/rmt", (char *) 0);
  403.             execl("/usr/bin/remsh", "remsh", system,
  404.                 "/etc/rmt", (char *) 0);
  405.             execl("/usr/bin/rsh", "rsh", system,
  406.                 "/etc/rmt", (char *) 0);
  407.             execl("/usr/bsd/rsh", "rsh", system,
  408.                 "/etc/rmt", (char *) 0);
  409.         }
  410.  
  411. /*
  412.  *    bad problems if we get here
  413.  */
  414.  
  415.         perror("remote shell exec");
  416.         exit(1);
  417.     }
  418.  
  419.     close(Ptc[i][0]); close(Ctp[i][1]);
  420. #endif
  421.  
  422. /*
  423.  *    now attempt to open the tape device
  424.  */
  425.  
  426.     sprintf(buffer, "O%s\n%d\n", device, oflag);
  427.     if (command(i, buffer) == -1 || status(i) == -1)
  428.         return(-1);
  429.  
  430.     return(i+bias);
  431. }
  432.  
  433.  
  434.  
  435. /*
  436.  *    _rmt_close --- close a remote magtape unit and shut down
  437.  */
  438.  
  439.  int __rmt_close(fildes)
  440. int fildes;
  441. {
  442.     int rc;
  443.  
  444.     if (command(fildes, "C\n") != -1)
  445.     {
  446.         rc = status(fildes);
  447.  
  448.         _rmt_panic(fildes);
  449.         return(rc);
  450.     }
  451.  
  452.     return(-1);
  453. }
  454.  
  455.  
  456.  
  457. /*
  458.  *    _rmt_read --- read a buffer from a remote tape
  459.  */
  460.  
  461. int __rmt_read(fildes, buf, nbyte)
  462. int fildes;
  463. char *buf;
  464. unsigned int nbyte;
  465. {
  466.     int rc, i;
  467.     static char buffer[BUFMAGIC];
  468.  
  469.     sprintf(buffer, "R%d\n", nbyte);
  470.     if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
  471.         return(-1);
  472.  
  473.     for (i = 0; i < rc; i += nbyte, buf += nbyte)
  474.     {
  475.         nbyte = read(READ(fildes), buf, rc);
  476.         if (nbyte <= 0)
  477.         {
  478.             _rmt_panic(fildes);
  479.             errno = EIO;
  480.             return(-1);
  481.         }
  482.     }
  483.  
  484.     return(rc);
  485. }
  486.  
  487.  
  488.  
  489. /*
  490.  *    _rmt_write --- write a buffer to the remote tape
  491.  */
  492.  
  493. int __rmt_write(fildes, buf, nbyte)
  494. int fildes;
  495. char *buf;
  496. unsigned int nbyte;
  497. {
  498.     static char buffer[BUFMAGIC];
  499. #ifdef USG
  500.     void (*pstat)();
  501. #else
  502.     int (*pstat)();
  503. #endif
  504.  
  505.     sprintf(buffer, "W%d\n", nbyte);
  506.     if (command(fildes, buffer) == -1)
  507.         return(-1);
  508.  
  509.     pstat = signal(SIGPIPE, SIG_IGN);
  510.     if (write(WRITE(fildes), buf, nbyte) == nbyte)
  511.     {
  512.         signal (SIGPIPE, pstat);
  513.         return(status(fildes));
  514.     }
  515.  
  516.     signal (SIGPIPE, pstat);
  517.     _rmt_panic(fildes);
  518.     errno = EIO;
  519.     return(-1);
  520. }
  521.  
  522.  
  523.  
  524. /*
  525.  *    _rmt_lseek --- perform an imitation lseek operation remotely
  526.  */
  527.  
  528. long __rmt_lseek(fildes, offset, whence)
  529. int fildes;
  530. long offset;
  531. int whence;
  532. {
  533.     static char buffer[BUFMAGIC];
  534.  
  535.     sprintf(buffer, "L%d\n%d\n", offset, whence);
  536.     if (command(fildes, buffer) == -1)
  537.         return(-1);
  538.  
  539.     return(status(fildes));
  540. }
  541.  
  542.  
  543. /*
  544.  *    _rmt_ioctl --- perform raw tape operations remotely
  545.  */
  546.  
  547. #ifdef RMTIOCTL
  548. __rmt_ioctl(fildes, op, arg)
  549. int fildes, op;
  550. char *arg;
  551. {
  552.     char c;
  553.     int rc, cnt;
  554.     static char buffer[BUFMAGIC];
  555.  
  556. /*
  557.  *    MTIOCOP is the easy one. nothing is transfered in binary
  558.  */
  559.  
  560.     if (op == MTIOCTOP)
  561.     {
  562.         sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  563.             ((struct mtop *) arg)->mt_count);
  564.         if (command(fildes, buffer) == -1)
  565.             return(-1);
  566.         return(status(fildes));
  567.     }
  568.  
  569. /*
  570.  *    we can only handle 2 ops, if not the other one, punt
  571.  */
  572.  
  573.     if (op != MTIOCGET)
  574.     {
  575.         errno = EINVAL;
  576.         return(-1);
  577.     }
  578.  
  579. /*
  580.  *    grab the status and read it directly into the structure
  581.  *    this assumes that the status buffer is (hopefully) not
  582.  *    padded and that 2 shorts fit in a long without any word
  583.  *    alignment problems, ie - the whole struct is contiguous
  584.  *    NOTE - this is probably NOT a good assumption.
  585.  */
  586.  
  587.     if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
  588.         return(-1);
  589.  
  590.     for (; rc > 0; rc -= cnt, arg += cnt)
  591.     {
  592.         cnt = read(READ(fildes), arg, rc);
  593.         if (cnt <= 0)
  594.         {
  595.             _rmt_panic(fildes);
  596.             errno = EIO;
  597.             return(-1);
  598.         }
  599.     }
  600.  
  601. /*
  602.  *    now we check for byte position. mt_type is a small integer field
  603.  *    (normally) so we will check its magnitude. if it is larger than
  604.  *    256, we will assume that the bytes are swapped and go through
  605.  *    and reverse all the bytes
  606.  */
  607.  
  608.     if (((struct mtget *) arg)->mt_type < 256)
  609.         return(0);
  610.  
  611.     for (cnt = 0; cnt < rc; cnt += 2)
  612.     {
  613.         c = arg[cnt];
  614.         arg[cnt] = arg[cnt+1];
  615.         arg[cnt+1] = c;
  616.     }
  617.  
  618.     return(0);
  619.   }
  620. #endif /* RMTIOCTL */
  621.