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