1*47aa9d2aSbluhm /* $OpenBSD: apply.c,v 1.29 2018/04/01 17:45:05 bluhm Exp $ */
2df930be7Sderaadt /* $NetBSD: apply.c,v 1.3 1995/03/25 03:38:23 glass Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*-
5df930be7Sderaadt * Copyright (c) 1994
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt * Jan-Simon Pendry.
10df930be7Sderaadt *
11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt * modification, are permitted provided that the following conditions
13df930be7Sderaadt * are met:
14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt * documentation and/or other materials provided with the distribution.
19f75387cbSmillert * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt * may be used to endorse or promote products derived from this software
21df930be7Sderaadt * without specific prior written permission.
22df930be7Sderaadt *
23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt * SUCH DAMAGE.
34df930be7Sderaadt */
35df930be7Sderaadt
36df930be7Sderaadt #include <sys/wait.h>
37df930be7Sderaadt
38df930be7Sderaadt #include <ctype.h>
39df930be7Sderaadt #include <err.h>
40df930be7Sderaadt #include <paths.h>
41df930be7Sderaadt #include <signal.h>
42df930be7Sderaadt #include <stdio.h>
43df930be7Sderaadt #include <stdlib.h>
44df930be7Sderaadt #include <string.h>
45df930be7Sderaadt #include <unistd.h>
46df930be7Sderaadt
4776f6aa52Stobias #define ISMAGICNO(p) \
4876f6aa52Stobias (p)[0] == magic && isdigit((unsigned char)(p)[1]) && (p)[1] != '0'
4976f6aa52Stobias
50e2b9258cSlum __dead void usage(void);
51e2b9258cSlum static int mysystem(const char *);
52df930be7Sderaadt
5376f6aa52Stobias char *str;
5476f6aa52Stobias size_t sz;
5576f6aa52Stobias
5676f6aa52Stobias void
stradd(char * p)5776f6aa52Stobias stradd(char *p)
5876f6aa52Stobias {
5976f6aa52Stobias size_t n;
6076f6aa52Stobias
6176f6aa52Stobias n = strlen(p);
62*47aa9d2aSbluhm if (str == NULL) {
63*47aa9d2aSbluhm sz = (n / 1024 + 1) * 1024;
64*47aa9d2aSbluhm if ((str = malloc(sz)) == NULL)
65*47aa9d2aSbluhm err(1, "malloc");
66*47aa9d2aSbluhm *str = '\0';
67*47aa9d2aSbluhm } else if (sz - strlen(str) <= n) {
6876f6aa52Stobias sz += (n / 1024 + 1) * 1024;
6976f6aa52Stobias if ((str = realloc(str, sz)) == NULL)
7076f6aa52Stobias err(1, "realloc");
7176f6aa52Stobias }
7276f6aa52Stobias strlcat(str, p, sz);
7376f6aa52Stobias }
7476f6aa52Stobias
7576f6aa52Stobias void
strset(char * p)7676f6aa52Stobias strset(char *p)
7776f6aa52Stobias {
7876f6aa52Stobias if (str != NULL)
7976f6aa52Stobias str[0] = '\0';
8076f6aa52Stobias stradd(p);
8176f6aa52Stobias }
8276f6aa52Stobias
83df930be7Sderaadt int
main(int argc,char * argv[])841837a5caSderaadt main(int argc, char *argv[])
85df930be7Sderaadt {
8676f6aa52Stobias int ch, debug, i, magic, n, nargs, rval;
8776f6aa52Stobias char buf[4], *cmd, *p;
88df930be7Sderaadt
89f72d6950Sderaadt if (pledge("stdio proc exec", NULL) == -1)
90f72d6950Sderaadt err(1, "pledge");
91f72d6950Sderaadt
92df930be7Sderaadt debug = 0;
93df930be7Sderaadt magic = '%'; /* Default magic char is `%'. */
94df930be7Sderaadt nargs = -1;
9572799b18Smillert while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
96df930be7Sderaadt switch (ch) {
97df930be7Sderaadt case 'a':
9876f6aa52Stobias if (optarg[0] == '\0' || optarg[1] != '\0')
99df930be7Sderaadt errx(1,
100df930be7Sderaadt "illegal magic character specification.");
101df930be7Sderaadt magic = optarg[0];
102df930be7Sderaadt break;
103df930be7Sderaadt case 'd':
104df930be7Sderaadt debug = 1;
105df930be7Sderaadt break;
106df930be7Sderaadt case '0': case '1': case '2': case '3': case '4':
107df930be7Sderaadt case '5': case '6': case '7': case '8': case '9':
108df930be7Sderaadt if (nargs != -1)
109df930be7Sderaadt errx(1,
110df930be7Sderaadt "only one -# argument may be specified.");
1118327610cSjaredy nargs = ch - '0';
112df930be7Sderaadt break;
113df930be7Sderaadt default:
114df930be7Sderaadt usage();
115df930be7Sderaadt }
116df930be7Sderaadt argc -= optind;
117df930be7Sderaadt argv += optind;
118df930be7Sderaadt
119df930be7Sderaadt if (argc < 2)
120df930be7Sderaadt usage();
121df930be7Sderaadt
122df930be7Sderaadt /*
123df930be7Sderaadt * The command to run is argv[0], and the args are argv[1..].
124df930be7Sderaadt * Look for %digit references in the command, remembering the
125df930be7Sderaadt * largest one.
126df930be7Sderaadt */
127df930be7Sderaadt for (n = 0, p = argv[0]; *p != '\0'; ++p)
12876f6aa52Stobias if (ISMAGICNO(p)) {
129df930be7Sderaadt ++p;
130df930be7Sderaadt if (p[0] - '0' > n)
131df930be7Sderaadt n = p[0] - '0';
132df930be7Sderaadt }
133df930be7Sderaadt
134df930be7Sderaadt /*
135df930be7Sderaadt * If there were any %digit references, then use those, otherwise
136df930be7Sderaadt * build a new command string with sufficient %digit references at
137df930be7Sderaadt * the end to consume (nargs) arguments each time round the loop.
138df930be7Sderaadt * Allocate enough space to hold the maximum command.
139df930be7Sderaadt */
14076f6aa52Stobias strset(argv[0]);
1414aa9e3d2Sderaadt if (n == 0) {
142df930be7Sderaadt /* If nargs not set, default to a single argument. */
143df930be7Sderaadt if (nargs == -1)
144df930be7Sderaadt nargs = 1;
145df930be7Sderaadt
14686b5c977Sderaadt for (i = 1; i <= nargs; i++) {
14776f6aa52Stobias snprintf(buf, sizeof(buf), " %c%d", magic, i);
14876f6aa52Stobias stradd(buf);
14986b5c977Sderaadt }
150df930be7Sderaadt
151df930be7Sderaadt /*
152df930be7Sderaadt * If nargs set to the special value 0, eat a single
153df930be7Sderaadt * argument for each command execution.
154df930be7Sderaadt */
155df930be7Sderaadt if (nargs == 0)
156df930be7Sderaadt nargs = 1;
15776f6aa52Stobias } else
158df930be7Sderaadt nargs = n;
15976f6aa52Stobias if ((cmd = strdup(str)) == NULL)
16076f6aa52Stobias err(1, "strdup");
161df930be7Sderaadt
162df930be7Sderaadt /*
163df930be7Sderaadt * (argc) and (argv) are still offset by one to make it simpler to
164df930be7Sderaadt * expand %digit references. At the end of the loop check for (argc)
165df930be7Sderaadt * equals 1 means that all the (argv) has been consumed.
166df930be7Sderaadt */
167df930be7Sderaadt for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
16876f6aa52Stobias strset("exec ");
169df930be7Sderaadt
170df930be7Sderaadt /* Expand command argv references. */
17176f6aa52Stobias for (p = cmd; *p != '\0'; ++p)
17276f6aa52Stobias if (ISMAGICNO(p))
17376f6aa52Stobias stradd(argv[*(++p) - '0']);
17476f6aa52Stobias else {
17576f6aa52Stobias strlcpy(buf, p, 2);
17676f6aa52Stobias stradd(buf);
17776f6aa52Stobias }
178df930be7Sderaadt
179df930be7Sderaadt /* Run the command. */
180df930be7Sderaadt if (debug)
18176f6aa52Stobias (void)printf("%s\n", str);
18276f6aa52Stobias else if (mysystem(str))
183df930be7Sderaadt rval = 1;
184df930be7Sderaadt }
185df930be7Sderaadt
186df930be7Sderaadt if (argc != 1)
187df930be7Sderaadt errx(1, "expecting additional argument%s after \"%s\"",
188df930be7Sderaadt (nargs - argc) ? "s" : "", argv[argc - 1]);
189df930be7Sderaadt exit(rval);
190df930be7Sderaadt }
191df930be7Sderaadt
192df930be7Sderaadt /*
193e2b9258cSlum * mysystem --
194df930be7Sderaadt * Private version of system(3). Use the user's SHELL environment
195df930be7Sderaadt * variable as the shell to execute.
196df930be7Sderaadt */
197e2b9258cSlum static int
mysystem(const char * command)19884e69d03Sderaadt mysystem(const char *command)
199df930be7Sderaadt {
200e2b9258cSlum static const char *name, *shell;
201df930be7Sderaadt pid_t pid;
2029a7fa6a3Smillert int pstat;
2039a7fa6a3Smillert sigset_t mask, omask;
204df930be7Sderaadt sig_t intsave, quitsave;
205df930be7Sderaadt
206df930be7Sderaadt if (shell == NULL) {
207df930be7Sderaadt if ((shell = getenv("SHELL")) == NULL)
208df930be7Sderaadt shell = _PATH_BSHELL;
209df930be7Sderaadt if ((name = strrchr(shell, '/')) == NULL)
210df930be7Sderaadt name = shell;
211df930be7Sderaadt else
212df930be7Sderaadt ++name;
213df930be7Sderaadt }
214df930be7Sderaadt if (!command) /* just checking... */
215df930be7Sderaadt return(1);
216df930be7Sderaadt
2179a7fa6a3Smillert sigemptyset(&mask);
2189a7fa6a3Smillert sigaddset(&mask, SIGCHLD);
2199a7fa6a3Smillert sigprocmask(SIG_BLOCK, &mask, &omask);
2206c1ddd6cSbitblt switch(pid = fork()) {
221df930be7Sderaadt case -1: /* error */
222df930be7Sderaadt err(1, "fork");
223df930be7Sderaadt case 0: /* child */
2249a7fa6a3Smillert sigprocmask(SIG_SETMASK, &omask, NULL);
225c96f6a27Sderaadt execl(shell, name, "-c", command, (char *)NULL);
226df930be7Sderaadt err(1, "%s", shell);
227df930be7Sderaadt }
228df930be7Sderaadt intsave = signal(SIGINT, SIG_IGN);
229df930be7Sderaadt quitsave = signal(SIGQUIT, SIG_IGN);
230559ddf74Sderaadt pid = waitpid(pid, &pstat, 0);
2319a7fa6a3Smillert sigprocmask(SIG_SETMASK, &omask, NULL);
232df930be7Sderaadt (void)signal(SIGINT, intsave);
233df930be7Sderaadt (void)signal(SIGQUIT, quitsave);
234559ddf74Sderaadt return(pid == -1 ? -1 : pstat);
235df930be7Sderaadt }
236df930be7Sderaadt
237e2b9258cSlum __dead void
usage(void)2381837a5caSderaadt usage(void)
239df930be7Sderaadt {
240df930be7Sderaadt (void)fprintf(stderr,
241b3ebc89bSjaredy "usage: apply [-#] [-d] [-a magic] command argument ...\n");
242df930be7Sderaadt exit(1);
243df930be7Sderaadt }
244