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 6901e0c94..b4492a062 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).
@@ -348,6 +348,7 @@ do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
348 addargs(&args, "-l"); 348 addargs(&args, "-l");
349 addargs(&args, "%s", remuser); 349 addargs(&args, "%s", remuser);
350 } 350 }
351 addargs(&args, "-oBatchMode=yes");
351 addargs(&args, "--"); 352 addargs(&args, "--");
352 addargs(&args, "%s", host); 353 addargs(&args, "%s", host);
353 addargs(&args, "%s", cmd); 354 addargs(&args, "%s", cmd);
@@ -373,6 +374,7 @@ BUF *allocbuf(BUF *, int, int);
373void lostconn(int); 374void lostconn(int);
374int okname(char *); 375int okname(char *);
375void run_err(const char *,...); 376void run_err(const char *,...);
377int note_err(const char *,...);
376void verifydir(char *); 378void verifydir(char *);
377 379
378struct passwd *pwd; 380struct passwd *pwd;
@@ -1230,9 +1232,6 @@ sink(int argc, char **argv, const char *src)
1230{ 1232{
1231 static BUF buffer; 1233 static BUF buffer;
1232 struct stat stb; 1234 struct stat stb;
1233 enum {
1234 YES, NO, DISPLAYED
1235 } wrerr;
1236 BUF *bp; 1235 BUF *bp;
1237 off_t i; 1236 off_t i;
1238 size_t j, count; 1237 size_t j, count;
@@ -1240,7 +1239,7 @@ sink(int argc, char **argv, const char *src)
1240 mode_t mode, omode, mask; 1239 mode_t mode, omode, mask;
1241 off_t size, statbytes; 1240 off_t size, statbytes;
1242 unsigned long long ull; 1241 unsigned long long ull;
1243 int setimes, targisdir, wrerrno = 0; 1242 int setimes, targisdir, wrerr;
1244 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; 1243 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
1245 char **patterns = NULL; 1244 char **patterns = NULL;
1246 size_t n, npatterns = 0; 1245 size_t n, npatterns = 0;
@@ -1428,9 +1427,7 @@ sink(int argc, char **argv, const char *src)
1428 sink(1, vect, src); 1427 sink(1, vect, src);
1429 if (setimes) { 1428 if (setimes) {
1430 setimes = 0; 1429 setimes = 0;
1431 if (utimes(vect[0], tv) == -1) 1430 (void) utimes(vect[0], tv);
1432 run_err("%s: set times: %s",
1433 vect[0], strerror(errno));
1434 } 1431 }
1435 if (mod_flag) 1432 if (mod_flag)
1436 (void) chmod(vect[0], mode); 1433 (void) chmod(vect[0], mode);
@@ -1449,8 +1446,13 @@ bad: run_err("%s: %s", np, strerror(errno));
1449 continue; 1446 continue;
1450 } 1447 }
1451 cp = bp->buf; 1448 cp = bp->buf;
1452 wrerr = NO; 1449 wrerr = 0;
1453 1450
1451 /*
1452 * NB. do not use run_err() unless immediately followed by
1453 * exit() below as it may send a spurious reply that might
1454 * desyncronise us from the peer. Use note_err() instead.
1455 */
1454 statbytes = 0; 1456 statbytes = 0;
1455 if (showprogress) 1457 if (showprogress)
1456 start_progress_meter(curfile, size, &statbytes); 1458 start_progress_meter(curfile, size, &statbytes);
@@ -1475,11 +1477,12 @@ bad: run_err("%s: %s", np, strerror(errno));
1475 1477
1476 if (count == bp->cnt) { 1478 if (count == bp->cnt) {
1477 /* Keep reading so we stay sync'd up. */ 1479 /* Keep reading so we stay sync'd up. */
1478 if (wrerr == NO) { 1480 if (!wrerr) {
1479 if (atomicio(vwrite, ofd, bp->buf, 1481 if (atomicio(vwrite, ofd, bp->buf,
1480 count) != count) { 1482 count) != count) {
1481 wrerr = YES; 1483 note_err("%s: %s", np,
1482 wrerrno = errno; 1484 strerror(errno));
1485 wrerr = 1;
1483 } 1486 }
1484 } 1487 }
1485 count = 0; 1488 count = 0;
@@ -1487,16 +1490,14 @@ bad: run_err("%s: %s", np, strerror(errno));
1487 } 1490 }
1488 } 1491 }
1489 unset_nonblock(remin); 1492 unset_nonblock(remin);
1490 if (count != 0 && wrerr == NO && 1493 if (count != 0 && !wrerr &&
1491 atomicio(vwrite, ofd, bp->buf, count) != count) { 1494 atomicio(vwrite, ofd, bp->buf, count) != count) {
1492 wrerr = YES; 1495 note_err("%s: %s", np, strerror(errno));
1493 wrerrno = errno; 1496 wrerr = 1;
1494 }
1495 if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
1496 ftruncate(ofd, size) != 0) {
1497 run_err("%s: truncate: %s", np, strerror(errno));
1498 wrerr = DISPLAYED;
1499 } 1497 }
1498 if (!wrerr && (!exists || S_ISREG(stb.st_mode)) &&
1499 ftruncate(ofd, size) != 0)
1500 note_err("%s: truncate: %s", np, strerror(errno));
1500 if (pflag) { 1501 if (pflag) {
1501 if (exists || omode != mode) 1502 if (exists || omode != mode)
1502#ifdef HAVE_FCHMOD 1503#ifdef HAVE_FCHMOD
@@ -1504,9 +1505,8 @@ bad: run_err("%s: %s", np, strerror(errno));
1504#else /* HAVE_FCHMOD */ 1505#else /* HAVE_FCHMOD */
1505 if (chmod(np, omode)) { 1506 if (chmod(np, omode)) {
1506#endif /* HAVE_FCHMOD */ 1507#endif /* HAVE_FCHMOD */
1507 run_err("%s: set mode: %s", 1508 note_err("%s: set mode: %s",
1508 np, strerror(errno)); 1509 np, strerror(errno));
1509 wrerr = DISPLAYED;
1510 } 1510 }
1511 } else { 1511 } else {
1512 if (!exists && omode != mode) 1512 if (!exists && omode != mode)
@@ -1515,36 +1515,25 @@ bad: run_err("%s: %s", np, strerror(errno));
1515#else /* HAVE_FCHMOD */ 1515#else /* HAVE_FCHMOD */
1516 if (chmod(np, omode & ~mask)) { 1516 if (chmod(np, omode & ~mask)) {
1517#endif /* HAVE_FCHMOD */ 1517#endif /* HAVE_FCHMOD */
1518 run_err("%s: set mode: %s", 1518 note_err("%s: set mode: %s",
1519 np, strerror(errno)); 1519 np, strerror(errno));
1520 wrerr = DISPLAYED;
1521 } 1520 }
1522 } 1521 }
1523 if (close(ofd) == -1) { 1522 if (close(ofd) == -1)
1524 wrerr = YES; 1523 note_err(np, "%s: close: %s", np, strerror(errno));
1525 wrerrno = errno;
1526 }
1527 (void) response(); 1524 (void) response();
1528 if (showprogress) 1525 if (showprogress)
1529 stop_progress_meter(); 1526 stop_progress_meter();
1530 if (setimes && wrerr == NO) { 1527 if (setimes && !wrerr) {
1531 setimes = 0; 1528 setimes = 0;
1532 if (utimes(np, tv) == -1) { 1529 if (utimes(np, tv) == -1) {
1533 run_err("%s: set times: %s", 1530 note_err("%s: set times: %s",
1534 np, strerror(errno)); 1531 np, strerror(errno));
1535 wrerr = DISPLAYED;
1536 } 1532 }
1537 } 1533 }
1538 switch (wrerr) { 1534 /* If no error was noted then signal success for this file */
1539 case YES: 1535 if (note_err(NULL) == 0)
1540 run_err("%s: %s", np, strerror(wrerrno));
1541 break;
1542 case NO:
1543 (void) atomicio(vwrite, remout, "", 1); 1536 (void) atomicio(vwrite, remout, "", 1);
1544 break;
1545 case DISPLAYED:
1546 break;
1547 }
1548 } 1537 }
1549done: 1538done:
1550 for (n = 0; n < npatterns; n++) 1539 for (n = 0; n < npatterns; n++)
@@ -1632,6 +1621,38 @@ run_err(const char *fmt,...)
1632 } 1621 }
1633} 1622}
1634 1623
1624/*
1625 * Notes a sink error for sending at the end of a file transfer. Returns 0 if
1626 * no error has been noted or -1 otherwise. Use note_err(NULL) to flush
1627 * any active error at the end of the transfer.
1628 */
1629int
1630note_err(const char *fmt, ...)
1631{
1632 static char *emsg;
1633 va_list ap;
1634
1635 /* Replay any previously-noted error */
1636 if (fmt == NULL) {
1637 if (emsg == NULL)
1638 return 0;
1639 run_err("%s", emsg);
1640 free(emsg);
1641 emsg = NULL;
1642 return -1;
1643 }
1644
1645 errs++;
1646 /* Prefer first-noted error */
1647 if (emsg != NULL)
1648 return -1;
1649
1650 va_start(ap, fmt);
1651 vasnmprintf(&emsg, INT_MAX, NULL, fmt, ap);
1652 va_end(ap);
1653 return -1;
1654}
1655
1635void 1656void
1636verifydir(char *cp) 1657verifydir(char *cp)
1637{ 1658{