aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-02-08 17:17:30 +0100
committerMattias Andrée <m@maandree.se>2025-02-08 17:17:30 +0100
commit6c84566aad08dcfd49482e07543487ece4e23261 (patch)
tree6d217bbba0ed4044f84aca4b85cc6b5f68929d73
parentAdd cd option (diff)
downloadsshexec-6c84566aad08dcfd49482e07543487ece4e23261.tar.gz
sshexec-6c84566aad08dcfd49482e07543487ece4e23261.tar.bz2
sshexec-6c84566aad08dcfd49482e07543487ece4e23261.tar.xz
Add asis and nasis options
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--README16
-rw-r--r--sshexec.120
-rw-r--r--sshexec.c42
3 files changed, 71 insertions, 7 deletions
diff --git a/README b/README
index 71bf2af..b87c6d3 100644
--- a/README
+++ b/README
@@ -3,8 +3,9 @@ NAME
SYNOPSIS
sshexec [{ [ssh=ssh-command] [dir=directory] [cd=(strict|lax)]
- [[fd]{>,>>,>|,<,<>}[&]=file] }] [ssh-option] ...
- destination command [argument] ...
+ [[fd]{>,>>,>|,<,<>}[&]=file] [asis=asis-marker
+ [nasis=asis-count]] }] [ssh-option] ... destination
+ command [argument] ...
DESCRIPTION
The sshexec utility is a wrapper for SSH that makes it easy to
@@ -103,6 +104,17 @@ OPTIONS
Close the file descriptor fd. (Default fd is 0
(standard input).)
+ asis=asis-marker
+ Any argument equal to asis-marker will be skipped over
+ and instead the next argument (regardless of whether
+ it to is equal to asis-marker) will be interpreted as
+ raw shell code string that shall be inserted without
+ escaping.
+
+ masis=asis-count
+ If specified, asis-marker shall only have it's specified
+ affect up to asis-count times.
+
OPERANDS
The following operands are supported:
diff --git a/sshexec.1 b/sshexec.1
index d18635d..e824cb5 100644
--- a/sshexec.1
+++ b/sshexec.1
@@ -10,6 +10,8 @@ sshexec - run a command through ssh(1) with normal command syntax
.RI [\fBdir=\fP directory ]
.RB [ cd= ( strict | lax )]
.RB [[\fIfd\fP]{ > , >> , >| , < , <> }[ & ] = \fIfile\fP]
+.RB [ asis= \fIasis-marker\fP
+.RB [ nasis= \fIasis-count\fP]]
.BR } ]
.RI [ ssh-option ]\ ...\,
.I destination
@@ -206,6 +208,24 @@ Close the file descriptor
(Default
.I fd
is 0 (standard input).)
+.TP
+.BI asis= asis-marker
+Any
+.I argument
+equal to
+.I asis-marker
+will be skipped over and instead the next argument
+(regardless of whether it to is equal to
+.IR asis-marker )
+will be interpreted as raw shell code string that
+shall be inserted without escaping.
+.TP
+.BI masis= asis-count
+If specified,
+.I asis-marker
+shall only have it's specified affect up to
+.I asis-count
+times.
.SH OPERANDS
The following operands are supported:
diff --git a/sshexec.c b/sshexec.c
index 03810e8..e0912c9 100644
--- a/sshexec.c
+++ b/sshexec.c
@@ -19,7 +19,8 @@ static void
usage(void)
{
exitf("usage: %s [{ %s }] [ssh-option] ... destination command [argument] ...\n",
- argv0, "[ssh=command] [dir=directory] [cd=(strict|lax)] [[fd]{>,>>,>|,<>}[&]=file]");
+ argv0, "[ssh=command] [dir=directory] [cd=(strict|lax)] [[fd]{>,>>,>|,<>}[&]=file] "
+ "[asis=asis-marker [nasis=asis-count]]");
}
@@ -130,6 +131,8 @@ main(int argc_unused, char *argv[])
const char *dir = NULL;
const char *ssh = NULL;
const char *cd = NULL;
+ const char *asis = NULL;
+ const char *nasis_str = NULL;
struct redirection *redirections = NULL;
size_t nredirections = 0;
char *destination;
@@ -142,6 +145,8 @@ main(int argc_unused, char *argv[])
const char **args;
size_t i;
int strict_cd;
+ unsigned long long int nasis = ULLONG_MAX;
+ int next_asis;
(void) argc_unused;
@@ -160,7 +165,8 @@ main(int argc_unused, char *argv[])
for (; *argv && strcmp(*argv, "}"); argv++) {
STORE_OPT(&ssh, "ssh")
STORE_OPT(&dir, "dir")
- STORE_OPT(&cd, "cd")
+ STORE_OPT(&asis, "asis")
+ STORE_OPT(&nasis_str, "nasis")
p = *argv;
while (isdigit(*p))
@@ -212,6 +218,16 @@ main(int argc_unused, char *argv[])
else
usage();
+ if (nasis_str) {
+ char *end;
+ if (!asis || !isdigit(*nasis_str))
+ usage();
+ errno = 0;
+ nasis = strtoull(nasis_str, &end, 10);
+ if ((!nasis && errno) || *end)
+ usage();
+ }
+
opts = argv;
nopts = 0;
while (*argv) {
@@ -275,11 +291,27 @@ dest_dir_checked:
build_command_escape(dir);
build_command_asis(strict_cd ? " && " : " ; ");
}
- build_command_asis("exec env --");
+ if (asis)
+ build_command_asis("( env --");
+ else
+ build_command_asis("exec env --");
+ next_asis = 0;
for (; *argv; argv++) {
- build_command_asis(" ");
- build_command_escape(*argv);
+ if (asis && nasis && !strcmp(*argv, asis)) {
+ nasis -= 1U;
+ next_asis = 1;
+ } else {
+ build_command_asis(" ");
+ if (next_asis) {
+ next_asis = 0;
+ build_command_asis(*argv);
+ } else {
+ build_command_escape(*argv);
+ }
+ }
}
+ if (asis)
+ build_command_asis(" )");
for (i = 0; i < nredirections; i++) {
build_command_asis(" ");
build_command_asis(redirections[i].asis);