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