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