diff options
Diffstat (limited to 'scp.c')
-rw-r--r-- | scp.c | 101 |
1 files changed, 61 insertions, 40 deletions
@@ -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); | |||
381 | void lostconn(int); | 382 | void lostconn(int); |
382 | int okname(char *); | 383 | int okname(char *); |
383 | void run_err(const char *,...); | 384 | void run_err(const char *,...); |
385 | int note_err(const char *,...); | ||
384 | void verifydir(char *); | 386 | void verifydir(char *); |
385 | 387 | ||
386 | struct passwd *pwd; | 388 | struct 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 | } |
1557 | done: | 1546 | done: |
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 | */ | ||
1637 | int | ||
1638 | note_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 | |||
1643 | void | 1664 | void |
1644 | verifydir(char *cp) | 1665 | verifydir(char *cp) |
1645 | { | 1666 | { |