-/* $NetBSD: apply.c,v 1.6 1997/12/31 05:53:45 thorpej Exp $ */
-
/*-
* Copyright (c) 1994
* The Regents of the University of California. All rights reserved.
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#ifndef lint
#if 0
+#ifndef lint
static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94";
-#else
-__RCSID("$NetBSD: apply.c,v 1.6 1997/12/31 05:53:45 thorpej Exp $");
#endif
-#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/apply/apply.c,v 1.22 2002/07/14 18:22:12 alfred Exp $");
+
+#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
-int main __P((int, char **));
-void usage __P((void));
-int system __P((const char *));
+#define EXEC "exec "
+
+static int exec_shell(const char *, char *, char *);
+static void usage(void);
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, offset, rval;
+ size_t clen, cmdsize, l;
+ char *c, *cmd, *name, *p, *q, *shell, *slashp, *tmpshell;
debug = 0;
magic = '%'; /* Default magic char is `%'. */
case 'a':
if (optarg[1] != '\0')
errx(1,
- "illegal magic character specification.");
+ "illegal magic character specification");
magic = optarg[0];
break;
case 'd':
case '5': case '6': case '7': case '8': case '9':
if (nargs != -1)
errx(1,
- "only one -# argument may be specified.");
+ "only one -# argument may be specified");
nargs = optopt - '0';
break;
default:
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)
- err(1, "malloc");
-
+ cmdsize = sizeof(EXEC) - 1 + strlen(argv[0])
+ + 9 * (sizeof(" %1") - 1) + 1;
+ if ((cmd = malloc(cmdsize)) == NULL)
+ err(1, NULL);
+
if (n == 0) {
/* If nargs not set, default to a single argument. */
if (nargs == -1)
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;
+ cmdsize -= 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;
+ cmdsize -= offset;
+ }
/*
* If nargs set to the special value 0, eat a single
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;
}
* for the normal case.
*/
if ((c = malloc(clen = 1024)) == NULL)
- err(1, "malloc");
+ err(1, NULL);
/*
* (argc) and (argv) are still offset by one to make it simpler to
* there's enough space to build it.
*/
for (l = strlen(cmd), i = 0; i < nargs; i++)
- l += strlen(argv[i]);
+ l += strlen(argv[i+1]);
if (l > clen && (c = realloc(c, clen = l)) == NULL)
- err(1, "malloc");
+ err(1, NULL);
/* 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;
+ l -= offset;
+ } else
*q++ = *p;
/* Terminate the command string. */
if (debug)
(void)printf("%s\n", c);
else
- if (system(c))
+ if (exec_shell(c, shell, name))
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(const char *command, char *use_shell, char *use_name)
{
- static char *name, *shell;
- union wait pstat;
pid_t pid;
- int omask;
+ 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);
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, (char *)NULL);
+ warn("%s", use_shell);
_exit(1);
}
intsave = signal(SIGINT, SIG_IGN);
quitsave = signal(SIGQUIT, SIG_IGN);
- pid = waitpid(pid, (int *)&pstat, 0);
+ pid = waitpid(pid, &pstat, 0);
(void)sigsetmask(omask);
(void)signal(SIGINT, intsave);
(void)signal(SIGQUIT, quitsave);
- return(pid == -1 ? -1 : pstat.w_status);
+ return(pid == -1 ? -1 : pstat);
}
void
-usage()
+usage(void)
{
(void)fprintf(stderr,
- "usage: apply [-a magic] [-0123456789] command arguments ...\n");
+ "usage: apply [-a magic] [-d] [-0123456789] command arguments ...\n");
exit(1);
}