home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / clients / rcp.lha / rcp / src / rcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-05  |  17.4 KB  |  759 lines

  1. /* 
  2.  * Copyright (c) 1983, 1990, 1992, 1993 The Regents of the University of 
  3.  * California.  All rights reserved. Redistribution and use in source and 
  4.  * binary forms, with or without modification, are permitted provided that
  5.  * the following conditions are met: 1. Redistributions of source code
  6.  * must retain the above copyright notice, this list of conditions and
  7.  * the following disclaimer. 2. Redistributions in binary form must
  8.  * reproduce the above copyright notice, this list of conditions and the 
  9.  * following disclaimer in the documentation and/or other materials
  10.  * provided with the distribution. 3. All advertising materials mentioning
  11.  * features or use of this software must display the following
  12.  * acknowledgement: This product includes software developed by the
  13.  * University of California, Berkeley and its contributors. 4. Neither
  14.  * the name of the University nor the names of its contributors may be
  15.  * used to endorse or promote products derived from this software 
  16.  * without specific prior written permission. THIS SOFTWARE IS PROVIDED
  17.  * BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN 
  20.  * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  21.  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  24.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  27.  * SUCH DAMAGE. 
  28.  *
  29.  * Ported to the Amiga by Michael Heinz. 
  30.  */
  31.  
  32. #include <sys/param.h>
  33. #include <sys/stat.h>
  34. #include <sys/time.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <netinet/in_systm.h>
  38. #include <netinet/ip.h>
  39.  
  40. #include <ctype.h>
  41. #include <dirent.h>
  42. #include "err.h"
  43. #include <errno.h>
  44. #include <fcntl.h>
  45. #include <netdb.h>
  46. #include <pwd.h>
  47. #include <signal.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <string.h>
  52. #include <unistd.h>
  53. #include <dos.h>
  54.  
  55. #include "pathnames.h"
  56. #include "extern.h"
  57.  
  58. /* MHEINZ */
  59. #define MAXPATHLEN 256
  60. /* #define BUFSIZ 2048 */
  61.  
  62. #define    OPTIONS "dfprt"
  63.  
  64. struct passwd *pwd;
  65. u_short port;
  66. uid_t userid;
  67. int errs, rem;
  68. int pflag, iamremote, iamrecursive, targetshouldbedirectory;
  69.  
  70. /* 
  71.  * must hold "rcp -r -p -d\0" 
  72.  */
  73. #define    CMDNEEDS    64
  74. char cmd[CMDNEEDS];                 
  75.  
  76. int response(void);
  77. void rsource(char *, struct stat *);
  78. void sink(int, char *[]);
  79. void source(int, char *[]);
  80. void tolocal(int, char *[]);
  81. void toremote(char *, int, char *[]);
  82. void usage(void);
  83.  
  84. /* 
  85.  * * MHEINZ - emulate UNIX ftruncate function. */
  86. int
  87. ftruncate(int fd, long len)
  88. {
  89.     long i, olen;
  90.     char buf = '\0';
  91.  
  92.     olen = lseek(fd, 0L, 2);
  93.  
  94.     if (olen == len)
  95.     return 0;
  96.  
  97.     for (i = olen; i < len; i++) {
  98.     write(fd, &buf, 1);
  99.     }
  100.  
  101.     return 0;
  102. }
  103.  
  104. int
  105. main(int argc, char *argv[])
  106. {
  107.     struct servent *sp;
  108.     int ch, fflag, tflag;
  109.     char *targ, *shell;
  110.  
  111.     fflag = tflag = 0;
  112.     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
  113.     switch (ch) {                 /* User-visible flags. */
  114.         case 'p':
  115.         pflag = 1;
  116.         break;
  117.         case 'r':
  118.         iamrecursive = 1;
  119.         break;
  120.         /* Server options. */
  121.         case 'd':
  122.         targetshouldbedirectory = 1;
  123.         break;
  124.         case 'f':                 /* "from" */
  125.         iamremote = 1;
  126.         fflag = 1;
  127.         break;
  128.         case 't':                 /* "to" */
  129.         iamremote = 1;
  130.         tflag = 1;
  131.         break;
  132.         case '?':
  133.         default:
  134.         usage();
  135.     }
  136.     argc -= optind;
  137.     argv += optind;
  138.  
  139.     sp = getservbyname(shell = "shell", "tcp");
  140.     if (sp == NULL)
  141.     errx(stderr, "%s/tcp: unknown service", shell);
  142.     port = sp->s_port;
  143.  
  144.     if ((pwd = getpwuid(userid = getuid())) == NULL)
  145.     errx(stderr, "unknown user %d", (int)userid);
  146.  
  147.     rem = 0;                     /* stdin - mheinz */
  148.  
  149.     if (fflag) {
  150.     /* Follow "protocol", send data. */
  151.     (void)response();
  152.     (void)setuid(userid);
  153.     source(argc, argv);
  154.     exit(errs);
  155.     }
  156.     if (tflag) {                 /* Receive data. */
  157.     (void)setuid(userid);
  158.     sink(argc, argv);
  159.     exit(errs);
  160.     }
  161.     if (argc < 2)
  162.     usage();
  163.     if (argc > 2)
  164.     targetshouldbedirectory = 1;
  165.  
  166.     rem = -1;
  167.     /* Command to be executed on remote system using "rsh". */
  168.     (void)sprintf(cmd, "rcp%s%s%s",
  169.           iamrecursive ? " -r" : "", 
  170.           pflag ? " -p" : "",
  171.           targetshouldbedirectory ? " -d" : "");
  172.     if (targ = colon(argv[argc - 1]))         /* Dest is remote host. */
  173.     toremote(targ, argc, argv);
  174.     else {
  175.     if (targetshouldbedirectory)
  176.         verifydir(argv[argc - 1]);
  177.     tolocal(argc, argv);             /* Dest is local host. */
  178.     }
  179.     exit(errs);
  180. }
  181.  
  182. void
  183. toremote(char *targ, int argc, char *argv[])
  184. {
  185.     int i, len, tos;
  186.     char *bp, *host, *src, *suser, *thost, *tuser;
  187.  
  188.     *targ++ = 0;
  189.     if (*targ == 0)
  190.     targ = ".";
  191.  
  192.     if (thost = strchr(argv[argc - 1], '@')) {
  193.        /* user@host */
  194.     *thost++ = 0;
  195.     tuser = argv[argc - 1];
  196.     if (*tuser == '\0')
  197.         tuser = NULL;
  198.     else if (!okname(tuser))
  199.         exit(1);
  200.     } else {
  201.     thost = argv[argc - 1];
  202.     tuser = NULL;
  203.     }
  204.  
  205.     for (i = 0; i < argc - 1; i++) {
  206.     src = colon(argv[i]);
  207.     if (src) {                 /* remote to remote */
  208.         *src++ = 0;
  209.         if (*src == 0)
  210.         src = ".";
  211.         host = strchr(argv[i], '@');
  212.         len = strlen(_PATH_RSH) + strlen(argv[i]) +
  213.         strlen(src) + (tuser ? strlen(tuser) : 0) +
  214.         strlen(thost) + strlen(targ) + CMDNEEDS + 20;
  215.         if (!(bp = malloc(len)))
  216.         err(stderr, "Failed to allocate a buffer.");
  217.         if (host) {
  218.         *host++ = 0;
  219.         suser = argv[i];
  220.         if (*suser == '\0')
  221.             suser = pwd->pw_name;
  222.         else if (!okname(suser))
  223.             continue;
  224.         (void)sprintf(bp, "%s %s -l %s -n %s %s '%s%s%s:%s'",
  225.                   _PATH_RSH, host, suser, cmd, src,
  226.                   tuser ? tuser : "", tuser ? "@" : "",
  227.                   thost, targ);
  228.         } else
  229.         (void)sprintf(bp, "exec %s %s -n %s %s '%s%s%s:%s'",
  230.                   _PATH_RSH, argv[i], cmd, src,
  231.                   tuser ? tuser : "", tuser ? "@" : "",
  232.                   thost, targ);
  233.         (void)susystem(bp, userid);
  234.         (void)free(bp);
  235.     } else {                 /* local to remote */
  236.         if (rem == -1) {
  237.         len = strlen(targ) + CMDNEEDS + 20;
  238.         if (!(bp = malloc(len)))
  239.             err(stderr, "Failed to allocate a buffer.");
  240.         (void)sprintf(bp, "%s -t %s", cmd, targ);
  241.         host = thost;
  242.         rem = rcmd(&host, port, pwd->pw_name,
  243.                tuser ? tuser : pwd->pw_name,
  244.                bp, 0);
  245.         if (rem < 0)
  246.             errx(stderr, "rcmd failed.");
  247.  
  248.         tos = IPTOS_THROUGHPUT; 
  249.         /* tos = IPTOS_RELIABILITY;*/
  250.  
  251.         if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  252.                    &tos, sizeof(int)) < 0)
  253.              warn("TOS (ignored)");
  254.  
  255.         if (response() < 0)
  256.             exit(1);
  257.         (void)free(bp);
  258.         (void)setuid(userid);
  259.         }
  260.         source(1, argv + i);
  261.     }
  262.     }
  263. }
  264.  
  265. void
  266. tolocal(int argc, char *argv[])
  267. {
  268.     int i, len, tos;
  269.     char *bp, *host, *src, *suser;
  270.  
  271.     for (i = 0; i < argc - 1; i++) {
  272.     if (!(src = colon(argv[i]))) {         /* Local to local. */
  273.         len = strlen(_PATH_CP) + strlen(argv[i]) +
  274.         strlen(argv[argc - 1]) + 20;
  275.         if (!(bp = malloc(len)))
  276.         err(stderr, "Failed to allocate a buffer.");
  277.         (void)sprintf(bp, "%s %s %s %s %s", _PATH_CP,
  278.               argv[i], argv[argc - 1],
  279.               iamrecursive ? "all" : "", pflag ? "clone" : "");
  280.         if (susystem(bp, userid))
  281.         ++errs;
  282.         (void)free(bp);
  283.         continue;
  284.     }
  285.     *src++ = 0;
  286.     if (*src == 0)
  287.         src = ".";
  288.     if ((host = strchr(argv[i], '@')) == NULL) {
  289.         host = argv[i];
  290.         suser = pwd->pw_name;
  291.     } else {
  292.         *host++ = 0;
  293.         suser = argv[i];
  294.         if (*suser == '\0')
  295.         suser = pwd->pw_name;
  296.         else if (!okname(suser))
  297.         continue;
  298.     }
  299.     len = strlen(src) + CMDNEEDS + 20;
  300.     if ((bp = malloc(len)) == NULL)
  301.         err(stderr, "Failed to allocate a buffer.");
  302.     (void)sprintf(bp, "%s -f %s", cmd, src);
  303.     rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0);
  304.     (void)free(bp);
  305.     if (rem < 0) {
  306.         ++errs;
  307.         continue;
  308.     }
  309.     (void)seteuid(userid);
  310.     /* tos = IPTOS_THROUGHPUT; */
  311.     tos = IPTOS_RELIABILITY;
  312.     if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
  313.          warn("TOS (ignored)");
  314.  
  315.     sink(1, argv + argc - 1);
  316.     (void)seteuid(0);
  317.     (void)close(rem);
  318.     rem = -1;
  319.     }
  320. }
  321.  
  322. void
  323. source(int argc, char *argv[])
  324. {
  325.     struct stat stb;
  326.     static BUF buffer;
  327.     BUF *bp;
  328.     off_t i;
  329.     int amt, fd, haderr, indx, result;
  330.     char *last, *name, buf[BUFSIZ];
  331.  
  332.     for (indx = 0; indx < argc; ++indx) {
  333.     name = argv[indx];
  334.     if ((fd = open(name, O_RDONLY, 0)) < 0)
  335.         goto syserr;
  336.     if (fstat(fd, &stb)) {
  337.       syserr:run_err("%s: %s", name, strerror(errno));
  338.         goto next;
  339.     }
  340.     switch (stb.st_mode & S_IFMT) {
  341.         case S_IFREG:
  342.         break;
  343.         case S_IFDIR:
  344.         if (iamrecursive) {
  345.             rsource(name, &stb);
  346.             goto next;
  347.         }
  348.         /* FALLTHROUGH */
  349.         default:
  350.         run_err("%s: not a regular file", name);
  351.         goto next;
  352.     }
  353.     if ((last = strrchr(name, '/')) == NULL)
  354.         last = name;
  355.     else
  356.         ++last;
  357.     if (pflag) {
  358.         /* 
  359.          * Make it compatible with possible future
  360.          * versions expecting microseconds.
  361.          */
  362.         (void)sprintf(buf, "T%ld 0 %ld 0\n",
  363.               stb.st_mtime, stb.st_atime);
  364.         (void)write(rem, buf, strlen(buf));
  365.         if (response() < 0)
  366.         goto next;
  367.     }
  368.     (void)sprintf(buf, "C%04o %ld %s\n",
  369.               stb.st_mode & 0755, stb.st_size, last);
  370.     (void)write(rem, buf, strlen(buf));
  371.     if (response() < 0)
  372.         goto next;
  373.     if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
  374.       next:(void)close(fd);
  375.         continue;
  376.     }
  377.     /* Keep writing after an error so that we stay sync'd up. */
  378.     for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
  379.         amt = bp->cnt;
  380.         if (i + amt > stb.st_size)
  381.         amt = stb.st_size - i;
  382.         if (!haderr) {
  383.         result = read(fd, bp->buf, amt);
  384.         if (result != amt)
  385.             haderr = result >= 0 ? EIO : errno;
  386.         }
  387.         if (haderr)
  388.         (void)write(rem, bp->buf, amt);
  389.         else {
  390.         result = write(rem, bp->buf, amt);
  391.         if (result != amt)
  392.             haderr = result >= 0 ? EIO : errno;
  393.         }
  394.     }
  395.     if (close(fd) && !haderr)
  396.         haderr = errno;
  397.     if (!haderr)
  398.         (void)write(rem, "", 1);
  399.     else
  400.         run_err("%s: %s", name, strerror(haderr));
  401.     (void)response();
  402.     }
  403. }
  404.  
  405. void
  406. rsource(char *name, struct stat *statp)
  407. {
  408.     DIR *dirp;
  409.     struct dirent *dp;
  410.     char *last, *vect[1], path[MAXPATHLEN];
  411.  
  412.     if (!(dirp = opendir(name))) {
  413.     run_err("%s: %s", name, strerror(errno));
  414.     return;
  415.     }
  416.     last = strrchr(name, '/');
  417.     if (last == 0)
  418.     last = name;
  419.     else
  420.     last++;
  421.     if (pflag) {
  422.     (void)sprintf(path, "T%ld 0 %ld 0\n",
  423.               statp->st_mtime, statp->st_atime);
  424.     (void)write(rem, path, strlen(path));
  425.     if (response() < 0) {
  426.         closedir(dirp);
  427.         return;
  428.     }
  429.     }
  430.     (void)sprintf(path, "D%04o %d %s\n", statp->st_mode & 0755, 0, last);
  431.     (void)write(rem, path, strlen(path));
  432.     if (response() < 0) {
  433.     closedir(dirp);
  434.     return;
  435.     }
  436.     while (dp = readdir(dirp)) {
  437.     if (dp->d_ino == 0)
  438.         continue;
  439.     if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  440.         continue;
  441.     if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
  442.         run_err("%s/%s: name too long", name, dp->d_name);
  443.         continue;
  444.     }
  445.     (void)sprintf(path, "%s/%s", name, dp->d_name);
  446.     vect[0] = path;
  447.     source(1, vect);
  448.     }
  449.     (void)closedir(dirp);
  450.     (void)write(rem, "E\n", 2);
  451.     (void)response();
  452. }
  453.  
  454. void
  455. sink(int argc, char *argv[])
  456. {
  457.     static BUF buffer;
  458.     struct stat stb;
  459.     struct timeval tv[2];
  460.     enum {
  461.     YES, NO, DISPLAYED
  462.     } wrerr;
  463.     BUF *bp;
  464.     off_t i, j;
  465.     int amt, count, exists, first, mask, mode, ofd, omode;
  466.     int setimes, size, targisdir, wrerrno;
  467.     char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ];
  468.  
  469. #define    atime    tv[0]
  470. #define    mtime    tv[1]
  471. #define    SCREWUP(str)    { why = str; goto screwup; }
  472.  
  473.     setimes = targisdir = 0;
  474.     mask = umask(0);
  475.     if (!pflag)
  476.     (void)umask(mask);
  477.     if (argc != 1) {
  478.     run_err("ambiguous target");
  479.     exit(1);
  480.     }
  481.     targ = *argv;
  482.     if (targetshouldbedirectory)
  483.     verifydir(targ);
  484.     (void)write(rem, "", 1);
  485.     if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
  486.     targisdir = 1;
  487.     for (first = 1;; first = 0) {
  488.     cp = buf;
  489.     if (read(rem, cp, 1) <= 0)
  490.         return;
  491.     if (*cp++ == '\n')
  492.         SCREWUP("unexpected <newline>");
  493.     do {
  494.         if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  495.         SCREWUP("lost connection");
  496.         *cp++ = ch;
  497.     } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
  498.     *cp = 0;
  499.  
  500.     if (buf[0] == '\01' || buf[0] == '\02') {
  501.         if (iamremote == 0)
  502.         (void)write(2,
  503.                 buf + 1, strlen(buf + 1));
  504.         if (buf[0] == '\02')
  505.         exit(1);
  506.         ++errs;
  507.         continue;
  508.     }
  509.     if (buf[0] == 'E') {
  510.         (void)write(rem, "", 1);
  511.         return;
  512.     }
  513.     if (ch == '\n')
  514.         *--cp = 0;
  515.  
  516. #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
  517.     cp = buf;
  518.     if (*cp == 'T') {
  519.         setimes++;
  520.         cp++;
  521.         getnum(mtime.tv_sec);
  522.         if (*cp++ != ' ')
  523.         SCREWUP("mtime.sec not delimited");
  524.         getnum(mtime.tv_usec);
  525.         if (*cp++ != ' ')
  526.         SCREWUP("mtime.usec not delimited");
  527.         getnum(atime.tv_sec);
  528.         if (*cp++ != ' ')
  529.         SCREWUP("atime.sec not delimited");
  530.         getnum(atime.tv_usec);
  531.         if (*cp++ != '\0')
  532.         SCREWUP("atime.usec not delimited");
  533.         (void)write(rem, "", 1);
  534.         continue;
  535.     }
  536.     if (*cp != 'C' && *cp != 'D') {
  537.         /* 
  538.          * Check for the case "rcp remote:foo\* local:bar".
  539.          * In this case, the line "No match." can be returned
  540.          * by the shell before the rcp command on the remote is
  541.          * executed so the ^Aerror_message convention isn't
  542.          * followed.
  543.          */
  544.         if (first) {
  545.         run_err("%s", cp);
  546.         exit(1);
  547.         }
  548.         SCREWUP("expected control record");
  549.     }
  550.     mode = 0;
  551.     for (++cp; cp < buf + 5; cp++) {
  552.         if (*cp < '0' || *cp > '7')
  553.         SCREWUP("bad mode");
  554.         mode = (mode << 3) | (*cp - '0');
  555.     }
  556.     if (*cp++ != ' ')
  557.         SCREWUP("mode not delimited");
  558.  
  559.     for (size = 0; isdigit(*cp);)
  560.         size = size * 10 + (*cp++ - '0');
  561.     if (*cp++ != ' ')
  562.         SCREWUP("size not delimited");
  563.     if (targisdir) {
  564.         static char *namebuf;
  565.         static int cursize;
  566.         size_t need;
  567.  
  568.         need = strlen(targ) + strlen(cp) + 250;
  569.         if (need > cursize) {
  570.         if (!(namebuf = malloc(need)))
  571.             run_err("%s", strerror(errno));
  572.         }
  573.         (void)sprintf(namebuf, "%s%s%s", targ,
  574.               *targ ? "/" : "", cp);
  575.         np = namebuf;
  576.     } else
  577.         np = targ;
  578.     exists = stat(np, &stb) == 0;
  579.     if (buf[0] == 'D') {
  580.         int mod_flag = pflag;
  581.  
  582.         if (exists) {
  583.         if (!S_ISDIR(stb.st_mode)) {
  584.             errno = ENOTDIR;
  585.             goto bad;
  586.         }
  587.         if (pflag)
  588.             (void)chmod(np, mode);
  589.         } else {
  590.         /* Handle copying from a read-only directory */
  591.         mod_flag = 1;
  592.         if (mkdir(np) < 0)
  593.             goto bad;
  594.         }
  595.         vect[0] = np;
  596.         sink(1, vect);
  597.         if (setimes) {
  598.         setimes = 0;
  599.         /* if (utimes(np, tv) < 0) run_err("%s: set times: %s", np, * 
  600.          * 
  601.          * *  * * strerror(errno)); MHEINZ */
  602.         }
  603.         if (mod_flag)
  604.         (void)chmod(np, mode);
  605.         continue;
  606.     }
  607.     omode = mode;
  608.     mode |= S_IWRITE;
  609.     if ((ofd = open(np, O_WRONLY | O_CREAT, mode)) < 0) {
  610.       bad:run_err("%s: %s", np, strerror(errno));
  611.         continue;
  612.     }
  613.     (void)write(rem, "", 1);
  614.     if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
  615.         (void)close(ofd);
  616.         continue;
  617.     }
  618.     cp = bp->buf;
  619.     wrerr = NO;
  620.     for (count = i = 0; i < size; i += BUFSIZ) {
  621.         amt = BUFSIZ;
  622.         if (i + amt > size)
  623.         amt = size - i;
  624.         count += amt;
  625.         do {
  626.         j = read(rem, cp, amt);
  627.         if (j <= 0) {
  628.             run_err("%s", j ? strerror(errno) :
  629.                 "dropped connection");
  630.             exit(1);
  631.         }
  632.         amt -= j;
  633.         cp += j;
  634.         } while (amt > 0);
  635.         if (count == bp->cnt) {
  636.         /* Keep reading so we stay sync'd up. */
  637.         if (wrerr == NO) {
  638.             j = write(ofd, bp->buf, count);
  639.             if (j != count) {
  640.             wrerr = YES;
  641.             wrerrno = j >= 0 ? EIO : errno;
  642.             }
  643.         }
  644.         count = 0;
  645.         cp = bp->buf;
  646.         }
  647.     }
  648.     if (count != 0 && wrerr == NO &&
  649.         (j = write(ofd, bp->buf, count)) != count) {
  650.         wrerr = YES;
  651.         wrerrno = j >= 0 ? EIO : errno;
  652.     }
  653.     if (ftruncate(ofd, size)) {
  654.         run_err("%s: truncate: %s", np, strerror(errno));
  655.         wrerr = DISPLAYED;
  656.     }
  657.     if (pflag) {
  658.         if (exists || omode != mode)
  659.         if (chmod(np, omode))
  660.             run_err("%s: set mode: %s",
  661.                 np, strerror(errno));
  662.     } else {
  663.         if (!exists && omode != mode)
  664.         if (chmod(np, omode & ~mask))
  665.             run_err("%s: set mode: %s",
  666.                 np, strerror(errno));
  667.     }
  668.     (void)close(ofd);
  669.     (void)response();
  670.     if (setimes && wrerr == NO) {
  671.         setimes = 0;
  672.     }
  673.     switch (wrerr) {
  674.         case YES:
  675.         run_err("%s: %s", np, strerror(wrerrno));
  676.         break;
  677.         case NO:
  678.         (void)write(rem, "", 1);
  679.         break;
  680.         case DISPLAYED:
  681.         break;
  682.     }
  683.     }
  684.   screwup:
  685.     run_err("protocol error: %s", why);
  686.     exit(1);
  687. }
  688.  
  689. int
  690. response()
  691. {
  692.     char ch, *cp, resp, rbuf[BUFSIZ];
  693.  
  694.     if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
  695.     lostconn(0);
  696.  
  697.     cp = rbuf;
  698.     switch (resp) {
  699.     case 0:                 /* ok */
  700.         return (0);
  701.     default:
  702.         *cp++ = resp;
  703.         /* FALLTHROUGH */
  704.     case 1:                 
  705.         /* error, followed by error msg */
  706.     case 2:                 
  707.         /* fatal error */
  708.         do {
  709.         if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  710.             lostconn(0);
  711.         *cp++ = ch;
  712.         } while (cp < &rbuf[BUFSIZ] && ch != '\n');
  713.         *cp = '\0';
  714.         if (!iamremote)
  715.         err(stderr, rbuf);
  716.         ++errs;
  717.         if (resp == 1)
  718.         return (-1);
  719.         exit(1);
  720.     }
  721.     /* NOTREACHED */
  722. }
  723.  
  724. void
  725. usage()
  726. {
  727.     (void)fprintf(stderr,
  728.           "rcp - ported to the Amiga and AmiTCP by Michael Heinz.\nusage: rcp [-p] f1 f2; or: rcp [-pr] f1 ... fn directory\n");
  729.     exit(1);
  730. }
  731.  
  732. #include <stdarg.h>
  733.  
  734. void
  735. run_err(const char *fmt,...)
  736. {
  737.     static FILE *fp;
  738.     va_list ap;
  739.  
  740.     va_start(ap, fmt);
  741.  
  742.     ++errs;
  743.     if (fp == NULL && !(fp = fdopen(rem, "w")))
  744.     return;
  745.     (void)fprintf(fp, "%c", 0x01);
  746.     (void)fprintf(fp, "rcp: ");
  747.     (void)vfprintf(fp, fmt, ap);
  748.     (void)fprintf(fp, "\n");
  749.     (void)fflush(fp);
  750.  
  751.     if (!iamremote) {
  752.     char buf[256];
  753.  
  754.     vsprintf(buf, fmt, ap);
  755.     warn(buf);
  756.     }
  757.     va_end(ap);
  758. }
  759.