summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c101
1 files changed, 61 insertions, 40 deletions
diff --git a/scp.c b/scp.c
index 9b64aa5f4..66b4af8e8 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: scp.c,v 1.207 2020/01/23 07:10:22 dtucker Exp $ */ 1/* $OpenBSD: scp.c,v 1.210 2020/05/06 20:57:38 djm Exp $ */
2/* 2/*
3 * scp - secure remote copy. This is basically patched BSD rcp which 3 * scp - secure remote copy. This is basically patched BSD rcp which
4 * uses ssh to do the data transfer (instead of using rcmd). 4 * uses ssh to do the data transfer (instead of using rcmd).
@@ -356,6 +356,7 @@ do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
356 addargs(&args, "-l"); 356 addargs(&args, "-l");
357 addargs(&args, "%s", remuser); 357 addargs(&args, "%s", remuser);
358 } 358 }
359 addargs(&args, "-oBatchMode=yes");
359 addargs(&args, "--"); 360 addargs(&args, "--");
360 addargs(&args, "%s", host); 361 addargs(&args, "%s", host);
361 addargs(&args, "%s", cmd); 362 addargs(&args, "%s", cmd);
@@ -381,6 +382,7 @@ BUF *allocbuf(BUF *, int, int);
381void lostconn(int); 382void lostconn(int);
382int okname(char *); 383int okname(char *);
383void run_err(const char *,...); 384void run_err(const char *,...);
385int note_err(const char *,...);
384void verifydir(char *); 386void verifydir(char *);
385 387
386struct passwd *pwd; 388struct passwd *pwd;
@@ -1238,9 +1240,6 @@ sink(int argc, char **argv, const char *src)
1238{ 1240{
1239 static BUF buffer; 1241 static BUF buffer;
1240 struct stat stb; 1242 struct stat stb;
1241 enum {
1242 YES, NO, DISPLAYED
1243 } wrerr;
1244 BUF *bp; 1243 BUF *bp;
1245 off_t i; 1244 off_t i;
1246 size_t j, count; 1245 size_t j, count;
@@ -1248,7 +1247,7 @@ sink(int argc, char **argv, const char *src)
1248 mode_t mode, omode, mask; 1247 mode_t mode, omode, mask;
1249 off_t size, statbytes; 1248 off_t size, statbytes;
1250 unsigned long long ull; 1249 unsigned long long ull;
1251 int setimes, targisdir, wrerrno = 0; 1250 int setimes, targisdir, wrerr;
1252 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; 1251 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
1253 char **patterns = NULL; 1252 char **patterns = NULL;
1254 size_t n, npatterns = 0; 1253 size_t n, npatterns = 0;
@@ -1436,9 +1435,7 @@ sink(int argc, char **argv, const char *src)
1436 sink(1, vect, src); 1435 sink(1, vect, src);
1437 if (setimes) { 1436 if (setimes) {
1438 setimes = 0; 1437 setimes = 0;
1439 if (utimes(vect[0], tv) == -1) 1438 (void) utimes(vect[0], tv);
1440 run_err("%s: set times: %s",
1441 vect[0], strerror(errno));
1442 } 1439 }
1443 if (mod_flag) 1440 if (mod_flag)
1444 (void) chmod(vect[0], mode); 1441 (void) chmod(vect[0], mode);
@@ -1457,8 +1454,13 @@ bad: run_err("%s: %s", np, strerror(errno));
1457 continue; 1454 continue;
1458 } 1455 }
1459 cp = bp->buf; 1456 cp = bp->buf;
1460 wrerr = NO; 1457 wrerr = 0;
1461 1458
1459 /*
1460 * NB. do not use run_err() unless immediately followed by
1461 * exit() below as it may send a spurious reply that might
1462 * desyncronise us from the peer. Use note_err() instead.
1463 */
1462 statbytes = 0; 1464 statbytes = 0;
1463 if (showprogress) 1465 if (showprogress)
1464 start_progress_meter(curfile, size, &statbytes); 1466 start_progress_meter(curfile, size, &statbytes);
@@ -1483,11 +1485,12 @@ bad: run_err("%s: %s", np, strerror(errno));
1483 1485
1484 if (count == bp->cnt) { 1486 if (count == bp->cnt) {
1485 /* Keep reading so we stay sync'd up. */ 1487 /* Keep reading so we stay sync'd up. */
1486 if (wrerr == NO) { 1488 if (!wrerr) {
1487 if (atomicio(vwrite, ofd, bp->buf, 1489 if (atomicio(vwrite, ofd, bp->buf,
1488 count) != count) { 1490 count) != count) {
1489 wrerr = YES; 1491 note_err("%s: %s", np,
1490 wrerrno = errno; 1492 strerror(errno));
1493 wrerr = 1;
1491 } 1494 }
1492 } 1495 }
1493 count = 0; 1496 count = 0;
@@ -1495,16 +1498,14 @@ bad: run_err("%s: %s", np, strerror(errno));
1495 } 1498 }
1496 } 1499 }
1497 unset_nonblock(remin); 1500 unset_nonblock(remin);
1498 if (count != 0 && wrerr == NO && 1501 if (count != 0 && !wrerr &&
1499 atomicio(vwrite, ofd, bp->buf, count) != count) { 1502 atomicio(vwrite, ofd, bp->buf, count) != count) {
1500 wrerr = YES; 1503 note_err("%s: %s", np, strerror(errno));
1501 wrerrno = errno; 1504 wrerr = 1;
1502 }
1503 if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
1504 ftruncate(ofd, size) != 0) {
1505 run_err("%s: truncate: %s", np, strerror(errno));
1506 wrerr = DISPLAYED;
1507 } 1505 }
1506 if (!wrerr && (!exists || S_ISREG(stb.st_mode)) &&
1507 ftruncate(ofd, size) != 0)
1508 note_err("%s: truncate: %s", np, strerror(errno));
1508 if (pflag) { 1509 if (pflag) {
1509 if (exists || omode != mode) 1510 if (exists || omode != mode)
1510#ifdef HAVE_FCHMOD 1511#ifdef HAVE_FCHMOD
@@ -1512,9 +1513,8 @@ bad: run_err("%s: %s", np, strerror(errno));
1512#else /* HAVE_FCHMOD */ 1513#else /* HAVE_FCHMOD */
1513 if (chmod(np, omode)) { 1514 if (chmod(np, omode)) {
1514#endif /* HAVE_FCHMOD */ 1515#endif /* HAVE_FCHMOD */
1515 run_err("%s: set mode: %s", 1516 note_err("%s: set mode: %s",
1516 np, strerror(errno)); 1517 np, strerror(errno));
1517 wrerr = DISPLAYED;
1518 } 1518 }
1519 } else { 1519 } else {
1520 if (!exists && omode != mode) 1520 if (!exists && omode != mode)
@@ -1523,36 +1523,25 @@ bad: run_err("%s: %s", np, strerror(errno));
1523#else /* HAVE_FCHMOD */ 1523#else /* HAVE_FCHMOD */
1524 if (chmod(np, omode & ~mask)) { 1524 if (chmod(np, omode & ~mask)) {
1525#endif /* HAVE_FCHMOD */ 1525#endif /* HAVE_FCHMOD */
1526 run_err("%s: set mode: %s", 1526 note_err("%s: set mode: %s",
1527 np, strerror(errno)); 1527 np, strerror(errno));
1528 wrerr = DISPLAYED;
1529 } 1528 }
1530 } 1529 }
1531 if (close(ofd) == -1) { 1530 if (close(ofd) == -1)
1532 wrerr = YES; 1531 note_err(np, "%s: close: %s", np, strerror(errno));
1533 wrerrno = errno;
1534 }
1535 (void) response(); 1532 (void) response();
1536 if (showprogress) 1533 if (showprogress)
1537 stop_progress_meter(); 1534 stop_progress_meter();
1538 if (setimes && wrerr == NO) { 1535 if (setimes && !wrerr) {
1539 setimes = 0; 1536 setimes = 0;
1540 if (utimes(np, tv) == -1) { 1537 if (utimes(np, tv) == -1) {
1541 run_err("%s: set times: %s", 1538 note_err("%s: set times: %s",
1542 np, strerror(errno)); 1539 np, strerror(errno));
1543 wrerr = DISPLAYED;
1544 } 1540 }
1545 } 1541 }
1546 switch (wrerr) { 1542 /* If no error was noted then signal success for this file */
1547 case YES: 1543 if (note_err(NULL) == 0)
1548 run_err("%s: %s", np, strerror(wrerrno));
1549 break;
1550 case NO:
1551 (void) atomicio(vwrite, remout, "", 1); 1544 (void) atomicio(vwrite, remout, "", 1);
1552 break;
1553 case DISPLAYED:
1554 break;
1555 }
1556 } 1545 }
1557done: 1546done:
1558 for (n = 0; n < npatterns; n++) 1547 for (n = 0; n < npatterns; n++)
@@ -1640,6 +1629,38 @@ run_err(const char *fmt,...)
1640 } 1629 }
1641} 1630}
1642 1631
1632/*
1633 * Notes a sink error for sending at the end of a file transfer. Returns 0 if
1634 * no error has been noted or -1 otherwise. Use note_err(NULL) to flush
1635 * any active error at the end of the transfer.
1636 */
1637int
1638note_err(const char *fmt, ...)
1639{
1640 static char *emsg;
1641 va_list ap;
1642
1643 /* Replay any previously-noted error */
1644 if (fmt == NULL) {
1645 if (emsg == NULL)
1646 return 0;
1647 run_err("%s", emsg);
1648 free(emsg);
1649 emsg = NULL;
1650 return -1;
1651 }
1652
1653 errs++;
1654 /* Prefer first-noted error */
1655 if (emsg != NULL)
1656 return -1;
1657
1658 va_start(ap, fmt);
1659 vasnmprintf(&emsg, INT_MAX, NULL, fmt, ap);
1660 va_end(ap);
1661 return -1;
1662}
1663
1643void 1664void
1644verifydir(char *cp) 1665verifydir(char *cp)
1645{ 1666{