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