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