1 /* $OpenBSD: sftp.c,v 1.186 2018/09/07 04:26:56 dtucker 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 /* FALLTHROUGH */ 1447 case I_CHOWN: 1448 case I_CHGRP: 1449 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) 1450 return -1; 1451 /* Get numeric arg (mandatory) */ 1452 if (argc - optidx < 1) 1453 goto need_num_arg; 1454 errno = 0; 1455 l = strtol(argv[optidx], &cp2, base); 1456 if (cp2 == argv[optidx] || *cp2 != '\0' || 1457 ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) || 1458 l < 0) { 1459 need_num_arg: 1460 error("You must supply a numeric argument " 1461 "to the %s command.", cmd); 1462 return -1; 1463 } 1464 *n_arg = l; 1465 if (cmdnum == I_LUMASK) 1466 break; 1467 /* Get pathname (mandatory) */ 1468 if (argc - optidx < 2) { 1469 error("You must specify a path after a %s command.", 1470 cmd); 1471 return -1; 1472 } 1473 *path1 = xstrdup(argv[optidx + 1]); 1474 break; 1475 case I_QUIT: 1476 case I_PWD: 1477 case I_LPWD: 1478 case I_HELP: 1479 case I_VERSION: 1480 case I_PROGRESS: 1481 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) 1482 return -1; 1483 break; 1484 default: 1485 fatal("Command not implemented"); 1486 } 1487 1488 *cpp = cp; 1489 return(cmdnum); 1490 } 1491 1492 static int 1493 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, 1494 const char *startdir, int err_abort) 1495 { 1496 char *path1, *path2, *tmp; 1497 int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, 1498 iflag = 0; 1499 int lflag = 0, pflag = 0, rflag = 0, sflag = 0; 1500 int cmdnum, i; 1501 unsigned long n_arg = 0; 1502 Attrib a, *aa; 1503 char path_buf[PATH_MAX]; 1504 int err = 0; 1505 glob_t g; 1506 1507 path1 = path2 = NULL; 1508 cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, 1509 &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); 1510 if (ignore_errors != 0) 1511 err_abort = 0; 1512 1513 memset(&g, 0, sizeof(g)); 1514 1515 /* Perform command */ 1516 switch (cmdnum) { 1517 case 0: 1518 /* Blank line */ 1519 break; 1520 case -1: 1521 /* Unrecognized command */ 1522 err = -1; 1523 break; 1524 case I_REGET: 1525 aflag = 1; 1526 /* FALLTHROUGH */ 1527 case I_GET: 1528 err = process_get(conn, path1, path2, *pwd, pflag, 1529 rflag, aflag, fflag); 1530 break; 1531 case I_REPUT: 1532 aflag = 1; 1533 /* FALLTHROUGH */ 1534 case I_PUT: 1535 err = process_put(conn, path1, path2, *pwd, pflag, 1536 rflag, aflag, fflag); 1537 break; 1538 case I_RENAME: 1539 path1 = make_absolute(path1, *pwd); 1540 path2 = make_absolute(path2, *pwd); 1541 err = do_rename(conn, path1, path2, lflag); 1542 break; 1543 case I_SYMLINK: 1544 sflag = 1; 1545 /* FALLTHROUGH */ 1546 case I_LINK: 1547 if (!sflag) 1548 path1 = make_absolute(path1, *pwd); 1549 path2 = make_absolute(path2, *pwd); 1550 err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); 1551 break; 1552 case I_RM: 1553 path1 = make_absolute(path1, *pwd); 1554 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1555 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1556 if (!quiet) 1557 mprintf("Removing %s\n", g.gl_pathv[i]); 1558 err = do_rm(conn, g.gl_pathv[i]); 1559 if (err != 0 && err_abort) 1560 break; 1561 } 1562 break; 1563 case I_MKDIR: 1564 path1 = make_absolute(path1, *pwd); 1565 attrib_clear(&a); 1566 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1567 a.perm = 0777; 1568 err = do_mkdir(conn, path1, &a, 1); 1569 break; 1570 case I_RMDIR: 1571 path1 = make_absolute(path1, *pwd); 1572 err = do_rmdir(conn, path1); 1573 break; 1574 case I_CHDIR: 1575 if (path1 == NULL || *path1 == '\0') 1576 path1 = xstrdup(startdir); 1577 path1 = make_absolute(path1, *pwd); 1578 if ((tmp = do_realpath(conn, path1)) == NULL) { 1579 err = 1; 1580 break; 1581 } 1582 if ((aa = do_stat(conn, tmp, 0)) == NULL) { 1583 free(tmp); 1584 err = 1; 1585 break; 1586 } 1587 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { 1588 error("Can't change directory: Can't check target"); 1589 free(tmp); 1590 err = 1; 1591 break; 1592 } 1593 if (!S_ISDIR(aa->perm)) { 1594 error("Can't change directory: \"%s\" is not " 1595 "a directory", tmp); 1596 free(tmp); 1597 err = 1; 1598 break; 1599 } 1600 free(*pwd); 1601 *pwd = tmp; 1602 break; 1603 case I_LS: 1604 if (!path1) { 1605 do_ls_dir(conn, *pwd, *pwd, lflag); 1606 break; 1607 } 1608 1609 /* Strip pwd off beginning of non-absolute paths */ 1610 tmp = NULL; 1611 if (*path1 != '/') 1612 tmp = *pwd; 1613 1614 path1 = make_absolute(path1, *pwd); 1615 err = do_globbed_ls(conn, path1, tmp, lflag); 1616 break; 1617 case I_DF: 1618 /* Default to current directory if no path specified */ 1619 if (path1 == NULL) 1620 path1 = xstrdup(*pwd); 1621 path1 = make_absolute(path1, *pwd); 1622 err = do_df(conn, path1, hflag, iflag); 1623 break; 1624 case I_LCHDIR: 1625 if (path1 == NULL || *path1 == '\0') 1626 path1 = xstrdup("~"); 1627 tmp = tilde_expand_filename(path1, getuid()); 1628 free(path1); 1629 path1 = tmp; 1630 if (chdir(path1) == -1) { 1631 error("Couldn't change local directory to " 1632 "\"%s\": %s", path1, strerror(errno)); 1633 err = 1; 1634 } 1635 break; 1636 case I_LMKDIR: 1637 if (mkdir(path1, 0777) == -1) { 1638 error("Couldn't create local directory " 1639 "\"%s\": %s", path1, strerror(errno)); 1640 err = 1; 1641 } 1642 break; 1643 case I_LLS: 1644 local_do_ls(cmd); 1645 break; 1646 case I_SHELL: 1647 local_do_shell(cmd); 1648 break; 1649 case I_LUMASK: 1650 umask(n_arg); 1651 printf("Local umask: %03lo\n", n_arg); 1652 break; 1653 case I_CHMOD: 1654 path1 = make_absolute(path1, *pwd); 1655 attrib_clear(&a); 1656 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1657 a.perm = n_arg; 1658 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1659 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1660 if (!quiet) 1661 mprintf("Changing mode on %s\n", 1662 g.gl_pathv[i]); 1663 err = do_setstat(conn, g.gl_pathv[i], &a); 1664 if (err != 0 && err_abort) 1665 break; 1666 } 1667 break; 1668 case I_CHOWN: 1669 case I_CHGRP: 1670 path1 = make_absolute(path1, *pwd); 1671 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1672 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1673 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { 1674 if (err_abort) { 1675 err = -1; 1676 break; 1677 } else 1678 continue; 1679 } 1680 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { 1681 error("Can't get current ownership of " 1682 "remote file \"%s\"", g.gl_pathv[i]); 1683 if (err_abort) { 1684 err = -1; 1685 break; 1686 } else 1687 continue; 1688 } 1689 aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; 1690 if (cmdnum == I_CHOWN) { 1691 if (!quiet) 1692 mprintf("Changing owner on %s\n", 1693 g.gl_pathv[i]); 1694 aa->uid = n_arg; 1695 } else { 1696 if (!quiet) 1697 mprintf("Changing group on %s\n", 1698 g.gl_pathv[i]); 1699 aa->gid = n_arg; 1700 } 1701 err = do_setstat(conn, g.gl_pathv[i], aa); 1702 if (err != 0 && err_abort) 1703 break; 1704 } 1705 break; 1706 case I_PWD: 1707 mprintf("Remote working directory: %s\n", *pwd); 1708 break; 1709 case I_LPWD: 1710 if (!getcwd(path_buf, sizeof(path_buf))) { 1711 error("Couldn't get local cwd: %s", strerror(errno)); 1712 err = -1; 1713 break; 1714 } 1715 mprintf("Local working directory: %s\n", path_buf); 1716 break; 1717 case I_QUIT: 1718 /* Processed below */ 1719 break; 1720 case I_HELP: 1721 help(); 1722 break; 1723 case I_VERSION: 1724 printf("SFTP protocol version %u\n", sftp_proto_version(conn)); 1725 break; 1726 case I_PROGRESS: 1727 showprogress = !showprogress; 1728 if (showprogress) 1729 printf("Progress meter enabled\n"); 1730 else 1731 printf("Progress meter disabled\n"); 1732 break; 1733 default: 1734 fatal("%d is not implemented", cmdnum); 1735 } 1736 1737 if (g.gl_pathc) 1738 globfree(&g); 1739 free(path1); 1740 free(path2); 1741 1742 /* If an unignored error occurs in batch mode we should abort. */ 1743 if (err_abort && err != 0) 1744 return (-1); 1745 else if (cmdnum == I_QUIT) 1746 return (1); 1747 1748 return (0); 1749 } 1750 1751 #ifdef USE_LIBEDIT 1752 static char * 1753 prompt(EditLine *el) 1754 { 1755 return ("sftp> "); 1756 } 1757 1758 /* Display entries in 'list' after skipping the first 'len' chars */ 1759 static void 1760 complete_display(char **list, u_int len) 1761 { 1762 u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; 1763 struct winsize ws; 1764 char *tmp; 1765 1766 /* Count entries for sort and find longest */ 1767 for (y = 0; list[y]; y++) 1768 m = MAXIMUM(m, strlen(list[y])); 1769 1770 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 1771 width = ws.ws_col; 1772 1773 m = m > len ? m - len : 0; 1774 columns = width / (m + 2); 1775 columns = MAXIMUM(columns, 1); 1776 colspace = width / columns; 1777 colspace = MINIMUM(colspace, width); 1778 1779 printf("\n"); 1780 m = 1; 1781 for (y = 0; list[y]; y++) { 1782 llen = strlen(list[y]); 1783 tmp = llen > len ? list[y] + len : ""; 1784 mprintf("%-*s", colspace, tmp); 1785 if (m >= columns) { 1786 printf("\n"); 1787 m = 1; 1788 } else 1789 m++; 1790 } 1791 printf("\n"); 1792 } 1793 1794 /* 1795 * Given a "list" of words that begin with a common prefix of "word", 1796 * attempt to find an autocompletion to extends "word" by the next 1797 * characters common to all entries in "list". 1798 */ 1799 static char * 1800 complete_ambiguous(const char *word, char **list, size_t count) 1801 { 1802 if (word == NULL) 1803 return NULL; 1804 1805 if (count > 0) { 1806 u_int y, matchlen = strlen(list[0]); 1807 1808 /* Find length of common stem */ 1809 for (y = 1; list[y]; y++) { 1810 u_int x; 1811 1812 for (x = 0; x < matchlen; x++) 1813 if (list[0][x] != list[y][x]) 1814 break; 1815 1816 matchlen = x; 1817 } 1818 1819 if (matchlen > strlen(word)) { 1820 char *tmp = xstrdup(list[0]); 1821 1822 tmp[matchlen] = '\0'; 1823 return tmp; 1824 } 1825 } 1826 1827 return xstrdup(word); 1828 } 1829 1830 /* Autocomplete a sftp command */ 1831 static int 1832 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, 1833 int terminated) 1834 { 1835 u_int y, count = 0, cmdlen, tmplen; 1836 char *tmp, **list, argterm[3]; 1837 const LineInfo *lf; 1838 1839 list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); 1840 1841 /* No command specified: display all available commands */ 1842 if (cmd == NULL) { 1843 for (y = 0; cmds[y].c; y++) 1844 list[count++] = xstrdup(cmds[y].c); 1845 1846 list[count] = NULL; 1847 complete_display(list, 0); 1848 1849 for (y = 0; list[y] != NULL; y++) 1850 free(list[y]); 1851 free(list); 1852 return count; 1853 } 1854 1855 /* Prepare subset of commands that start with "cmd" */ 1856 cmdlen = strlen(cmd); 1857 for (y = 0; cmds[y].c; y++) { 1858 if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 1859 list[count++] = xstrdup(cmds[y].c); 1860 } 1861 list[count] = NULL; 1862 1863 if (count == 0) { 1864 free(list); 1865 return 0; 1866 } 1867 1868 /* Complete ambiguous command */ 1869 tmp = complete_ambiguous(cmd, list, count); 1870 if (count > 1) 1871 complete_display(list, 0); 1872 1873 for (y = 0; list[y]; y++) 1874 free(list[y]); 1875 free(list); 1876 1877 if (tmp != NULL) { 1878 tmplen = strlen(tmp); 1879 cmdlen = strlen(cmd); 1880 /* If cmd may be extended then do so */ 1881 if (tmplen > cmdlen) 1882 if (el_insertstr(el, tmp + cmdlen) == -1) 1883 fatal("el_insertstr failed."); 1884 lf = el_line(el); 1885 /* Terminate argument cleanly */ 1886 if (count == 1) { 1887 y = 0; 1888 if (!terminated) 1889 argterm[y++] = quote; 1890 if (lastarg || *(lf->cursor) != ' ') 1891 argterm[y++] = ' '; 1892 argterm[y] = '\0'; 1893 if (y > 0 && el_insertstr(el, argterm) == -1) 1894 fatal("el_insertstr failed."); 1895 } 1896 free(tmp); 1897 } 1898 1899 return count; 1900 } 1901 1902 /* 1903 * Determine whether a particular sftp command's arguments (if any) 1904 * represent local or remote files. 1905 */ 1906 static int 1907 complete_is_remote(char *cmd) { 1908 int i; 1909 1910 if (cmd == NULL) 1911 return -1; 1912 1913 for (i = 0; cmds[i].c; i++) { 1914 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 1915 return cmds[i].t; 1916 } 1917 1918 return -1; 1919 } 1920 1921 /* Autocomplete a filename "file" */ 1922 static int 1923 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, 1924 char *file, int remote, int lastarg, char quote, int terminated) 1925 { 1926 glob_t g; 1927 char *tmp, *tmp2, ins[8]; 1928 u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; 1929 int clen; 1930 const LineInfo *lf; 1931 1932 /* Glob from "file" location */ 1933 if (file == NULL) 1934 tmp = xstrdup("*"); 1935 else 1936 xasprintf(&tmp, "%s*", file); 1937 1938 /* Check if the path is absolute. */ 1939 isabs = tmp[0] == '/'; 1940 1941 memset(&g, 0, sizeof(g)); 1942 if (remote != LOCAL) { 1943 tmp = make_absolute(tmp, remote_path); 1944 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1945 } else 1946 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1947 1948 /* Determine length of pwd so we can trim completion display */ 1949 for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { 1950 /* Terminate counting on first unescaped glob metacharacter */ 1951 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { 1952 if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') 1953 hadglob = 1; 1954 break; 1955 } 1956 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') 1957 tmplen++; 1958 if (tmp[tmplen] == '/') 1959 pwdlen = tmplen + 1; /* track last seen '/' */ 1960 } 1961 free(tmp); 1962 tmp = NULL; 1963 1964 if (g.gl_matchc == 0) 1965 goto out; 1966 1967 if (g.gl_matchc > 1) 1968 complete_display(g.gl_pathv, pwdlen); 1969 1970 /* Don't try to extend globs */ 1971 if (file == NULL || hadglob) 1972 goto out; 1973 1974 tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); 1975 tmp = path_strip(tmp2, isabs ? NULL : remote_path); 1976 free(tmp2); 1977 1978 if (tmp == NULL) 1979 goto out; 1980 1981 tmplen = strlen(tmp); 1982 filelen = strlen(file); 1983 1984 /* Count the number of escaped characters in the input string. */ 1985 cesc = isesc = 0; 1986 for (i = 0; i < filelen; i++) { 1987 if (!isesc && file[i] == '\\' && i + 1 < filelen){ 1988 isesc = 1; 1989 cesc++; 1990 } else 1991 isesc = 0; 1992 } 1993 1994 if (tmplen > (filelen - cesc)) { 1995 tmp2 = tmp + filelen - cesc; 1996 len = strlen(tmp2); 1997 /* quote argument on way out */ 1998 for (i = 0; i < len; i += clen) { 1999 if ((clen = mblen(tmp2 + i, len - i)) < 0 || 2000 (size_t)clen > sizeof(ins) - 2) 2001 fatal("invalid multibyte character"); 2002 ins[0] = '\\'; 2003 memcpy(ins + 1, tmp2 + i, clen); 2004 ins[clen + 1] = '\0'; 2005 switch (tmp2[i]) { 2006 case '\'': 2007 case '"': 2008 case '\\': 2009 case '\t': 2010 case '[': 2011 case ' ': 2012 case '#': 2013 case '*': 2014 if (quote == '\0' || tmp2[i] == quote) { 2015 if (el_insertstr(el, ins) == -1) 2016 fatal("el_insertstr " 2017 "failed."); 2018 break; 2019 } 2020 /* FALLTHROUGH */ 2021 default: 2022 if (el_insertstr(el, ins + 1) == -1) 2023 fatal("el_insertstr failed."); 2024 break; 2025 } 2026 } 2027 } 2028 2029 lf = el_line(el); 2030 if (g.gl_matchc == 1) { 2031 i = 0; 2032 if (!terminated && quote != '\0') 2033 ins[i++] = quote; 2034 if (*(lf->cursor - 1) != '/' && 2035 (lastarg || *(lf->cursor) != ' ')) 2036 ins[i++] = ' '; 2037 ins[i] = '\0'; 2038 if (i > 0 && el_insertstr(el, ins) == -1) 2039 fatal("el_insertstr failed."); 2040 } 2041 free(tmp); 2042 2043 out: 2044 globfree(&g); 2045 return g.gl_matchc; 2046 } 2047 2048 /* tab-completion hook function, called via libedit */ 2049 static unsigned char 2050 complete(EditLine *el, int ch) 2051 { 2052 char **argv, *line, quote; 2053 int argc, carg; 2054 u_int cursor, len, terminated, ret = CC_ERROR; 2055 const LineInfo *lf; 2056 struct complete_ctx *complete_ctx; 2057 2058 lf = el_line(el); 2059 if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) 2060 fatal("%s: el_get failed", __func__); 2061 2062 /* Figure out which argument the cursor points to */ 2063 cursor = lf->cursor - lf->buffer; 2064 line = xmalloc(cursor + 1); 2065 memcpy(line, lf->buffer, cursor); 2066 line[cursor] = '\0'; 2067 argv = makeargv(line, &carg, 1, "e, &terminated); 2068 free(line); 2069 2070 /* Get all the arguments on the line */ 2071 len = lf->lastchar - lf->buffer; 2072 line = xmalloc(len + 1); 2073 memcpy(line, lf->buffer, len); 2074 line[len] = '\0'; 2075 argv = makeargv(line, &argc, 1, NULL, NULL); 2076 2077 /* Ensure cursor is at EOL or a argument boundary */ 2078 if (line[cursor] != ' ' && line[cursor] != '\0' && 2079 line[cursor] != '\n') { 2080 free(line); 2081 return ret; 2082 } 2083 2084 if (carg == 0) { 2085 /* Show all available commands */ 2086 complete_cmd_parse(el, NULL, argc == carg, '\0', 1); 2087 ret = CC_REDISPLAY; 2088 } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { 2089 /* Handle the command parsing */ 2090 if (complete_cmd_parse(el, argv[0], argc == carg, 2091 quote, terminated) != 0) 2092 ret = CC_REDISPLAY; 2093 } else if (carg >= 1) { 2094 /* Handle file parsing */ 2095 int remote = complete_is_remote(argv[0]); 2096 char *filematch = NULL; 2097 2098 if (carg > 1 && line[cursor-1] != ' ') 2099 filematch = argv[carg - 1]; 2100 2101 if (remote != 0 && 2102 complete_match(el, complete_ctx->conn, 2103 *complete_ctx->remote_pathp, filematch, 2104 remote, carg == argc, quote, terminated) != 0) 2105 ret = CC_REDISPLAY; 2106 } 2107 2108 free(line); 2109 return ret; 2110 } 2111 #endif /* USE_LIBEDIT */ 2112 2113 static int 2114 interactive_loop(struct sftp_conn *conn, char *file1, char *file2) 2115 { 2116 char *remote_path; 2117 char *dir = NULL, *startdir = NULL; 2118 char cmd[2048]; 2119 int err, interactive; 2120 EditLine *el = NULL; 2121 #ifdef USE_LIBEDIT 2122 History *hl = NULL; 2123 HistEvent hev; 2124 extern char *__progname; 2125 struct complete_ctx complete_ctx; 2126 2127 if (!batchmode && isatty(STDIN_FILENO)) { 2128 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) 2129 fatal("Couldn't initialise editline"); 2130 if ((hl = history_init()) == NULL) 2131 fatal("Couldn't initialise editline history"); 2132 history(hl, &hev, H_SETSIZE, 100); 2133 el_set(el, EL_HIST, history, hl); 2134 2135 el_set(el, EL_PROMPT, prompt); 2136 el_set(el, EL_EDITOR, "emacs"); 2137 el_set(el, EL_TERMINAL, NULL); 2138 el_set(el, EL_SIGNAL, 1); 2139 el_source(el, NULL); 2140 2141 /* Tab Completion */ 2142 el_set(el, EL_ADDFN, "ftp-complete", 2143 "Context sensitive argument completion", complete); 2144 complete_ctx.conn = conn; 2145 complete_ctx.remote_pathp = &remote_path; 2146 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); 2147 el_set(el, EL_BIND, "^I", "ftp-complete", NULL); 2148 /* enable ctrl-left-arrow and ctrl-right-arrow */ 2149 el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL); 2150 el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL); 2151 el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); 2152 el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); 2153 /* make ^w match ksh behaviour */ 2154 el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL); 2155 } 2156 #endif /* USE_LIBEDIT */ 2157 2158 remote_path = do_realpath(conn, "."); 2159 if (remote_path == NULL) 2160 fatal("Need cwd"); 2161 startdir = xstrdup(remote_path); 2162 2163 if (file1 != NULL) { 2164 dir = xstrdup(file1); 2165 dir = make_absolute(dir, remote_path); 2166 2167 if (remote_is_dir(conn, dir) && file2 == NULL) { 2168 if (!quiet) 2169 mprintf("Changing to: %s\n", dir); 2170 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 2171 if (parse_dispatch_command(conn, cmd, 2172 &remote_path, startdir, 1) != 0) { 2173 free(dir); 2174 free(startdir); 2175 free(remote_path); 2176 free(conn); 2177 return (-1); 2178 } 2179 } else { 2180 /* XXX this is wrong wrt quoting */ 2181 snprintf(cmd, sizeof cmd, "get%s %s%s%s", 2182 global_aflag ? " -a" : "", dir, 2183 file2 == NULL ? "" : " ", 2184 file2 == NULL ? "" : file2); 2185 err = parse_dispatch_command(conn, cmd, 2186 &remote_path, startdir, 1); 2187 free(dir); 2188 free(startdir); 2189 free(remote_path); 2190 free(conn); 2191 return (err); 2192 } 2193 free(dir); 2194 } 2195 2196 setvbuf(stdout, NULL, _IOLBF, 0); 2197 setvbuf(infile, NULL, _IOLBF, 0); 2198 2199 interactive = !batchmode && isatty(STDIN_FILENO); 2200 err = 0; 2201 for (;;) { 2202 char *cp; 2203 2204 signal(SIGINT, SIG_IGN); 2205 2206 if (el == NULL) { 2207 if (interactive) 2208 printf("sftp> "); 2209 if (fgets(cmd, sizeof(cmd), infile) == NULL) { 2210 if (interactive) 2211 printf("\n"); 2212 break; 2213 } 2214 if (!interactive) { /* Echo command */ 2215 mprintf("sftp> %s", cmd); 2216 if (strlen(cmd) > 0 && 2217 cmd[strlen(cmd) - 1] != '\n') 2218 printf("\n"); 2219 } 2220 } else { 2221 #ifdef USE_LIBEDIT 2222 const char *line; 2223 int count = 0; 2224 2225 if ((line = el_gets(el, &count)) == NULL || 2226 count <= 0) { 2227 printf("\n"); 2228 break; 2229 } 2230 history(hl, &hev, H_ENTER, line); 2231 if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { 2232 fprintf(stderr, "Error: input line too long\n"); 2233 continue; 2234 } 2235 #endif /* USE_LIBEDIT */ 2236 } 2237 2238 cp = strrchr(cmd, '\n'); 2239 if (cp) 2240 *cp = '\0'; 2241 2242 /* Handle user interrupts gracefully during commands */ 2243 interrupted = 0; 2244 signal(SIGINT, cmd_interrupt); 2245 2246 err = parse_dispatch_command(conn, cmd, &remote_path, 2247 startdir, batchmode); 2248 if (err != 0) 2249 break; 2250 } 2251 signal(SIGCHLD, SIG_DFL); 2252 free(remote_path); 2253 free(startdir); 2254 free(conn); 2255 2256 #ifdef USE_LIBEDIT 2257 if (el != NULL) 2258 el_end(el); 2259 #endif /* USE_LIBEDIT */ 2260 2261 /* err == 1 signifies normal "quit" exit */ 2262 return (err >= 0 ? 0 : -1); 2263 } 2264 2265 static void 2266 connect_to_server(char *path, char **args, int *in, int *out) 2267 { 2268 int c_in, c_out; 2269 2270 #ifdef USE_PIPES 2271 int pin[2], pout[2]; 2272 2273 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 2274 fatal("pipe: %s", strerror(errno)); 2275 *in = pin[0]; 2276 *out = pout[1]; 2277 c_in = pout[0]; 2278 c_out = pin[1]; 2279 #else /* USE_PIPES */ 2280 int inout[2]; 2281 2282 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 2283 fatal("socketpair: %s", strerror(errno)); 2284 *in = *out = inout[0]; 2285 c_in = c_out = inout[1]; 2286 #endif /* USE_PIPES */ 2287 2288 if ((sshpid = fork()) == -1) 2289 fatal("fork: %s", strerror(errno)); 2290 else if (sshpid == 0) { 2291 if ((dup2(c_in, STDIN_FILENO) == -1) || 2292 (dup2(c_out, STDOUT_FILENO) == -1)) { 2293 fprintf(stderr, "dup2: %s\n", strerror(errno)); 2294 _exit(1); 2295 } 2296 close(*in); 2297 close(*out); 2298 close(c_in); 2299 close(c_out); 2300 2301 /* 2302 * The underlying ssh is in the same process group, so we must 2303 * ignore SIGINT if we want to gracefully abort commands, 2304 * otherwise the signal will make it to the ssh process and 2305 * kill it too. Contrawise, since sftp sends SIGTERMs to the 2306 * underlying ssh, it must *not* ignore that signal. 2307 */ 2308 signal(SIGINT, SIG_IGN); 2309 signal(SIGTERM, SIG_DFL); 2310 execvp(path, args); 2311 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 2312 _exit(1); 2313 } 2314 2315 signal(SIGTERM, killchild); 2316 signal(SIGINT, killchild); 2317 signal(SIGHUP, killchild); 2318 signal(SIGTSTP, suspchild); 2319 signal(SIGTTIN, suspchild); 2320 signal(SIGTTOU, suspchild); 2321 signal(SIGCHLD, sigchld_handler); 2322 close(c_in); 2323 close(c_out); 2324 } 2325 2326 static void 2327 usage(void) 2328 { 2329 extern char *__progname; 2330 2331 fprintf(stderr, 2332 "usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2333 " [-D sftp_server_path] [-F ssh_config] " 2334 "[-i identity_file] [-l limit]\n" 2335 " [-o ssh_option] [-P port] [-R num_requests] " 2336 "[-S program]\n" 2337 " [-s subsystem | sftp_server] destination\n", 2338 __progname); 2339 exit(1); 2340 } 2341 2342 int 2343 main(int argc, char **argv) 2344 { 2345 int in, out, ch, err, tmp, port = -1; 2346 char *host = NULL, *user, *cp, *file2 = NULL; 2347 int debug_level = 0, sshver = 2; 2348 char *file1 = NULL, *sftp_server = NULL; 2349 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 2350 const char *errstr; 2351 LogLevel ll = SYSLOG_LEVEL_INFO; 2352 arglist args; 2353 extern int optind; 2354 extern char *optarg; 2355 struct sftp_conn *conn; 2356 size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; 2357 size_t num_requests = DEFAULT_NUM_REQUESTS; 2358 long long limit_kbps = 0; 2359 2360 ssh_malloc_init(); /* must be called before any mallocs */ 2361 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2362 sanitise_stdfd(); 2363 msetlocale(); 2364 2365 __progname = ssh_get_progname(argv[0]); 2366 memset(&args, '\0', sizeof(args)); 2367 args.list = NULL; 2368 addargs(&args, "%s", ssh_program); 2369 addargs(&args, "-oForwardX11 no"); 2370 addargs(&args, "-oForwardAgent no"); 2371 addargs(&args, "-oPermitLocalCommand no"); 2372 addargs(&args, "-oClearAllForwardings yes"); 2373 2374 ll = SYSLOG_LEVEL_INFO; 2375 infile = stdin; 2376 2377 while ((ch = getopt(argc, argv, 2378 "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { 2379 switch (ch) { 2380 /* Passed through to ssh(1) */ 2381 case '4': 2382 case '6': 2383 case 'C': 2384 addargs(&args, "-%c", ch); 2385 break; 2386 /* Passed through to ssh(1) with argument */ 2387 case 'F': 2388 case 'c': 2389 case 'i': 2390 case 'o': 2391 addargs(&args, "-%c", ch); 2392 addargs(&args, "%s", optarg); 2393 break; 2394 case 'q': 2395 ll = SYSLOG_LEVEL_ERROR; 2396 quiet = 1; 2397 showprogress = 0; 2398 addargs(&args, "-%c", ch); 2399 break; 2400 case 'P': 2401 port = a2port(optarg); 2402 if (port <= 0) 2403 fatal("Bad port \"%s\"\n", optarg); 2404 break; 2405 case 'v': 2406 if (debug_level < 3) { 2407 addargs(&args, "-v"); 2408 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 2409 } 2410 debug_level++; 2411 break; 2412 case '1': 2413 sshver = 1; 2414 if (sftp_server == NULL) 2415 sftp_server = _PATH_SFTP_SERVER; 2416 break; 2417 case '2': 2418 sshver = 2; 2419 break; 2420 case 'a': 2421 global_aflag = 1; 2422 break; 2423 case 'B': 2424 copy_buffer_len = strtol(optarg, &cp, 10); 2425 if (copy_buffer_len == 0 || *cp != '\0') 2426 fatal("Invalid buffer size \"%s\"", optarg); 2427 break; 2428 case 'b': 2429 if (batchmode) 2430 fatal("Batch file already specified."); 2431 2432 /* Allow "-" as stdin */ 2433 if (strcmp(optarg, "-") != 0 && 2434 (infile = fopen(optarg, "r")) == NULL) 2435 fatal("%s (%s).", strerror(errno), optarg); 2436 showprogress = 0; 2437 quiet = batchmode = 1; 2438 addargs(&args, "-obatchmode yes"); 2439 break; 2440 case 'f': 2441 global_fflag = 1; 2442 break; 2443 case 'p': 2444 global_pflag = 1; 2445 break; 2446 case 'D': 2447 sftp_direct = optarg; 2448 break; 2449 case 'l': 2450 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, 2451 &errstr); 2452 if (errstr != NULL) 2453 usage(); 2454 limit_kbps *= 1024; /* kbps */ 2455 break; 2456 case 'r': 2457 global_rflag = 1; 2458 break; 2459 case 'R': 2460 num_requests = strtol(optarg, &cp, 10); 2461 if (num_requests == 0 || *cp != '\0') 2462 fatal("Invalid number of requests \"%s\"", 2463 optarg); 2464 break; 2465 case 's': 2466 sftp_server = optarg; 2467 break; 2468 case 'S': 2469 ssh_program = optarg; 2470 replacearg(&args, 0, "%s", ssh_program); 2471 break; 2472 case 'h': 2473 default: 2474 usage(); 2475 } 2476 } 2477 2478 if (!isatty(STDERR_FILENO)) 2479 showprogress = 0; 2480 2481 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 2482 2483 if (sftp_direct == NULL) { 2484 if (optind == argc || argc > (optind + 2)) 2485 usage(); 2486 argv += optind; 2487 2488 switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) { 2489 case -1: 2490 usage(); 2491 break; 2492 case 0: 2493 if (tmp != -1) 2494 port = tmp; 2495 break; 2496 default: 2497 if (parse_user_host_path(*argv, &user, &host, 2498 &file1) == -1) { 2499 /* Treat as a plain hostname. */ 2500 host = xstrdup(*argv); 2501 host = cleanhostname(host); 2502 } 2503 break; 2504 } 2505 file2 = *(argv + 1); 2506 2507 if (!*host) { 2508 fprintf(stderr, "Missing hostname\n"); 2509 usage(); 2510 } 2511 2512 if (port != -1) 2513 addargs(&args, "-oPort %d", port); 2514 if (user != NULL) { 2515 addargs(&args, "-l"); 2516 addargs(&args, "%s", user); 2517 } 2518 addargs(&args, "-oProtocol %d", sshver); 2519 2520 /* no subsystem if the server-spec contains a '/' */ 2521 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 2522 addargs(&args, "-s"); 2523 2524 addargs(&args, "--"); 2525 addargs(&args, "%s", host); 2526 addargs(&args, "%s", (sftp_server != NULL ? 2527 sftp_server : "sftp")); 2528 2529 connect_to_server(ssh_program, args.list, &in, &out); 2530 } else { 2531 args.list = NULL; 2532 addargs(&args, "sftp-server"); 2533 2534 connect_to_server(sftp_direct, args.list, &in, &out); 2535 } 2536 freeargs(&args); 2537 2538 conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); 2539 if (conn == NULL) 2540 fatal("Couldn't initialise connection to server"); 2541 2542 if (!quiet) { 2543 if (sftp_direct == NULL) 2544 fprintf(stderr, "Connected to %s.\n", host); 2545 else 2546 fprintf(stderr, "Attached to %s.\n", sftp_direct); 2547 } 2548 2549 err = interactive_loop(conn, file1, file2); 2550 2551 #if !defined(USE_PIPES) 2552 shutdown(in, SHUT_RDWR); 2553 shutdown(out, SHUT_RDWR); 2554 #endif 2555 2556 close(in); 2557 close(out); 2558 if (batchmode) 2559 fclose(infile); 2560 2561 while (waitpid(sshpid, NULL, 0) == -1 && sshpid > 1) 2562 if (errno != EINTR) 2563 fatal("Couldn't wait for ssh process: %s", 2564 strerror(errno)); 2565 2566 exit(err == 0 ? 0 : 1); 2567 } 2568