1 /* 2 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "includes.h" 18 19 RCSID("$OpenBSD: sftp.c,v 1.70 2006/01/31 10:19:02 djm Exp $"); 20 21 #ifdef USE_LIBEDIT 22 #include <histedit.h> 23 #else 24 typedef void EditLine; 25 #endif 26 27 #include "buffer.h" 28 #include "xmalloc.h" 29 #include "log.h" 30 #include "pathnames.h" 31 #include "misc.h" 32 33 #include "sftp.h" 34 #include "sftp-common.h" 35 #include "sftp-client.h" 36 37 /* File to read commands from */ 38 FILE* infile; 39 40 /* Are we in batchfile mode? */ 41 int batchmode = 0; 42 43 /* Size of buffer used when copying files */ 44 size_t copy_buffer_len = 32768; 45 46 /* Number of concurrent outstanding requests */ 47 size_t num_requests = 16; 48 49 /* PID of ssh transport process */ 50 static pid_t sshpid = -1; 51 52 /* This is set to 0 if the progressmeter is not desired. */ 53 int showprogress = 1; 54 55 /* SIGINT received during command processing */ 56 volatile sig_atomic_t interrupted = 0; 57 58 /* I wish qsort() took a separate ctx for the comparison function...*/ 59 int sort_flag; 60 61 int remote_glob(struct sftp_conn *, const char *, int, 62 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ 63 64 extern char *__progname; 65 66 /* Separators for interactive commands */ 67 #define WHITESPACE " \t\r\n" 68 69 /* ls flags */ 70 #define LS_LONG_VIEW 0x01 /* Full view ala ls -l */ 71 #define LS_SHORT_VIEW 0x02 /* Single row view ala ls -1 */ 72 #define LS_NUMERIC_VIEW 0x04 /* Long view with numeric uid/gid */ 73 #define LS_NAME_SORT 0x08 /* Sort by name (default) */ 74 #define LS_TIME_SORT 0x10 /* Sort by mtime */ 75 #define LS_SIZE_SORT 0x20 /* Sort by file size */ 76 #define LS_REVERSE_SORT 0x40 /* Reverse sort order */ 77 #define LS_SHOW_ALL 0x80 /* Don't skip filenames starting with '.' */ 78 79 #define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW) 80 #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) 81 82 /* Commands for interactive mode */ 83 #define I_CHDIR 1 84 #define I_CHGRP 2 85 #define I_CHMOD 3 86 #define I_CHOWN 4 87 #define I_GET 5 88 #define I_HELP 6 89 #define I_LCHDIR 7 90 #define I_LLS 8 91 #define I_LMKDIR 9 92 #define I_LPWD 10 93 #define I_LS 11 94 #define I_LUMASK 12 95 #define I_MKDIR 13 96 #define I_PUT 14 97 #define I_PWD 15 98 #define I_QUIT 16 99 #define I_RENAME 17 100 #define I_RM 18 101 #define I_RMDIR 19 102 #define I_SHELL 20 103 #define I_SYMLINK 21 104 #define I_VERSION 22 105 #define I_PROGRESS 23 106 107 struct CMD { 108 const char *c; 109 const int n; 110 }; 111 112 static const struct CMD cmds[] = { 113 { "bye", I_QUIT }, 114 { "cd", I_CHDIR }, 115 { "chdir", I_CHDIR }, 116 { "chgrp", I_CHGRP }, 117 { "chmod", I_CHMOD }, 118 { "chown", I_CHOWN }, 119 { "dir", I_LS }, 120 { "exit", I_QUIT }, 121 { "get", I_GET }, 122 { "mget", I_GET }, 123 { "help", I_HELP }, 124 { "lcd", I_LCHDIR }, 125 { "lchdir", I_LCHDIR }, 126 { "lls", I_LLS }, 127 { "lmkdir", I_LMKDIR }, 128 { "ln", I_SYMLINK }, 129 { "lpwd", I_LPWD }, 130 { "ls", I_LS }, 131 { "lumask", I_LUMASK }, 132 { "mkdir", I_MKDIR }, 133 { "progress", I_PROGRESS }, 134 { "put", I_PUT }, 135 { "mput", I_PUT }, 136 { "pwd", I_PWD }, 137 { "quit", I_QUIT }, 138 { "rename", I_RENAME }, 139 { "rm", I_RM }, 140 { "rmdir", I_RMDIR }, 141 { "symlink", I_SYMLINK }, 142 { "version", I_VERSION }, 143 { "!", I_SHELL }, 144 { "?", I_HELP }, 145 { NULL, -1} 146 }; 147 148 int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); 149 150 static void 151 killchild(int signo) 152 { 153 if (sshpid > 1) { 154 kill(sshpid, SIGTERM); 155 waitpid(sshpid, NULL, 0); 156 } 157 158 _exit(1); 159 } 160 161 static void 162 cmd_interrupt(int signo) 163 { 164 const char msg[] = "\rInterrupt \n"; 165 int olderrno = errno; 166 167 write(STDERR_FILENO, msg, sizeof(msg) - 1); 168 interrupted = 1; 169 errno = olderrno; 170 } 171 172 static void 173 help(void) 174 { 175 printf("Available commands:\n"); 176 printf("cd path Change remote directory to 'path'\n"); 177 printf("lcd path Change local directory to 'path'\n"); 178 printf("chgrp grp path Change group of file 'path' to 'grp'\n"); 179 printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); 180 printf("chown own path Change owner of file 'path' to 'own'\n"); 181 printf("help Display this help text\n"); 182 printf("get remote-path [local-path] Download file\n"); 183 printf("lls [ls-options [path]] Display local directory listing\n"); 184 printf("ln oldpath newpath Symlink remote file\n"); 185 printf("lmkdir path Create local directory\n"); 186 printf("lpwd Print local working directory\n"); 187 printf("ls [path] Display remote directory listing\n"); 188 printf("lumask umask Set local umask to 'umask'\n"); 189 printf("mkdir path Create remote directory\n"); 190 printf("progress Toggle display of progress meter\n"); 191 printf("put local-path [remote-path] Upload file\n"); 192 printf("pwd Display remote working directory\n"); 193 printf("exit Quit sftp\n"); 194 printf("quit Quit sftp\n"); 195 printf("rename oldpath newpath Rename remote file\n"); 196 printf("rmdir path Remove remote directory\n"); 197 printf("rm path Delete remote file\n"); 198 printf("symlink oldpath newpath Symlink remote file\n"); 199 printf("version Show SFTP version\n"); 200 printf("!command Execute 'command' in local shell\n"); 201 printf("! Escape to local shell\n"); 202 printf("? Synonym for help\n"); 203 } 204 205 static void 206 local_do_shell(const char *args) 207 { 208 int status; 209 char *shell; 210 pid_t pid; 211 212 if (!*args) 213 args = NULL; 214 215 if ((shell = getenv("SHELL")) == NULL) 216 shell = _PATH_BSHELL; 217 218 if ((pid = fork()) == -1) 219 fatal("Couldn't fork: %s", strerror(errno)); 220 221 if (pid == 0) { 222 /* XXX: child has pipe fds to ssh subproc open - issue? */ 223 if (args) { 224 debug3("Executing %s -c \"%s\"", shell, args); 225 execl(shell, shell, "-c", args, (char *)NULL); 226 } else { 227 debug3("Executing %s", shell); 228 execl(shell, shell, (char *)NULL); 229 } 230 fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, 231 strerror(errno)); 232 _exit(1); 233 } 234 while (waitpid(pid, &status, 0) == -1) 235 if (errno != EINTR) 236 fatal("Couldn't wait for child: %s", strerror(errno)); 237 if (!WIFEXITED(status)) 238 error("Shell exited abormally"); 239 else if (WEXITSTATUS(status)) 240 error("Shell exited with status %d", WEXITSTATUS(status)); 241 } 242 243 static void 244 local_do_ls(const char *args) 245 { 246 if (!args || !*args) 247 local_do_shell(_PATH_LS); 248 else { 249 int len = strlen(_PATH_LS " ") + strlen(args) + 1; 250 char *buf = xmalloc(len); 251 252 /* XXX: quoting - rip quoting code from ftp? */ 253 snprintf(buf, len, _PATH_LS " %s", args); 254 local_do_shell(buf); 255 xfree(buf); 256 } 257 } 258 259 /* Strip one path (usually the pwd) from the start of another */ 260 static char * 261 path_strip(char *path, char *strip) 262 { 263 size_t len; 264 265 if (strip == NULL) 266 return (xstrdup(path)); 267 268 len = strlen(strip); 269 if (strncmp(path, strip, len) == 0) { 270 if (strip[len - 1] != '/' && path[len] == '/') 271 len++; 272 return (xstrdup(path + len)); 273 } 274 275 return (xstrdup(path)); 276 } 277 278 static char * 279 path_append(char *p1, char *p2) 280 { 281 char *ret; 282 int len = strlen(p1) + strlen(p2) + 2; 283 284 ret = xmalloc(len); 285 strlcpy(ret, p1, len); 286 if (p1[strlen(p1) - 1] != '/') 287 strlcat(ret, "/", len); 288 strlcat(ret, p2, len); 289 290 return(ret); 291 } 292 293 static char * 294 make_absolute(char *p, char *pwd) 295 { 296 char *abs_str; 297 298 /* Derelativise */ 299 if (p && p[0] != '/') { 300 abs_str = path_append(pwd, p); 301 xfree(p); 302 return(abs_str); 303 } else 304 return(p); 305 } 306 307 static int 308 infer_path(const char *p, char **ifp) 309 { 310 char *cp; 311 312 cp = strrchr(p, '/'); 313 if (cp == NULL) { 314 *ifp = xstrdup(p); 315 return(0); 316 } 317 318 if (!cp[1]) { 319 error("Invalid path"); 320 return(-1); 321 } 322 323 *ifp = xstrdup(cp + 1); 324 return(0); 325 } 326 327 static int 328 parse_getput_flags(const char **cpp, int *pflag) 329 { 330 const char *cp = *cpp; 331 332 /* Check for flags */ 333 if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { 334 switch (cp[1]) { 335 case 'p': 336 case 'P': 337 *pflag = 1; 338 break; 339 default: 340 error("Invalid flag -%c", cp[1]); 341 return(-1); 342 } 343 cp += 2; 344 *cpp = cp + strspn(cp, WHITESPACE); 345 } 346 347 return(0); 348 } 349 350 static int 351 parse_ls_flags(const char **cpp, int *lflag) 352 { 353 const char *cp = *cpp; 354 355 /* Defaults */ 356 *lflag = LS_NAME_SORT; 357 358 /* Check for flags */ 359 if (cp++[0] == '-') { 360 for (; strchr(WHITESPACE, *cp) == NULL; cp++) { 361 switch (*cp) { 362 case 'l': 363 *lflag &= ~VIEW_FLAGS; 364 *lflag |= LS_LONG_VIEW; 365 break; 366 case '1': 367 *lflag &= ~VIEW_FLAGS; 368 *lflag |= LS_SHORT_VIEW; 369 break; 370 case 'n': 371 *lflag &= ~VIEW_FLAGS; 372 *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; 373 break; 374 case 'S': 375 *lflag &= ~SORT_FLAGS; 376 *lflag |= LS_SIZE_SORT; 377 break; 378 case 't': 379 *lflag &= ~SORT_FLAGS; 380 *lflag |= LS_TIME_SORT; 381 break; 382 case 'r': 383 *lflag |= LS_REVERSE_SORT; 384 break; 385 case 'f': 386 *lflag &= ~SORT_FLAGS; 387 break; 388 case 'a': 389 *lflag |= LS_SHOW_ALL; 390 break; 391 default: 392 error("Invalid flag -%c", *cp); 393 return(-1); 394 } 395 } 396 *cpp = cp + strspn(cp, WHITESPACE); 397 } 398 399 return(0); 400 } 401 402 static int 403 get_pathname(const char **cpp, char **path) 404 { 405 const char *cp = *cpp, *end; 406 char quot; 407 u_int i, j; 408 409 cp += strspn(cp, WHITESPACE); 410 if (!*cp) { 411 *cpp = cp; 412 *path = NULL; 413 return (0); 414 } 415 416 *path = xmalloc(strlen(cp) + 1); 417 418 /* Check for quoted filenames */ 419 if (*cp == '\"' || *cp == '\'') { 420 quot = *cp++; 421 422 /* Search for terminating quote, unescape some chars */ 423 for (i = j = 0; i <= strlen(cp); i++) { 424 if (cp[i] == quot) { /* Found quote */ 425 i++; 426 (*path)[j] = '\0'; 427 break; 428 } 429 if (cp[i] == '\0') { /* End of string */ 430 error("Unterminated quote"); 431 goto fail; 432 } 433 if (cp[i] == '\\') { /* Escaped characters */ 434 i++; 435 if (cp[i] != '\'' && cp[i] != '\"' && 436 cp[i] != '\\') { 437 error("Bad escaped character '\\%c'", 438 cp[i]); 439 goto fail; 440 } 441 } 442 (*path)[j++] = cp[i]; 443 } 444 445 if (j == 0) { 446 error("Empty quotes"); 447 goto fail; 448 } 449 *cpp = cp + i + strspn(cp + i, WHITESPACE); 450 } else { 451 /* Read to end of filename */ 452 end = strpbrk(cp, WHITESPACE); 453 if (end == NULL) 454 end = strchr(cp, '\0'); 455 *cpp = end + strspn(end, WHITESPACE); 456 457 memcpy(*path, cp, end - cp); 458 (*path)[end - cp] = '\0'; 459 } 460 return (0); 461 462 fail: 463 xfree(*path); 464 *path = NULL; 465 return (-1); 466 } 467 468 static int 469 is_dir(char *path) 470 { 471 struct stat sb; 472 473 /* XXX: report errors? */ 474 if (stat(path, &sb) == -1) 475 return(0); 476 477 return(sb.st_mode & S_IFDIR); 478 } 479 480 static int 481 is_reg(char *path) 482 { 483 struct stat sb; 484 485 if (stat(path, &sb) == -1) 486 fatal("stat %s: %s", path, strerror(errno)); 487 488 return(S_ISREG(sb.st_mode)); 489 } 490 491 static int 492 remote_is_dir(struct sftp_conn *conn, char *path) 493 { 494 Attrib *a; 495 496 /* XXX: report errors? */ 497 if ((a = do_stat(conn, path, 1)) == NULL) 498 return(0); 499 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 500 return(0); 501 return(a->perm & S_IFDIR); 502 } 503 504 static int 505 process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) 506 { 507 char *abs_src = NULL; 508 char *abs_dst = NULL; 509 char *tmp; 510 glob_t g; 511 int err = 0; 512 int i; 513 514 abs_src = xstrdup(src); 515 abs_src = make_absolute(abs_src, pwd); 516 517 memset(&g, 0, sizeof(g)); 518 debug3("Looking up %s", abs_src); 519 if (remote_glob(conn, abs_src, 0, NULL, &g)) { 520 error("File \"%s\" not found.", abs_src); 521 err = -1; 522 goto out; 523 } 524 525 /* If multiple matches, dst must be a directory or unspecified */ 526 if (g.gl_matchc > 1 && dst && !is_dir(dst)) { 527 error("Multiple files match, but \"%s\" is not a directory", 528 dst); 529 err = -1; 530 goto out; 531 } 532 533 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 534 if (infer_path(g.gl_pathv[i], &tmp)) { 535 err = -1; 536 goto out; 537 } 538 539 if (g.gl_matchc == 1 && dst) { 540 /* If directory specified, append filename */ 541 if (is_dir(dst)) { 542 if (infer_path(g.gl_pathv[0], &tmp)) { 543 err = 1; 544 goto out; 545 } 546 abs_dst = path_append(dst, tmp); 547 xfree(tmp); 548 } else 549 abs_dst = xstrdup(dst); 550 } else if (dst) { 551 abs_dst = path_append(dst, tmp); 552 xfree(tmp); 553 } else 554 abs_dst = tmp; 555 556 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); 557 if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) 558 err = -1; 559 xfree(abs_dst); 560 abs_dst = NULL; 561 } 562 563 out: 564 xfree(abs_src); 565 if (abs_dst) 566 xfree(abs_dst); 567 globfree(&g); 568 return(err); 569 } 570 571 static int 572 process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) 573 { 574 char *tmp_dst = NULL; 575 char *abs_dst = NULL; 576 char *tmp; 577 glob_t g; 578 int err = 0; 579 int i; 580 581 if (dst) { 582 tmp_dst = xstrdup(dst); 583 tmp_dst = make_absolute(tmp_dst, pwd); 584 } 585 586 memset(&g, 0, sizeof(g)); 587 debug3("Looking up %s", src); 588 if (glob(src, 0, NULL, &g)) { 589 error("File \"%s\" not found.", src); 590 err = -1; 591 goto out; 592 } 593 594 /* If multiple matches, dst may be directory or unspecified */ 595 if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) { 596 error("Multiple files match, but \"%s\" is not a directory", 597 tmp_dst); 598 err = -1; 599 goto out; 600 } 601 602 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 603 if (!is_reg(g.gl_pathv[i])) { 604 error("skipping non-regular file %s", 605 g.gl_pathv[i]); 606 continue; 607 } 608 if (infer_path(g.gl_pathv[i], &tmp)) { 609 err = -1; 610 goto out; 611 } 612 613 if (g.gl_matchc == 1 && tmp_dst) { 614 /* If directory specified, append filename */ 615 if (remote_is_dir(conn, tmp_dst)) { 616 if (infer_path(g.gl_pathv[0], &tmp)) { 617 err = 1; 618 goto out; 619 } 620 abs_dst = path_append(tmp_dst, tmp); 621 xfree(tmp); 622 } else 623 abs_dst = xstrdup(tmp_dst); 624 625 } else if (tmp_dst) { 626 abs_dst = path_append(tmp_dst, tmp); 627 xfree(tmp); 628 } else 629 abs_dst = make_absolute(tmp, pwd); 630 631 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); 632 if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1) 633 err = -1; 634 } 635 636 out: 637 if (abs_dst) 638 xfree(abs_dst); 639 if (tmp_dst) 640 xfree(tmp_dst); 641 globfree(&g); 642 return(err); 643 } 644 645 static int 646 sdirent_comp(const void *aa, const void *bb) 647 { 648 SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; 649 SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; 650 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 651 652 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 653 if (sort_flag & LS_NAME_SORT) 654 return (rmul * strcmp(a->filename, b->filename)); 655 else if (sort_flag & LS_TIME_SORT) 656 return (rmul * NCMP(a->a.mtime, b->a.mtime)); 657 else if (sort_flag & LS_SIZE_SORT) 658 return (rmul * NCMP(a->a.size, b->a.size)); 659 660 fatal("Unknown ls sort type"); 661 } 662 663 /* sftp ls.1 replacement for directories */ 664 static int 665 do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) 666 { 667 int n; 668 u_int c = 1, colspace = 0, columns = 1; 669 SFTP_DIRENT **d; 670 671 if ((n = do_readdir(conn, path, &d)) != 0) 672 return (n); 673 674 if (!(lflag & LS_SHORT_VIEW)) { 675 u_int m = 0, width = 80; 676 struct winsize ws; 677 char *tmp; 678 679 /* Count entries for sort and find longest filename */ 680 for (n = 0; d[n] != NULL; n++) { 681 if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) 682 m = MAX(m, strlen(d[n]->filename)); 683 } 684 685 /* Add any subpath that also needs to be counted */ 686 tmp = path_strip(path, strip_path); 687 m += strlen(tmp); 688 xfree(tmp); 689 690 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 691 width = ws.ws_col; 692 693 columns = width / (m + 2); 694 columns = MAX(columns, 1); 695 colspace = width / columns; 696 colspace = MIN(colspace, width); 697 } 698 699 if (lflag & SORT_FLAGS) { 700 for (n = 0; d[n] != NULL; n++) 701 ; /* count entries */ 702 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); 703 qsort(d, n, sizeof(*d), sdirent_comp); 704 } 705 706 for (n = 0; d[n] != NULL && !interrupted; n++) { 707 char *tmp, *fname; 708 709 if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) 710 continue; 711 712 tmp = path_append(path, d[n]->filename); 713 fname = path_strip(tmp, strip_path); 714 xfree(tmp); 715 716 if (lflag & LS_LONG_VIEW) { 717 if (lflag & LS_NUMERIC_VIEW) { 718 char *lname; 719 struct stat sb; 720 721 memset(&sb, 0, sizeof(sb)); 722 attrib_to_stat(&d[n]->a, &sb); 723 lname = ls_file(fname, &sb, 1); 724 printf("%s\n", lname); 725 xfree(lname); 726 } else 727 printf("%s\n", d[n]->longname); 728 } else { 729 printf("%-*s", colspace, fname); 730 if (c >= columns) { 731 printf("\n"); 732 c = 1; 733 } else 734 c++; 735 } 736 737 xfree(fname); 738 } 739 740 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 741 printf("\n"); 742 743 free_sftp_dirents(d); 744 return (0); 745 } 746 747 /* sftp ls.1 replacement which handles path globs */ 748 static int 749 do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, 750 int lflag) 751 { 752 glob_t g; 753 u_int i, c = 1, colspace = 0, columns = 1; 754 Attrib *a = NULL; 755 756 memset(&g, 0, sizeof(g)); 757 758 if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, 759 NULL, &g) || (g.gl_pathc && !g.gl_matchc)) { 760 if (g.gl_pathc) 761 globfree(&g); 762 error("Can't ls: \"%s\" not found", path); 763 return (-1); 764 } 765 766 if (interrupted) 767 goto out; 768 769 /* 770 * If the glob returns a single match and it is a directory, 771 * then just list its contents. 772 */ 773 if (g.gl_matchc == 1) { 774 if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) { 775 globfree(&g); 776 return (-1); 777 } 778 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 779 S_ISDIR(a->perm)) { 780 int err; 781 782 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); 783 globfree(&g); 784 return (err); 785 } 786 } 787 788 if (!(lflag & LS_SHORT_VIEW)) { 789 u_int m = 0, width = 80; 790 struct winsize ws; 791 792 /* Count entries for sort and find longest filename */ 793 for (i = 0; g.gl_pathv[i]; i++) 794 m = MAX(m, strlen(g.gl_pathv[i])); 795 796 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 797 width = ws.ws_col; 798 799 columns = width / (m + 2); 800 columns = MAX(columns, 1); 801 colspace = width / columns; 802 } 803 804 for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) { 805 char *fname; 806 807 fname = path_strip(g.gl_pathv[i], strip_path); 808 809 if (lflag & LS_LONG_VIEW) { 810 char *lname; 811 struct stat sb; 812 813 /* 814 * XXX: this is slow - 1 roundtrip per path 815 * A solution to this is to fork glob() and 816 * build a sftp specific version which keeps the 817 * attribs (which currently get thrown away) 818 * that the server returns as well as the filenames. 819 */ 820 memset(&sb, 0, sizeof(sb)); 821 if (a == NULL) 822 a = do_lstat(conn, g.gl_pathv[i], 1); 823 if (a != NULL) 824 attrib_to_stat(a, &sb); 825 lname = ls_file(fname, &sb, 1); 826 printf("%s\n", lname); 827 xfree(lname); 828 } else { 829 printf("%-*s", colspace, fname); 830 if (c >= columns) { 831 printf("\n"); 832 c = 1; 833 } else 834 c++; 835 } 836 xfree(fname); 837 } 838 839 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 840 printf("\n"); 841 842 out: 843 if (g.gl_pathc) 844 globfree(&g); 845 846 return (0); 847 } 848 849 static int 850 parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, 851 unsigned long *n_arg, char **path1, char **path2) 852 { 853 const char *cmd, *cp = *cpp; 854 char *cp2; 855 int base = 0; 856 long l; 857 int i, cmdnum; 858 859 /* Skip leading whitespace */ 860 cp = cp + strspn(cp, WHITESPACE); 861 862 /* Ignore blank lines and lines which begin with comment '#' char */ 863 if (*cp == '\0' || *cp == '#') 864 return (0); 865 866 /* Check for leading '-' (disable error processing) */ 867 *iflag = 0; 868 if (*cp == '-') { 869 *iflag = 1; 870 cp++; 871 } 872 873 /* Figure out which command we have */ 874 for (i = 0; cmds[i].c; i++) { 875 int cmdlen = strlen(cmds[i].c); 876 877 /* Check for command followed by whitespace */ 878 if (!strncasecmp(cp, cmds[i].c, cmdlen) && 879 strchr(WHITESPACE, cp[cmdlen])) { 880 cp += cmdlen; 881 cp = cp + strspn(cp, WHITESPACE); 882 break; 883 } 884 } 885 cmdnum = cmds[i].n; 886 cmd = cmds[i].c; 887 888 /* Special case */ 889 if (*cp == '!') { 890 cp++; 891 cmdnum = I_SHELL; 892 } else if (cmdnum == -1) { 893 error("Invalid command."); 894 return (-1); 895 } 896 897 /* Get arguments and parse flags */ 898 *lflag = *pflag = *n_arg = 0; 899 *path1 = *path2 = NULL; 900 switch (cmdnum) { 901 case I_GET: 902 case I_PUT: 903 if (parse_getput_flags(&cp, pflag)) 904 return(-1); 905 /* Get first pathname (mandatory) */ 906 if (get_pathname(&cp, path1)) 907 return(-1); 908 if (*path1 == NULL) { 909 error("You must specify at least one path after a " 910 "%s command.", cmd); 911 return(-1); 912 } 913 /* Try to get second pathname (optional) */ 914 if (get_pathname(&cp, path2)) 915 return(-1); 916 break; 917 case I_RENAME: 918 case I_SYMLINK: 919 if (get_pathname(&cp, path1)) 920 return(-1); 921 if (get_pathname(&cp, path2)) 922 return(-1); 923 if (!*path1 || !*path2) { 924 error("You must specify two paths after a %s " 925 "command.", cmd); 926 return(-1); 927 } 928 break; 929 case I_RM: 930 case I_MKDIR: 931 case I_RMDIR: 932 case I_CHDIR: 933 case I_LCHDIR: 934 case I_LMKDIR: 935 /* Get pathname (mandatory) */ 936 if (get_pathname(&cp, path1)) 937 return(-1); 938 if (*path1 == NULL) { 939 error("You must specify a path after a %s command.", 940 cmd); 941 return(-1); 942 } 943 break; 944 case I_LS: 945 if (parse_ls_flags(&cp, lflag)) 946 return(-1); 947 /* Path is optional */ 948 if (get_pathname(&cp, path1)) 949 return(-1); 950 break; 951 case I_LLS: 952 case I_SHELL: 953 /* Uses the rest of the line */ 954 break; 955 case I_LUMASK: 956 base = 8; 957 case I_CHMOD: 958 base = 8; 959 case I_CHOWN: 960 case I_CHGRP: 961 /* Get numeric arg (mandatory) */ 962 l = strtol(cp, &cp2, base); 963 if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) && 964 errno == ERANGE) || l < 0) { 965 error("You must supply a numeric argument " 966 "to the %s command.", cmd); 967 return(-1); 968 } 969 cp = cp2; 970 *n_arg = l; 971 if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp)) 972 break; 973 if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) { 974 error("You must supply a numeric argument " 975 "to the %s command.", cmd); 976 return(-1); 977 } 978 cp += strspn(cp, WHITESPACE); 979 980 /* Get pathname (mandatory) */ 981 if (get_pathname(&cp, path1)) 982 return(-1); 983 if (*path1 == NULL) { 984 error("You must specify a path after a %s command.", 985 cmd); 986 return(-1); 987 } 988 break; 989 case I_QUIT: 990 case I_PWD: 991 case I_LPWD: 992 case I_HELP: 993 case I_VERSION: 994 case I_PROGRESS: 995 break; 996 default: 997 fatal("Command not implemented"); 998 } 999 1000 *cpp = cp; 1001 return(cmdnum); 1002 } 1003 1004 static int 1005 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, 1006 int err_abort) 1007 { 1008 char *path1, *path2, *tmp; 1009 int pflag, lflag, iflag, cmdnum, i; 1010 unsigned long n_arg; 1011 Attrib a, *aa; 1012 char path_buf[MAXPATHLEN]; 1013 int err = 0; 1014 glob_t g; 1015 1016 path1 = path2 = NULL; 1017 cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg, 1018 &path1, &path2); 1019 1020 if (iflag != 0) 1021 err_abort = 0; 1022 1023 memset(&g, 0, sizeof(g)); 1024 1025 /* Perform command */ 1026 switch (cmdnum) { 1027 case 0: 1028 /* Blank line */ 1029 break; 1030 case -1: 1031 /* Unrecognized command */ 1032 err = -1; 1033 break; 1034 case I_GET: 1035 err = process_get(conn, path1, path2, *pwd, pflag); 1036 break; 1037 case I_PUT: 1038 err = process_put(conn, path1, path2, *pwd, pflag); 1039 break; 1040 case I_RENAME: 1041 path1 = make_absolute(path1, *pwd); 1042 path2 = make_absolute(path2, *pwd); 1043 err = do_rename(conn, path1, path2); 1044 break; 1045 case I_SYMLINK: 1046 path2 = make_absolute(path2, *pwd); 1047 err = do_symlink(conn, path1, path2); 1048 break; 1049 case I_RM: 1050 path1 = make_absolute(path1, *pwd); 1051 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1052 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1053 printf("Removing %s\n", g.gl_pathv[i]); 1054 err = do_rm(conn, g.gl_pathv[i]); 1055 if (err != 0 && err_abort) 1056 break; 1057 } 1058 break; 1059 case I_MKDIR: 1060 path1 = make_absolute(path1, *pwd); 1061 attrib_clear(&a); 1062 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1063 a.perm = 0777; 1064 err = do_mkdir(conn, path1, &a); 1065 break; 1066 case I_RMDIR: 1067 path1 = make_absolute(path1, *pwd); 1068 err = do_rmdir(conn, path1); 1069 break; 1070 case I_CHDIR: 1071 path1 = make_absolute(path1, *pwd); 1072 if ((tmp = do_realpath(conn, path1)) == NULL) { 1073 err = 1; 1074 break; 1075 } 1076 if ((aa = do_stat(conn, tmp, 0)) == NULL) { 1077 xfree(tmp); 1078 err = 1; 1079 break; 1080 } 1081 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { 1082 error("Can't change directory: Can't check target"); 1083 xfree(tmp); 1084 err = 1; 1085 break; 1086 } 1087 if (!S_ISDIR(aa->perm)) { 1088 error("Can't change directory: \"%s\" is not " 1089 "a directory", tmp); 1090 xfree(tmp); 1091 err = 1; 1092 break; 1093 } 1094 xfree(*pwd); 1095 *pwd = tmp; 1096 break; 1097 case I_LS: 1098 if (!path1) { 1099 do_globbed_ls(conn, *pwd, *pwd, lflag); 1100 break; 1101 } 1102 1103 /* Strip pwd off beginning of non-absolute paths */ 1104 tmp = NULL; 1105 if (*path1 != '/') 1106 tmp = *pwd; 1107 1108 path1 = make_absolute(path1, *pwd); 1109 err = do_globbed_ls(conn, path1, tmp, lflag); 1110 break; 1111 case I_LCHDIR: 1112 if (chdir(path1) == -1) { 1113 error("Couldn't change local directory to " 1114 "\"%s\": %s", path1, strerror(errno)); 1115 err = 1; 1116 } 1117 break; 1118 case I_LMKDIR: 1119 if (mkdir(path1, 0777) == -1) { 1120 error("Couldn't create local directory " 1121 "\"%s\": %s", path1, strerror(errno)); 1122 err = 1; 1123 } 1124 break; 1125 case I_LLS: 1126 local_do_ls(cmd); 1127 break; 1128 case I_SHELL: 1129 local_do_shell(cmd); 1130 break; 1131 case I_LUMASK: 1132 umask(n_arg); 1133 printf("Local umask: %03lo\n", n_arg); 1134 break; 1135 case I_CHMOD: 1136 path1 = make_absolute(path1, *pwd); 1137 attrib_clear(&a); 1138 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1139 a.perm = n_arg; 1140 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1141 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1142 printf("Changing mode on %s\n", g.gl_pathv[i]); 1143 err = do_setstat(conn, g.gl_pathv[i], &a); 1144 if (err != 0 && err_abort) 1145 break; 1146 } 1147 break; 1148 case I_CHOWN: 1149 case I_CHGRP: 1150 path1 = make_absolute(path1, *pwd); 1151 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1152 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1153 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { 1154 if (err != 0 && err_abort) 1155 break; 1156 else 1157 continue; 1158 } 1159 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { 1160 error("Can't get current ownership of " 1161 "remote file \"%s\"", g.gl_pathv[i]); 1162 if (err != 0 && err_abort) 1163 break; 1164 else 1165 continue; 1166 } 1167 aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; 1168 if (cmdnum == I_CHOWN) { 1169 printf("Changing owner on %s\n", g.gl_pathv[i]); 1170 aa->uid = n_arg; 1171 } else { 1172 printf("Changing group on %s\n", g.gl_pathv[i]); 1173 aa->gid = n_arg; 1174 } 1175 err = do_setstat(conn, g.gl_pathv[i], aa); 1176 if (err != 0 && err_abort) 1177 break; 1178 } 1179 break; 1180 case I_PWD: 1181 printf("Remote working directory: %s\n", *pwd); 1182 break; 1183 case I_LPWD: 1184 if (!getcwd(path_buf, sizeof(path_buf))) { 1185 error("Couldn't get local cwd: %s", strerror(errno)); 1186 err = -1; 1187 break; 1188 } 1189 printf("Local working directory: %s\n", path_buf); 1190 break; 1191 case I_QUIT: 1192 /* Processed below */ 1193 break; 1194 case I_HELP: 1195 help(); 1196 break; 1197 case I_VERSION: 1198 printf("SFTP protocol version %u\n", sftp_proto_version(conn)); 1199 break; 1200 case I_PROGRESS: 1201 showprogress = !showprogress; 1202 if (showprogress) 1203 printf("Progress meter enabled\n"); 1204 else 1205 printf("Progress meter disabled\n"); 1206 break; 1207 default: 1208 fatal("%d is not implemented", cmdnum); 1209 } 1210 1211 if (g.gl_pathc) 1212 globfree(&g); 1213 if (path1) 1214 xfree(path1); 1215 if (path2) 1216 xfree(path2); 1217 1218 /* If an unignored error occurs in batch mode we should abort. */ 1219 if (err_abort && err != 0) 1220 return (-1); 1221 else if (cmdnum == I_QUIT) 1222 return (1); 1223 1224 return (0); 1225 } 1226 1227 #ifdef USE_LIBEDIT 1228 static char * 1229 prompt(EditLine *el) 1230 { 1231 return ("sftp> "); 1232 } 1233 #endif 1234 1235 int 1236 interactive_loop(int fd_in, int fd_out, char *file1, char *file2) 1237 { 1238 char *pwd; 1239 char *dir = NULL; 1240 char cmd[2048]; 1241 struct sftp_conn *conn; 1242 int err, interactive; 1243 EditLine *el = NULL; 1244 #ifdef USE_LIBEDIT 1245 History *hl = NULL; 1246 HistEvent hev; 1247 extern char *__progname; 1248 1249 if (!batchmode && isatty(STDIN_FILENO)) { 1250 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) 1251 fatal("Couldn't initialise editline"); 1252 if ((hl = history_init()) == NULL) 1253 fatal("Couldn't initialise editline history"); 1254 history(hl, &hev, H_SETSIZE, 100); 1255 el_set(el, EL_HIST, history, hl); 1256 1257 el_set(el, EL_PROMPT, prompt); 1258 el_set(el, EL_EDITOR, "emacs"); 1259 el_set(el, EL_TERMINAL, NULL); 1260 el_set(el, EL_SIGNAL, 1); 1261 el_source(el, NULL); 1262 } 1263 #endif /* USE_LIBEDIT */ 1264 1265 conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); 1266 if (conn == NULL) 1267 fatal("Couldn't initialise connection to server"); 1268 1269 pwd = do_realpath(conn, "."); 1270 if (pwd == NULL) 1271 fatal("Need cwd"); 1272 1273 if (file1 != NULL) { 1274 dir = xstrdup(file1); 1275 dir = make_absolute(dir, pwd); 1276 1277 if (remote_is_dir(conn, dir) && file2 == NULL) { 1278 printf("Changing to: %s\n", dir); 1279 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 1280 if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) { 1281 xfree(dir); 1282 xfree(pwd); 1283 return (-1); 1284 } 1285 } else { 1286 if (file2 == NULL) 1287 snprintf(cmd, sizeof cmd, "get %s", dir); 1288 else 1289 snprintf(cmd, sizeof cmd, "get %s %s", dir, 1290 file2); 1291 1292 err = parse_dispatch_command(conn, cmd, &pwd, 1); 1293 xfree(dir); 1294 xfree(pwd); 1295 return (err); 1296 } 1297 xfree(dir); 1298 } 1299 1300 #if defined(HAVE_SETVBUF) && !defined(BROKEN_SETVBUF) 1301 setvbuf(stdout, NULL, _IOLBF, 0); 1302 setvbuf(infile, NULL, _IOLBF, 0); 1303 #else 1304 setlinebuf(stdout); 1305 setlinebuf(infile); 1306 #endif 1307 1308 interactive = !batchmode && isatty(STDIN_FILENO); 1309 err = 0; 1310 for (;;) { 1311 char *cp; 1312 1313 signal(SIGINT, SIG_IGN); 1314 1315 if (el == NULL) { 1316 if (interactive) 1317 printf("sftp> "); 1318 if (fgets(cmd, sizeof(cmd), infile) == NULL) { 1319 if (interactive) 1320 printf("\n"); 1321 break; 1322 } 1323 if (!interactive) { /* Echo command */ 1324 printf("sftp> %s", cmd); 1325 if (strlen(cmd) > 0 && 1326 cmd[strlen(cmd) - 1] != '\n') 1327 printf("\n"); 1328 } 1329 } else { 1330 #ifdef USE_LIBEDIT 1331 const char *line; 1332 int count = 0; 1333 1334 if ((line = el_gets(el, &count)) == NULL || count <= 0) { 1335 printf("\n"); 1336 break; 1337 } 1338 history(hl, &hev, H_ENTER, line); 1339 if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { 1340 fprintf(stderr, "Error: input line too long\n"); 1341 continue; 1342 } 1343 #endif /* USE_LIBEDIT */ 1344 } 1345 1346 cp = strrchr(cmd, '\n'); 1347 if (cp) 1348 *cp = '\0'; 1349 1350 /* Handle user interrupts gracefully during commands */ 1351 interrupted = 0; 1352 signal(SIGINT, cmd_interrupt); 1353 1354 err = parse_dispatch_command(conn, cmd, &pwd, batchmode); 1355 if (err != 0) 1356 break; 1357 } 1358 xfree(pwd); 1359 1360 #ifdef USE_LIBEDIT 1361 if (el != NULL) 1362 el_end(el); 1363 #endif /* USE_LIBEDIT */ 1364 1365 /* err == 1 signifies normal "quit" exit */ 1366 return (err >= 0 ? 0 : -1); 1367 } 1368 1369 static void 1370 connect_to_server(char *path, char **args, int *in, int *out) 1371 { 1372 int c_in, c_out; 1373 1374 #ifdef USE_PIPES 1375 int pin[2], pout[2]; 1376 1377 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 1378 fatal("pipe: %s", strerror(errno)); 1379 *in = pin[0]; 1380 *out = pout[1]; 1381 c_in = pout[0]; 1382 c_out = pin[1]; 1383 #else /* USE_PIPES */ 1384 int inout[2]; 1385 1386 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 1387 fatal("socketpair: %s", strerror(errno)); 1388 *in = *out = inout[0]; 1389 c_in = c_out = inout[1]; 1390 #endif /* USE_PIPES */ 1391 1392 if ((sshpid = fork()) == -1) 1393 fatal("fork: %s", strerror(errno)); 1394 else if (sshpid == 0) { 1395 if ((dup2(c_in, STDIN_FILENO) == -1) || 1396 (dup2(c_out, STDOUT_FILENO) == -1)) { 1397 fprintf(stderr, "dup2: %s\n", strerror(errno)); 1398 _exit(1); 1399 } 1400 close(*in); 1401 close(*out); 1402 close(c_in); 1403 close(c_out); 1404 1405 /* 1406 * The underlying ssh is in the same process group, so we must 1407 * ignore SIGINT if we want to gracefully abort commands, 1408 * otherwise the signal will make it to the ssh process and 1409 * kill it too 1410 */ 1411 signal(SIGINT, SIG_IGN); 1412 execvp(path, args); 1413 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 1414 _exit(1); 1415 } 1416 1417 signal(SIGTERM, killchild); 1418 signal(SIGINT, killchild); 1419 signal(SIGHUP, killchild); 1420 close(c_in); 1421 close(c_out); 1422 } 1423 1424 static void 1425 usage(void) 1426 { 1427 extern char *__progname; 1428 1429 fprintf(stderr, 1430 "usage: %s [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n" 1431 " [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n" 1432 " [-S program] [-s subsystem | sftp_server] host\n" 1433 " %s [[user@]host[:file [file]]]\n" 1434 " %s [[user@]host[:dir[/]]]\n" 1435 " %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname); 1436 exit(1); 1437 } 1438 1439 int 1440 main(int argc, char **argv) 1441 { 1442 int in, out, ch, err; 1443 char *host, *userhost, *cp, *file2 = NULL; 1444 int debug_level = 0, sshver = 2; 1445 char *file1 = NULL, *sftp_server = NULL; 1446 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 1447 LogLevel ll = SYSLOG_LEVEL_INFO; 1448 arglist args; 1449 extern int optind; 1450 extern char *optarg; 1451 1452 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 1453 sanitise_stdfd(); 1454 1455 __progname = ssh_get_progname(argv[0]); 1456 memset(&args, '\0', sizeof(args)); 1457 args.list = NULL; 1458 addargs(&args, ssh_program); 1459 addargs(&args, "-oForwardX11 no"); 1460 addargs(&args, "-oForwardAgent no"); 1461 addargs(&args, "-oPermitLocalCommand no"); 1462 addargs(&args, "-oClearAllForwardings yes"); 1463 1464 ll = SYSLOG_LEVEL_INFO; 1465 infile = stdin; 1466 1467 while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 1468 switch (ch) { 1469 case 'C': 1470 addargs(&args, "-C"); 1471 break; 1472 case 'v': 1473 if (debug_level < 3) { 1474 addargs(&args, "-v"); 1475 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 1476 } 1477 debug_level++; 1478 break; 1479 case 'F': 1480 case 'o': 1481 addargs(&args, "-%c%s", ch, optarg); 1482 break; 1483 case '1': 1484 sshver = 1; 1485 if (sftp_server == NULL) 1486 sftp_server = _PATH_SFTP_SERVER; 1487 break; 1488 case 's': 1489 sftp_server = optarg; 1490 break; 1491 case 'S': 1492 ssh_program = optarg; 1493 replacearg(&args, 0, "%s", ssh_program); 1494 break; 1495 case 'b': 1496 if (batchmode) 1497 fatal("Batch file already specified."); 1498 1499 /* Allow "-" as stdin */ 1500 if (strcmp(optarg, "-") != 0 && 1501 (infile = fopen(optarg, "r")) == NULL) 1502 fatal("%s (%s).", strerror(errno), optarg); 1503 showprogress = 0; 1504 batchmode = 1; 1505 addargs(&args, "-obatchmode yes"); 1506 break; 1507 case 'P': 1508 sftp_direct = optarg; 1509 break; 1510 case 'B': 1511 copy_buffer_len = strtol(optarg, &cp, 10); 1512 if (copy_buffer_len == 0 || *cp != '\0') 1513 fatal("Invalid buffer size \"%s\"", optarg); 1514 break; 1515 case 'R': 1516 num_requests = strtol(optarg, &cp, 10); 1517 if (num_requests == 0 || *cp != '\0') 1518 fatal("Invalid number of requests \"%s\"", 1519 optarg); 1520 break; 1521 case 'h': 1522 default: 1523 usage(); 1524 } 1525 } 1526 1527 if (!isatty(STDERR_FILENO)) 1528 showprogress = 0; 1529 1530 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 1531 1532 if (sftp_direct == NULL) { 1533 if (optind == argc || argc > (optind + 2)) 1534 usage(); 1535 1536 userhost = xstrdup(argv[optind]); 1537 file2 = argv[optind+1]; 1538 1539 if ((host = strrchr(userhost, '@')) == NULL) 1540 host = userhost; 1541 else { 1542 *host++ = '\0'; 1543 if (!userhost[0]) { 1544 fprintf(stderr, "Missing username\n"); 1545 usage(); 1546 } 1547 addargs(&args, "-l%s",userhost); 1548 } 1549 1550 if ((cp = colon(host)) != NULL) { 1551 *cp++ = '\0'; 1552 file1 = cp; 1553 } 1554 1555 host = cleanhostname(host); 1556 if (!*host) { 1557 fprintf(stderr, "Missing hostname\n"); 1558 usage(); 1559 } 1560 1561 addargs(&args, "-oProtocol %d", sshver); 1562 1563 /* no subsystem if the server-spec contains a '/' */ 1564 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 1565 addargs(&args, "-s"); 1566 1567 addargs(&args, "%s", host); 1568 addargs(&args, "%s", (sftp_server != NULL ? 1569 sftp_server : "sftp")); 1570 1571 if (!batchmode) 1572 fprintf(stderr, "Connecting to %s...\n", host); 1573 connect_to_server(ssh_program, args.list, &in, &out); 1574 } else { 1575 args.list = NULL; 1576 addargs(&args, "sftp-server"); 1577 1578 if (!batchmode) 1579 fprintf(stderr, "Attaching to %s...\n", sftp_direct); 1580 connect_to_server(sftp_direct, args.list, &in, &out); 1581 } 1582 freeargs(&args); 1583 1584 err = interactive_loop(in, out, file1, file2); 1585 1586 #if !defined(USE_PIPES) 1587 shutdown(in, SHUT_RDWR); 1588 shutdown(out, SHUT_RDWR); 1589 #endif 1590 1591 close(in); 1592 close(out); 1593 if (batchmode) 1594 fclose(infile); 1595 1596 while (waitpid(sshpid, NULL, 0) == -1) 1597 if (errno != EINTR) 1598 fatal("Couldn't wait for ssh process: %s", 1599 strerror(errno)); 1600 1601 exit(err == 0 ? 0 : 1); 1602 } 1603