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