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