home *** CD-ROM | disk | FTP | other *** search
/ linuxmafia.com 2016 / linuxmafia.com.tar / linuxmafia.com / pub / linux / backup / star-1.3.1.tar.gz / star-1.3.1.tar / star-1.3.1 / star / remote.c < prev    next >
C/C++ Source or Header  |  2000-11-12  |  14KB  |  699 lines

  1. /*#define    USE_REMOTE*/
  2. #ifdef    USE_REMOTE
  3. /* @(#)remote.c    1.22 00/11/12 Copyright 1990 J. Schilling */
  4. #ifndef lint
  5. static    char sccsid[] =
  6.     "@(#)remote.c    1.22 00/11/12 Copyright 1990 J. Schilling";
  7. #endif
  8. /*
  9.  *    Remote tape interface
  10.  *
  11.  *    Copyright (c) 1990 J. Schilling
  12.  */
  13. /*
  14.  * This program is free software; you can redistribute it and/or modify
  15.  * it under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2, or (at your option)
  17.  * any later version.
  18.  *
  19.  * This program is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  * GNU General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; see the file COPYING.  If not, write to
  26.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  27.  */
  28.  
  29. #include <mconfig.h>
  30. #include <stdio.h>
  31. #include <sys/types.h>
  32. #include <fctldefs.h>
  33. #ifdef    HAVE_SYS_MTIO_H
  34. #include <sys/mtio.h>
  35. #else
  36. #include "mtio.h"
  37. #endif
  38. #include <sys/ioctl.h>
  39. #include <sys/socket.h>
  40. #include <errno.h>
  41. #include <signal.h>
  42. #include <netdb.h>
  43. #include <pwd.h>
  44. #include <standard.h>
  45. #include <stdxlib.h>
  46. #include <unixstd.h>
  47. #include <strdefs.h>
  48. #include <schily.h>
  49. #include "remote.h"
  50.  
  51. #if    defined(SIGDEFER) || defined(SVR4)
  52. #define    signal    sigset
  53. #endif
  54.  
  55. #define    CMD_SIZE    80
  56.  
  57. extern    BOOL    debug;
  58.  
  59. LOCAL    void    rmtabrt            __PR((int sig));
  60. EXPORT    int    rmtgetconn        __PR((char* host, int size));
  61. LOCAL    void    rmtoflags        __PR((int fmode, char *cmode));
  62. EXPORT    int    rmtopen            __PR((int fd, char* fname, int fmode));
  63. EXPORT    int    rmtclose        __PR((int fd));
  64. EXPORT    int    rmtread            __PR((int fd, char* buf, int count));
  65. EXPORT    int    rmtwrite        __PR((int fd, char* buf, int count));
  66. EXPORT    int    rmtseek            __PR((int fd, long offset, int whence));
  67. EXPORT    int    rmtioctl        __PR((int fd, int cmd, int count));
  68. LOCAL    int    rmtmapold        __PR((int cmd));
  69. LOCAL    int    rmtmapnew        __PR((int cmd));
  70. LOCAL    int    rmtxstatus        __PR((int fd, int cmd));
  71. LOCAL    struct    mtget* rmt_v1_status    __PR((int fd));
  72. EXPORT    struct    mtget* rmtstatus    __PR((int fd));
  73. LOCAL    int    rmtcmd            __PR((int fd, char* name, char* cbuf));
  74. LOCAL    void    rmtsendcmd        __PR((int fd, char* name, char* cbuf));
  75. LOCAL    int    rmtgetline        __PR((int fd, char* line, int count));
  76. LOCAL    int    rmtgetstatus        __PR((int fd, char* name));
  77. LOCAL    int    rmtaborted        __PR((int fd));
  78.  
  79. LOCAL void
  80. rmtabrt(sig)
  81.     int    sig;
  82. {
  83.     rmtaborted(-1);
  84. }
  85.  
  86. EXPORT int
  87. rmtgetconn(host, size)
  88.     char    *host;
  89.     int    size;
  90. {
  91.     static    struct servent    *sp = 0;
  92.     static    struct passwd    *pw = 0;
  93.         char        *name = "root";
  94.         char        *p;
  95.         int        rmtsock;
  96.         char        *rmtpeer;
  97.         char        rmtuser[128];
  98.  
  99.  
  100.     signal(SIGPIPE, rmtabrt);
  101.     if (sp == 0) {
  102.         sp = getservbyname("shell", "tcp");
  103.         if (sp == 0) {
  104.             comerrno(EX_BAD, "shell/tcp: unknown service\n");
  105.             /* NOTREACHED */
  106.         }
  107.         pw = getpwuid(getuid());
  108.         if (pw == 0) {
  109.             comerrno(EX_BAD, "who are you? No passwd entry found.\n");
  110.             /* NOTREACHED */
  111.         }
  112.     }
  113.     if ((p = strchr(host, '@')) != NULL) {
  114.         js_snprintf(rmtuser, sizeof(rmtuser), "%.*s", p - host, host);
  115.         name = rmtuser;
  116.         host = &p[1];
  117.     } else {
  118.         name = pw->pw_name;
  119.     }
  120.     if (debug)
  121.         errmsgno(EX_BAD, "locuser: '%s' rmtuser: '%s' host: '%s'\n",
  122.                         pw->pw_name, name, host);
  123.     rmtpeer = host;
  124.     rmtsock = rcmd(&rmtpeer, (unsigned short)sp->s_port,
  125.                     pw->pw_name, name, "/etc/rmt", 0);
  126. /*                    pw->pw_name, name, "/etc/xrmt", 0);*/
  127.  
  128.     if (rmtsock < 0)
  129.         return (-1);
  130.  
  131.  
  132. #ifdef    SO_SNDBUF
  133.     while (size > 512 &&
  134.         setsockopt(rmtsock, SOL_SOCKET, SO_SNDBUF,
  135.                     (char *)&size, sizeof (size)) < 0) {
  136.         size -= 512;
  137.     }
  138.     if (debug)
  139.         errmsgno(EX_BAD, "sndsize: %d\n", size);
  140. #endif
  141. #ifdef    SO_RCVBUF
  142.     while (size > 512 &&
  143.         setsockopt(rmtsock, SOL_SOCKET, SO_RCVBUF,
  144.                     (char *)&size, sizeof (size)) < 0) {
  145.         size -= 512;
  146.     }
  147.     if (debug)
  148.         errmsgno(EX_BAD, "rcvsize: %d\n", size);
  149. #endif
  150.  
  151.     return (rmtsock);
  152. }
  153.  
  154. LOCAL void
  155. rmtoflags(fmode, cmode)
  156.     int    fmode;
  157.     char    *cmode;
  158. {
  159.     register char    *p;
  160.     register int    amt;
  161.     register int    maxcnt = CMD_SIZE;
  162.  
  163.     switch (fmode & O_ACCMODE) {
  164.  
  165.     case O_RDONLY:    p = "O_RDONLY";    break;
  166.     case O_RDWR:    p = "O_RDWR";    break;
  167.     case O_WRONLY:    p = "O_WRONLY";    break;
  168.  
  169.     default:    p = "Cannot Happen";
  170.     }
  171.     amt = js_snprintf(cmode, maxcnt, p); if (amt < 0) return;
  172.     p = cmode;
  173.     p += amt;
  174.     maxcnt -= amt;
  175. #ifdef    O_TEXT
  176.     if (fmode & O_TEXT) {
  177.         amt = js_snprintf(p, maxcnt, "|O_TEXT"); if (amt < 0) return;
  178.         p += amt;
  179.         maxcnt -= amt;
  180.     }
  181. #endif
  182. #ifdef    O_NDELAY
  183.     if (fmode & O_NDELAY) {
  184.         amt = js_snprintf(p, maxcnt, "|O_NDELAY"); if (amt < 0) return;
  185.         p += amt;
  186.         maxcnt -= amt;
  187.     }
  188. #endif
  189. #ifdef    O_APPEND
  190.     if (fmode & O_APPEND) {
  191.         amt = js_snprintf(p, maxcnt, "|O_APPEND"); if (amt < 0) return;
  192.         p += amt;
  193.         maxcnt -= amt;
  194.     }
  195. #endif
  196. #ifdef    O_SYNC
  197.     if (fmode & O_SYNC) {
  198.         amt = js_snprintf(p, maxcnt, "|O_SYNC"); if (amt < 0) return;
  199.         p += amt;
  200.         maxcnt -= amt;
  201.     }
  202. #endif
  203. #ifdef    O_DSYNC
  204.     if (fmode & O_DSYNC) {
  205.         amt = js_snprintf(p, maxcnt, "|O_DSYNC"); if (amt < 0) return;
  206.         p += amt;
  207.         maxcnt -= amt;
  208.     }
  209. #endif
  210. #ifdef    O_RSYNC
  211.     if (fmode & O_RSYNC) {
  212.         amt = js_snprintf(p, maxcnt, "|O_RSYNC"); if (amt < 0) return;
  213.         p += amt;
  214.         maxcnt -= amt;
  215.     }
  216. #endif
  217. #ifdef    O_NONBLOCK
  218.     if (fmode & O_NONBLOCK) {
  219.         amt = js_snprintf(p, maxcnt, "|O_NONBLOCK"); if (amt < 0) return;
  220.         p += amt;
  221.         maxcnt -= amt;
  222.     }
  223. #endif
  224. #ifdef    O_PRIV
  225.     if (fmode & O_PRIV) {
  226.         amt = js_snprintf(p, maxcnt, "|O_PRIV"); if (amt < 0) return;
  227.         p += amt;
  228.         maxcnt -= amt;
  229.     }
  230. #endif
  231. #ifdef    O_LARGEFILE
  232.     if (fmode & O_LARGEFILE) {
  233.         amt = js_snprintf(p, maxcnt, "|O_LARGEFILE"); if (amt < 0) return;
  234.         p += amt;
  235.         maxcnt -= amt;
  236.     }
  237. #endif
  238. #ifdef    O_CREAT
  239.     if (fmode & O_CREAT) {
  240.         amt = js_snprintf(p, maxcnt, "|O_CREAT"); if (amt < 0) return;
  241.         p += amt;
  242.         maxcnt -= amt;
  243.     }
  244. #endif
  245. #ifdef    O_TRUNC
  246.     if (fmode & O_TRUNC) {
  247.         amt = js_snprintf(p, maxcnt, "|O_TRUNC"); if (amt < 0) return;
  248.         p += amt;
  249.         maxcnt -= amt;
  250.     }
  251. #endif
  252. #ifdef    O_EXCL
  253.     if (fmode & O_EXCL) {
  254.         amt = js_snprintf(p, maxcnt, "|O_EXCL"); if (amt < 0) return;
  255.         p += amt;
  256.         maxcnt -= amt;
  257.     }
  258. #endif
  259. #ifdef    O_NOCTTY
  260.     if (fmode & O_NOCTTY) {
  261.         amt = js_snprintf(p, maxcnt, "|O_NOCTTY"); if (amt < 0) return;
  262.         p += amt;
  263.         maxcnt -= amt;
  264.     }
  265. #endif
  266. }
  267.  
  268. EXPORT int
  269. rmtopen(fd, fname, fmode)
  270.     int    fd;
  271.     char    *fname;
  272.     int    fmode;
  273. {
  274.     char    cbuf[CMD_SIZE];
  275.     char    cmode[CMD_SIZE];
  276.     int    ret;
  277.  
  278.     /*
  279.      * Convert all fmode bits into the symbolic fmode.
  280.      * only send the lowest 2 bits in numeric mode as it would be too
  281.      * dangerous because the apropriate bits differ between different
  282.      * operating systems.
  283.      */
  284.     rmtoflags(fmode, cmode);
  285.     js_snprintf(cbuf, CMD_SIZE, "O%s\n%d %s\n", fname, fmode & O_ACCMODE, cmode);
  286.     ret = rmtcmd(fd, "open", cbuf);
  287.  
  288.     /*
  289.      * Tell the rmt server that we are aware of Version 1 commands.
  290.      */
  291. /*    (void)rmtioctl(fd, RMTIVERSION, 0);*/
  292.     (void)rmtioctl(fd, -1, 0);
  293.  
  294.     return (ret);
  295. }
  296.  
  297. EXPORT int
  298. rmtclose(fd)
  299.     int    fd;
  300. {
  301.     return (rmtcmd(fd, "close", "C\n"));
  302. }
  303.  
  304. EXPORT int
  305. rmtread(fd, buf, count)
  306.     int    fd;
  307.     char    *buf;
  308.     int    count;
  309. {
  310.     char    cbuf[CMD_SIZE];
  311.     int    n;
  312.     int    amt = 0;
  313.     int    cnt;
  314.  
  315.     js_snprintf(cbuf, CMD_SIZE, "R%d\n", count);
  316.     n = rmtcmd(fd, "read", cbuf);
  317.     if (n < 0)
  318.         return (-1);
  319.  
  320.     while (amt < n) {
  321.         if ((cnt = read(fd, &buf[amt], n - amt)) <= 0) {
  322.             return (rmtaborted(fd));
  323.         }
  324.         amt += cnt;
  325.     }
  326.  
  327.     return (amt);
  328. }
  329.  
  330. EXPORT int
  331. rmtwrite(fd, buf, count)
  332.     int    fd;
  333.     char    *buf;
  334.     int    count;
  335. {
  336.     char    cbuf[CMD_SIZE];
  337.  
  338.     js_snprintf(cbuf, CMD_SIZE, "W%d\n", count);
  339.     rmtsendcmd(fd, "write", cbuf);
  340.     write(fd, buf, count);
  341.     return (rmtgetstatus(fd, "write"));
  342. }
  343.  
  344. EXPORT int
  345. rmtseek(fd, offset, whence)
  346.     int    fd;
  347.     long    offset;
  348.     int    whence;
  349. {
  350.     char    cbuf[CMD_SIZE];
  351.  
  352.     js_snprintf(cbuf, CMD_SIZE, "L%ld\n%d\n", offset, whence);
  353.     return (rmtcmd(fd, "seek", cbuf));
  354. }
  355.  
  356. /*
  357.  * Definitions for the new RMT Protocol version 1
  358.  *
  359.  * The new Protocol version tries to make the use
  360.  * of rmtioctl() more portable between different platforms.
  361.  */
  362. #define    RMTIVERSION    -1
  363. #define    RMT_NOVERSION    -1
  364. #define    RMT_VERSION    1
  365.  
  366. /*
  367.  * Support for commands bejond MTWEOF..MTNOP (0..7)
  368.  */
  369. #define    RMTICACHE    0
  370. #define    RMTINOCACHE    1
  371. #define    RMTIRETEN    2
  372. #define    RMTIERASE    3
  373. #define    RMTIEOM        4
  374. #define    RMTINBSF    5
  375.  
  376. /*
  377.  * Old MTIOCGET copies a binary version of struct mtget back
  378.  * over the wire. This is highly non portable.
  379.  * MTS_* retrieves ascii versions (%d format) of a single
  380.  * field in the struct mtget.
  381.  * NOTE: MTS_ERREG may only be valid on the first call and
  382.  *     must be retrived first.
  383.  */
  384. #define    MTS_TYPE    'T'        /* mtget.mt_type */
  385. #define    MTS_DSREG    'D'        /* mtget.mt_dsreg */
  386. #define    MTS_ERREG    'E'        /* mtget.mt_erreg */
  387. #define    MTS_RESID    'R'        /* mtget.mt_resid */
  388. #define    MTS_FILENO    'F'        /* mtget.mt_fileno */
  389. #define    MTS_BLKNO    'B'        /* mtget.mt_blkno */
  390. #define    MTS_FLAGS    'f'        /* mtget.mt_flags */
  391. #define    MTS_BF        'b'        /* mtget.mt_bf */
  392.  
  393. EXPORT int
  394. rmtioctl(fd, cmd, count)
  395.     int    fd;
  396.     int    cmd;
  397.     int    count;
  398. {
  399.     char    cbuf[CMD_SIZE];
  400.     char    c = 'I';
  401.     int    rmtversion = RMT_NOVERSION;
  402.     int    i;
  403.  
  404.     if (cmd != RMTIVERSION)
  405.         rmtversion = rmtioctl(fd, RMTIVERSION, 0);
  406.  
  407.     if (cmd >= 0 && (rmtversion == RMT_VERSION)) {
  408.         /*
  409.          * Opcodes 0..7 are unique across different architectures.
  410.          * But as in many cases Linux does not even follow this rule.
  411.          * If we know that we are calling a VERSION 1 client, we may 
  412.          * safely assume that the client is not using Linux mapping
  413.          * but the standard mapping.
  414.          */
  415.         i = rmtmapold(cmd);
  416.         if (cmd <= 7 && i  < 0) {
  417.             /*
  418.              * We cannot map the current command but it's value is
  419.              * within the range 0..7. Do not send it over the wire.
  420.              */
  421.             errno = EINVAL;
  422.             return (-1);
  423.         }
  424.         if (i >= 0)
  425.             cmd = i;
  426.     }
  427.     if (cmd > 7 && (rmtversion == RMT_VERSION)) {
  428.         i = rmtmapnew(cmd);
  429.         if (i >= 0) {
  430.             cmd = i;
  431.             c = 'i';
  432.         }
  433.     }
  434.  
  435.     js_snprintf(cbuf, CMD_SIZE, "%c%d\n%d\n", c, cmd, count);
  436.     return (rmtcmd(fd, "ioctl", cbuf));
  437. }
  438.  
  439. /*
  440.  * Map all old opcodes that should be in range 0..7 to numbers /etc/rmt expects
  441.  * This is needed because Linux does not follow the UNIX conventions.
  442.  */
  443. LOCAL int
  444. rmtmapold(cmd)
  445.     int    cmd;
  446. {
  447.     switch (cmd) {
  448.  
  449. #ifdef    MTWEOF
  450.     case  MTWEOF:    return (0);
  451. #endif
  452.  
  453. #ifdef    MTFSF
  454.     case MTFSF:    return (1);
  455. #endif
  456.  
  457. #ifdef    MTBSF
  458.     case MTBSF:    return (2);
  459. #endif
  460.  
  461. #ifdef    MTFSR
  462.     case MTFSR:    return (3);
  463. #endif
  464.  
  465. #ifdef    MTBSR
  466.     case MTBSR:    return (4);
  467. #endif
  468.  
  469. #ifdef    MTREW
  470.     case MTREW:    return (5);
  471. #endif
  472.  
  473. #ifdef    MTOFFL
  474.     case MTOFFL:    return (6);
  475. #endif
  476.  
  477. #ifdef    MTNOP
  478.     case MTNOP:    return (7);
  479. #endif
  480.     }
  481.     return (-1);
  482. }
  483.  
  484. /*
  485.  * Map all new opcodes that should be in range above 7 to the 
  486.  * values expected by the 'i' command of /etc/rmt.
  487.  */
  488. LOCAL int
  489. rmtmapnew(cmd)
  490.     int    cmd;
  491. {
  492.     switch (cmd) {
  493.  
  494. #ifdef    MTCACHE
  495.     case MTCACHE:    return (RMTICACHE);
  496. #endif
  497.  
  498. #ifdef    MTNOCACHE
  499.     case MTNOCACHE:    return (RMTINOCACHE);
  500. #endif
  501.  
  502. #ifdef    MTRETEN
  503.     case MTRETEN:    return (RMTIRETEN);
  504. #endif
  505.  
  506. #ifdef    MTERASE
  507.     case MTERASE:    return (RMTIERASE);
  508. #endif
  509.  
  510. #ifdef    MTEOM
  511.     case MTEOM:    return (RMTIEOM);
  512. #endif
  513.  
  514. #ifdef    MTNBSF
  515.     case MTNBSF:    return (RMTINBSF);
  516. #endif
  517.     }
  518.     return (-1);
  519. }
  520.  
  521. static struct    mtget mts;
  522.  
  523. LOCAL int
  524. rmtxstatus(fd, cmd)
  525.     int    fd;
  526.     char    cmd;
  527. {
  528.     char    cbuf[CMD_SIZE];
  529.  
  530.             /* No newline */
  531.     js_snprintf(cbuf, CMD_SIZE, "s%c", cmd);
  532.     return (rmtcmd(fd, "extended status", cbuf));
  533. }
  534.  
  535. LOCAL struct mtget *
  536. rmt_v1_status(fd)
  537.     int    fd;
  538. {
  539.     mts.mt_erreg = mts.mt_type = 0;
  540.  
  541. #ifdef    HAVE_MTGET_ERREG
  542.     mts.mt_erreg  = rmtxstatus(fd, MTS_ERREG); /* must be first */
  543. #endif
  544. #ifdef    HAVE_MTGET_TYPE
  545.     mts.mt_type   = rmtxstatus(fd, MTS_TYPE);
  546. #endif
  547.     if (mts.mt_erreg == -1 || mts.mt_type == -1)
  548.         return (0);
  549.  
  550. #ifdef    HAVE_MTGET_DSREG    /* doch immer vorhanden ??? */
  551.     mts.mt_dsreg  = rmtxstatus(fd, MTS_DSREG);
  552. #endif
  553. #ifdef    HAVE_MTGET_RESID
  554.     mts.mt_resid  = rmtxstatus(fd, MTS_RESID);
  555. #endif
  556. #ifdef    HAVE_MTGET_FILENO
  557.     mts.mt_fileno = rmtxstatus(fd, MTS_FILENO);
  558. #endif
  559. #ifdef    HAVE_MTGET_BLKNO
  560.     mts.mt_blkno  = rmtxstatus(fd, MTS_BLKNO);
  561. #endif
  562. #ifdef    HAVE_MTGET_FLAGS
  563.     mts.mt_flags  = rmtxstatus(fd, MTS_FLAGS);
  564. #endif
  565. #ifdef    HAVE_MTGET_BF
  566.     mts.mt_bf     = rmtxstatus(fd, MTS_BF);
  567. #endif
  568.     return (&mts);
  569. }
  570.  
  571. EXPORT struct mtget *
  572. rmtstatus(fd)
  573.     int    fd;
  574. {
  575.     register int i;
  576.     register char *cp;
  577.     char    c;
  578.     int    n;
  579.  
  580.     if (rmtioctl(fd, RMTIVERSION, 0) == RMT_VERSION)
  581.         return (rmt_v1_status(fd));
  582.  
  583.                 /* No newline */
  584.     if ((n = rmtcmd(fd, "status", "S")) < 0)
  585.         return (0);
  586.  
  587.     for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
  588.         *cp++ = 0;
  589.     for (i = 0, cp = (char *)&mts; i < n; i++) {
  590.         /*
  591.          * Make sure to read all bytes because we otherwise
  592.          * would confuse the protocol. Do not copy more
  593.          * than the size of our local struct mtget.
  594.          */
  595.         if (read(fd, &c, 1) != 1) {
  596.             rmtaborted(fd);
  597.             return (0);
  598.         }
  599.         if (i < sizeof(mts))
  600.             *cp++ = c;
  601.     }
  602.     /*
  603.      * The GNU remote tape lib tries to swap the structure based on the
  604.      * value of mt_type. While this makes sense for UNIX, it will not
  605.      * work if one system is running Linux. The Linux mtget structure
  606.      * is completely incompatible (mt_type is long instead of short).
  607.      */
  608.     return (&mts);
  609. }
  610.  
  611. LOCAL int
  612. rmtcmd(fd, name, cbuf)
  613.     int    fd;
  614.     char    *name;
  615.     char    *cbuf;
  616. {
  617.     rmtsendcmd(fd, name, cbuf);
  618.     return (rmtgetstatus(fd, name));
  619. }
  620.  
  621. LOCAL void
  622. rmtsendcmd(fd, name, cbuf)
  623.     int    fd;
  624.     char    *name;
  625.     char    *cbuf;
  626. {
  627.     int    buflen = strlen(cbuf);
  628.  
  629.     errno = 0;
  630.     if (write(fd, cbuf, buflen) != buflen)
  631.         rmtaborted(fd);
  632. }
  633.  
  634. LOCAL int
  635. rmtgetline(fd, line, count)
  636.     int    fd;
  637.     char    *line;
  638.     int    count;
  639. {
  640.     register char    *cp;
  641.  
  642.     for (cp = line; cp < &line[count]; cp++) {
  643.         if (read(fd, cp, 1) != 1)
  644.             return (rmtaborted(fd));
  645.  
  646.         if (*cp == '\n') {
  647.             *cp = '\0';
  648.             return (cp - line);
  649.         }
  650.     }
  651.     return (rmtaborted(fd));
  652. }
  653.  
  654. LOCAL int
  655. rmtgetstatus(fd, name)
  656.     int    fd;
  657.     char    *name;
  658. {
  659.     char    cbuf[CMD_SIZE];
  660.     char    code;
  661.     int    number;
  662.  
  663.     rmtgetline(fd, cbuf, sizeof(cbuf));
  664.     code = cbuf[0];
  665.     number = atoi(&cbuf[1]);
  666.  
  667.     if (code == 'E' || code == 'F') {
  668.         rmtgetline(fd, cbuf, sizeof(cbuf));
  669.         if (code == 'F')    /* should close file ??? */
  670.             rmtaborted(fd);
  671.         if (debug)
  672.             errmsgno(number, "Remote status(%s): %d '%s'.\n",
  673.                             name, number, cbuf);
  674.         errno = number;
  675.         return (-1);
  676.     }
  677.     if (code != 'A') {
  678.         /* XXX Hier kommt evt Command not found ... */
  679.         if (debug)
  680.             errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf);
  681.         return (rmtaborted(fd));
  682.     }
  683.     return (number);
  684. }
  685.  
  686. LOCAL int
  687. rmtaborted(fd)
  688.     int    fd;
  689. {
  690.     if (debug)
  691.         errmsgno(EX_BAD, "Lost connection to remote host ??\n");
  692.     /* if fd >= 0 */
  693.     /* close file */
  694.     if (errno == 0)
  695.         errno = EIO;
  696.     return (-1);
  697. }
  698. #endif    /* USE_REMOTE */
  699.