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