148231Sbostic /*-
266705Sbostic * Copyright (c) 1994
361903Sbostic * The Regents of the University of California. All rights reserved.
448231Sbostic *
566705Sbostic * This code is derived from software contributed to Berkeley by
666705Sbostic * Jan-Simon Pendry.
766705Sbostic *
866705Sbostic * %sccs.include.redist.c%
921546Sdist */
108730Smckusick
1121546Sdist #ifndef lint
12*66707Sbostic static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 04/04/94";
1348231Sbostic #endif /* not lint */
1421546Sdist
1566706Sbostic #include <sys/wait.h>
1666706Sbostic
1766706Sbostic #include <ctype.h>
1866705Sbostic #include <err.h>
1966706Sbostic #include <paths.h>
2066706Sbostic #include <signal.h>
218730Smckusick #include <stdio.h>
2266705Sbostic #include <stdlib.h>
2366705Sbostic #include <string.h>
2466705Sbostic #include <unistd.h>
2537871Sbostic
2666705Sbostic void usage __P((void));
2766706Sbostic int system __P((const char *));
2810820Ssam
2966705Sbostic int
main(argc,argv)308730Smckusick main(argc, argv)
3166705Sbostic int argc;
328730Smckusick char *argv[];
338730Smckusick {
3466706Sbostic int ch, clen, debug, i, l, magic, n, nargs, rval;
3566706Sbostic char *c, *cmd, *p, *q;
3666705Sbostic
3766705Sbostic debug = 0;
3866706Sbostic magic = '%'; /* Default magic char is `%'. */
3966706Sbostic nargs = -1;
4066706Sbostic while ((ch = getopt(argc, argv, "a:d0123456789")) != EOF)
4166705Sbostic switch (ch) {
4266706Sbostic case 'a':
4366706Sbostic if (optarg[1] != '\0')
4466706Sbostic errx(1,
4566706Sbostic "illegal magic character specification.");
4666706Sbostic magic = optarg[0];
4766706Sbostic break;
4866706Sbostic case 'd':
4966706Sbostic debug = 1;
5066706Sbostic break;
5166706Sbostic case '0': case '1': case '2': case '3': case '4':
5266706Sbostic case '5': case '6': case '7': case '8': case '9':
5366706Sbostic if (nargs != -1)
5466706Sbostic errx(1,
5566706Sbostic "only one -# argument may be specified.");
5666706Sbostic nargs = optopt - '0';
5766706Sbostic break;
5866706Sbostic default:
5966706Sbostic usage();
608730Smckusick }
6166705Sbostic argc -= optind;
6266705Sbostic argv += optind;
6366705Sbostic
6466705Sbostic if (argc < 2)
6566705Sbostic usage();
6666705Sbostic
6766705Sbostic /*
6866706Sbostic * The command to run is argv[0], and the args are argv[1..].
6966706Sbostic * Look for %digit references in the command, remembering the
7066706Sbostic * largest one.
7166705Sbostic */
7266706Sbostic for (n = 0, p = argv[0]; *p != '\0'; ++p)
7366706Sbostic if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
7466706Sbostic ++p;
7566706Sbostic if (p[0] - '0' > n)
7666706Sbostic n = p[0] - '0';
7766705Sbostic }
7866705Sbostic
7966705Sbostic /*
8066706Sbostic * If there were any %digit references, then use those, otherwise
8166706Sbostic * build a new command string with sufficient %digit references at
8266706Sbostic * the end to consume (nargs) arguments each time round the loop.
83*66707Sbostic * Allocate enough space to hold the maximum command.
8466705Sbostic */
85*66707Sbostic if ((cmd = malloc(sizeof("exec ") - 1 +
86*66707Sbostic strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1)) == NULL)
8766705Sbostic err(1, NULL);
8866705Sbostic
8966706Sbostic if (n == 0) {
9066706Sbostic /* If nargs not set, default to a single argument. */
9166706Sbostic if (nargs == -1)
9266706Sbostic nargs = 1;
9366705Sbostic
9466706Sbostic p = cmd;
9566706Sbostic p += sprintf(cmd, "exec %s", argv[0]);
9666705Sbostic for (i = 1; i <= nargs; i++)
9766705Sbostic p += sprintf(p, " %c%d", magic, i);
9866706Sbostic
9966706Sbostic /*
10066706Sbostic * If nargs set to the special value 0, eat a single
10166706Sbostic * argument for each command execution.
10266706Sbostic */
10366706Sbostic if (nargs == 0)
10466706Sbostic nargs = 1;
10566706Sbostic } else {
10666706Sbostic (void)sprintf(cmd, "exec %s", argv[0]);
10766706Sbostic nargs = n;
1088730Smckusick }
10966705Sbostic
11066705Sbostic /*
11166706Sbostic * Grab some space in which to build the command. Allocate
11266706Sbostic * as necessary later, but no reason to build it up slowly
11366706Sbostic * for the normal case.
11466705Sbostic */
11566706Sbostic if ((c = malloc(clen = 1024)) == NULL)
11666706Sbostic err(1, NULL);
11766705Sbostic
11866706Sbostic /*
11966706Sbostic * (argc) and (argv) are still offset by one to make it simpler to
12066706Sbostic * expand %digit references. At the end of the loop check for (argc)
12166706Sbostic * equals 1 means that all the (argv) has been consumed.
12266706Sbostic */
12366706Sbostic for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
12466706Sbostic /*
12566706Sbostic * Find a max value for the command length, and ensure
12666706Sbostic * there's enough space to build it.
12766706Sbostic */
12866706Sbostic for (l = strlen(cmd), i = 0; i < nargs; i++)
12966705Sbostic l += strlen(argv[i]);
13066706Sbostic if (l > clen && (c = realloc(c, clen = l)) == NULL)
13166706Sbostic err(1, NULL);
13266705Sbostic
13366706Sbostic /* Expand command argv references. */
13466706Sbostic for (p = cmd, q = c; *p != '\0'; ++p)
13566706Sbostic if (p[0] == magic && isdigit(p[1]) && p[1] != '0')
13666706Sbostic q += sprintf(q, "%s", argv[(++p)[0] - '0']);
13766706Sbostic else
13866705Sbostic *q++ = *p;
13966705Sbostic
14066706Sbostic /* Terminate the command string. */
14166705Sbostic *q = '\0';
14266705Sbostic
14366706Sbostic /* Run the command. */
14466706Sbostic if (debug)
14566706Sbostic (void)printf("%s\n", c);
14666706Sbostic else
14766705Sbostic if (system(c))
14866706Sbostic rval = 1;
1498730Smckusick }
15066705Sbostic
15166705Sbostic if (argc != 1)
15266706Sbostic errx(1, "expecting additional argument%s after \"%s\"",
15366706Sbostic (nargs - argc) ? "s" : "", argv[argc - 1]);
15466706Sbostic exit(rval);
1558730Smckusick }
15666705Sbostic
15766706Sbostic /*
15866706Sbostic * system --
15966706Sbostic * Private version of system(3). Use the user's SHELL environment
16066706Sbostic * variable as the shell to execute.
16166706Sbostic */
16266706Sbostic int
system(command)16366706Sbostic system(command)
16466706Sbostic const char *command;
16566706Sbostic {
16666706Sbostic static char *name, *shell;
16766706Sbostic union wait pstat;
16866706Sbostic pid_t pid;
16966706Sbostic int omask;
17066706Sbostic sig_t intsave, quitsave;
17166706Sbostic
17266706Sbostic if (shell == NULL) {
17366706Sbostic if ((shell = getenv("SHELL")) == NULL)
17466706Sbostic shell = _PATH_BSHELL;
17566706Sbostic if ((name = strrchr(shell, '/')) == NULL)
17666706Sbostic name = shell;
17766706Sbostic else
17866706Sbostic ++name;
17966706Sbostic }
18066706Sbostic if (!command) /* just checking... */
18166706Sbostic return(1);
18266706Sbostic
18366706Sbostic omask = sigblock(sigmask(SIGCHLD));
18466706Sbostic switch(pid = vfork()) {
18566706Sbostic case -1: /* error */
18666706Sbostic err(1, "fork");
18766706Sbostic case 0: /* child */
18866706Sbostic (void)sigsetmask(omask);
18966706Sbostic execl(shell, name, "-c", command, NULL);
19066706Sbostic err(1, "%s", shell);
19166706Sbostic }
19266706Sbostic intsave = signal(SIGINT, SIG_IGN);
19366706Sbostic quitsave = signal(SIGQUIT, SIG_IGN);
19466706Sbostic pid = waitpid(pid, (int *)&pstat, 0);
19566706Sbostic (void)sigsetmask(omask);
19666706Sbostic (void)signal(SIGINT, intsave);
19766706Sbostic (void)signal(SIGQUIT, quitsave);
19866706Sbostic return(pid == -1 ? -1 : pstat.w_status);
19966706Sbostic }
20066706Sbostic
20166705Sbostic void
usage()20266705Sbostic usage()
2038730Smckusick {
2048730Smckusick
20566706Sbostic (void)fprintf(stderr,
20666706Sbostic "usage: apply [-a magic] [-0123456789] command arguments ...\n");
20766705Sbostic exit(1);
2088730Smckusick }
209