version 1.27, 2015/10/10 17:48:34 |
version 1.28, 2018/03/27 10:00:16 |
|
|
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
|
#define ISMAGICNO(p) \ |
|
(p)[0] == magic && isdigit((unsigned char)(p)[1]) && (p)[1] != '0' |
|
|
__dead void usage(void); |
__dead void usage(void); |
static int mysystem(const char *); |
static int mysystem(const char *); |
|
|
|
char *str; |
|
size_t sz; |
|
|
|
void |
|
stradd(char *p) |
|
{ |
|
size_t n; |
|
|
|
n = strlen(p); |
|
if (str == NULL || sz - strlen(str) <= n) { |
|
sz += (n / 1024 + 1) * 1024; |
|
if ((str = realloc(str, sz)) == NULL) |
|
err(1, "realloc"); |
|
} |
|
strlcat(str, p, sz); |
|
} |
|
|
|
void |
|
strset(char *p) |
|
{ |
|
if (str != NULL) |
|
str[0] = '\0'; |
|
stradd(p); |
|
} |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
{ |
{ |
int ch, clen, debug, i, l, magic, n, nargs, rval; |
int ch, debug, i, magic, n, nargs, rval; |
char *c, *c2, *cmd, *p, *q; |
char buf[4], *cmd, *p; |
size_t len; |
|
|
|
if (pledge("stdio proc exec", NULL) == -1) |
if (pledge("stdio proc exec", NULL) == -1) |
err(1, "pledge"); |
err(1, "pledge"); |
|
|
while ((ch = getopt(argc, argv, "a:d0123456789")) != -1) |
while ((ch = getopt(argc, argv, "a:d0123456789")) != -1) |
switch (ch) { |
switch (ch) { |
case 'a': |
case 'a': |
if (optarg[1] != '\0') |
if (optarg[0] == '\0' || optarg[1] != '\0') |
errx(1, |
errx(1, |
"illegal magic character specification."); |
"illegal magic character specification."); |
magic = optarg[0]; |
magic = optarg[0]; |
|
|
* largest one. |
* largest one. |
*/ |
*/ |
for (n = 0, p = argv[0]; *p != '\0'; ++p) |
for (n = 0, p = argv[0]; *p != '\0'; ++p) |
if (p[0] == magic && |
if (ISMAGICNO(p)) { |
isdigit((unsigned char)p[1]) && p[1] != '0') { |
|
++p; |
++p; |
if (p[0] - '0' > n) |
if (p[0] - '0' > n) |
n = p[0] - '0'; |
n = p[0] - '0'; |
|
|
* the end to consume (nargs) arguments each time round the loop. |
* the end to consume (nargs) arguments each time round the loop. |
* Allocate enough space to hold the maximum command. |
* Allocate enough space to hold the maximum command. |
*/ |
*/ |
|
strset(argv[0]); |
if (n == 0) { |
if (n == 0) { |
len = sizeof("exec ") - 1 + |
|
strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1; |
|
if ((cmd = malloc(len)) == NULL) |
|
err(1, NULL); |
|
|
|
/* If nargs not set, default to a single argument. */ |
/* If nargs not set, default to a single argument. */ |
if (nargs == -1) |
if (nargs == -1) |
nargs = 1; |
nargs = 1; |
|
|
l = snprintf(cmd, len, "exec %s", argv[0]); |
|
if (l >= len || l == -1) |
|
errx(1, "error building exec string"); |
|
len -= l; |
|
p = cmd + l; |
|
|
|
for (i = 1; i <= nargs; i++) { |
for (i = 1; i <= nargs; i++) { |
l = snprintf(p, len, " %c%d", magic, i); |
snprintf(buf, sizeof(buf), " %c%d", magic, i); |
if (l >= len || l == -1) |
stradd(buf); |
errx(1, "error numbering arguments"); |
|
len -= l; |
|
p += l; |
|
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
if (nargs == 0) |
if (nargs == 0) |
nargs = 1; |
nargs = 1; |
} else { |
} else |
if (asprintf(&cmd, "exec %s", argv[0]) == -1) |
|
err(1, NULL); |
|
nargs = n; |
nargs = n; |
} |
if ((cmd = strdup(str)) == NULL) |
|
err(1, "strdup"); |
|
|
/* |
/* |
* Grab some space in which to build the command. Allocate |
|
* as necessary later, but no reason to build it up slowly |
|
* for the normal case. |
|
*/ |
|
if ((c = malloc(clen = 1024)) == NULL) |
|
err(1, NULL); |
|
|
|
/* |
|
* (argc) and (argv) are still offset by one to make it simpler to |
* (argc) and (argv) are still offset by one to make it simpler to |
* expand %digit references. At the end of the loop check for (argc) |
* expand %digit references. At the end of the loop check for (argc) |
* equals 1 means that all the (argv) has been consumed. |
* equals 1 means that all the (argv) has been consumed. |
*/ |
*/ |
for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) { |
for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) { |
/* |
strset("exec "); |
* Find a max value for the command length, and ensure |
|
* there's enough space to build it. |
|
*/ |
|
for (l = strlen(cmd), i = 0; i < nargs; i++) |
|
l += strlen(argv[i+1]); |
|
if (l > clen) { |
|
if ((c2 = realloc(c, l)) == NULL) |
|
err(1, NULL); |
|
c = c2; |
|
clen = l; |
|
} |
|
|
|
/* Expand command argv references. */ |
/* Expand command argv references. */ |
for (p = cmd, q = c; *p != '\0'; ++p) |
for (p = cmd; *p != '\0'; ++p) |
if (p[0] == magic && |
if (ISMAGICNO(p)) |
isdigit((unsigned char)p[1]) && p[1] != '0') { |
stradd(argv[*(++p) - '0']); |
strlcpy(q, argv[(++p)[0] - '0'], c + clen - q); |
else { |
q += strlen(q); |
strlcpy(buf, p, 2); |
} else |
stradd(buf); |
*q++ = *p; |
} |
|
|
/* Terminate the command string. */ |
|
*q = '\0'; |
|
|
|
/* Run the command. */ |
/* Run the command. */ |
if (debug) |
if (debug) |
(void)printf("%s\n", c); |
(void)printf("%s\n", str); |
else if (mysystem(c)) |
else if (mysystem(str)) |
rval = 1; |
rval = 1; |
} |
} |
|
|