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