home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / rmtlib2 / rmtlib.c < prev    next >
C/C++ Source or Header  |  1989-04-19  |  16KB  |  930 lines

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