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