1 /* $OpenBSD: sftp.c,v 1.142 2013/02/08 00:41:12 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 #include "xmalloc.h" 59 #include "log.h" 60 #include "pathnames.h" 61 #include "misc.h" 62 63 #include "sftp.h" 64 #include "buffer.h" 65 #include "sftp-common.h" 66 #include "sftp-client.h" 67 68 #define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */ 69 #define DEFAULT_NUM_REQUESTS 256 /* # concurrent outstanding requests */ 70 71 /* File to read commands from */ 72 FILE* infile; 73 74 /* Are we in batchfile mode? */ 75 int batchmode = 0; 76 77 /* PID of ssh transport process */ 78 static pid_t sshpid = -1; 79 80 /* This is set to 0 if the progressmeter is not desired. */ 81 int showprogress = 1; 82 83 /* When this option is set, we always recursively download/upload directories */ 84 int global_rflag = 0; 85 86 /* When this option is set, the file transfers will always preserve times */ 87 int global_pflag = 0; 88 89 /* SIGINT received during command processing */ 90 volatile sig_atomic_t interrupted = 0; 91 92 /* I wish qsort() took a separate ctx for the comparison function...*/ 93 int sort_flag; 94 95 /* Context used for commandline completion */ 96 struct complete_ctx { 97 struct sftp_conn *conn; 98 char **remote_pathp; 99 }; 100 101 int remote_glob(struct sftp_conn *, const char *, int, 102 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ 103 104 extern char *__progname; 105 106 /* Separators for interactive commands */ 107 #define WHITESPACE " \t\r\n" 108 109 /* ls flags */ 110 #define LS_LONG_VIEW 0x0001 /* Full view ala ls -l */ 111 #define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */ 112 #define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */ 113 #define LS_NAME_SORT 0x0008 /* Sort by name (default) */ 114 #define LS_TIME_SORT 0x0010 /* Sort by mtime */ 115 #define LS_SIZE_SORT 0x0020 /* Sort by file size */ 116 #define LS_REVERSE_SORT 0x0040 /* Reverse sort order */ 117 #define LS_SHOW_ALL 0x0080 /* Don't skip filenames starting with '.' */ 118 #define LS_SI_UNITS 0x0100 /* Display sizes as K, M, G, etc. */ 119 120 #define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS) 121 #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) 122 123 /* Commands for interactive mode */ 124 #define I_CHDIR 1 125 #define I_CHGRP 2 126 #define I_CHMOD 3 127 #define I_CHOWN 4 128 #define I_DF 24 129 #define I_GET 5 130 #define I_HELP 6 131 #define I_LCHDIR 7 132 #define I_LINK 25 133 #define I_LLS 8 134 #define I_LMKDIR 9 135 #define I_LPWD 10 136 #define I_LS 11 137 #define I_LUMASK 12 138 #define I_MKDIR 13 139 #define I_PUT 14 140 #define I_PWD 15 141 #define I_QUIT 16 142 #define I_RENAME 17 143 #define I_RM 18 144 #define I_RMDIR 19 145 #define I_SHELL 20 146 #define I_SYMLINK 21 147 #define I_VERSION 22 148 #define I_PROGRESS 23 149 150 struct CMD { 151 const char *c; 152 const int n; 153 const int t; 154 }; 155 156 /* Type of completion */ 157 #define NOARGS 0 158 #define REMOTE 1 159 #define LOCAL 2 160 161 static const struct CMD cmds[] = { 162 { "bye", I_QUIT, NOARGS }, 163 { "cd", I_CHDIR, REMOTE }, 164 { "chdir", I_CHDIR, REMOTE }, 165 { "chgrp", I_CHGRP, REMOTE }, 166 { "chmod", I_CHMOD, REMOTE }, 167 { "chown", I_CHOWN, REMOTE }, 168 { "df", I_DF, REMOTE }, 169 { "dir", I_LS, REMOTE }, 170 { "exit", I_QUIT, NOARGS }, 171 { "get", I_GET, REMOTE }, 172 { "help", I_HELP, NOARGS }, 173 { "lcd", I_LCHDIR, LOCAL }, 174 { "lchdir", I_LCHDIR, LOCAL }, 175 { "lls", I_LLS, LOCAL }, 176 { "lmkdir", I_LMKDIR, LOCAL }, 177 { "ln", I_LINK, REMOTE }, 178 { "lpwd", I_LPWD, LOCAL }, 179 { "ls", I_LS, REMOTE }, 180 { "lumask", I_LUMASK, NOARGS }, 181 { "mkdir", I_MKDIR, REMOTE }, 182 { "mget", I_GET, REMOTE }, 183 { "mput", I_PUT, LOCAL }, 184 { "progress", I_PROGRESS, NOARGS }, 185 { "put", I_PUT, LOCAL }, 186 { "pwd", I_PWD, REMOTE }, 187 { "quit", I_QUIT, NOARGS }, 188 { "rename", I_RENAME, REMOTE }, 189 { "rm", I_RM, REMOTE }, 190 { "rmdir", I_RMDIR, REMOTE }, 191 { "symlink", I_SYMLINK, REMOTE }, 192 { "version", I_VERSION, NOARGS }, 193 { "!", I_SHELL, NOARGS }, 194 { "?", I_HELP, NOARGS }, 195 { NULL, -1, -1 } 196 }; 197 198 int interactive_loop(struct sftp_conn *, char *file1, char *file2); 199 200 /* ARGSUSED */ 201 static void 202 killchild(int signo) 203 { 204 if (sshpid > 1) { 205 kill(sshpid, SIGTERM); 206 waitpid(sshpid, NULL, 0); 207 } 208 209 _exit(1); 210 } 211 212 /* ARGSUSED */ 213 static void 214 cmd_interrupt(int signo) 215 { 216 const char msg[] = "\rInterrupt \n"; 217 int olderrno = errno; 218 219 write(STDERR_FILENO, msg, sizeof(msg) - 1); 220 interrupted = 1; 221 errno = olderrno; 222 } 223 224 static void 225 help(void) 226 { 227 printf("Available commands:\n" 228 "bye Quit sftp\n" 229 "cd path Change remote directory to 'path'\n" 230 "chgrp grp path Change group of file 'path' to 'grp'\n" 231 "chmod mode path Change permissions of file 'path' to 'mode'\n" 232 "chown own path Change owner of file 'path' to 'own'\n" 233 "df [-hi] [path] Display statistics for current directory or\n" 234 " filesystem containing 'path'\n" 235 "exit Quit sftp\n" 236 "get [-Ppr] remote [local] Download file\n" 237 "help Display this help text\n" 238 "lcd path Change local directory to 'path'\n" 239 "lls [ls-options [path]] Display local directory listing\n" 240 "lmkdir path Create local directory\n" 241 "ln [-s] oldpath newpath Link remote file (-s for symlink)\n" 242 "lpwd Print local working directory\n" 243 "ls [-1afhlnrSt] [path] Display remote directory listing\n" 244 "lumask umask Set local umask to 'umask'\n" 245 "mkdir path Create remote directory\n" 246 "progress Toggle display of progress meter\n" 247 "put [-Ppr] local [remote] Upload file\n" 248 "pwd Display remote working directory\n" 249 "quit Quit sftp\n" 250 "rename oldpath newpath Rename remote file\n" 251 "rm path Delete remote file\n" 252 "rmdir path Remove remote directory\n" 253 "symlink oldpath newpath Symlink remote file\n" 254 "version Show SFTP version\n" 255 "!command Execute 'command' in local shell\n" 256 "! Escape to local shell\n" 257 "? Synonym for help\n"); 258 } 259 260 static void 261 local_do_shell(const char *args) 262 { 263 int status; 264 char *shell; 265 pid_t pid; 266 267 if (!*args) 268 args = NULL; 269 270 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 271 shell = _PATH_BSHELL; 272 273 if ((pid = fork()) == -1) 274 fatal("Couldn't fork: %s", strerror(errno)); 275 276 if (pid == 0) { 277 /* XXX: child has pipe fds to ssh subproc open - issue? */ 278 if (args) { 279 debug3("Executing %s -c \"%s\"", shell, args); 280 execl(shell, shell, "-c", args, (char *)NULL); 281 } else { 282 debug3("Executing %s", shell); 283 execl(shell, shell, (char *)NULL); 284 } 285 fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, 286 strerror(errno)); 287 _exit(1); 288 } 289 while (waitpid(pid, &status, 0) == -1) 290 if (errno != EINTR) 291 fatal("Couldn't wait for child: %s", strerror(errno)); 292 if (!WIFEXITED(status)) 293 error("Shell exited abnormally"); 294 else if (WEXITSTATUS(status)) 295 error("Shell exited with status %d", WEXITSTATUS(status)); 296 } 297 298 static void 299 local_do_ls(const char *args) 300 { 301 if (!args || !*args) 302 local_do_shell(_PATH_LS); 303 else { 304 int len = strlen(_PATH_LS " ") + strlen(args) + 1; 305 char *buf = xmalloc(len); 306 307 /* XXX: quoting - rip quoting code from ftp? */ 308 snprintf(buf, len, _PATH_LS " %s", args); 309 local_do_shell(buf); 310 xfree(buf); 311 } 312 } 313 314 /* Strip one path (usually the pwd) from the start of another */ 315 static char * 316 path_strip(char *path, char *strip) 317 { 318 size_t len; 319 320 if (strip == NULL) 321 return (xstrdup(path)); 322 323 len = strlen(strip); 324 if (strncmp(path, strip, len) == 0) { 325 if (strip[len - 1] != '/' && path[len] == '/') 326 len++; 327 return (xstrdup(path + len)); 328 } 329 330 return (xstrdup(path)); 331 } 332 333 static char * 334 make_absolute(char *p, char *pwd) 335 { 336 char *abs_str; 337 338 /* Derelativise */ 339 if (p && p[0] != '/') { 340 abs_str = path_append(pwd, p); 341 xfree(p); 342 return(abs_str); 343 } else 344 return(p); 345 } 346 347 static int 348 parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, 349 int *rflag) 350 { 351 extern int opterr, optind, optopt, optreset; 352 int ch; 353 354 optind = optreset = 1; 355 opterr = 0; 356 357 *rflag = *pflag = 0; 358 while ((ch = getopt(argc, argv, "PpRr")) != -1) { 359 switch (ch) { 360 case 'p': 361 case 'P': 362 *pflag = 1; 363 break; 364 case 'r': 365 case 'R': 366 *rflag = 1; 367 break; 368 default: 369 error("%s: Invalid flag -%c", cmd, optopt); 370 return -1; 371 } 372 } 373 374 return optind; 375 } 376 377 static int 378 parse_link_flags(const char *cmd, char **argv, int argc, int *sflag) 379 { 380 extern int opterr, optind, optopt, optreset; 381 int ch; 382 383 optind = optreset = 1; 384 opterr = 0; 385 386 *sflag = 0; 387 while ((ch = getopt(argc, argv, "s")) != -1) { 388 switch (ch) { 389 case 's': 390 *sflag = 1; 391 break; 392 default: 393 error("%s: Invalid flag -%c", cmd, optopt); 394 return -1; 395 } 396 } 397 398 return optind; 399 } 400 401 static int 402 parse_ls_flags(char **argv, int argc, int *lflag) 403 { 404 extern int opterr, optind, optopt, optreset; 405 int ch; 406 407 optind = optreset = 1; 408 opterr = 0; 409 410 *lflag = LS_NAME_SORT; 411 while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) { 412 switch (ch) { 413 case '1': 414 *lflag &= ~VIEW_FLAGS; 415 *lflag |= LS_SHORT_VIEW; 416 break; 417 case 'S': 418 *lflag &= ~SORT_FLAGS; 419 *lflag |= LS_SIZE_SORT; 420 break; 421 case 'a': 422 *lflag |= LS_SHOW_ALL; 423 break; 424 case 'f': 425 *lflag &= ~SORT_FLAGS; 426 break; 427 case 'h': 428 *lflag |= LS_SI_UNITS; 429 break; 430 case 'l': 431 *lflag &= ~LS_SHORT_VIEW; 432 *lflag |= LS_LONG_VIEW; 433 break; 434 case 'n': 435 *lflag &= ~LS_SHORT_VIEW; 436 *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; 437 break; 438 case 'r': 439 *lflag |= LS_REVERSE_SORT; 440 break; 441 case 't': 442 *lflag &= ~SORT_FLAGS; 443 *lflag |= LS_TIME_SORT; 444 break; 445 default: 446 error("ls: Invalid flag -%c", optopt); 447 return -1; 448 } 449 } 450 451 return optind; 452 } 453 454 static int 455 parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) 456 { 457 extern int opterr, optind, optopt, optreset; 458 int ch; 459 460 optind = optreset = 1; 461 opterr = 0; 462 463 *hflag = *iflag = 0; 464 while ((ch = getopt(argc, argv, "hi")) != -1) { 465 switch (ch) { 466 case 'h': 467 *hflag = 1; 468 break; 469 case 'i': 470 *iflag = 1; 471 break; 472 default: 473 error("%s: Invalid flag -%c", cmd, optopt); 474 return -1; 475 } 476 } 477 478 return optind; 479 } 480 481 static int 482 is_dir(char *path) 483 { 484 struct stat sb; 485 486 /* XXX: report errors? */ 487 if (stat(path, &sb) == -1) 488 return(0); 489 490 return(S_ISDIR(sb.st_mode)); 491 } 492 493 static int 494 remote_is_dir(struct sftp_conn *conn, char *path) 495 { 496 Attrib *a; 497 498 /* XXX: report errors? */ 499 if ((a = do_stat(conn, path, 1)) == NULL) 500 return(0); 501 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 502 return(0); 503 return(S_ISDIR(a->perm)); 504 } 505 506 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 507 static int 508 pathname_is_dir(char *pathname) 509 { 510 size_t l = strlen(pathname); 511 512 return l > 0 && pathname[l - 1] == '/'; 513 } 514 515 static int 516 process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, 517 int pflag, int rflag) 518 { 519 char *abs_src = NULL; 520 char *abs_dst = NULL; 521 glob_t g; 522 char *filename, *tmp=NULL; 523 int i, err = 0; 524 525 abs_src = xstrdup(src); 526 abs_src = make_absolute(abs_src, pwd); 527 memset(&g, 0, sizeof(g)); 528 529 debug3("Looking up %s", abs_src); 530 if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) { 531 error("File \"%s\" not found.", abs_src); 532 err = -1; 533 goto out; 534 } 535 536 /* 537 * If multiple matches then dst must be a directory or 538 * unspecified. 539 */ 540 if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) { 541 error("Multiple source paths, but destination " 542 "\"%s\" is not a directory", dst); 543 err = -1; 544 goto out; 545 } 546 547 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 548 tmp = xstrdup(g.gl_pathv[i]); 549 if ((filename = basename(tmp)) == NULL) { 550 error("basename %s: %s", tmp, strerror(errno)); 551 xfree(tmp); 552 err = -1; 553 goto out; 554 } 555 556 if (g.gl_matchc == 1 && dst) { 557 if (is_dir(dst)) { 558 abs_dst = path_append(dst, filename); 559 } else { 560 abs_dst = xstrdup(dst); 561 } 562 } else if (dst) { 563 abs_dst = path_append(dst, filename); 564 } else { 565 abs_dst = xstrdup(filename); 566 } 567 xfree(tmp); 568 569 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); 570 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 571 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, 572 pflag || global_pflag, 1) == -1) 573 err = -1; 574 } else { 575 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, 576 pflag || global_pflag) == -1) 577 err = -1; 578 } 579 xfree(abs_dst); 580 abs_dst = NULL; 581 } 582 583 out: 584 xfree(abs_src); 585 globfree(&g); 586 return(err); 587 } 588 589 static int 590 process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, 591 int pflag, int rflag) 592 { 593 char *tmp_dst = NULL; 594 char *abs_dst = NULL; 595 char *tmp = NULL, *filename = NULL; 596 glob_t g; 597 int err = 0; 598 int i, dst_is_dir = 1; 599 struct stat sb; 600 601 if (dst) { 602 tmp_dst = xstrdup(dst); 603 tmp_dst = make_absolute(tmp_dst, pwd); 604 } 605 606 memset(&g, 0, sizeof(g)); 607 debug3("Looking up %s", src); 608 if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { 609 error("File \"%s\" not found.", src); 610 err = -1; 611 goto out; 612 } 613 614 /* If we aren't fetching to pwd then stash this status for later */ 615 if (tmp_dst != NULL) 616 dst_is_dir = remote_is_dir(conn, tmp_dst); 617 618 /* If multiple matches, dst may be directory or unspecified */ 619 if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { 620 error("Multiple paths match, but destination " 621 "\"%s\" is not a directory", tmp_dst); 622 err = -1; 623 goto out; 624 } 625 626 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 627 if (stat(g.gl_pathv[i], &sb) == -1) { 628 err = -1; 629 error("stat %s: %s", g.gl_pathv[i], strerror(errno)); 630 continue; 631 } 632 633 tmp = xstrdup(g.gl_pathv[i]); 634 if ((filename = basename(tmp)) == NULL) { 635 error("basename %s: %s", tmp, strerror(errno)); 636 xfree(tmp); 637 err = -1; 638 goto out; 639 } 640 641 if (g.gl_matchc == 1 && tmp_dst) { 642 /* If directory specified, append filename */ 643 if (dst_is_dir) 644 abs_dst = path_append(tmp_dst, filename); 645 else 646 abs_dst = xstrdup(tmp_dst); 647 } else if (tmp_dst) { 648 abs_dst = path_append(tmp_dst, filename); 649 } else { 650 abs_dst = make_absolute(xstrdup(filename), pwd); 651 } 652 xfree(tmp); 653 654 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); 655 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 656 if (upload_dir(conn, g.gl_pathv[i], abs_dst, 657 pflag || global_pflag, 1) == -1) 658 err = -1; 659 } else { 660 if (do_upload(conn, g.gl_pathv[i], abs_dst, 661 pflag || global_pflag) == -1) 662 err = -1; 663 } 664 } 665 666 out: 667 if (abs_dst) 668 xfree(abs_dst); 669 if (tmp_dst) 670 xfree(tmp_dst); 671 globfree(&g); 672 return(err); 673 } 674 675 static int 676 sdirent_comp(const void *aa, const void *bb) 677 { 678 SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; 679 SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; 680 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 681 682 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 683 if (sort_flag & LS_NAME_SORT) 684 return (rmul * strcmp(a->filename, b->filename)); 685 else if (sort_flag & LS_TIME_SORT) 686 return (rmul * NCMP(a->a.mtime, b->a.mtime)); 687 else if (sort_flag & LS_SIZE_SORT) 688 return (rmul * NCMP(a->a.size, b->a.size)); 689 690 fatal("Unknown ls sort type"); 691 } 692 693 /* sftp ls.1 replacement for directories */ 694 static int 695 do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) 696 { 697 int n; 698 u_int c = 1, colspace = 0, columns = 1; 699 SFTP_DIRENT **d; 700 701 if ((n = do_readdir(conn, path, &d)) != 0) 702 return (n); 703 704 if (!(lflag & LS_SHORT_VIEW)) { 705 u_int m = 0, width = 80; 706 struct winsize ws; 707 char *tmp; 708 709 /* Count entries for sort and find longest filename */ 710 for (n = 0; d[n] != NULL; n++) { 711 if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) 712 m = MAX(m, strlen(d[n]->filename)); 713 } 714 715 /* Add any subpath that also needs to be counted */ 716 tmp = path_strip(path, strip_path); 717 m += strlen(tmp); 718 xfree(tmp); 719 720 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 721 width = ws.ws_col; 722 723 columns = width / (m + 2); 724 columns = MAX(columns, 1); 725 colspace = width / columns; 726 colspace = MIN(colspace, width); 727 } 728 729 if (lflag & SORT_FLAGS) { 730 for (n = 0; d[n] != NULL; n++) 731 ; /* count entries */ 732 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); 733 qsort(d, n, sizeof(*d), sdirent_comp); 734 } 735 736 for (n = 0; d[n] != NULL && !interrupted; n++) { 737 char *tmp, *fname; 738 739 if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) 740 continue; 741 742 tmp = path_append(path, d[n]->filename); 743 fname = path_strip(tmp, strip_path); 744 xfree(tmp); 745 746 if (lflag & LS_LONG_VIEW) { 747 if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { 748 char *lname; 749 struct stat sb; 750 751 memset(&sb, 0, sizeof(sb)); 752 attrib_to_stat(&d[n]->a, &sb); 753 lname = ls_file(fname, &sb, 1, 754 (lflag & LS_SI_UNITS)); 755 printf("%s\n", lname); 756 xfree(lname); 757 } else 758 printf("%s\n", d[n]->longname); 759 } else { 760 printf("%-*s", colspace, fname); 761 if (c >= columns) { 762 printf("\n"); 763 c = 1; 764 } else 765 c++; 766 } 767 768 xfree(fname); 769 } 770 771 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 772 printf("\n"); 773 774 free_sftp_dirents(d); 775 return (0); 776 } 777 778 /* sftp ls.1 replacement which handles path globs */ 779 static int 780 do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, 781 int lflag) 782 { 783 char *fname, *lname; 784 glob_t g; 785 int err; 786 struct winsize ws; 787 u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; 788 789 memset(&g, 0, sizeof(g)); 790 791 if (remote_glob(conn, path, 792 GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, 793 NULL, &g) || 794 (g.gl_pathc && !g.gl_matchc)) { 795 if (g.gl_pathc) 796 globfree(&g); 797 error("Can't ls: \"%s\" not found", path); 798 return -1; 799 } 800 801 if (interrupted) 802 goto out; 803 804 /* 805 * If the glob returns a single match and it is a directory, 806 * then just list its contents. 807 */ 808 if (g.gl_matchc == 1 && g.gl_statv[0] != NULL && 809 S_ISDIR(g.gl_statv[0]->st_mode)) { 810 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); 811 globfree(&g); 812 return err; 813 } 814 815 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 816 width = ws.ws_col; 817 818 if (!(lflag & LS_SHORT_VIEW)) { 819 /* Count entries for sort and find longest filename */ 820 for (i = 0; g.gl_pathv[i]; i++) 821 m = MAX(m, strlen(g.gl_pathv[i])); 822 823 columns = width / (m + 2); 824 columns = MAX(columns, 1); 825 colspace = width / columns; 826 } 827 828 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 829 fname = path_strip(g.gl_pathv[i], strip_path); 830 if (lflag & LS_LONG_VIEW) { 831 if (g.gl_statv[i] == NULL) { 832 error("no stat information for %s", fname); 833 continue; 834 } 835 lname = ls_file(fname, g.gl_statv[i], 1, 836 (lflag & LS_SI_UNITS)); 837 printf("%s\n", lname); 838 xfree(lname); 839 } else { 840 printf("%-*s", colspace, fname); 841 if (c >= columns) { 842 printf("\n"); 843 c = 1; 844 } else 845 c++; 846 } 847 xfree(fname); 848 } 849 850 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 851 printf("\n"); 852 853 out: 854 if (g.gl_pathc) 855 globfree(&g); 856 857 return 0; 858 } 859 860 static int 861 do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) 862 { 863 struct sftp_statvfs st; 864 char s_used[FMT_SCALED_STRSIZE]; 865 char s_avail[FMT_SCALED_STRSIZE]; 866 char s_root[FMT_SCALED_STRSIZE]; 867 char s_total[FMT_SCALED_STRSIZE]; 868 unsigned long long ffree; 869 870 if (do_statvfs(conn, path, &st, 1) == -1) 871 return -1; 872 if (iflag) { 873 ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0; 874 printf(" Inodes Used Avail " 875 "(root) %%Capacity\n"); 876 printf("%11llu %11llu %11llu %11llu %3llu%%\n", 877 (unsigned long long)st.f_files, 878 (unsigned long long)(st.f_files - st.f_ffree), 879 (unsigned long long)st.f_favail, 880 (unsigned long long)st.f_ffree, ffree); 881 } else if (hflag) { 882 strlcpy(s_used, "error", sizeof(s_used)); 883 strlcpy(s_avail, "error", sizeof(s_avail)); 884 strlcpy(s_root, "error", sizeof(s_root)); 885 strlcpy(s_total, "error", sizeof(s_total)); 886 fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used); 887 fmt_scaled(st.f_bavail * st.f_frsize, s_avail); 888 fmt_scaled(st.f_bfree * st.f_frsize, s_root); 889 fmt_scaled(st.f_blocks * st.f_frsize, s_total); 890 printf(" Size Used Avail (root) %%Capacity\n"); 891 printf("%7sB %7sB %7sB %7sB %3llu%%\n", 892 s_total, s_used, s_avail, s_root, 893 (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / 894 st.f_blocks)); 895 } else { 896 printf(" Size Used Avail " 897 "(root) %%Capacity\n"); 898 printf("%12llu %12llu %12llu %12llu %3llu%%\n", 899 (unsigned long long)(st.f_frsize * st.f_blocks / 1024), 900 (unsigned long long)(st.f_frsize * 901 (st.f_blocks - st.f_bfree) / 1024), 902 (unsigned long long)(st.f_frsize * st.f_bavail / 1024), 903 (unsigned long long)(st.f_frsize * st.f_bfree / 1024), 904 (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / 905 st.f_blocks)); 906 } 907 return 0; 908 } 909 910 /* 911 * Undo escaping of glob sequences in place. Used to undo extra escaping 912 * applied in makeargv() when the string is destined for a function that 913 * does not glob it. 914 */ 915 static void 916 undo_glob_escape(char *s) 917 { 918 size_t i, j; 919 920 for (i = j = 0;;) { 921 if (s[i] == '\0') { 922 s[j] = '\0'; 923 return; 924 } 925 if (s[i] != '\\') { 926 s[j++] = s[i++]; 927 continue; 928 } 929 /* s[i] == '\\' */ 930 ++i; 931 switch (s[i]) { 932 case '?': 933 case '[': 934 case '*': 935 case '\\': 936 s[j++] = s[i++]; 937 break; 938 case '\0': 939 s[j++] = '\\'; 940 s[j] = '\0'; 941 return; 942 default: 943 s[j++] = '\\'; 944 s[j++] = s[i++]; 945 break; 946 } 947 } 948 } 949 950 /* 951 * Split a string into an argument vector using sh(1)-style quoting, 952 * comment and escaping rules, but with some tweaks to handle glob(3) 953 * wildcards. 954 * The "sloppy" flag allows for recovery from missing terminating quote, for 955 * use in parsing incomplete commandlines during tab autocompletion. 956 * 957 * Returns NULL on error or a NULL-terminated array of arguments. 958 * 959 * If "lastquote" is not NULL, the quoting character used for the last 960 * argument is placed in *lastquote ("\0", "'" or "\""). 961 * 962 * If "terminated" is not NULL, *terminated will be set to 1 when the 963 * last argument's quote has been properly terminated or 0 otherwise. 964 * This parameter is only of use if "sloppy" is set. 965 */ 966 #define MAXARGS 128 967 #define MAXARGLEN 8192 968 static char ** 969 makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, 970 u_int *terminated) 971 { 972 int argc, quot; 973 size_t i, j; 974 static char argvs[MAXARGLEN]; 975 static char *argv[MAXARGS + 1]; 976 enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q; 977 978 *argcp = argc = 0; 979 if (strlen(arg) > sizeof(argvs) - 1) { 980 args_too_longs: 981 error("string too long"); 982 return NULL; 983 } 984 if (terminated != NULL) 985 *terminated = 1; 986 if (lastquote != NULL) 987 *lastquote = '\0'; 988 state = MA_START; 989 i = j = 0; 990 for (;;) { 991 if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){ 992 error("Too many arguments."); 993 return NULL; 994 } 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 (argv[0] != NULL && 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 xfree(list); 1636 return 0; 1637 } 1638 1639 /* Complete ambigious command */ 1640 tmp = complete_ambiguous(cmd, list, count); 1641 if (count > 1) 1642 complete_display(list, 0); 1643 1644 for (y = 0; list[y]; y++) 1645 xfree(list[y]); 1646 xfree(list); 1647 1648 if (tmp != NULL) { 1649 tmplen = strlen(tmp); 1650 cmdlen = strlen(cmd); 1651 /* If cmd may be extended then do so */ 1652 if (tmplen > cmdlen) 1653 if (el_insertstr(el, tmp + cmdlen) == -1) 1654 fatal("el_insertstr failed."); 1655 lf = el_line(el); 1656 /* Terminate argument cleanly */ 1657 if (count == 1) { 1658 y = 0; 1659 if (!terminated) 1660 argterm[y++] = quote; 1661 if (lastarg || *(lf->cursor) != ' ') 1662 argterm[y++] = ' '; 1663 argterm[y] = '\0'; 1664 if (y > 0 && el_insertstr(el, argterm) == -1) 1665 fatal("el_insertstr failed."); 1666 } 1667 xfree(tmp); 1668 } 1669 1670 return count; 1671 } 1672 1673 /* 1674 * Determine whether a particular sftp command's arguments (if any) 1675 * represent local or remote files. 1676 */ 1677 static int 1678 complete_is_remote(char *cmd) { 1679 int i; 1680 1681 if (cmd == NULL) 1682 return -1; 1683 1684 for (i = 0; cmds[i].c; i++) { 1685 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 1686 return cmds[i].t; 1687 } 1688 1689 return -1; 1690 } 1691 1692 /* Autocomplete a filename "file" */ 1693 static int 1694 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, 1695 char *file, int remote, int lastarg, char quote, int terminated) 1696 { 1697 glob_t g; 1698 char *tmp, *tmp2, ins[3]; 1699 u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; 1700 const LineInfo *lf; 1701 1702 /* Glob from "file" location */ 1703 if (file == NULL) 1704 tmp = xstrdup("*"); 1705 else 1706 xasprintf(&tmp, "%s*", file); 1707 1708 /* Check if the path is absolute. */ 1709 isabs = tmp[0] == '/'; 1710 1711 memset(&g, 0, sizeof(g)); 1712 if (remote != LOCAL) { 1713 tmp = make_absolute(tmp, remote_path); 1714 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1715 } else 1716 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1717 1718 /* Determine length of pwd so we can trim completion display */ 1719 for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { 1720 /* Terminate counting on first unescaped glob metacharacter */ 1721 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { 1722 if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') 1723 hadglob = 1; 1724 break; 1725 } 1726 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') 1727 tmplen++; 1728 if (tmp[tmplen] == '/') 1729 pwdlen = tmplen + 1; /* track last seen '/' */ 1730 } 1731 xfree(tmp); 1732 1733 if (g.gl_matchc == 0) 1734 goto out; 1735 1736 if (g.gl_matchc > 1) 1737 complete_display(g.gl_pathv, pwdlen); 1738 1739 tmp = NULL; 1740 /* Don't try to extend globs */ 1741 if (file == NULL || hadglob) 1742 goto out; 1743 1744 tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); 1745 tmp = path_strip(tmp2, isabs ? NULL : remote_path); 1746 xfree(tmp2); 1747 1748 if (tmp == NULL) 1749 goto out; 1750 1751 tmplen = strlen(tmp); 1752 filelen = strlen(file); 1753 1754 /* Count the number of escaped characters in the input string. */ 1755 cesc = isesc = 0; 1756 for (i = 0; i < filelen; i++) { 1757 if (!isesc && file[i] == '\\' && i + 1 < filelen){ 1758 isesc = 1; 1759 cesc++; 1760 } else 1761 isesc = 0; 1762 } 1763 1764 if (tmplen > (filelen - cesc)) { 1765 tmp2 = tmp + filelen - cesc; 1766 len = strlen(tmp2); 1767 /* quote argument on way out */ 1768 for (i = 0; i < len; i++) { 1769 ins[0] = '\\'; 1770 ins[1] = tmp2[i]; 1771 ins[2] = '\0'; 1772 switch (tmp2[i]) { 1773 case '\'': 1774 case '"': 1775 case '\\': 1776 case '\t': 1777 case '[': 1778 case ' ': 1779 case '#': 1780 case '*': 1781 if (quote == '\0' || tmp2[i] == quote) { 1782 if (el_insertstr(el, ins) == -1) 1783 fatal("el_insertstr " 1784 "failed."); 1785 break; 1786 } 1787 /* FALLTHROUGH */ 1788 default: 1789 if (el_insertstr(el, ins + 1) == -1) 1790 fatal("el_insertstr failed."); 1791 break; 1792 } 1793 } 1794 } 1795 1796 lf = el_line(el); 1797 if (g.gl_matchc == 1) { 1798 i = 0; 1799 if (!terminated) 1800 ins[i++] = quote; 1801 if (*(lf->cursor - 1) != '/' && 1802 (lastarg || *(lf->cursor) != ' ')) 1803 ins[i++] = ' '; 1804 ins[i] = '\0'; 1805 if (i > 0 && el_insertstr(el, ins) == -1) 1806 fatal("el_insertstr failed."); 1807 } 1808 xfree(tmp); 1809 1810 out: 1811 globfree(&g); 1812 return g.gl_matchc; 1813 } 1814 1815 /* tab-completion hook function, called via libedit */ 1816 static unsigned char 1817 complete(EditLine *el, int ch) 1818 { 1819 char **argv, *line, quote; 1820 u_int argc, carg, cursor, len, terminated, ret = CC_ERROR; 1821 const LineInfo *lf; 1822 struct complete_ctx *complete_ctx; 1823 1824 lf = el_line(el); 1825 if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) 1826 fatal("%s: el_get failed", __func__); 1827 1828 /* Figure out which argument the cursor points to */ 1829 cursor = lf->cursor - lf->buffer; 1830 line = (char *)xmalloc(cursor + 1); 1831 memcpy(line, lf->buffer, cursor); 1832 line[cursor] = '\0'; 1833 argv = makeargv(line, &carg, 1, "e, &terminated); 1834 xfree(line); 1835 1836 /* Get all the arguments on the line */ 1837 len = lf->lastchar - lf->buffer; 1838 line = (char *)xmalloc(len + 1); 1839 memcpy(line, lf->buffer, len); 1840 line[len] = '\0'; 1841 argv = makeargv(line, &argc, 1, NULL, NULL); 1842 1843 /* Ensure cursor is at EOL or a argument boundary */ 1844 if (line[cursor] != ' ' && line[cursor] != '\0' && 1845 line[cursor] != '\n') { 1846 xfree(line); 1847 return ret; 1848 } 1849 1850 if (carg == 0) { 1851 /* Show all available commands */ 1852 complete_cmd_parse(el, NULL, argc == carg, '\0', 1); 1853 ret = CC_REDISPLAY; 1854 } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { 1855 /* Handle the command parsing */ 1856 if (complete_cmd_parse(el, argv[0], argc == carg, 1857 quote, terminated) != 0) 1858 ret = CC_REDISPLAY; 1859 } else if (carg >= 1) { 1860 /* Handle file parsing */ 1861 int remote = complete_is_remote(argv[0]); 1862 char *filematch = NULL; 1863 1864 if (carg > 1 && line[cursor-1] != ' ') 1865 filematch = argv[carg - 1]; 1866 1867 if (remote != 0 && 1868 complete_match(el, complete_ctx->conn, 1869 *complete_ctx->remote_pathp, filematch, 1870 remote, carg == argc, quote, terminated) != 0) 1871 ret = CC_REDISPLAY; 1872 } 1873 1874 xfree(line); 1875 return ret; 1876 } 1877 #endif /* USE_LIBEDIT */ 1878 1879 int 1880 interactive_loop(struct sftp_conn *conn, char *file1, char *file2) 1881 { 1882 char *remote_path; 1883 char *dir = NULL; 1884 char cmd[2048]; 1885 int err, interactive; 1886 EditLine *el = NULL; 1887 #ifdef USE_LIBEDIT 1888 History *hl = NULL; 1889 HistEvent hev; 1890 extern char *__progname; 1891 struct complete_ctx complete_ctx; 1892 1893 if (!batchmode && isatty(STDIN_FILENO)) { 1894 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) 1895 fatal("Couldn't initialise editline"); 1896 if ((hl = history_init()) == NULL) 1897 fatal("Couldn't initialise editline history"); 1898 history(hl, &hev, H_SETSIZE, 100); 1899 el_set(el, EL_HIST, history, hl); 1900 1901 el_set(el, EL_PROMPT, prompt); 1902 el_set(el, EL_EDITOR, "emacs"); 1903 el_set(el, EL_TERMINAL, NULL); 1904 el_set(el, EL_SIGNAL, 1); 1905 el_source(el, NULL); 1906 1907 /* Tab Completion */ 1908 el_set(el, EL_ADDFN, "ftp-complete", 1909 "Context sensitive argument completion", complete); 1910 complete_ctx.conn = conn; 1911 complete_ctx.remote_pathp = &remote_path; 1912 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); 1913 el_set(el, EL_BIND, "^I", "ftp-complete", NULL); 1914 } 1915 #endif /* USE_LIBEDIT */ 1916 1917 remote_path = do_realpath(conn, "."); 1918 if (remote_path == NULL) 1919 fatal("Need cwd"); 1920 1921 if (file1 != NULL) { 1922 dir = xstrdup(file1); 1923 dir = make_absolute(dir, remote_path); 1924 1925 if (remote_is_dir(conn, dir) && file2 == NULL) { 1926 printf("Changing to: %s\n", dir); 1927 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 1928 if (parse_dispatch_command(conn, cmd, 1929 &remote_path, 1) != 0) { 1930 xfree(dir); 1931 xfree(remote_path); 1932 xfree(conn); 1933 return (-1); 1934 } 1935 } else { 1936 /* XXX this is wrong wrt quoting */ 1937 if (file2 == NULL) 1938 snprintf(cmd, sizeof cmd, "get %s", dir); 1939 else 1940 snprintf(cmd, sizeof cmd, "get %s %s", dir, 1941 file2); 1942 1943 err = parse_dispatch_command(conn, cmd, 1944 &remote_path, 1); 1945 xfree(dir); 1946 xfree(remote_path); 1947 xfree(conn); 1948 return (err); 1949 } 1950 xfree(dir); 1951 } 1952 1953 setlinebuf(stdout); 1954 setlinebuf(infile); 1955 1956 interactive = !batchmode && isatty(STDIN_FILENO); 1957 err = 0; 1958 for (;;) { 1959 char *cp; 1960 1961 signal(SIGINT, SIG_IGN); 1962 1963 if (el == NULL) { 1964 if (interactive) 1965 printf("sftp> "); 1966 if (fgets(cmd, sizeof(cmd), infile) == NULL) { 1967 if (interactive) 1968 printf("\n"); 1969 break; 1970 } 1971 if (!interactive) { /* Echo command */ 1972 printf("sftp> %s", cmd); 1973 if (strlen(cmd) > 0 && 1974 cmd[strlen(cmd) - 1] != '\n') 1975 printf("\n"); 1976 } 1977 } else { 1978 #ifdef USE_LIBEDIT 1979 const char *line; 1980 int count = 0; 1981 1982 if ((line = el_gets(el, &count)) == NULL || 1983 count <= 0) { 1984 printf("\n"); 1985 break; 1986 } 1987 history(hl, &hev, H_ENTER, line); 1988 if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { 1989 fprintf(stderr, "Error: input line too long\n"); 1990 continue; 1991 } 1992 #endif /* USE_LIBEDIT */ 1993 } 1994 1995 cp = strrchr(cmd, '\n'); 1996 if (cp) 1997 *cp = '\0'; 1998 1999 /* Handle user interrupts gracefully during commands */ 2000 interrupted = 0; 2001 signal(SIGINT, cmd_interrupt); 2002 2003 err = parse_dispatch_command(conn, cmd, &remote_path, 2004 batchmode); 2005 if (err != 0) 2006 break; 2007 } 2008 xfree(remote_path); 2009 xfree(conn); 2010 2011 #ifdef USE_LIBEDIT 2012 if (el != NULL) 2013 el_end(el); 2014 #endif /* USE_LIBEDIT */ 2015 2016 /* err == 1 signifies normal "quit" exit */ 2017 return (err >= 0 ? 0 : -1); 2018 } 2019 2020 static void 2021 connect_to_server(char *path, char **args, int *in, int *out) 2022 { 2023 int c_in, c_out; 2024 2025 #ifdef USE_PIPES 2026 int pin[2], pout[2]; 2027 2028 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 2029 fatal("pipe: %s", strerror(errno)); 2030 *in = pin[0]; 2031 *out = pout[1]; 2032 c_in = pout[0]; 2033 c_out = pin[1]; 2034 #else /* USE_PIPES */ 2035 int inout[2]; 2036 2037 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 2038 fatal("socketpair: %s", strerror(errno)); 2039 *in = *out = inout[0]; 2040 c_in = c_out = inout[1]; 2041 #endif /* USE_PIPES */ 2042 2043 if ((sshpid = fork()) == -1) 2044 fatal("fork: %s", strerror(errno)); 2045 else if (sshpid == 0) { 2046 if ((dup2(c_in, STDIN_FILENO) == -1) || 2047 (dup2(c_out, STDOUT_FILENO) == -1)) { 2048 fprintf(stderr, "dup2: %s\n", strerror(errno)); 2049 _exit(1); 2050 } 2051 close(*in); 2052 close(*out); 2053 close(c_in); 2054 close(c_out); 2055 2056 /* 2057 * The underlying ssh is in the same process group, so we must 2058 * ignore SIGINT if we want to gracefully abort commands, 2059 * otherwise the signal will make it to the ssh process and 2060 * kill it too. Contrawise, since sftp sends SIGTERMs to the 2061 * underlying ssh, it must *not* ignore that signal. 2062 */ 2063 signal(SIGINT, SIG_IGN); 2064 signal(SIGTERM, SIG_DFL); 2065 execvp(path, args); 2066 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 2067 _exit(1); 2068 } 2069 2070 signal(SIGTERM, killchild); 2071 signal(SIGINT, killchild); 2072 signal(SIGHUP, killchild); 2073 close(c_in); 2074 close(c_out); 2075 } 2076 2077 static void 2078 usage(void) 2079 { 2080 extern char *__progname; 2081 2082 fprintf(stderr, 2083 "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2084 " [-D sftp_server_path] [-F ssh_config] " 2085 "[-i identity_file] [-l limit]\n" 2086 " [-o ssh_option] [-P port] [-R num_requests] " 2087 "[-S program]\n" 2088 " [-s subsystem | sftp_server] host\n" 2089 " %s [user@]host[:file ...]\n" 2090 " %s [user@]host[:dir[/]]\n" 2091 " %s -b batchfile [user@]host\n", 2092 __progname, __progname, __progname, __progname); 2093 exit(1); 2094 } 2095 2096 int 2097 main(int argc, char **argv) 2098 { 2099 int in, out, ch, err; 2100 char *host = NULL, *userhost, *cp, *file2 = NULL; 2101 int debug_level = 0, sshver = 2; 2102 char *file1 = NULL, *sftp_server = NULL; 2103 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 2104 const char *errstr; 2105 LogLevel ll = SYSLOG_LEVEL_INFO; 2106 arglist args; 2107 extern int optind; 2108 extern char *optarg; 2109 struct sftp_conn *conn; 2110 size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; 2111 size_t num_requests = DEFAULT_NUM_REQUESTS; 2112 long long limit_kbps = 0; 2113 2114 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2115 sanitise_stdfd(); 2116 2117 __progname = ssh_get_progname(argv[0]); 2118 memset(&args, '\0', sizeof(args)); 2119 args.list = NULL; 2120 addargs(&args, "%s", ssh_program); 2121 addargs(&args, "-oForwardX11 no"); 2122 addargs(&args, "-oForwardAgent no"); 2123 addargs(&args, "-oPermitLocalCommand no"); 2124 addargs(&args, "-oClearAllForwardings yes"); 2125 2126 ll = SYSLOG_LEVEL_INFO; 2127 infile = stdin; 2128 2129 while ((ch = getopt(argc, argv, 2130 "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { 2131 switch (ch) { 2132 /* Passed through to ssh(1) */ 2133 case '4': 2134 case '6': 2135 case 'C': 2136 addargs(&args, "-%c", ch); 2137 break; 2138 /* Passed through to ssh(1) with argument */ 2139 case 'F': 2140 case 'c': 2141 case 'i': 2142 case 'o': 2143 addargs(&args, "-%c", ch); 2144 addargs(&args, "%s", optarg); 2145 break; 2146 case 'q': 2147 showprogress = 0; 2148 addargs(&args, "-%c", ch); 2149 break; 2150 case 'P': 2151 addargs(&args, "-oPort %s", optarg); 2152 break; 2153 case 'v': 2154 if (debug_level < 3) { 2155 addargs(&args, "-v"); 2156 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 2157 } 2158 debug_level++; 2159 break; 2160 case '1': 2161 sshver = 1; 2162 if (sftp_server == NULL) 2163 sftp_server = _PATH_SFTP_SERVER; 2164 break; 2165 case '2': 2166 sshver = 2; 2167 break; 2168 case 'B': 2169 copy_buffer_len = strtol(optarg, &cp, 10); 2170 if (copy_buffer_len == 0 || *cp != '\0') 2171 fatal("Invalid buffer size \"%s\"", optarg); 2172 break; 2173 case 'b': 2174 if (batchmode) 2175 fatal("Batch file already specified."); 2176 2177 /* Allow "-" as stdin */ 2178 if (strcmp(optarg, "-") != 0 && 2179 (infile = fopen(optarg, "r")) == NULL) 2180 fatal("%s (%s).", strerror(errno), optarg); 2181 showprogress = 0; 2182 batchmode = 1; 2183 addargs(&args, "-obatchmode yes"); 2184 break; 2185 case 'p': 2186 global_pflag = 1; 2187 break; 2188 case 'D': 2189 sftp_direct = optarg; 2190 break; 2191 case 'l': 2192 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, 2193 &errstr); 2194 if (errstr != NULL) 2195 usage(); 2196 limit_kbps *= 1024; /* kbps */ 2197 break; 2198 case 'r': 2199 global_rflag = 1; 2200 break; 2201 case 'R': 2202 num_requests = strtol(optarg, &cp, 10); 2203 if (num_requests == 0 || *cp != '\0') 2204 fatal("Invalid number of requests \"%s\"", 2205 optarg); 2206 break; 2207 case 's': 2208 sftp_server = optarg; 2209 break; 2210 case 'S': 2211 ssh_program = optarg; 2212 replacearg(&args, 0, "%s", ssh_program); 2213 break; 2214 case 'h': 2215 default: 2216 usage(); 2217 } 2218 } 2219 2220 if (!isatty(STDERR_FILENO)) 2221 showprogress = 0; 2222 2223 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 2224 2225 if (sftp_direct == NULL) { 2226 if (optind == argc || argc > (optind + 2)) 2227 usage(); 2228 2229 userhost = xstrdup(argv[optind]); 2230 file2 = argv[optind+1]; 2231 2232 if ((host = strrchr(userhost, '@')) == NULL) 2233 host = userhost; 2234 else { 2235 *host++ = '\0'; 2236 if (!userhost[0]) { 2237 fprintf(stderr, "Missing username\n"); 2238 usage(); 2239 } 2240 addargs(&args, "-l"); 2241 addargs(&args, "%s", userhost); 2242 } 2243 2244 if ((cp = colon(host)) != NULL) { 2245 *cp++ = '\0'; 2246 file1 = cp; 2247 } 2248 2249 host = cleanhostname(host); 2250 if (!*host) { 2251 fprintf(stderr, "Missing hostname\n"); 2252 usage(); 2253 } 2254 2255 addargs(&args, "-oProtocol %d", sshver); 2256 2257 /* no subsystem if the server-spec contains a '/' */ 2258 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 2259 addargs(&args, "-s"); 2260 2261 addargs(&args, "--"); 2262 addargs(&args, "%s", host); 2263 addargs(&args, "%s", (sftp_server != NULL ? 2264 sftp_server : "sftp")); 2265 2266 connect_to_server(ssh_program, args.list, &in, &out); 2267 } else { 2268 args.list = NULL; 2269 addargs(&args, "sftp-server"); 2270 2271 connect_to_server(sftp_direct, args.list, &in, &out); 2272 } 2273 freeargs(&args); 2274 2275 conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); 2276 if (conn == NULL) 2277 fatal("Couldn't initialise connection to server"); 2278 2279 if (!batchmode) { 2280 if (sftp_direct == NULL) 2281 fprintf(stderr, "Connected to %s.\n", host); 2282 else 2283 fprintf(stderr, "Attached to %s.\n", sftp_direct); 2284 } 2285 2286 err = interactive_loop(conn, file1, file2); 2287 2288 #if !defined(USE_PIPES) 2289 shutdown(in, SHUT_RDWR); 2290 shutdown(out, SHUT_RDWR); 2291 #endif 2292 2293 close(in); 2294 close(out); 2295 if (batchmode) 2296 fclose(infile); 2297 2298 while (waitpid(sshpid, NULL, 0) == -1) 2299 if (errno != EINTR) 2300 fatal("Couldn't wait for ssh process: %s", 2301 strerror(errno)); 2302 2303 exit(err == 0 ? 0 : 1); 2304 } 2305