From: Ken Hornstein Date: Fri, 18 Jan 2013 21:03:26 +0000 (-0500) Subject: Beginning of implementation of new argsplit() function to handle arguments X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/78211e93e9a370556c7c44b204dfac7b47766b43?hp=-c Beginning of implementation of new argsplit() function to handle arguments to profile-defined commands. --- 78211e93e9a370556c7c44b204dfac7b47766b43 diff --git a/Makefile.am b/Makefile.am index 0fbf441a..b79e930d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -472,7 +472,8 @@ uninstall-hook: ## ## Our rules to build our internal libraries (libmh.a, libmts.a) ## -sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/base64.c \ +sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \ + sbr/base64.c \ sbr/brkstring.c sbr/check_charset.c sbr/client.c \ sbr/closefds.c sbr/concat.c sbr/context_del.c \ sbr/context_find.c sbr/context_foil.c sbr/context_read.c \ diff --git a/sbr/arglist.c b/sbr/arglist.c new file mode 100644 index 00000000..20bf84c7 --- /dev/null +++ b/sbr/arglist.c @@ -0,0 +1,124 @@ + +/* + * arglist.c -- Routines for handling argument lists for execvp() and friends + * + * This code is Copyright (c) 2013, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. + */ + +#include +#include + +/* + * Split up a command into an appropriate array to pass to execvp() + * or similar function. Returns an allocated argv[] array. + * + * Function arguments: + * + * command - String to split up + * file - the first argument to "command", suitable for the first argument + * to execvp(). Returns allocated memory that must be free()d. + * argp - Index to last element (NULL) of returned argv[] array. + * + * Our basic algorithm is this: + * + * - If there are no spaces or shell metacharacters in "command", then + * take it as-is. + * - If there are spaces in command, space-split command string and + * append an argument list to it. + * - If we have shell metacharacters, run the command using + * /bin/sh -c 'command "${@}"'. + * + * In all cases additional arguments can be added to the argv[] array. + */ + +/* Shell metacharacters we use to trigger a call to the shell */ + +#define METACHARS "$&*(){}[]'\";\\|?<>~`\n" + +char ** +argsplit(char *command, char **file, int *argp) +{ + char **argvarray, *p; + int space = 0, metachar = 0, i; + + for (p = command; *p; p++) { + if (*p == ' ' || *p == '\t') { + space = 1; + } else if (strchr(METACHARS, *p)) { + metachar = 1; + break; + } + } + + argvarray = (char **) mh_xmalloc((sizeof(char **) * MAXARGS)); + + /* + * The simple case - no spaces or shell metacharacters + */ + + if (!space && !metachar) { + argvarray[0] = getcpy(r1bindex(command, '/')); + argvarray[1] = NULL; + *file = getcpy(command); + if (argp) + *argp = 1; + return argvarray; + } + + /* + * Spaces, but no shell metacharacters; space-split into seperate + * arguments + */ + + if (space && !metachar) { + char **split; + p = getcpy(command); + split = brkstring(p, " \t", NULL); + if (split[0] == NULL) { + adios(NULL, "Invalid blank command found"); + } + argvarray[0] = getcpy(r1bindex(split[0], '/')); + for (i = 1; split[i] != NULL; i++) { + if (i > MAXARGS) { + adios(NULL, "Command exceeded argument limit"); + } + argvarray[i] = getcpy(split[i]); + } + argvarray[i] = NULL; + *file = getcpy(split[0]); + if (argp) + *argp = i; + return argvarray; + } + + /* + * Remaining option - pass to the shell. + * + * Some notes here: + * + * - The command passed to "sh -c" is actually: + * command "$@" + * + * If there are additional arguments they will be expanded by the + * shell, otherwise "$@" expands to nothing. + * + * - Every argument after the -c string gets put into positional + * parameters starting at $0, but $@ starts expanding with $1. + * So we put in a dummy argument (we just use /bin/sh) + */ + + *file = getcpy("/bin/sh"); + argvarray[0] = getcpy("sh"); + argvarray[1] = getcpy("-c"); + argvarray[2] = getcpy(command); + argvarray[2] = add(" \"$@\"", argvarray[2]); + argvarray[3] = getcpy("/bin/sh"); + argvarray[4] = NULL; + + if (argp) + *argp = 4; + + return argvarray; +}