1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-04 12:52:15 +00:00

Reinstate revision 1.11:

BDECFLAGS; ANSIfy; use EXEC instead of "exec " where appropriate; use
proper types (size_t, int); use proper variable names for certain things;
get rid of static 'cache' style stuff by moving and sanitizing the
original SHELL checking code to main(), this also makes it easier to
free() the string; rename file-scope system() to exec_shell(); use
snprintf() everywhere instead of sprintf(); actually remember to free()
other malloc()'d char pointers in main().

I left out the -s option in this revision along with getusershell()
checking because of objections made by Warner Losh <imp> and Garrett
Wollman <wollman>.  I agreed with their assertions that such code was
unnecessary in a program like this.

I dare people to make this coredump now.

Some suggestions:	nectar (snprintf() truncate checking)
Reviewed by:		markm, eivind, jedgar
Tortured by:		examples in apply(1), fuzz(1),
			and a lot of random ideas I came up with
This commit is contained in:
Will Andrews 2001-01-05 18:15:17 +00:00
parent c05aa33cb0
commit f697348034
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=70692

View File

@ -55,16 +55,16 @@ static const char rcsid[] =
#include <string.h>
#include <unistd.h>
void usage __P((void));
int system __P((const char *));
void usage(void);
static int exec_shell(char *, char *, const char *);
#define EXEC "exec "
int
main(argc, argv)
int argc;
char *argv[];
{
int ch, clen, debug, i, l, magic, n, nargs, rval;
char *c, *cmd, *p, *q;
main(int argc, char **argv) {
int ch, debug, i, magic, n, nargs, rval, offset;
size_t clen, l, cmdsize;
char *c, *cmd, *p, *q, *shell, *name, *tmpshell, *slashp;
debug = 0;
magic = '%'; /* Default magic char is `%'. */
@ -108,14 +108,32 @@ main(argc, argv)
n = p[0] - '0';
}
/*
* Figure out the shell and name arguments to pass to execl()
* in exec_shell(). Always malloc() shell and just set name
* to point at the last part of shell if there are any backslashes,
* otherwise just set it to point at the space malloc()'d. If
* SHELL environment variable exists, replace contents of
* shell with it.
*/
shell = name = NULL;
tmpshell = getenv("SHELL");
shell = (tmpshell != NULL) ? strdup(tmpshell) : strdup(_PATH_BSHELL);
if (shell == NULL)
err(1, "strdup() failed");
slashp = strrchr(shell, '/');
name = (slashp != NULL) ? slashp + 1 : shell;
/*
* If there were any %digit references, then use those, otherwise
* build a new command string with sufficient %digit references at
* 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. Save the
* size to pass to snprintf().
*/
if ((cmd = malloc(sizeof("exec ") - 1 +
strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1)) == NULL)
cmdsize = sizeof(EXEC) - 1 + strlen(argv[0]) + 9 *
(sizeof(" %1") - 1) + 1;
if ((cmd = malloc(cmdsize)) == NULL)
err(1, NULL);
if (n == 0) {
@ -124,9 +142,16 @@ main(argc, argv)
nargs = 1;
p = cmd;
p += sprintf(cmd, "exec %s", argv[0]);
for (i = 1; i <= nargs; i++)
p += sprintf(p, " %c%d", magic, i);
offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
if ((size_t)offset >= cmdsize)
err(1, "snprintf() failed");
p += offset;
for (i = 1; i <= nargs; i++) {
offset = snprintf(p, cmdsize, " %c%d", magic, i);
if ((size_t)offset >= cmdsize)
err(1, "snprintf() failed");
p += offset;
}
/*
* If nargs set to the special value 0, eat a single
@ -135,7 +160,9 @@ main(argc, argv)
if (nargs == 0)
nargs = 1;
} else {
(void)sprintf(cmd, "exec %s", argv[0]);
offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
if ((size_t)offset >= cmdsize)
err(1, "snprintf() failed");
nargs = n;
}
@ -164,9 +191,13 @@ main(argc, argv)
/* Expand command argv references. */
for (p = cmd, q = c; *p != '\0'; ++p)
if (p[0] == magic && isdigit(p[1]) && p[1] != '0')
q += sprintf(q, "%s", argv[(++p)[0] - '0']);
else
if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
offset = snprintf(q, l, "%s",
argv[(++p)[0] - '0']);
if ((size_t)offset >= l)
err(1, "snprintf() failed");
q += offset;
} else
*q++ = *p;
/* Terminate the command string. */
@ -176,38 +207,32 @@ main(argc, argv)
if (debug)
(void)printf("%s\n", c);
else
if (system(c))
if (exec_shell(shell, name, c))
rval = 1;
}
if (argc != 1)
errx(1, "expecting additional argument%s after \"%s\"",
(nargs - argc) ? "s" : "", argv[argc - 1]);
(nargs - argc) ? "s" : "", argv[argc - 1]);
free(cmd);
free(c);
free(shell);
exit(rval);
}
/*
* system --
* Private version of system(3). Use the user's SHELL environment
* variable as the shell to execute.
* exec_shell --
* Execute a shell command using passed use_shell and use_name
* arguments.
*/
int
system(command)
const char *command;
static int
exec_shell(char *use_shell, char *use_name, const char *command)
{
static char *name, *shell;
pid_t pid;
int omask, pstat;
sig_t intsave, quitsave;
if (shell == NULL) {
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
if ((name = strrchr(shell, '/')) == NULL)
name = shell;
else
++name;
}
if (!command) /* just checking... */
return(1);
@ -217,8 +242,8 @@ system(command)
err(1, "vfork");
case 0: /* child */
(void)sigsetmask(omask);
execl(shell, name, "-c", command, NULL);
warn("%s", shell);
execl(use_shell, use_name, "-c", command, NULL);
warn("%s", use_shell);
_exit(1);
}
intsave = signal(SIGINT, SIG_IGN);