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). |
@@ -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); | |||
373 | void lostconn(int); | 374 | void lostconn(int); |
374 | int okname(char *); | 375 | int okname(char *); |
375 | void run_err(const char *,...); | 376 | void run_err(const char *,...); |
377 | int note_err(const char *,...); | ||
376 | void verifydir(char *); | 378 | void verifydir(char *); |
377 | 379 | ||
378 | struct passwd *pwd; | 380 | struct 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 | } |
1549 | done: | 1538 | done: |
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 | */ | ||
1629 | int | ||
1630 | note_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 | |||
1635 | void | 1656 | void |
1636 | verifydir(char *cp) | 1657 | verifydir(char *cp) |
1637 | { | 1658 | { |