diff options
| author | Mattias Andrée <maandree@kth.se> | 2024-07-26 16:13:57 +0200 | 
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2024-07-26 16:15:26 +0200 | 
| commit | 4b99f670d7e35ac87340258fadba58b5dc1543d8 (patch) | |
| tree | 8977170ed1e214352f9d749b74ab54483586fd81 | |
| parent | Empty signed commit (diff) | |
| download | sshexec-4b99f670d7e35ac87340258fadba58b5dc1543d8.tar.gz sshexec-4b99f670d7e35ac87340258fadba58b5dc1543d8.tar.bz2 sshexec-4b99f670d7e35ac87340258fadba58b5dc1543d8.tar.xz  | |
Add support for redirecting file descriptors1.1
Signed-off-by: Mattias Andrée <maandree@kth.se>
| -rw-r--r-- | sshexec.1 | 90 | ||||
| -rw-r--r-- | sshexec.c | 59 | 
2 files changed, 143 insertions, 6 deletions
@@ -6,8 +6,9 @@ sshexec - run a command through ssh(1) with normal command syntax  .SH SYNOPSIS  .B sshexec  .RB [ { -.RI [\fBssh= ssh-command ] -.RI [\fBdir= directory ] +.RI [\fBssh=\fP ssh-command ] +.RI [\fBdir=\fP directory ] +.RB [[\fIfd\fP]{ > , >> , >| , < , <> }[ & ] = \fIfile\fP]  .BR } ]  [ssh-option] ...\,  .I destination @@ -97,6 +98,91 @@ In the remote, change working directory to  .I directory  before executing  .IR command . +.TP +.IB \fR[\fPfd\fP]\fP >= file +After changing working directory (assuming one is specified), +create or truncate the specified +.I file +and open it for writing, using file descriptor number +.IR fd . +(Default +.I fd +is 1 (standard output).) +.TP +.IB \fR[\fPfd\fP]\fP >>= file +After changing working directory (assuming one is specified), +create the specified +.I file +if it does not exist and open it for writing in +append-mode, using file descriptor number +.IR fd . +(Default +.I fd +is 1 (standard output).) +.TP +.IB \fR[\fPfd\fP]\fP >|= file +After changing working directory (assuming one is specified), +create the specified +.IR file , +but fail if it already exists, and open it for writing, +using file descriptor number +.IR fd . +(Default +.I fd +is 1 (standard output).) +.TP +.IB \fR[\fPfd\fP]\fP <= file +After changing working directory (assuming one is specified), +open the specified +.IR file , +for reading, using file descriptor number +.IR fd . +(Default +.I fd +is 0 (standard input).) +.TP +.IB \fR[\fPfd\fP]\fP <>= file +After changing working directory (assuming one is specified), +open the specified +.IR file , +for reading and writing, creating it if it does not +already exist, using file descriptor number +.IR fd . +(Default +.I fd +is 0 (standard input).) +.TP +.IB \fR[\fPfd\fP]\fP \fR{\fP>\fP,\fP>>\fP,\fP>|\fP}\fP&= file +Duplicate the file descriptor +.I fd +giving the new file descriptor the number +.IR file . +(Default +.I fd +is 1 (standard output).) +.TP +.IB \fR[\fPfd\fP]\fP \fR{\fP>\fP,\fP>>\fP,\fP>|\fP}\fP&=- +Close the file descriptor +.IR fd . +(Default +.I fd +is 1 (standard output).) +.TP +.IB \fR[\fPfd\fP]\fP \fR{\fP<\fP,\fP<>\fP}\fP&= file +Duplicate the file descriptor +.I fd +giving the new file descriptor the number +.IR file . +(Default +.I fd +is 0 (standard input).) +.TP +.IB \fR[\fPfd\fP]\fP \fR{\fP<\fP,\fP<>\fP}\fP&=- +Close the file descriptor +.IR fd . +(Default +.I fd +is 0 (standard input).)  .SH OPERANDS  The following operands are supported: @@ -19,9 +19,16 @@ static void  usage(void)  {  	exitf("usage: %s [{ %s }] [ssh-option] ... destination command [argument] ...\n", -	      argv0, "[ssh=command] [dir=directory]"); +	      argv0, "[ssh=command] [dir=directory] [[fd]{>,>>,>|,<>}[&]=file]");  } + +struct redirection { +	const char *asis; +	const char *escape; +}; + +  static const enum optclass {  	NO_RECOGNISED = 0,  	NO_ARGUMENT, @@ -54,7 +61,7 @@ static size_t command_len = 0;  	} while (0)  #define build_command_asis(S)\ -	build_command(S, sizeof(S) - 1) +	build_command(S, strlen(S))  #define finalise_command()\  	build_command("", 1) @@ -122,8 +129,10 @@ main(int argc_unused, char *argv[])  {  	const char *dir = NULL;  	const char *ssh = NULL; +	struct redirection *redirections = NULL; +	size_t nredirections = 0;  	const char *destination; -	char **opts; +	char **opts, *p;  	size_t nopts;  	enum optclass class;  	const char *arg; @@ -142,17 +151,51 @@ main(int argc_unused, char *argv[])  			usage();\  		continue;\  	} +  	if (*argv && !strcmp(*argv, "{")) {  		argv++;  		for (; *argv && strcmp(*argv, "}"); argv++) {  			STORE_OPT(&ssh, "ssh")  			STORE_OPT(&dir, "dir") -			usage(); + +			p = *argv; +			while (isdigit(*p)) +				p++; +			if (p[0] == '>') +				p = &p[1 + (p[1] == '>' || p[1] == '|')]; +			else if (p[0] == '<') +				p = &p[1 + (p[1] == '>')]; +			else +				usage(); +			if (p[p[0] == '&'] != '=') +				usage();  +			redirections = realloc(redirections, (nredirections + 1U) * sizeof(*redirections)); +			if (!redirections) +				exitf("%s: could not allocate enough memory\n", argv0); +			if (*p == '&') { +				p = &p[1]; +				memmove(p, &p[1], strlen(&p[1]) + 1U); +				if (isdigit(*p)) { +					p++; +					while (isdigit(*p)) +						p++; +				} else if (*p == '-') { +					p++; +				} +				if (*p) +					usage(); +				redirections[nredirections].escape = NULL; +			} else { +				*p++ = '\0'; +				redirections[nredirections].escape = p; +			} +			redirections[nredirections++].asis = *argv;  		}  		if (!*argv)  			usage();  		argv++;  	} +  #undef STORE_OPT  	if (!ssh) @@ -202,6 +245,14 @@ main(int argc_unused, char *argv[])  		build_command_asis(" ");  		build_command_escape(*argv);  	} +	for (i = 0; i < nredirections; i++) { +		build_command_asis(" "); +		build_command_asis(redirections[i].asis); +		if (redirections[i].escape) { +			build_command_asis(" "); +			build_command_escape(redirections[i].escape); +		} +	}  	finalise_command();  	i = 0;  | 
