PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/commands/rcp/rcp.c

http://www.minix3.org/
C | 850 lines | 764 code | 57 blank | 29 comment | 224 complexity | a5437697d4c0f34c5fb3436591b64fe8 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /*
  2. * Copyright (c) 1983 Regents of the University of California.
  3. * All rights reserved. The Berkeley software License Agreement
  4. * specifies the terms and conditions for redistribution.
  5. */
  6. #ifndef lint
  7. char copyright[] =
  8. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  9. All rights reserved.\n";
  10. #endif /* not lint */
  11. #ifndef lint
  12. #if 0
  13. static char sccsid[] = "@(#)rcp.c 1.1 87/12/21 SMI"; /* from UCB 5.3 6/8/85"*/
  14. #endif
  15. #endif /* not lint */
  16. /*
  17. * rcp
  18. */
  19. #undef _MINIX
  20. #define NAMESERVER
  21. #include <ctype.h>
  22. #include <errno.h>
  23. #include <stdarg.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <time.h>
  28. #include <utime.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <sys/wait.h>
  32. #include <dirent.h>
  33. #include <fcntl.h>
  34. #include <pwd.h>
  35. #include <signal.h>
  36. #include <unistd.h>
  37. #include <net/gen/netdb.h>
  38. #include <net/netlib.h>
  39. #if __STDC__
  40. #define PROTO(func, args) func args
  41. #else
  42. #define PROTO(func, args) func ()
  43. #endif /* __STDC__ */
  44. PROTO (int main, (int argc, char *argv[]));
  45. PROTO (void lostconn, (int sig));
  46. PROTO (void error, (char *fmt, ...) );
  47. PROTO (int response, (void) );
  48. PROTO (void source, (int argc, char *argv[]) );
  49. PROTO (void sink, (int argc, char *argv[]) );
  50. PROTO (void usage, (void) );
  51. PROTO (char *colon, (char *cp) );
  52. PROTO (int okname, (char *cp0) );
  53. PROTO (int susystem, (char *s) );
  54. PROTO (void verifydir, (char *cp) );
  55. PROTO (void rsource, (char *name, struct stat *statp) );
  56. PROTO (struct buffer *allocbuf, (struct buffer *bp, int fd, int blksize) );
  57. #define vfork fork
  58. int rem;
  59. int errs;
  60. int errno;
  61. int iamremote, targetshouldbedirectory;
  62. int iamrecursive;
  63. int myuid; /* uid of invoker */
  64. int pflag;
  65. struct passwd *pwd;
  66. int userid;
  67. int port;
  68. struct buffer {
  69. int cnt;
  70. char *buf;
  71. };
  72. #define ga() (void) write(rem, "", 1)
  73. int main(argc, argv)
  74. int argc;
  75. char **argv;
  76. {
  77. char *targ, *host, *src;
  78. #ifndef NAMESERVER
  79. char *suser, *tuser;
  80. #else /* NAMESERVER */
  81. char *suser, *tuser, *thost;
  82. #endif /* NAMESERVER */
  83. int i;
  84. char buf[BUFSIZ], cmd[16];
  85. struct servent *sp;
  86. sp = getservbyname("shell", "tcp");
  87. if (sp == NULL) {
  88. fprintf(stderr, "rcp: shell/tcp: unknown service\n");
  89. exit(1);
  90. }
  91. port = sp->s_port;
  92. pwd = getpwuid(userid = getuid());
  93. if (pwd == 0) {
  94. fprintf(stderr, "who are you?\n");
  95. exit(1);
  96. }
  97. #ifdef NOT_DEF
  98. /*
  99. * This is a kludge to allow seteuid to user before touching
  100. * files and seteuid root before doing rcmd so we can open
  101. * the socket.
  102. */
  103. myuid = getuid();
  104. if (setruid(0) < 0) {
  105. perror("setruid root");
  106. exit(1);
  107. }
  108. seteuid(myuid);
  109. #endif
  110. for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
  111. (*argv)++;
  112. while (**argv) switch (*(*argv)++) {
  113. case 'r':
  114. iamrecursive++;
  115. break;
  116. case 'p': /* preserve mtimes and atimes */
  117. pflag++;
  118. break;
  119. /* The rest of these are not for users. */
  120. case 'd':
  121. targetshouldbedirectory = 1;
  122. break;
  123. case 'f': /* "from" */
  124. iamremote = 1;
  125. (void) response();
  126. source(--argc, ++argv);
  127. exit(errs);
  128. case 't': /* "to" */
  129. iamremote = 1;
  130. sink(--argc, ++argv);
  131. exit(errs);
  132. default:
  133. usage();
  134. exit(1);
  135. }
  136. }
  137. if (iamremote)
  138. {
  139. close(2);
  140. open("/dev/tty", 2);
  141. }
  142. if (argc < 2) {
  143. usage();
  144. exit(1);
  145. }
  146. rem = -1;
  147. if (argc > 2)
  148. targetshouldbedirectory = 1;
  149. (void) sprintf(cmd, "rcp%s%s%s",
  150. iamrecursive ? " -r" : "", pflag ? " -p" : "",
  151. targetshouldbedirectory ? " -d" : "");
  152. (void) signal(SIGPIPE, lostconn);
  153. targ = colon(argv[argc - 1]);
  154. if (targ) { /* ... to remote */
  155. *targ++ = 0;
  156. if (*targ == 0)
  157. targ = ".";
  158. #ifndef NAMESERVER
  159. tuser = strrchr(argv[argc - 1], '.');
  160. if (tuser) {
  161. *tuser++ = 0;
  162. if (!okname(tuser))
  163. exit(1);
  164. } else
  165. tuser = pwd->pw_name;
  166. #else /* NAMESERVER */
  167. thost = strchr(argv[argc - 1], '@');
  168. if (thost) {
  169. *thost++ = 0;
  170. tuser = argv[argc - 1];
  171. if (*tuser == '\0')
  172. tuser = pwd->pw_name;
  173. else if (!okname(tuser))
  174. exit(1);
  175. } else {
  176. thost = argv[argc - 1];
  177. tuser = pwd->pw_name;
  178. }
  179. #endif /* NAMESERVER */
  180. for (i = 0; i < argc - 1; i++) {
  181. src = colon(argv[i]);
  182. if (src) { /* remote to remote */
  183. *src++ = 0;
  184. if (*src == 0)
  185. src = ".";
  186. #ifndef NAMESERVER
  187. suser = strrchr(argv[i], '.');
  188. if (suser) {
  189. *suser++ = 0;
  190. if (!okname(suser))
  191. #else /* NAMESERVER */
  192. host = strchr(argv[i], '@');
  193. if (host) {
  194. *host++ = 0;
  195. suser = argv[i];
  196. if (*suser == '\0')
  197. suser = pwd->pw_name;
  198. else if (!okname(suser))
  199. #endif /* NAMESERVER */
  200. continue;
  201. #ifndef NAMESERVER
  202. (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s.%s:%s'",
  203. argv[i], suser, cmd, src,
  204. argv[argc - 1], tuser, targ);
  205. } else
  206. (void) sprintf(buf, "rsh %s -n %s %s '%s.%s:%s'",
  207. argv[i], cmd, src,
  208. argv[argc - 1], tuser, targ);
  209. #else /* NAMESERVER */
  210. (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s@%s:%s'",
  211. host, suser, cmd, src,
  212. tuser, thost, targ);
  213. } else
  214. (void) sprintf(buf, "rsh %s -n %s %s '%s@%s:%s'",
  215. argv[i], cmd, src,
  216. tuser, thost, targ);
  217. #endif /* NAMESERVER */
  218. (void) susystem(buf);
  219. } else { /* local to remote */
  220. if (rem == -1) {
  221. (void) sprintf(buf, "%s -t %s",
  222. cmd, targ);
  223. #ifndef NAMESERVER
  224. host = argv[argc - 1];
  225. #else /* NAMESERVER */
  226. host = thost;
  227. #endif /* NAMESERVER */
  228. #ifdef NOT_DEF
  229. if (seteuid(0) < 0) {
  230. perror("seteuid root");
  231. exit(1);
  232. }
  233. #endif
  234. rem = rcmd(&host, port, pwd->pw_name,
  235. tuser, buf, 0);
  236. #ifdef NO_DEF
  237. seteuid(myuid);
  238. #endif
  239. if (rem < 0)
  240. exit(1);
  241. if (response() < 0)
  242. exit(1);
  243. }
  244. source(1, argv+i);
  245. }
  246. }
  247. } else { /* ... to local */
  248. if (targetshouldbedirectory)
  249. verifydir(argv[argc - 1]);
  250. for (i = 0; i < argc - 1; i++) {
  251. src = colon(argv[i]);
  252. if (src == 0) { /* local to local */
  253. (void) sprintf(buf, "cp%s%s %s %s",
  254. iamrecursive ? " -r" : "",
  255. pflag ? " -p" : "",
  256. argv[i], argv[argc - 1]);
  257. (void) susystem(buf);
  258. } else { /* remote to local */
  259. *src++ = 0;
  260. if (*src == 0)
  261. src = ".";
  262. #ifndef NAMESERVER
  263. suser = strrchr(argv[i], '.');
  264. if (suser) {
  265. *suser++ = 0;
  266. if (!okname(suser))
  267. #else /* NAMESERVER */
  268. host = strchr(argv[i], '@');
  269. if (host) {
  270. *host++ = 0;
  271. suser = argv[i];
  272. if (*suser == '\0')
  273. suser = pwd->pw_name;
  274. else if (!okname(suser))
  275. #endif /* NAMESERVER */
  276. continue;
  277. #ifndef NAMESERVER
  278. } else
  279. #else /* NAMESERVER */
  280. } else {
  281. host = argv[i];
  282. #endif /* NAMESERVER */
  283. suser = pwd->pw_name;
  284. #ifdef NAMESERVER
  285. }
  286. #endif /* NAMESERVER */
  287. (void) sprintf(buf, "%s -f %s", cmd, src);
  288. #ifndef NAMESERVER
  289. host = argv[i];
  290. #endif /* NAMESERVER */
  291. #ifdef NOT_DEF
  292. if (seteuid(0) < 0) {
  293. perror("seteuid root");
  294. exit(1);
  295. }
  296. #endif
  297. rem = rcmd(&host, port, pwd->pw_name, suser,
  298. buf, 0);
  299. #ifdef NOT_DEF
  300. seteuid(myuid);
  301. #endif
  302. if (rem < 0) {
  303. errs++;
  304. continue;
  305. }
  306. sink(1, argv+argc-1);
  307. (void) close(rem);
  308. rem = -1;
  309. }
  310. }
  311. }
  312. exit(errs);
  313. }
  314. void
  315. verifydir(cp)
  316. char *cp;
  317. {
  318. struct stat stb;
  319. if (stat(cp, &stb) >= 0) {
  320. if ((stb.st_mode & S_IFMT) == S_IFDIR)
  321. return;
  322. errno = ENOTDIR;
  323. }
  324. error("rcp: %s: %s.\n", cp, strerror(errno));
  325. exit(1);
  326. }
  327. char *
  328. colon(cp)
  329. char *cp;
  330. {
  331. while (*cp) {
  332. if (*cp == ':')
  333. return (cp);
  334. if (*cp == '/')
  335. return (0);
  336. cp++;
  337. }
  338. return (0);
  339. }
  340. int
  341. okname(cp0)
  342. char *cp0;
  343. {
  344. register char *cp = cp0;
  345. register int c;
  346. do {
  347. c = *cp;
  348. if (c & 0200)
  349. goto bad;
  350. if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
  351. goto bad;
  352. cp++;
  353. } while (*cp);
  354. return (1);
  355. bad:
  356. fprintf(stderr, "rcp: invalid user name %s\n", cp0);
  357. return (0);
  358. }
  359. int
  360. susystem(s)
  361. char *s;
  362. {
  363. int status, pid, w;
  364. register void PROTO ((*istat), (int) ), PROTO ((*qstat), (int) );
  365. if ((pid = vfork()) == 0) {
  366. #ifdef NOT_DEF
  367. (void) setruid(myuid);
  368. #endif
  369. execl("/bin/sh", "sh", "-c", s, (char *)0);
  370. _exit(127);
  371. }
  372. istat = signal(SIGINT, SIG_IGN);
  373. qstat = signal(SIGQUIT, SIG_IGN);
  374. while ((w = wait(&status)) != pid && w != -1)
  375. ;
  376. if (w == -1)
  377. status = -1;
  378. (void) signal(SIGINT, istat);
  379. (void) signal(SIGQUIT, qstat);
  380. return (status);
  381. }
  382. void
  383. source(argc, argv)
  384. int argc;
  385. char **argv;
  386. {
  387. char *last, *name;
  388. struct stat stb;
  389. static struct buffer buffer;
  390. struct buffer *bp;
  391. int x, sizerr, f, amt;
  392. off_t i;
  393. char buf[BUFSIZ];
  394. for (x = 0; x < argc; x++) {
  395. name = argv[x];
  396. if ((f = open(name, 0)) < 0) {
  397. error("rcp: %s: %s\n", name, strerror(errno));
  398. continue;
  399. }
  400. if (fstat(f, &stb) < 0)
  401. goto notreg;
  402. switch (stb.st_mode&S_IFMT) {
  403. case S_IFREG:
  404. break;
  405. case S_IFDIR:
  406. if (iamrecursive) {
  407. (void) close(f);
  408. rsource(name, &stb);
  409. continue;
  410. }
  411. /* fall into ... */
  412. default:
  413. notreg:
  414. (void) close(f);
  415. error("rcp: %s: not a plain file\n", name);
  416. continue;
  417. }
  418. last = strrchr(name, '/');
  419. if (last == 0)
  420. last = name;
  421. else
  422. last++;
  423. if (pflag) {
  424. /*
  425. * Make it compatible with possible future
  426. * versions expecting microseconds.
  427. */
  428. (void) sprintf(buf, "T%d 0 %d 0\n",
  429. stb.st_mtime, stb.st_atime);
  430. (void) write(rem, buf, strlen(buf));
  431. if (response() < 0) {
  432. (void) close(f);
  433. continue;
  434. }
  435. }
  436. (void) sprintf(buf, "C%04o %lld %s\n",
  437. stb.st_mode&07777, stb.st_size, last);
  438. (void) write(rem, buf, strlen(buf));
  439. if (response() < 0) {
  440. (void) close(f);
  441. continue;
  442. }
  443. if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
  444. (void) close(f);
  445. continue;
  446. }
  447. sizerr = 0;
  448. for (i = 0; i < stb.st_size; i += bp->cnt) {
  449. amt = bp->cnt;
  450. if (i + amt > stb.st_size)
  451. amt = stb.st_size - i;
  452. if (sizerr == 0 && read(f, bp->buf, amt) != amt)
  453. sizerr = 1;
  454. (void) write(rem, bp->buf, amt);
  455. }
  456. (void) close(f);
  457. if (sizerr == 0)
  458. ga();
  459. else
  460. error("rcp: %s: file changed size\n", name);
  461. (void) response();
  462. }
  463. }
  464. void
  465. rsource(name, statp)
  466. char *name;
  467. struct stat *statp;
  468. {
  469. DIR *d = opendir(name);
  470. char *last;
  471. struct dirent *dp;
  472. char buf[BUFSIZ];
  473. char *bufv[1];
  474. if (d == 0) {
  475. error("rcp: %s: %s\n", name, strerror(errno));
  476. return;
  477. }
  478. last = strrchr(name, '/');
  479. if (last == 0)
  480. last = name;
  481. else
  482. last++;
  483. if (pflag) {
  484. (void) sprintf(buf, "T%d 0 %d 0\n",
  485. statp->st_mtime, statp->st_atime);
  486. (void) write(rem, buf, strlen(buf));
  487. if (response() < 0) {
  488. closedir(d);
  489. return;
  490. }
  491. }
  492. (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
  493. (void) write(rem, buf, strlen(buf));
  494. if (response() < 0) {
  495. closedir(d);
  496. return;
  497. }
  498. while ((dp = readdir(d))) {
  499. if (dp->d_ino == 0)
  500. continue;
  501. if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  502. continue;
  503. if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
  504. error("%s/%s: Name too long.\n", name, dp->d_name);
  505. continue;
  506. }
  507. (void) sprintf(buf, "%s/%s", name, dp->d_name);
  508. bufv[0] = buf;
  509. source(1, bufv);
  510. }
  511. closedir(d);
  512. (void) write(rem, "E\n", 2);
  513. (void) response();
  514. }
  515. int
  516. response()
  517. {
  518. char resp, c, rbuf[BUFSIZ], *cp = rbuf;
  519. if (read(rem, &resp, 1) != 1)
  520. lostconn(0);
  521. switch (resp) {
  522. case 0: /* ok */
  523. return (0);
  524. default:
  525. *cp++ = resp;
  526. /* fall into... */
  527. case 1: /* error, followed by err msg */
  528. case 2: /* fatal error, "" */
  529. do {
  530. if (read(rem, &c, 1) != 1)
  531. lostconn(0);
  532. *cp++ = c;
  533. } while (cp < &rbuf[BUFSIZ] && c != '\n');
  534. if (iamremote == 0)
  535. (void) write(2, rbuf, cp - rbuf);
  536. errs++;
  537. if (resp == 1)
  538. return (-1);
  539. exit(1);
  540. }
  541. /*NOTREACHED*/
  542. }
  543. void
  544. lostconn(sig)
  545. int sig;
  546. {
  547. if (iamremote == 0)
  548. fprintf(stderr, "rcp: lost connection\n");
  549. exit(1);
  550. }
  551. void
  552. sink(argc, argv)
  553. int argc;
  554. char **argv;
  555. {
  556. off_t i, j, size;
  557. char *targ, *whopp, *cp;
  558. int of, mode, wrerr, exists, first, count, amt;
  559. struct buffer *bp;
  560. static struct buffer buffer;
  561. struct stat stb;
  562. int targisdir = 0;
  563. int mask = umask(0);
  564. char *myargv[1];
  565. char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
  566. int setimes = 0;
  567. struct utimbuf utimbuf;
  568. #define atime utimbuf.actime
  569. #define mtime utimbuf.modtime
  570. time_t dummy;
  571. #define SCREWUP(str) { whopp = str; goto screwup; }
  572. #ifdef NOT_DEF
  573. seteuid(pwd->pw_uid);
  574. #endif
  575. if (!pflag)
  576. (void) umask(mask);
  577. if (argc != 1) {
  578. error("rcp: ambiguous target\n");
  579. exit(1);
  580. }
  581. targ = *argv;
  582. if (targetshouldbedirectory)
  583. verifydir(targ);
  584. ga();
  585. if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
  586. targisdir = 1;
  587. for (first = 1; ; first = 0) {
  588. cp = cmdbuf;
  589. if (read(rem, cp, 1) <= 0)
  590. return;
  591. if (*cp++ == '\n')
  592. SCREWUP("unexpected '\\n'");
  593. do {
  594. if (read(rem, cp, 1) != 1)
  595. SCREWUP("lost connection");
  596. } while (*cp++ != '\n');
  597. *cp = 0;
  598. if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
  599. if (iamremote == 0)
  600. (void) write(2, cmdbuf+1, strlen(cmdbuf+1));
  601. if (cmdbuf[0] == '\02')
  602. exit(1);
  603. errs++;
  604. continue;
  605. }
  606. *--cp = 0;
  607. cp = cmdbuf;
  608. if (*cp == 'E') {
  609. ga();
  610. return;
  611. }
  612. #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
  613. if (*cp == 'T') {
  614. setimes++;
  615. cp++;
  616. getnum(mtime);
  617. if (*cp++ != ' ')
  618. SCREWUP("mtime.sec not delimited");
  619. getnum(dummy);
  620. if (*cp++ != ' ')
  621. SCREWUP("mtime.usec not delimited");
  622. getnum(atime);
  623. if (*cp++ != ' ')
  624. SCREWUP("atime.sec not delimited");
  625. getnum(dummy);
  626. if (*cp++ != '\0')
  627. SCREWUP("atime.usec not delimited");
  628. ga();
  629. continue;
  630. }
  631. if (*cp != 'C' && *cp != 'D') {
  632. /*
  633. * Check for the case "rcp remote:foo\* local:bar".
  634. * In this case, the line "No match." can be returned
  635. * by the shell before the rcp command on the remote is
  636. * executed so the ^Aerror_message convention isn't
  637. * followed.
  638. */
  639. if (first) {
  640. error("%s\n", cp);
  641. exit(1);
  642. }
  643. SCREWUP("expected control record");
  644. }
  645. cp++;
  646. mode = 0;
  647. for (; cp < cmdbuf+5; cp++) {
  648. if (*cp < '0' || *cp > '7')
  649. SCREWUP("bad mode");
  650. mode = (mode << 3) | (*cp - '0');
  651. }
  652. if (*cp++ != ' ')
  653. SCREWUP("mode not delimited");
  654. size = 0;
  655. while (isdigit(*cp))
  656. size = size * 10 + (*cp++ - '0');
  657. if (*cp++ != ' ')
  658. SCREWUP("size not delimited");
  659. if (targisdir)
  660. (void) sprintf(nambuf, "%s%s%s", targ,
  661. *targ ? "/" : "", cp);
  662. else
  663. (void) strcpy(nambuf, targ);
  664. exists = stat(nambuf, &stb) == 0;
  665. if (cmdbuf[0] == 'D') {
  666. if (exists) {
  667. if ((stb.st_mode&S_IFMT) != S_IFDIR) {
  668. errno = ENOTDIR;
  669. goto bad;
  670. }
  671. if (pflag)
  672. (void) chmod(nambuf, mode);
  673. } else if (mkdir(nambuf, mode) < 0)
  674. goto bad;
  675. myargv[0] = nambuf;
  676. sink(1, myargv);
  677. if (setimes) {
  678. setimes = 0;
  679. if (utime(nambuf, &utimbuf) < 0)
  680. error("rcp: can't set times on %s: %s\n",
  681. nambuf, strerror(errno));
  682. }
  683. continue;
  684. }
  685. if ((of = creat(nambuf, mode)) < 0) {
  686. bad:
  687. error("rcp: %s: %s\n", nambuf, strerror(errno));
  688. continue;
  689. }
  690. if (exists && pflag)
  691. (void) chmod(nambuf, mode);
  692. ga();
  693. if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) {
  694. (void) close(of);
  695. continue;
  696. }
  697. cp = bp->buf;
  698. count = 0;
  699. wrerr = 0;
  700. for (i = 0; i < size; i += BUFSIZ) {
  701. amt = BUFSIZ;
  702. if (i + amt > size)
  703. amt = size - i;
  704. count += amt;
  705. do {
  706. j = read(rem, cp, amt);
  707. if (j <= 0)
  708. exit(1);
  709. amt -= j;
  710. cp += j;
  711. } while (amt > 0);
  712. if (count == bp->cnt) {
  713. if (wrerr == 0 &&
  714. write(of, bp->buf, count) != count)
  715. wrerr++;
  716. count = 0;
  717. cp = bp->buf;
  718. }
  719. }
  720. if (count != 0 && wrerr == 0 &&
  721. write(of, bp->buf, count) != count)
  722. wrerr++;
  723. (void) close(of);
  724. (void) response();
  725. if (setimes) {
  726. setimes = 0;
  727. if (utime(nambuf, &utimbuf) < 0)
  728. error("rcp: can't set times on %s: %s\n",
  729. nambuf, strerror(errno));
  730. }
  731. if (wrerr)
  732. error("rcp: %s: %s\n", nambuf, strerror(errno));
  733. else
  734. ga();
  735. }
  736. screwup:
  737. error("rcp: protocol screwup: %s\n", whopp);
  738. exit(1);
  739. }
  740. struct buffer *
  741. allocbuf(bp, fd, blksize)
  742. struct buffer *bp;
  743. int fd, blksize;
  744. {
  745. struct stat stb;
  746. int size;
  747. if (fstat(fd, &stb) < 0) {
  748. error("rcp: fstat: %s\n", strerror(errno));
  749. return ((struct buffer *)0);
  750. }
  751. size= 0;
  752. #if NOT_DEF
  753. size = roundup(stb.st_blksize, blksize);
  754. #endif
  755. if (size == 0)
  756. size = blksize;
  757. if (bp->cnt < size) {
  758. if (bp->buf != 0)
  759. free(bp->buf);
  760. bp->buf = (char *)malloc((unsigned) size);
  761. if (bp->buf == 0) {
  762. error("rcp: malloc: out of memory\n");
  763. return ((struct buffer *)0);
  764. }
  765. }
  766. bp->cnt = size;
  767. return (bp);
  768. }
  769. /*VARARGS1*/
  770. #if __STDC__
  771. void
  772. error (char *fmt, ...)
  773. #else
  774. error(fmt)
  775. char *fmt;
  776. #endif
  777. {
  778. char buf[BUFSIZ], *cp = buf;
  779. va_list ap;
  780. va_start(ap, fmt);
  781. errs++;
  782. *cp++ = 1;
  783. (void) vsprintf(cp, fmt, ap);
  784. va_end(ap);
  785. (void) write(rem, buf, strlen(buf));
  786. if (iamremote == 0)
  787. (void) write(2, buf+1, strlen(buf+1));
  788. }
  789. void
  790. usage()
  791. {
  792. fprintf(stderr, "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n");
  793. }