1 /* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */ 2 /* 3 * Copyright (c) 2001-2004 Damien Miller <djm (at) openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "includes.h" 19 20 #include <sys/types.h> 21 #include <sys/ioctl.h> 22 #ifdef HAVE_SYS_STAT_H 23 # include <sys/stat.h> 24 #endif 25 #include <sys/param.h> 26 #include <sys/socket.h> 27 #include <sys/wait.h> 28 #ifdef HAVE_SYS_STATVFS_H 29 #include <sys/statvfs.h> 30 #endif 31 32 #include <ctype.h> 33 #include <errno.h> 34 35 #ifdef HAVE_PATHS_H 36 # include <paths.h> 37 #endif 38 #ifdef HAVE_LIBGEN_H 39 #include <libgen.h> 40 #endif 41 #ifdef USE_LIBEDIT 42 #include <histedit.h> 43 #else 44 typedef void EditLine; 45 #endif 46 #include <signal.h> 47 #include <stdlib.h> 48 #include <stdio.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <stdarg.h> 52 53 #ifdef HAVE_UTIL_H 54 # include <util.h> 55 #endif 56 57 #ifdef HAVE_LIBUTIL_H 58 # include <libutil.h> 59 #endif 60 61 #include "xmalloc.h" 62 #include "log.h" 63 #include "pathnames.h" 64 #include "misc.h" 65 66 #include "sftp.h" 67 #include "buffer.h" 68 #include "sftp-common.h" 69 #include "sftp-client.h" 70 71 #define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */ 72 #define DEFAULT_NUM_REQUESTS 64 /* # concurrent outstanding requests */ 73 74 /* File to read commands from */ 75 FILE* infile; 76 77 /* Are we in batchfile mode? */ 78 int batchmode = 0; 79 80 /* PID of ssh transport process */ 81 static pid_t sshpid = -1; 82 83 /* This is set to 0 if the progressmeter is not desired. */ 84 int showprogress = 1; 85 86 /* When this option is set, we always recursively download/upload directories */ 87 int global_rflag = 0; 88 89 /* When this option is set, the file transfers will always preserve times */ 90 int global_pflag = 0; 91 92 /* SIGINT received during command processing */ 93 volatile sig_atomic_t interrupted = 0; 94 95 /* I wish qsort() took a separate ctx for the comparison function...*/ 96 int sort_flag; 97 98 /* Context used for commandline completion */ 99 struct complete_ctx { 100 struct sftp_conn *conn; 101 char **remote_pathp; 102 }; 103 104 int remote_glob(struct sftp_conn *, const char *, int, 105 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ 106 107 extern char *__progname; 108 109 /* Separators for interactive commands */ 110 #define WHITESPACE " \t\r\n" 111 112 /* ls flags */ 113 #define LS_LONG_VIEW 0x0001 /* Full view ala ls -l */ 114 #define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */ 115 #define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */ 116 #define LS_NAME_SORT 0x0008 /* Sort by name (default) */ 117 #define LS_TIME_SORT 0x0010 /* Sort by mtime */ 118 #define LS_SIZE_SORT 0x0020 /* Sort by file size */ 119 #define LS_REVERSE_SORT 0x0040 /* Reverse sort order */ 120 #define LS_SHOW_ALL 0x0080 /* Don't skip filenames starting with '.' */ 121 #define LS_SI_UNITS 0x0100 /* Display sizes as K, M, G, etc. */ 122 123 #define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS) 124 #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) 125 126 /* Commands for interactive mode */ 127 #define I_CHDIR 1 128 #define I_CHGRP 2 129 #define I_CHMOD 3 130 #define I_CHOWN 4 131 #define I_DF 24 132 #define I_GET 5 133 #define I_HELP 6 134 #define I_LCHDIR 7 135 #define I_LINK 25 136 #define I_LLS 8 137 #define I_LMKDIR 9 138 #define I_LPWD 10 139 #define I_LS 11 140 #define I_LUMASK 12 141 #define I_MKDIR 13 142 #define I_PUT 14 143 #define I_PWD 15 144 #define I_QUIT 16 145 #define I_RENAME 17 146 #define I_RM 18 147 #define I_RMDIR 19 148 #define I_SHELL 20 149 #define I_SYMLINK 21 150 #define I_VERSION 22 151 #define I_PROGRESS 23 152 153 struct CMD { 154 const char *c; 155 const int n; 156 const int t; 157 }; 158 159 /* Type of completion */ 160 #define NOARGS 0 161 #define REMOTE 1 162 #define LOCAL 2 163 164 static const struct CMD cmds[] = { 165 { "bye", I_QUIT, NOARGS }, 166 { "cd", I_CHDIR, REMOTE }, 167 { "chdir", I_CHDIR, REMOTE }, 168 { "chgrp", I_CHGRP, REMOTE }, 169 { "chmod", I_CHMOD, REMOTE }, 170 { "chown", I_CHOWN, REMOTE }, 171 { "df", I_DF, REMOTE }, 172 { "dir", I_LS, REMOTE }, 173 { "exit", I_QUIT, NOARGS }, 174 { "get", I_GET, REMOTE }, 175 { "help", I_HELP, NOARGS }, 176 { "lcd", I_LCHDIR, LOCAL }, 177 { "lchdir", I_LCHDIR, LOCAL }, 178 { "lls", I_LLS, LOCAL }, 179 { "lmkdir", I_LMKDIR, LOCAL }, 180 { "ln", I_LINK, REMOTE }, 181 { "lpwd", I_LPWD, LOCAL }, 182 { "ls", I_LS, REMOTE }, 183 { "lumask", I_LUMASK, NOARGS }, 184 { "mkdir", I_MKDIR, REMOTE }, 185 { "mget", I_GET, REMOTE }, 186 { "mput", I_PUT, LOCAL }, 187 { "progress", I_PROGRESS, NOARGS }, 188 { "put", I_PUT, LOCAL }, 189 { "pwd", I_PWD, REMOTE }, 190 { "quit", I_QUIT, NOARGS }, 191 { "rename", I_RENAME, REMOTE }, 192 { "rm", I_RM, REMOTE }, 193 { "rmdir", I_RMDIR, REMOTE }, 194 { "symlink", I_SYMLINK, REMOTE }, 195 { "version", I_VERSION, NOARGS }, 196 { "!", I_SHELL, NOARGS }, 197 { "?", I_HELP, NOARGS }, 198 { NULL, -1, -1 } 199 }; 200 201 int interactive_loop(struct sftp_conn *, char *file1, char *file2); 202 203 /* ARGSUSED */ 204 static void 205 killchild(int signo) 206 { 207 if (sshpid > 1) { 208 kill(sshpid, SIGTERM); 209 waitpid(sshpid, NULL, 0); 210 } 211 212 _exit(1); 213 } 214 215 /* ARGSUSED */ 216 static void 217 cmd_interrupt(int signo) 218 { 219 const char msg[] = "\rInterrupt \n"; 220 int olderrno = errno; 221 222 write(STDERR_FILENO, msg, sizeof(msg) - 1); 223 interrupted = 1; 224 errno = olderrno; 225 } 226 227 static void 228 help(void) 229 { 230 printf("Available commands:\n" 231 "bye Quit sftp\n" 232 "cd path Change remote directory to 'path'\n" 233 "chgrp grp path Change group of file 'path' to 'grp'\n" 234 "chmod mode path Change permissions of file 'path' to 'mode'\n" 235 "chown own path Change owner of file 'path' to 'own'\n" 236 "df [-hi] [path] Display statistics for current directory or\n" 237 " filesystem containing 'path'\n" 238 "exit Quit sftp\n" 239 "get [-Ppr] remote [local] Download file\n" 240 "help Display this help text\n" 241 "lcd path Change local directory to 'path'\n" 242 "lls [ls-options [path]] Display local directory listing\n" 243 "lmkdir path Create local directory\n" 244 "ln [-s] oldpath newpath Link remote file (-s for symlink)\n" 245 "lpwd Print local working directory\n" 246 "ls [-1afhlnrSt] [path] Display remote directory listing\n" 247 "lumask umask Set local umask to 'umask'\n" 248 "mkdir path Create remote directory\n" 249 "progress Toggle display of progress meter\n" 250 "put [-Ppr] local [remote] Upload file\n" 251 "pwd Display remote working directory\n" 252 "quit Quit sftp\n" 253 "rename oldpath newpath Rename remote file\n" 254 "rm path Delete remote file\n" 255 "rmdir path Remove remote directory\n" 256 "symlink oldpath newpath Symlink remote file\n" 257 "version Show SFTP version\n" 258 "!command Execute 'command' in local shell\n" 259 "! Escape to local shell\n" 260 "? Synonym for help\n"); 261 } 262 263 static void 264 local_do_shell(const char *args) 265 { 266 int status; 267 char *shell; 268 pid_t pid; 269 270 if (!*args) 271 args = NULL; 272 273 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 274 shell = _PATH_BSHELL; 275 276 if ((pid = fork()) == -1) 277 fatal("Couldn't fork: %s", strerror(errno)); 278 279 if (pid == 0) { 280 /* XXX: child has pipe fds to ssh subproc open - issue? */ 281 if (args) { 282 debug3("Executing %s -c \"%s\"", shell, args); 283 execl(shell, shell, "-c", args, (char *)NULL); 284 } else { 285 debug3("Executing %s", shell); 286 execl(shell, shell, (char *)NULL); 287 } 288 fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, 289 strerror(errno)); 290 _exit(1); 291 } 292 while (waitpid(pid, &status, 0) == -1) 293 if (errno != EINTR) 294 fatal("Couldn't wait for child: %s", strerror(errno)); 295 if (!WIFEXITED(status)) 296 error("Shell exited abnormally"); 297 else if (WEXITSTATUS(status)) 298 error("Shell exited with status %d", WEXITSTATUS(status)); 299 } 300 301 static void 302 local_do_ls(const char *args) 303 { 304 if (!args || !*args) 305 local_do_shell(_PATH_LS); 306 else { 307 int len = strlen(_PATH_LS " ") + strlen(args) + 1; 308 char *buf = xmalloc(len); 309 310 /* XXX: quoting - rip quoting code from ftp? */ 311 snprintf(buf, len, _PATH_LS " %s", args); 312 local_do_shell(buf); 313 xfree(buf); 314 } 315 } 316 317 /* Strip one path (usually the pwd) from the start of another */ 318 static char * 319 path_strip(char *path, char *strip) 320 { 321 size_t len; 322 323 if (strip == NULL) 324 return (xstrdup(path)); 325 326 len = strlen(strip); 327 if (strncmp(path, strip, len) == 0) { 328 if (strip[len - 1] != '/' && path[len] == '/') 329 len++; 330 return (xstrdup(path + len)); 331 } 332 333 return (xstrdup(path)); 334 } 335 336 static char * 337 make_absolute(char *p, char *pwd) 338 { 339 char *abs_str; 340 341 /* Derelativise */ 342 if (p && p[0] != '/') { 343 abs_str = path_append(pwd, p); 344 xfree(p); 345 return(abs_str); 346 } else 347 return(p); 348 } 349 350 static int 351 parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, 352 int *rflag) 353 { 354 extern int opterr, optind, optopt, optreset; 355 int ch; 356 357 optind = optreset = 1; 358 opterr = 0; 359 360 *rflag = *pflag = 0; 361 while ((ch = getopt(argc, argv, "PpRr")) != -1) { 362 switch (ch) { 363 case 'p': 364 case 'P': 365 *pflag = 1; 366 break; 367 case 'r': 368 case 'R': 369 *rflag = 1; 370 break; 371 default: 372 error("%s: Invalid flag -%c", cmd, optopt); 373 return -1; 374 } 375 } 376 377 return optind; 378 } 379 380 static int 381 parse_link_flags(const char *cmd, char **argv, int argc, int *sflag) 382 { 383 extern int opterr, optind, optopt, optreset; 384 int ch; 385 386 optind = optreset = 1; 387 opterr = 0; 388 389 *sflag = 0; 390 while ((ch = getopt(argc, argv, "s")) != -1) { 391 switch (ch) { 392 case 's': 393 *sflag = 1; 394 break; 395 default: 396 error("%s: Invalid flag -%c", cmd, optopt); 397 return -1; 398 } 399 } 400 401 return optind; 402 } 403 404 static int 405 parse_ls_flags(char **argv, int argc, int *lflag) 406 { 407 extern int opterr, optind, optopt, optreset; 408 int ch; 409 410 optind = optreset = 1; 411 opterr = 0; 412 413 *lflag = LS_NAME_SORT; 414 while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) { 415 switch (ch) { 416 case '1': 417 *lflag &= ~VIEW_FLAGS; 418 *lflag |= LS_SHORT_VIEW; 419 break; 420 case 'S': 421 *lflag &= ~SORT_FLAGS; 422 *lflag |= LS_SIZE_SORT; 423 break; 424 case 'a': 425 *lflag |= LS_SHOW_ALL; 426 break; 427 case 'f': 428 *lflag &= ~SORT_FLAGS; 429 break; 430 case 'h': 431 *lflag |= LS_SI_UNITS; 432 break; 433 case 'l': 434 *lflag &= ~LS_SHORT_VIEW; 435 *lflag |= LS_LONG_VIEW; 436 break; 437 case 'n': 438 *lflag &= ~LS_SHORT_VIEW; 439 *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; 440 break; 441 case 'r': 442 *lflag |= LS_REVERSE_SORT; 443 break; 444 case 't': 445 *lflag &= ~SORT_FLAGS; 446 *lflag |= LS_TIME_SORT; 447 break; 448 default: 449 error("ls: Invalid flag -%c", optopt); 450 return -1; 451 } 452 } 453 454 return optind; 455 } 456 457 static int 458 parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) 459 { 460 extern int opterr, optind, optopt, optreset; 461 int ch; 462 463 optind = optreset = 1; 464 opterr = 0; 465 466 *hflag = *iflag = 0; 467 while ((ch = getopt(argc, argv, "hi")) != -1) { 468 switch (ch) { 469 case 'h': 470 *hflag = 1; 471 break; 472 case 'i': 473 *iflag = 1; 474 break; 475 default: 476 error("%s: Invalid flag -%c", cmd, optopt); 477 return -1; 478 } 479 } 480 481 return optind; 482 } 483 484 static int 485 is_dir(char *path) 486 { 487 struct stat sb; 488 489 /* XXX: report errors? */ 490 if (stat(path, &sb) == -1) 491 return(0); 492 493 return(S_ISDIR(sb.st_mode)); 494 } 495 496 static int 497 remote_is_dir(struct sftp_conn *conn, char *path) 498 { 499 Attrib *a; 500 501 /* XXX: report errors? */ 502 if ((a = do_stat(conn, path, 1)) == NULL) 503 return(0); 504 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 505 return(0); 506 return(S_ISDIR(a->perm)); 507 } 508 509 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 510 static int 511 pathname_is_dir(char *pathname) 512 { 513 size_t l = strlen(pathname); 514 515 return l > 0 && pathname[l - 1] == '/'; 516 } 517 518 static int 519 process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, 520 int pflag, int rflag) 521 { 522 char *abs_src = NULL; 523 char *abs_dst = NULL; 524 glob_t g; 525 char *filename, *tmp=NULL; 526 int i, err = 0; 527 528 abs_src = xstrdup(src); 529 abs_src = make_absolute(abs_src, pwd); 530 memset(&g, 0, sizeof(g)); 531 532 debug3("Looking up %s", abs_src); 533 if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) { 534 error("File \"%s\" not found.", abs_src); 535 err = -1; 536 goto out; 537 } 538 539 /* 540 * If multiple matches then dst must be a directory or 541 * unspecified. 542 */ 543 if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) { 544 error("Multiple source paths, but destination " 545 "\"%s\" is not a directory", dst); 546 err = -1; 547 goto out; 548 } 549 550 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 551 tmp = xstrdup(g.gl_pathv[i]); 552 if ((filename = basename(tmp)) == NULL) { 553 error("basename %s: %s", tmp, strerror(errno)); 554 xfree(tmp); 555 err = -1; 556 goto out; 557 } 558 559 if (g.gl_matchc == 1 && dst) { 560 if (is_dir(dst)) { 561 abs_dst = path_append(dst, filename); 562 } else { 563 abs_dst = xstrdup(dst); 564 } 565 } else if (dst) { 566 abs_dst = path_append(dst, filename); 567 } else { 568 abs_dst = xstrdup(filename); 569 } 570 xfree(tmp); 571 572 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); 573 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 574 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, 575 pflag || global_pflag, 1) == -1) 576 err = -1; 577 } else { 578 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, 579 pflag || global_pflag) == -1) 580 err = -1; 581 } 582 xfree(abs_dst); 583 abs_dst = NULL; 584 } 585 586 out: 587 xfree(abs_src); 588 globfree(&g); 589 return(err); 590 } 591 592 static int 593 process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, 594 int pflag, int rflag) 595 { 596 char *tmp_dst = NULL; 597 char *abs_dst = NULL; 598 char *tmp = NULL, *filename = NULL; 599 glob_t g; 600 int err = 0; 601 int i, dst_is_dir = 1; 602 struct stat sb; 603 604 if (dst) { 605 tmp_dst = xstrdup(dst); 606 tmp_dst = make_absolute(tmp_dst, pwd); 607 } 608 609 memset(&g, 0, sizeof(g)); 610 debug3("Looking up %s", src); 611 if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { 612 error("File \"%s\" not found.", src); 613 err = -1; 614 goto out; 615 } 616 617 /* If we aren't fetching to pwd then stash this status for later */ 618 if (tmp_dst != NULL) 619 dst_is_dir = remote_is_dir(conn, tmp_dst); 620 621 /* If multiple matches, dst may be directory or unspecified */ 622 if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { 623 error("Multiple paths match, but destination " 624 "\"%s\" is not a directory", tmp_dst); 625 err = -1; 626 goto out; 627 } 628 629 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 630 if (stat(g.gl_pathv[i], &sb) == -1) { 631 err = -1; 632 error("stat %s: %s", g.gl_pathv[i], strerror(errno)); 633 continue; 634 } 635 636 tmp = xstrdup(g.gl_pathv[i]); 637 if ((filename = basename(tmp)) == NULL) { 638 error("basename %s: %s", tmp, strerror(errno)); 639 xfree(tmp); 640 err = -1; 641 goto out; 642 } 643 644 if (g.gl_matchc == 1 && tmp_dst) { 645 /* If directory specified, append filename */ 646 if (dst_is_dir) 647 abs_dst = path_append(tmp_dst, filename); 648 else 649 abs_dst = xstrdup(tmp_dst); 650 } else if (tmp_dst) { 651 abs_dst = path_append(tmp_dst, filename); 652 } else { 653 abs_dst = make_absolute(xstrdup(filename), pwd); 654 } 655 xfree(tmp); 656 657 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); 658 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 659 if (upload_dir(conn, g.gl_pathv[i], abs_dst, 660 pflag || global_pflag, 1) == -1) 661 err = -1; 662 } else { 663 if (do_upload(conn, g.gl_pathv[i], abs_dst, 664 pflag || global_pflag) == -1) 665 err = -1; 666 } 667 } 668 669 out: 670 if (abs_dst) 671 xfree(abs_dst); 672 if (tmp_dst) 673 xfree(tmp_dst); 674 globfree(&g); 675 return(err); 676 } 677 678 static int 679 sdirent_comp(const void *aa, const void *bb) 680 { 681 SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; 682 SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; 683 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 684 685 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 686 if (sort_flag & LS_NAME_SORT) 687 return (rmul * strcmp(a->filename, b->filename)); 688 else if (sort_flag & LS_TIME_SORT) 689 return (rmul * NCMP(a->a.mtime, b->a.mtime)); 690 else if (sort_flag & LS_SIZE_SORT) 691 return (rmul * NCMP(a->a.size, b->a.size)); 692 693 fatal("Unknown ls sort type"); 694 } 695 696 /* sftp ls.1 replacement for directories */ 697 static int 698 do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) 699 { 700 int n; 701 u_int c = 1, colspace = 0, columns = 1; 702 SFTP_DIRENT **d; 703 704 if ((n = do_readdir(conn, path, &d)) != 0) 705 return (n); 706 707 if (!(lflag & LS_SHORT_VIEW)) { 708 u_int m = 0, width = 80; 709 struct winsize ws; 710 char *tmp; 711 712 /* Count entries for sort and find longest filename */ 713 for (n = 0; d[n] != NULL; n++) { 714 if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) 715 m = MAX(m, strlen(d[n]->filename)); 716 } 717 718 /* Add any subpath that also needs to be counted */ 719 tmp = path_strip(path, strip_path); 720 m += strlen(tmp); 721 xfree(tmp); 722 723 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 724 width = ws.ws_col; 725 726 columns = width / (m + 2); 727 columns = MAX(columns, 1); 728 colspace = width / columns; 729 colspace = MIN(colspace, width); 730 } 731 732 if (lflag & SORT_FLAGS) { 733 for (n = 0; d[n] != NULL; n++) 734 ; /* count entries */ 735 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); 736 qsort(d, n, sizeof(*d), sdirent_comp); 737 } 738 739 for (n = 0; d[n] != NULL && !interrupted; n++) { 740 char *tmp, *fname; 741 742 if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) 743 continue; 744 745 tmp = path_append(path, d[n]->filename); 746 fname = path_strip(tmp, strip_path); 747 xfree(tmp); 748 749 if (lflag & LS_LONG_VIEW) { 750 if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { 751 char *lname; 752 struct stat sb; 753 754 memset(&sb, 0, sizeof(sb)); 755 attrib_to_stat(&d[n]->a, &sb); 756 lname = ls_file(fname, &sb, 1, 757 (lflag & LS_SI_UNITS)); 758 printf("%s\n", lname); 759 xfree(lname); 760 } else 761 printf("%s\n", d[n]->longname); 762 } else { 763 printf("%-*s", colspace, fname); 764 if (c >= columns) { 765 printf("\n"); 766 c = 1; 767 } else 768 c++; 769 } 770 771 xfree(fname); 772 } 773 774 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 775 printf("\n"); 776 777 free_sftp_dirents(d); 778 return (0); 779 } 780 781 /* sftp ls.1 replacement which handles path globs */ 782 static int 783 do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, 784 int lflag) 785 { 786 Attrib *a = NULL; 787 char *fname, *lname; 788 glob_t g; 789 int err; 790 struct winsize ws; 791 u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; 792 793 memset(&g, 0, sizeof(g)); 794 795 if (remote_glob(conn, path, 796 GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT, NULL, &g) || 797 (g.gl_pathc && !g.gl_matchc)) { 798 if (g.gl_pathc) 799 globfree(&g); 800 error("Can't ls: \"%s\" not found", path); 801 return -1; 802 } 803 804 if (interrupted) 805 goto out; 806 807 /* 808 * If the glob returns a single match and it is a directory, 809 * then just list its contents. 810 */ 811 if (g.gl_matchc == 1 && g.gl_statv[0] != NULL && 812 S_ISDIR(g.gl_statv[0]->st_mode)) { 813 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); 814 globfree(&g); 815 return err; 816 } 817 818 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 819 width = ws.ws_col; 820 821 if (!(lflag & LS_SHORT_VIEW)) { 822 /* Count entries for sort and find longest filename */ 823 for (i = 0; g.gl_pathv[i]; i++) 824 m = MAX(m, strlen(g.gl_pathv[i])); 825 826 columns = width / (m + 2); 827 columns = MAX(columns, 1); 828 colspace = width / columns; 829 } 830 831 for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) { 832 fname = path_strip(g.gl_pathv[i], strip_path); 833 if (lflag & LS_LONG_VIEW) { 834 if (g.gl_statv[i] == NULL) { 835 error("no stat information for %s", fname); 836 continue; 837 } 838 lname = ls_file(fname, g.gl_statv[i], 1, 839 (lflag & LS_SI_UNITS)); 840 printf("%s\n", lname); 841 xfree(lname); 842 } else { 843 printf("%-*s", colspace, fname); 844 if (c >= columns) { 845 printf("\n"); 846 c = 1; 847 } else 848 c++; 849 } 850 xfree(fname); 851 } 852 853 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 854 printf("\n"); 855 856 out: 857 if (g.gl_pathc) 858 globfree(&g); 859 860 return 0; 861 } 862 863 static int 864 do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) 865 { 866 struct sftp_statvfs st; 867 char s_used[FMT_SCALED_STRSIZE]; 868 char s_avail[FMT_SCALED_STRSIZE]; 869 char s_root[FMT_SCALED_STRSIZE]; 870 char s_total[FMT_SCALED_STRSIZE]; 871 unsigned long long ffree; 872 873 if (do_statvfs(conn, path, &st, 1) == -1) 874 return -1; 875 if (iflag) { 876 ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0; 877 printf(" Inodes Used Avail " 878 "(root) %%Capacity\n"); 879 printf("%11llu %11llu %11llu %11llu %3llu%%\n", 880 (unsigned long long)st.f_files, 881 (unsigned long long)(st.f_files - st.f_ffree), 882 (unsigned long long)st.f_favail, 883 (unsigned long long)st.f_ffree, ffree); 884 } else if (hflag) { 885 strlcpy(s_used, "error", sizeof(s_used)); 886 strlcpy(s_avail, "error", sizeof(s_avail)); 887 strlcpy(s_root, "error", sizeof(s_root)); 888 strlcpy(s_total, "error", sizeof(s_total)); 889 fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used); 890 fmt_scaled(st.f_bavail * st.f_frsize, s_avail); 891 fmt_scaled(st.f_bfree * st.f_frsize, s_root); 892 fmt_scaled(st.f_blocks * st.f_frsize, s_total); 893 printf(" Size Used Avail (root) %%Capacity\n"); 894 printf("%7sB %7sB %7sB %7sB %3llu%%\n", 895 s_total, s_used, s_avail, s_root, 896 (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / 897 st.f_blocks)); 898 } else { 899 printf(" Size Used Avail " 900 "(root) %%Capacity\n"); 901 printf("%12llu %12llu %12llu %12llu %3llu%%\n", 902 (unsigned long long)(st.f_frsize * st.f_blocks / 1024), 903 (unsigned long long)(st.f_frsize * 904 (st.f_blocks - st.f_bfree) / 1024), 905 (unsigned long long)(st.f_frsize * st.f_bavail / 1024), 906 (unsigned long long)(st.f_frsize * st.f_bfree / 1024), 907 (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / 908 st.f_blocks)); 909 } 910 return 0; 911 } 912 913 /* 914 * Undo escaping of glob sequences in place. Used to undo extra escaping 915 * applied in makeargv() when the string is destined for a function that 916 * does not glob it. 917 */ 918 static void 919 undo_glob_escape(char *s) 920 { 921 size_t i, j; 922 923 for (i = j = 0;;) { 924 if (s[i] == '\0') { 925 s[j] = '\0'; 926 return; 927 } 928 if (s[i] != '\\') { 929 s[j++] = s[i++]; 930 continue; 931 } 932 /* s[i] == '\\' */ 933 ++i; 934 switch (s[i]) { 935 case '?': 936 case '[': 937 case '*': 938 case '\\': 939 s[j++] = s[i++]; 940 break; 941 case '\0': 942 s[j++] = '\\'; 943 s[j] = '\0'; 944 return; 945 default: 946 s[j++] = '\\'; 947 s[j++] = s[i++]; 948 break; 949 } 950 } 951 } 952 953 /* 954 * Split a string into an argument vector using sh(1)-style quoting, 955 * comment and escaping rules, but with some tweaks to handle glob(3) 956 * wildcards. 957 * The "sloppy" flag allows for recovery from missing terminating quote, for 958 * use in parsing incomplete commandlines during tab autocompletion. 959 * 960 * Returns NULL on error or a NULL-terminated array of arguments. 961 * 962 * If "lastquote" is not NULL, the quoting character used for the last 963 * argument is placed in *lastquote ("\0", "'" or "\""). 964 * 965 * If "terminated" is not NULL, *terminated will be set to 1 when the 966 * last argument's quote has been properly terminated or 0 otherwise. 967 * This parameter is only of use if "sloppy" is set. 968 */ 969 #define MAXARGS 128 970 #define MAXARGLEN 8192 971 static char ** 972 makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, 973 u_int *terminated) 974 { 975 int argc, quot; 976 size_t i, j; 977 static char argvs[MAXARGLEN]; 978 static char *argv[MAXARGS + 1]; 979 enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q; 980 981 *argcp = argc = 0; 982 if (strlen(arg) > sizeof(argvs) - 1) { 983 args_too_longs: 984 error("string too long"); 985 return NULL; 986 } 987 if (terminated != NULL) 988 *terminated = 1; 989 if (lastquote != NULL) 990 *lastquote = '\0'; 991 state = MA_START; 992 i = j = 0; 993 for (;;) { 994 if (isspace(arg[i])) { 995 if (state == MA_UNQUOTED) { 996 /* Terminate current argument */ 997 argvs[j++] = '\0'; 998 argc++; 999 state = MA_START; 1000 } else if (state != MA_START) 1001 argvs[j++] = arg[i]; 1002 } else if (arg[i] == '"' || arg[i] == '\'') { 1003 q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE; 1004 if (state == MA_START) { 1005 argv[argc] = argvs + j; 1006 state = q; 1007 if (lastquote != NULL) 1008 *lastquote = arg[i]; 1009 } else if (state == MA_UNQUOTED) 1010 state = q; 1011 else if (state == q) 1012 state = MA_UNQUOTED; 1013 else 1014 argvs[j++] = arg[i]; 1015 } else if (arg[i] == '\\') { 1016 if (state == MA_SQUOTE || state == MA_DQUOTE) { 1017 quot = state == MA_SQUOTE ? '\'' : '"'; 1018 /* Unescape quote we are in */ 1019 /* XXX support \n and friends? */ 1020 if (arg[i + 1] == quot) { 1021 i++; 1022 argvs[j++] = arg[i]; 1023 } else if (arg[i + 1] == '?' || 1024 arg[i + 1] == '[' || arg[i + 1] == '*') { 1025 /* 1026 * Special case for sftp: append 1027 * double-escaped glob sequence - 1028 * glob will undo one level of 1029 * escaping. NB. string can grow here. 1030 */ 1031 if (j >= sizeof(argvs) - 5) 1032 goto args_too_longs; 1033 argvs[j++] = '\\'; 1034 argvs[j++] = arg[i++]; 1035 argvs[j++] = '\\'; 1036 argvs[j++] = arg[i]; 1037 } else { 1038 argvs[j++] = arg[i++]; 1039 argvs[j++] = arg[i]; 1040 } 1041 } else { 1042 if (state == MA_START) { 1043 argv[argc] = argvs + j; 1044 state = MA_UNQUOTED; 1045 if (lastquote != NULL) 1046 *lastquote = '\0'; 1047 } 1048 if (arg[i + 1] == '?' || arg[i + 1] == '[' || 1049 arg[i + 1] == '*' || arg[i + 1] == '\\') { 1050 /* 1051 * Special case for sftp: append 1052 * escaped glob sequence - 1053 * glob will undo one level of 1054 * escaping. 1055 */ 1056 argvs[j++] = arg[i++]; 1057 argvs[j++] = arg[i]; 1058 } else { 1059 /* Unescape everything */ 1060 /* XXX support \n and friends? */ 1061 i++; 1062 argvs[j++] = arg[i]; 1063 } 1064 } 1065 } else if (arg[i] == '#') { 1066 if (state == MA_SQUOTE || state == MA_DQUOTE) 1067 argvs[j++] = arg[i]; 1068 else 1069 goto string_done; 1070 } else if (arg[i] == '\0') { 1071 if (state == MA_SQUOTE || state == MA_DQUOTE) { 1072 if (sloppy) { 1073 state = MA_UNQUOTED; 1074 if (terminated != NULL) 1075 *terminated = 0; 1076 goto string_done; 1077 } 1078 error("Unterminated quoted argument"); 1079 return NULL; 1080 } 1081 string_done: 1082 if (state == MA_UNQUOTED) { 1083 argvs[j++] = '\0'; 1084 argc++; 1085 } 1086 break; 1087 } else { 1088 if (state == MA_START) { 1089 argv[argc] = argvs + j; 1090 state = MA_UNQUOTED; 1091 if (lastquote != NULL) 1092 *lastquote = '\0'; 1093 } 1094 if ((state == MA_SQUOTE || state == MA_DQUOTE) && 1095 (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) { 1096 /* 1097 * Special case for sftp: escape quoted 1098 * glob(3) wildcards. NB. string can grow 1099 * here. 1100 */ 1101 if (j >= sizeof(argvs) - 3) 1102 goto args_too_longs; 1103 argvs[j++] = '\\'; 1104 argvs[j++] = arg[i]; 1105 } else 1106 argvs[j++] = arg[i]; 1107 } 1108 i++; 1109 } 1110 *argcp = argc; 1111 return argv; 1112 } 1113 1114 static int 1115 parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, 1116 int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) 1117 { 1118 const char *cmd, *cp = *cpp; 1119 char *cp2, **argv; 1120 int base = 0; 1121 long l; 1122 int i, cmdnum, optidx, argc; 1123 1124 /* Skip leading whitespace */ 1125 cp = cp + strspn(cp, WHITESPACE); 1126 1127 /* Check for leading '-' (disable error processing) */ 1128 *iflag = 0; 1129 if (*cp == '-') { 1130 *iflag = 1; 1131 cp++; 1132 cp = cp + strspn(cp, WHITESPACE); 1133 } 1134 1135 /* Ignore blank lines and lines which begin with comment '#' char */ 1136 if (*cp == '\0' || *cp == '#') 1137 return (0); 1138 1139 if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL) 1140 return -1; 1141 1142 /* Figure out which command we have */ 1143 for (i = 0; cmds[i].c != NULL; i++) { 1144 if (strcasecmp(cmds[i].c, argv[0]) == 0) 1145 break; 1146 } 1147 cmdnum = cmds[i].n; 1148 cmd = cmds[i].c; 1149 1150 /* Special case */ 1151 if (*cp == '!') { 1152 cp++; 1153 cmdnum = I_SHELL; 1154 } else if (cmdnum == -1) { 1155 error("Invalid command."); 1156 return -1; 1157 } 1158 1159 /* Get arguments and parse flags */ 1160 *lflag = *pflag = *rflag = *hflag = *n_arg = 0; 1161 *path1 = *path2 = NULL; 1162 optidx = 1; 1163 switch (cmdnum) { 1164 case I_GET: 1165 case I_PUT: 1166 if ((optidx = parse_getput_flags(cmd, argv, argc, 1167 pflag, rflag)) == -1) 1168 return -1; 1169 /* Get first pathname (mandatory) */ 1170 if (argc - optidx < 1) { 1171 error("You must specify at least one path after a " 1172 "%s command.", cmd); 1173 return -1; 1174 } 1175 *path1 = xstrdup(argv[optidx]); 1176 /* Get second pathname (optional) */ 1177 if (argc - optidx > 1) { 1178 *path2 = xstrdup(argv[optidx + 1]); 1179 /* Destination is not globbed */ 1180 undo_glob_escape(*path2); 1181 } 1182 break; 1183 case I_LINK: 1184 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) 1185 return -1; 1186 case I_SYMLINK: 1187 case I_RENAME: 1188 if (argc - optidx < 2) { 1189 error("You must specify two paths after a %s " 1190 "command.", cmd); 1191 return -1; 1192 } 1193 *path1 = xstrdup(argv[optidx]); 1194 *path2 = xstrdup(argv[optidx + 1]); 1195 /* Paths are not globbed */ 1196 undo_glob_escape(*path1); 1197 undo_glob_escape(*path2); 1198 break; 1199 case I_RM: 1200 case I_MKDIR: 1201 case I_RMDIR: 1202 case I_CHDIR: 1203 case I_LCHDIR: 1204 case I_LMKDIR: 1205 /* Get pathname (mandatory) */ 1206 if (argc - optidx < 1) { 1207 error("You must specify a path after a %s command.", 1208 cmd); 1209 return -1; 1210 } 1211 *path1 = xstrdup(argv[optidx]); 1212 /* Only "rm" globs */ 1213 if (cmdnum != I_RM) 1214 undo_glob_escape(*path1); 1215 break; 1216 case I_DF: 1217 if ((optidx = parse_df_flags(cmd, argv, argc, hflag, 1218 iflag)) == -1) 1219 return -1; 1220 /* Default to current directory if no path specified */ 1221 if (argc - optidx < 1) 1222 *path1 = NULL; 1223 else { 1224 *path1 = xstrdup(argv[optidx]); 1225 undo_glob_escape(*path1); 1226 } 1227 break; 1228 case I_LS: 1229 if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1) 1230 return(-1); 1231 /* Path is optional */ 1232 if (argc - optidx > 0) 1233 *path1 = xstrdup(argv[optidx]); 1234 break; 1235 case I_LLS: 1236 /* Skip ls command and following whitespace */ 1237 cp = cp + strlen(cmd) + strspn(cp, WHITESPACE); 1238 case I_SHELL: 1239 /* Uses the rest of the line */ 1240 break; 1241 case I_LUMASK: 1242 case I_CHMOD: 1243 base = 8; 1244 case I_CHOWN: 1245 case I_CHGRP: 1246 /* Get numeric arg (mandatory) */ 1247 if (argc - optidx < 1) 1248 goto need_num_arg; 1249 errno = 0; 1250 l = strtol(argv[optidx], &cp2, base); 1251 if (cp2 == argv[optidx] || *cp2 != '\0' || 1252 ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) || 1253 l < 0) { 1254 need_num_arg: 1255 error("You must supply a numeric argument " 1256 "to the %s command.", cmd); 1257 return -1; 1258 } 1259 *n_arg = l; 1260 if (cmdnum == I_LUMASK) 1261 break; 1262 /* Get pathname (mandatory) */ 1263 if (argc - optidx < 2) { 1264 error("You must specify a path after a %s command.", 1265 cmd); 1266 return -1; 1267 } 1268 *path1 = xstrdup(argv[optidx + 1]); 1269 break; 1270 case I_QUIT: 1271 case I_PWD: 1272 case I_LPWD: 1273 case I_HELP: 1274 case I_VERSION: 1275 case I_PROGRESS: 1276 break; 1277 default: 1278 fatal("Command not implemented"); 1279 } 1280 1281 *cpp = cp; 1282 return(cmdnum); 1283 } 1284 1285 static int 1286 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, 1287 int err_abort) 1288 { 1289 char *path1, *path2, *tmp; 1290 int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0; 1291 int cmdnum, i; 1292 unsigned long n_arg = 0; 1293 Attrib a, *aa; 1294 char path_buf[MAXPATHLEN]; 1295 int err = 0; 1296 glob_t g; 1297 1298 path1 = path2 = NULL; 1299 cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, 1300 &sflag, &n_arg, &path1, &path2); 1301 1302 if (iflag != 0) 1303 err_abort = 0; 1304 1305 memset(&g, 0, sizeof(g)); 1306 1307 /* Perform command */ 1308 switch (cmdnum) { 1309 case 0: 1310 /* Blank line */ 1311 break; 1312 case -1: 1313 /* Unrecognized command */ 1314 err = -1; 1315 break; 1316 case I_GET: 1317 err = process_get(conn, path1, path2, *pwd, pflag, rflag); 1318 break; 1319 case I_PUT: 1320 err = process_put(conn, path1, path2, *pwd, pflag, rflag); 1321 break; 1322 case I_RENAME: 1323 path1 = make_absolute(path1, *pwd); 1324 path2 = make_absolute(path2, *pwd); 1325 err = do_rename(conn, path1, path2); 1326 break; 1327 case I_SYMLINK: 1328 sflag = 1; 1329 case I_LINK: 1330 path1 = make_absolute(path1, *pwd); 1331 path2 = make_absolute(path2, *pwd); 1332 err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); 1333 break; 1334 case I_RM: 1335 path1 = make_absolute(path1, *pwd); 1336 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1337 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1338 printf("Removing %s\n", g.gl_pathv[i]); 1339 err = do_rm(conn, g.gl_pathv[i]); 1340 if (err != 0 && err_abort) 1341 break; 1342 } 1343 break; 1344 case I_MKDIR: 1345 path1 = make_absolute(path1, *pwd); 1346 attrib_clear(&a); 1347 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1348 a.perm = 0777; 1349 err = do_mkdir(conn, path1, &a, 1); 1350 break; 1351 case I_RMDIR: 1352 path1 = make_absolute(path1, *pwd); 1353 err = do_rmdir(conn, path1); 1354 break; 1355 case I_CHDIR: 1356 path1 = make_absolute(path1, *pwd); 1357 if ((tmp = do_realpath(conn, path1)) == NULL) { 1358 err = 1; 1359 break; 1360 } 1361 if ((aa = do_stat(conn, tmp, 0)) == NULL) { 1362 xfree(tmp); 1363 err = 1; 1364 break; 1365 } 1366 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { 1367 error("Can't change directory: Can't check target"); 1368 xfree(tmp); 1369 err = 1; 1370 break; 1371 } 1372 if (!S_ISDIR(aa->perm)) { 1373 error("Can't change directory: \"%s\" is not " 1374 "a directory", tmp); 1375 xfree(tmp); 1376 err = 1; 1377 break; 1378 } 1379 xfree(*pwd); 1380 *pwd = tmp; 1381 break; 1382 case I_LS: 1383 if (!path1) { 1384 do_ls_dir(conn, *pwd, *pwd, lflag); 1385 break; 1386 } 1387 1388 /* Strip pwd off beginning of non-absolute paths */ 1389 tmp = NULL; 1390 if (*path1 != '/') 1391 tmp = *pwd; 1392 1393 path1 = make_absolute(path1, *pwd); 1394 err = do_globbed_ls(conn, path1, tmp, lflag); 1395 break; 1396 case I_DF: 1397 /* Default to current directory if no path specified */ 1398 if (path1 == NULL) 1399 path1 = xstrdup(*pwd); 1400 path1 = make_absolute(path1, *pwd); 1401 err = do_df(conn, path1, hflag, iflag); 1402 break; 1403 case I_LCHDIR: 1404 if (chdir(path1) == -1) { 1405 error("Couldn't change local directory to " 1406 "\"%s\": %s", path1, strerror(errno)); 1407 err = 1; 1408 } 1409 break; 1410 case I_LMKDIR: 1411 if (mkdir(path1, 0777) == -1) { 1412 error("Couldn't create local directory " 1413 "\"%s\": %s", path1, strerror(errno)); 1414 err = 1; 1415 } 1416 break; 1417 case I_LLS: 1418 local_do_ls(cmd); 1419 break; 1420 case I_SHELL: 1421 local_do_shell(cmd); 1422 break; 1423 case I_LUMASK: 1424 umask(n_arg); 1425 printf("Local umask: %03lo\n", n_arg); 1426 break; 1427 case I_CHMOD: 1428 path1 = make_absolute(path1, *pwd); 1429 attrib_clear(&a); 1430 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1431 a.perm = n_arg; 1432 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1433 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1434 printf("Changing mode on %s\n", g.gl_pathv[i]); 1435 err = do_setstat(conn, g.gl_pathv[i], &a); 1436 if (err != 0 && err_abort) 1437 break; 1438 } 1439 break; 1440 case I_CHOWN: 1441 case I_CHGRP: 1442 path1 = make_absolute(path1, *pwd); 1443 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1444 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1445 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { 1446 if (err_abort) { 1447 err = -1; 1448 break; 1449 } else 1450 continue; 1451 } 1452 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { 1453 error("Can't get current ownership of " 1454 "remote file \"%s\"", g.gl_pathv[i]); 1455 if (err_abort) { 1456 err = -1; 1457 break; 1458 } else 1459 continue; 1460 } 1461 aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; 1462 if (cmdnum == I_CHOWN) { 1463 printf("Changing owner on %s\n", g.gl_pathv[i]); 1464 aa->uid = n_arg; 1465 } else { 1466 printf("Changing group on %s\n", g.gl_pathv[i]); 1467 aa->gid = n_arg; 1468 } 1469 err = do_setstat(conn, g.gl_pathv[i], aa); 1470 if (err != 0 && err_abort) 1471 break; 1472 } 1473 break; 1474 case I_PWD: 1475 printf("Remote working directory: %s\n", *pwd); 1476 break; 1477 case I_LPWD: 1478 if (!getcwd(path_buf, sizeof(path_buf))) { 1479 error("Couldn't get local cwd: %s", strerror(errno)); 1480 err = -1; 1481 break; 1482 } 1483 printf("Local working directory: %s\n", path_buf); 1484 break; 1485 case I_QUIT: 1486 /* Processed below */ 1487 break; 1488 case I_HELP: 1489 help(); 1490 break; 1491 case I_VERSION: 1492 printf("SFTP protocol version %u\n", sftp_proto_version(conn)); 1493 break; 1494 case I_PROGRESS: 1495 showprogress = !showprogress; 1496 if (showprogress) 1497 printf("Progress meter enabled\n"); 1498 else 1499 printf("Progress meter disabled\n"); 1500 break; 1501 default: 1502 fatal("%d is not implemented", cmdnum); 1503 } 1504 1505 if (g.gl_pathc) 1506 globfree(&g); 1507 if (path1) 1508 xfree(path1); 1509 if (path2) 1510 xfree(path2); 1511 1512 /* If an unignored error occurs in batch mode we should abort. */ 1513 if (err_abort && err != 0) 1514 return (-1); 1515 else if (cmdnum == I_QUIT) 1516 return (1); 1517 1518 return (0); 1519 } 1520 1521 #ifdef USE_LIBEDIT 1522 static char * 1523 prompt(EditLine *el) 1524 { 1525 return ("sftp> "); 1526 } 1527 1528 /* Display entries in 'list' after skipping the first 'len' chars */ 1529 static void 1530 complete_display(char **list, u_int len) 1531 { 1532 u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; 1533 struct winsize ws; 1534 char *tmp; 1535 1536 /* Count entries for sort and find longest */ 1537 for (y = 0; list[y]; y++) 1538 m = MAX(m, strlen(list[y])); 1539 1540 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 1541 width = ws.ws_col; 1542 1543 m = m > len ? m - len : 0; 1544 columns = width / (m + 2); 1545 columns = MAX(columns, 1); 1546 colspace = width / columns; 1547 colspace = MIN(colspace, width); 1548 1549 printf("\n"); 1550 m = 1; 1551 for (y = 0; list[y]; y++) { 1552 llen = strlen(list[y]); 1553 tmp = llen > len ? list[y] + len : ""; 1554 printf("%-*s", colspace, tmp); 1555 if (m >= columns) { 1556 printf("\n"); 1557 m = 1; 1558 } else 1559 m++; 1560 } 1561 printf("\n"); 1562 } 1563 1564 /* 1565 * Given a "list" of words that begin with a common prefix of "word", 1566 * attempt to find an autocompletion to extends "word" by the next 1567 * characters common to all entries in "list". 1568 */ 1569 static char * 1570 complete_ambiguous(const char *word, char **list, size_t count) 1571 { 1572 if (word == NULL) 1573 return NULL; 1574 1575 if (count > 0) { 1576 u_int y, matchlen = strlen(list[0]); 1577 1578 /* Find length of common stem */ 1579 for (y = 1; list[y]; y++) { 1580 u_int x; 1581 1582 for (x = 0; x < matchlen; x++) 1583 if (list[0][x] != list[y][x]) 1584 break; 1585 1586 matchlen = x; 1587 } 1588 1589 if (matchlen > strlen(word)) { 1590 char *tmp = xstrdup(list[0]); 1591 1592 tmp[matchlen] = '\0'; 1593 return tmp; 1594 } 1595 } 1596 1597 return xstrdup(word); 1598 } 1599 1600 /* Autocomplete a sftp command */ 1601 static int 1602 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, 1603 int terminated) 1604 { 1605 u_int y, count = 0, cmdlen, tmplen; 1606 char *tmp, **list, argterm[3]; 1607 const LineInfo *lf; 1608 1609 list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); 1610 1611 /* No command specified: display all available commands */ 1612 if (cmd == NULL) { 1613 for (y = 0; cmds[y].c; y++) 1614 list[count++] = xstrdup(cmds[y].c); 1615 1616 list[count] = NULL; 1617 complete_display(list, 0); 1618 1619 for (y = 0; list[y] != NULL; y++) 1620 xfree(list[y]); 1621 xfree(list); 1622 return count; 1623 } 1624 1625 /* Prepare subset of commands that start with "cmd" */ 1626 cmdlen = strlen(cmd); 1627 for (y = 0; cmds[y].c; y++) { 1628 if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 1629 list[count++] = xstrdup(cmds[y].c); 1630 } 1631 list[count] = NULL; 1632 1633 if (count == 0) 1634 return 0; 1635 1636 /* Complete ambigious command */ 1637 tmp = complete_ambiguous(cmd, list, count); 1638 if (count > 1) 1639 complete_display(list, 0); 1640 1641 for (y = 0; list[y]; y++) 1642 xfree(list[y]); 1643 xfree(list); 1644 1645 if (tmp != NULL) { 1646 tmplen = strlen(tmp); 1647 cmdlen = strlen(cmd); 1648 /* If cmd may be extended then do so */ 1649 if (tmplen > cmdlen) 1650 if (el_insertstr(el, tmp + cmdlen) == -1) 1651 fatal("el_insertstr failed."); 1652 lf = el_line(el); 1653 /* Terminate argument cleanly */ 1654 if (count == 1) { 1655 y = 0; 1656 if (!terminated) 1657 argterm[y++] = quote; 1658 if (lastarg || *(lf->cursor) != ' ') 1659 argterm[y++] = ' '; 1660 argterm[y] = '\0'; 1661 if (y > 0 && el_insertstr(el, argterm) == -1) 1662 fatal("el_insertstr failed."); 1663 } 1664 xfree(tmp); 1665 } 1666 1667 return count; 1668 } 1669 1670 /* 1671 * Determine whether a particular sftp command's arguments (if any) 1672 * represent local or remote files. 1673 */ 1674 static int 1675 complete_is_remote(char *cmd) { 1676 int i; 1677 1678 if (cmd == NULL) 1679 return -1; 1680 1681 for (i = 0; cmds[i].c; i++) { 1682 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 1683 return cmds[i].t; 1684 } 1685 1686 return -1; 1687 } 1688 1689 /* Autocomplete a filename "file" */ 1690 static int 1691 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, 1692 char *file, int remote, int lastarg, char quote, int terminated) 1693 { 1694 glob_t g; 1695 char *tmp, *tmp2, ins[3]; 1696 u_int i, hadglob, pwdlen, len, tmplen, filelen; 1697 const LineInfo *lf; 1698 1699 /* Glob from "file" location */ 1700 if (file == NULL) 1701 tmp = xstrdup("*"); 1702 else 1703 xasprintf(&tmp, "%s*", file); 1704 1705 memset(&g, 0, sizeof(g)); 1706 if (remote != LOCAL) { 1707 tmp = make_absolute(tmp, remote_path); 1708 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1709 } else 1710 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1711 1712 /* Determine length of pwd so we can trim completion display */ 1713 for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { 1714 /* Terminate counting on first unescaped glob metacharacter */ 1715 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { 1716 if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') 1717 hadglob = 1; 1718 break; 1719 } 1720 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') 1721 tmplen++; 1722 if (tmp[tmplen] == '/') 1723 pwdlen = tmplen + 1; /* track last seen '/' */ 1724 } 1725 xfree(tmp); 1726 1727 if (g.gl_matchc == 0) 1728 goto out; 1729 1730 if (g.gl_matchc > 1) 1731 complete_display(g.gl_pathv, pwdlen); 1732 1733 tmp = NULL; 1734 /* Don't try to extend globs */ 1735 if (file == NULL || hadglob) 1736 goto out; 1737 1738 tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); 1739 tmp = path_strip(tmp2, remote_path); 1740 xfree(tmp2); 1741 1742 if (tmp == NULL) 1743 goto out; 1744 1745 tmplen = strlen(tmp); 1746 filelen = strlen(file); 1747 1748 if (tmplen > filelen) { 1749 tmp2 = tmp + filelen; 1750 len = strlen(tmp2); 1751 /* quote argument on way out */ 1752 for (i = 0; i < len; i++) { 1753 ins[0] = '\\'; 1754 ins[1] = tmp2[i]; 1755 ins[2] = '\0'; 1756 switch (tmp2[i]) { 1757 case '\'': 1758 case '"': 1759 case '\\': 1760 case '\t': 1761 case '[': 1762 case ' ': 1763 if (quote == '\0' || tmp2[i] == quote) { 1764 if (el_insertstr(el, ins) == -1) 1765 fatal("el_insertstr " 1766 "failed."); 1767 break; 1768 } 1769 /* FALLTHROUGH */ 1770 default: 1771 if (el_insertstr(el, ins + 1) == -1) 1772 fatal("el_insertstr failed."); 1773 break; 1774 } 1775 } 1776 } 1777 1778 lf = el_line(el); 1779 if (g.gl_matchc == 1) { 1780 i = 0; 1781 if (!terminated) 1782 ins[i++] = quote; 1783 if (*(lf->cursor - 1) != '/' && 1784 (lastarg || *(lf->cursor) != ' ')) 1785 ins[i++] = ' '; 1786 ins[i] = '\0'; 1787 if (i > 0 && el_insertstr(el, ins) == -1) 1788 fatal("el_insertstr failed."); 1789 } 1790 xfree(tmp); 1791 1792 out: 1793 globfree(&g); 1794 return g.gl_matchc; 1795 } 1796 1797 /* tab-completion hook function, called via libedit */ 1798 static unsigned char 1799 complete(EditLine *el, int ch) 1800 { 1801 char **argv, *line, quote; 1802 u_int argc, carg, cursor, len, terminated, ret = CC_ERROR; 1803 const LineInfo *lf; 1804 struct complete_ctx *complete_ctx; 1805 1806 lf = el_line(el); 1807 if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) 1808 fatal("%s: el_get failed", __func__); 1809 1810 /* Figure out which argument the cursor points to */ 1811 cursor = lf->cursor - lf->buffer; 1812 line = (char *)xmalloc(cursor + 1); 1813 memcpy(line, lf->buffer, cursor); 1814 line[cursor] = '\0'; 1815 argv = makeargv(line, &carg, 1, "e, &terminated); 1816 xfree(line); 1817 1818 /* Get all the arguments on the line */ 1819 len = lf->lastchar - lf->buffer; 1820 line = (char *)xmalloc(len + 1); 1821 memcpy(line, lf->buffer, len); 1822 line[len] = '\0'; 1823 argv = makeargv(line, &argc, 1, NULL, NULL); 1824 1825 /* Ensure cursor is at EOL or a argument boundary */ 1826 if (line[cursor] != ' ' && line[cursor] != '\0' && 1827 line[cursor] != '\n') { 1828 xfree(line); 1829 return ret; 1830 } 1831 1832 if (carg == 0) { 1833 /* Show all available commands */ 1834 complete_cmd_parse(el, NULL, argc == carg, '\0', 1); 1835 ret = CC_REDISPLAY; 1836 } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { 1837 /* Handle the command parsing */ 1838 if (complete_cmd_parse(el, argv[0], argc == carg, 1839 quote, terminated) != 0) 1840 ret = CC_REDISPLAY; 1841 } else if (carg >= 1) { 1842 /* Handle file parsing */ 1843 int remote = complete_is_remote(argv[0]); 1844 char *filematch = NULL; 1845 1846 if (carg > 1 && line[cursor-1] != ' ') 1847 filematch = argv[carg - 1]; 1848 1849 if (remote != 0 && 1850 complete_match(el, complete_ctx->conn, 1851 *complete_ctx->remote_pathp, filematch, 1852 remote, carg == argc, quote, terminated) != 0) 1853 ret = CC_REDISPLAY; 1854 } 1855 1856 xfree(line); 1857 return ret; 1858 } 1859 #endif /* USE_LIBEDIT */ 1860 1861 int 1862 interactive_loop(struct sftp_conn *conn, char *file1, char *file2) 1863 { 1864 char *remote_path; 1865 char *dir = NULL; 1866 char cmd[2048]; 1867 int err, interactive; 1868 EditLine *el = NULL; 1869 #ifdef USE_LIBEDIT 1870 History *hl = NULL; 1871 HistEvent hev; 1872 extern char *__progname; 1873 struct complete_ctx complete_ctx; 1874 1875 if (!batchmode && isatty(STDIN_FILENO)) { 1876 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) 1877 fatal("Couldn't initialise editline"); 1878 if ((hl = history_init()) == NULL) 1879 fatal("Couldn't initialise editline history"); 1880 history(hl, &hev, H_SETSIZE, 100); 1881 el_set(el, EL_HIST, history, hl); 1882 1883 el_set(el, EL_PROMPT, prompt); 1884 el_set(el, EL_EDITOR, "emacs"); 1885 el_set(el, EL_TERMINAL, NULL); 1886 el_set(el, EL_SIGNAL, 1); 1887 el_source(el, NULL); 1888 1889 /* Tab Completion */ 1890 el_set(el, EL_ADDFN, "ftp-complete", 1891 "Context sensitive argument completion", complete); 1892 complete_ctx.conn = conn; 1893 complete_ctx.remote_pathp = &remote_path; 1894 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); 1895 el_set(el, EL_BIND, "^I", "ftp-complete", NULL); 1896 } 1897 #endif /* USE_LIBEDIT */ 1898 1899 remote_path = do_realpath(conn, "."); 1900 if (remote_path == NULL) 1901 fatal("Need cwd"); 1902 1903 if (file1 != NULL) { 1904 dir = xstrdup(file1); 1905 dir = make_absolute(dir, remote_path); 1906 1907 if (remote_is_dir(conn, dir) && file2 == NULL) { 1908 printf("Changing to: %s\n", dir); 1909 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 1910 if (parse_dispatch_command(conn, cmd, 1911 &remote_path, 1) != 0) { 1912 xfree(dir); 1913 xfree(remote_path); 1914 xfree(conn); 1915 return (-1); 1916 } 1917 } else { 1918 if (file2 == NULL) 1919 snprintf(cmd, sizeof cmd, "get %s", dir); 1920 else 1921 snprintf(cmd, sizeof cmd, "get %s %s", dir, 1922 file2); 1923 1924 err = parse_dispatch_command(conn, cmd, 1925 &remote_path, 1); 1926 xfree(dir); 1927 xfree(remote_path); 1928 xfree(conn); 1929 return (err); 1930 } 1931 xfree(dir); 1932 } 1933 1934 #if defined(HAVE_SETVBUF) && !defined(BROKEN_SETVBUF) 1935 setvbuf(stdout, NULL, _IOLBF, 0); 1936 setvbuf(infile, NULL, _IOLBF, 0); 1937 #else 1938 setlinebuf(stdout); 1939 setlinebuf(infile); 1940 #endif 1941 1942 interactive = !batchmode && isatty(STDIN_FILENO); 1943 err = 0; 1944 for (;;) { 1945 char *cp; 1946 1947 signal(SIGINT, SIG_IGN); 1948 1949 if (el == NULL) { 1950 if (interactive) 1951 printf("sftp> "); 1952 if (fgets(cmd, sizeof(cmd), infile) == NULL) { 1953 if (interactive) 1954 printf("\n"); 1955 break; 1956 } 1957 if (!interactive) { /* Echo command */ 1958 printf("sftp> %s", cmd); 1959 if (strlen(cmd) > 0 && 1960 cmd[strlen(cmd) - 1] != '\n') 1961 printf("\n"); 1962 } 1963 } else { 1964 #ifdef USE_LIBEDIT 1965 const char *line; 1966 int count = 0; 1967 1968 if ((line = el_gets(el, &count)) == NULL || 1969 count <= 0) { 1970 printf("\n"); 1971 break; 1972 } 1973 history(hl, &hev, H_ENTER, line); 1974 if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { 1975 fprintf(stderr, "Error: input line too long\n"); 1976 continue; 1977 } 1978 #endif /* USE_LIBEDIT */ 1979 } 1980 1981 cp = strrchr(cmd, '\n'); 1982 if (cp) 1983 *cp = '\0'; 1984 1985 /* Handle user interrupts gracefully during commands */ 1986 interrupted = 0; 1987 signal(SIGINT, cmd_interrupt); 1988 1989 err = parse_dispatch_command(conn, cmd, &remote_path, 1990 batchmode); 1991 if (err != 0) 1992 break; 1993 } 1994 xfree(remote_path); 1995 xfree(conn); 1996 1997 #ifdef USE_LIBEDIT 1998 if (el != NULL) 1999 el_end(el); 2000 #endif /* USE_LIBEDIT */ 2001 2002 /* err == 1 signifies normal "quit" exit */ 2003 return (err >= 0 ? 0 : -1); 2004 } 2005 2006 static void 2007 connect_to_server(char *path, char **args, int *in, int *out) 2008 { 2009 int c_in, c_out; 2010 2011 #ifdef USE_PIPES 2012 int pin[2], pout[2]; 2013 2014 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 2015 fatal("pipe: %s", strerror(errno)); 2016 *in = pin[0]; 2017 *out = pout[1]; 2018 c_in = pout[0]; 2019 c_out = pin[1]; 2020 #else /* USE_PIPES */ 2021 int inout[2]; 2022 2023 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 2024 fatal("socketpair: %s", strerror(errno)); 2025 *in = *out = inout[0]; 2026 c_in = c_out = inout[1]; 2027 #endif /* USE_PIPES */ 2028 2029 if ((sshpid = fork()) == -1) 2030 fatal("fork: %s", strerror(errno)); 2031 else if (sshpid == 0) { 2032 if ((dup2(c_in, STDIN_FILENO) == -1) || 2033 (dup2(c_out, STDOUT_FILENO) == -1)) { 2034 fprintf(stderr, "dup2: %s\n", strerror(errno)); 2035 _exit(1); 2036 } 2037 close(*in); 2038 close(*out); 2039 close(c_in); 2040 close(c_out); 2041 2042 /* 2043 * The underlying ssh is in the same process group, so we must 2044 * ignore SIGINT if we want to gracefully abort commands, 2045 * otherwise the signal will make it to the ssh process and 2046 * kill it too. Contrawise, since sftp sends SIGTERMs to the 2047 * underlying ssh, it must *not* ignore that signal. 2048 */ 2049 signal(SIGINT, SIG_IGN); 2050 signal(SIGTERM, SIG_DFL); 2051 execvp(path, args); 2052 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 2053 _exit(1); 2054 } 2055 2056 signal(SIGTERM, killchild); 2057 signal(SIGINT, killchild); 2058 signal(SIGHUP, killchild); 2059 close(c_in); 2060 close(c_out); 2061 } 2062 2063 static void 2064 usage(void) 2065 { 2066 extern char *__progname; 2067 2068 fprintf(stderr, 2069 "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2070 " [-D sftp_server_path] [-F ssh_config] " 2071 "[-i identity_file] [-l limit]\n" 2072 " [-o ssh_option] [-P port] [-R num_requests] " 2073 "[-S program]\n" 2074 " [-s subsystem | sftp_server] host\n" 2075 " %s [user@]host[:file ...]\n" 2076 " %s [user@]host[:dir[/]]\n" 2077 " %s -b batchfile [user@]host\n", 2078 __progname, __progname, __progname, __progname); 2079 exit(1); 2080 } 2081 2082 int 2083 main(int argc, char **argv) 2084 { 2085 int in, out, ch, err; 2086 char *host = NULL, *userhost, *cp, *file2 = NULL; 2087 int debug_level = 0, sshver = 2; 2088 char *file1 = NULL, *sftp_server = NULL; 2089 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 2090 const char *errstr; 2091 LogLevel ll = SYSLOG_LEVEL_INFO; 2092 arglist args; 2093 extern int optind; 2094 extern char *optarg; 2095 struct sftp_conn *conn; 2096 size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; 2097 size_t num_requests = DEFAULT_NUM_REQUESTS; 2098 long long limit_kbps = 0; 2099 2100 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2101 sanitise_stdfd(); 2102 2103 __progname = ssh_get_progname(argv[0]); 2104 memset(&args, '\0', sizeof(args)); 2105 args.list = NULL; 2106 addargs(&args, "%s", ssh_program); 2107 addargs(&args, "-oForwardX11 no"); 2108 addargs(&args, "-oForwardAgent no"); 2109 addargs(&args, "-oPermitLocalCommand no"); 2110 addargs(&args, "-oClearAllForwardings yes"); 2111 2112 ll = SYSLOG_LEVEL_INFO; 2113 infile = stdin; 2114 2115 while ((ch = getopt(argc, argv, 2116 "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { 2117 switch (ch) { 2118 /* Passed through to ssh(1) */ 2119 case '4': 2120 case '6': 2121 case 'C': 2122 addargs(&args, "-%c", ch); 2123 break; 2124 /* Passed through to ssh(1) with argument */ 2125 case 'F': 2126 case 'c': 2127 case 'i': 2128 case 'o': 2129 addargs(&args, "-%c", ch); 2130 addargs(&args, "%s", optarg); 2131 break; 2132 case 'q': 2133 showprogress = 0; 2134 addargs(&args, "-%c", ch); 2135 break; 2136 case 'P': 2137 addargs(&args, "-oPort %s", optarg); 2138 break; 2139 case 'v': 2140 if (debug_level < 3) { 2141 addargs(&args, "-v"); 2142 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 2143 } 2144 debug_level++; 2145 break; 2146 case '1': 2147 sshver = 1; 2148 if (sftp_server == NULL) 2149 sftp_server = _PATH_SFTP_SERVER; 2150 break; 2151 case '2': 2152 sshver = 2; 2153 break; 2154 case 'B': 2155 copy_buffer_len = strtol(optarg, &cp, 10); 2156 if (copy_buffer_len == 0 || *cp != '\0') 2157 fatal("Invalid buffer size \"%s\"", optarg); 2158 break; 2159 case 'b': 2160 if (batchmode) 2161 fatal("Batch file already specified."); 2162 2163 /* Allow "-" as stdin */ 2164 if (strcmp(optarg, "-") != 0 && 2165 (infile = fopen(optarg, "r")) == NULL) 2166 fatal("%s (%s).", strerror(errno), optarg); 2167 showprogress = 0; 2168 batchmode = 1; 2169 addargs(&args, "-obatchmode yes"); 2170 break; 2171 case 'p': 2172 global_pflag = 1; 2173 break; 2174 case 'D': 2175 sftp_direct = optarg; 2176 break; 2177 case 'l': 2178 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, 2179 &errstr); 2180 if (errstr != NULL) 2181 usage(); 2182 limit_kbps *= 1024; /* kbps */ 2183 break; 2184 case 'r': 2185 global_rflag = 1; 2186 break; 2187 case 'R': 2188 num_requests = strtol(optarg, &cp, 10); 2189 if (num_requests == 0 || *cp != '\0') 2190 fatal("Invalid number of requests \"%s\"", 2191 optarg); 2192 break; 2193 case 's': 2194 sftp_server = optarg; 2195 break; 2196 case 'S': 2197 ssh_program = optarg; 2198 replacearg(&args, 0, "%s", ssh_program); 2199 break; 2200 case 'h': 2201 default: 2202 usage(); 2203 } 2204 } 2205 2206 if (!isatty(STDERR_FILENO)) 2207 showprogress = 0; 2208 2209 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 2210 2211 if (sftp_direct == NULL) { 2212 if (optind == argc || argc > (optind + 2)) 2213 usage(); 2214 2215 userhost = xstrdup(argv[optind]); 2216 file2 = argv[optind+1]; 2217 2218 if ((host = strrchr(userhost, '@')) == NULL) 2219 host = userhost; 2220 else { 2221 *host++ = '\0'; 2222 if (!userhost[0]) { 2223 fprintf(stderr, "Missing username\n"); 2224 usage(); 2225 } 2226 addargs(&args, "-l"); 2227 addargs(&args, "%s", userhost); 2228 } 2229 2230 if ((cp = colon(host)) != NULL) { 2231 *cp++ = '\0'; 2232 file1 = cp; 2233 } 2234 2235 host = cleanhostname(host); 2236 if (!*host) { 2237 fprintf(stderr, "Missing hostname\n"); 2238 usage(); 2239 } 2240 2241 addargs(&args, "-oProtocol %d", sshver); 2242 2243 /* no subsystem if the server-spec contains a '/' */ 2244 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 2245 addargs(&args, "-s"); 2246 2247 addargs(&args, "--"); 2248 addargs(&args, "%s", host); 2249 addargs(&args, "%s", (sftp_server != NULL ? 2250 sftp_server : "sftp")); 2251 2252 connect_to_server(ssh_program, args.list, &in, &out); 2253 } else { 2254 args.list = NULL; 2255 addargs(&args, "sftp-server"); 2256 2257 connect_to_server(sftp_direct, args.list, &in, &out); 2258 } 2259 freeargs(&args); 2260 2261 conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); 2262 if (conn == NULL) 2263 fatal("Couldn't initialise connection to server"); 2264 2265 if (!batchmode) { 2266 if (sftp_direct == NULL) 2267 fprintf(stderr, "Connected to %s.\n", host); 2268 else 2269 fprintf(stderr, "Attached to %s.\n", sftp_direct); 2270 } 2271 2272 err = interactive_loop(conn, file1, file2); 2273 2274 #if !defined(USE_PIPES) 2275 shutdown(in, SHUT_RDWR); 2276 shutdown(out, SHUT_RDWR); 2277 #endif 2278 2279 close(in); 2280 close(out); 2281 if (batchmode) 2282 fclose(infile); 2283 2284 while (waitpid(sshpid, NULL, 0) == -1) 2285 if (errno != EINTR) 2286 fatal("Couldn't wait for ssh process: %s", 2287 strerror(errno)); 2288 2289 exit(err == 0 ? 0 : 1); 2290 } 2291