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