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