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