Annotation of src/usr.bin/apply/apply.c, Revision 1.28
1.28 ! tobias 1: /* $OpenBSD: apply.c,v 1.27 2015/10/10 17:48:34 deraadt Exp $ */
1.1 deraadt 2: /* $NetBSD: apply.c,v 1.3 1995/03/25 03:38:23 glass Exp $ */
3:
4: /*-
5: * Copyright (c) 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Jan-Simon Pendry.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
1.14 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #include <sys/wait.h>
37:
38: #include <ctype.h>
39: #include <err.h>
40: #include <paths.h>
41: #include <signal.h>
42: #include <stdio.h>
43: #include <stdlib.h>
44: #include <string.h>
45: #include <unistd.h>
46:
1.28 ! tobias 47: #define ISMAGICNO(p) \
! 48: (p)[0] == magic && isdigit((unsigned char)(p)[1]) && (p)[1] != '0'
! 49:
1.25 lum 50: __dead void usage(void);
51: static int mysystem(const char *);
1.1 deraadt 52:
1.28 ! tobias 53: char *str;
! 54: size_t sz;
! 55:
! 56: void
! 57: stradd(char *p)
! 58: {
! 59: size_t n;
! 60:
! 61: n = strlen(p);
! 62: if (str == NULL || sz - strlen(str) <= n) {
! 63: sz += (n / 1024 + 1) * 1024;
! 64: if ((str = realloc(str, sz)) == NULL)
! 65: err(1, "realloc");
! 66: }
! 67: strlcat(str, p, sz);
! 68: }
! 69:
! 70: void
! 71: strset(char *p)
! 72: {
! 73: if (str != NULL)
! 74: str[0] = '\0';
! 75: stradd(p);
! 76: }
! 77:
1.1 deraadt 78: int
1.15 deraadt 79: main(int argc, char *argv[])
1.1 deraadt 80: {
1.28 ! tobias 81: int ch, debug, i, magic, n, nargs, rval;
! 82: char buf[4], *cmd, *p;
1.27 deraadt 83:
84: if (pledge("stdio proc exec", NULL) == -1)
85: err(1, "pledge");
1.1 deraadt 86:
87: debug = 0;
88: magic = '%'; /* Default magic char is `%'. */
89: nargs = -1;
1.3 millert 90: while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
1.1 deraadt 91: switch (ch) {
92: case 'a':
1.28 ! tobias 93: if (optarg[0] == '\0' || optarg[1] != '\0')
1.1 deraadt 94: errx(1,
95: "illegal magic character specification.");
96: magic = optarg[0];
97: break;
98: case 'd':
99: debug = 1;
100: break;
101: case '0': case '1': case '2': case '3': case '4':
102: case '5': case '6': case '7': case '8': case '9':
103: if (nargs != -1)
104: errx(1,
105: "only one -# argument may be specified.");
1.20 jaredy 106: nargs = ch - '0';
1.1 deraadt 107: break;
108: default:
109: usage();
110: }
111: argc -= optind;
112: argv += optind;
113:
114: if (argc < 2)
115: usage();
116:
117: /*
118: * The command to run is argv[0], and the args are argv[1..].
119: * Look for %digit references in the command, remembering the
120: * largest one.
121: */
122: for (n = 0, p = argv[0]; *p != '\0'; ++p)
1.28 ! tobias 123: if (ISMAGICNO(p)) {
1.1 deraadt 124: ++p;
125: if (p[0] - '0' > n)
126: n = p[0] - '0';
127: }
128:
129: /*
130: * If there were any %digit references, then use those, otherwise
131: * build a new command string with sufficient %digit references at
132: * the end to consume (nargs) arguments each time round the loop.
133: * Allocate enough space to hold the maximum command.
134: */
1.28 ! tobias 135: strset(argv[0]);
1.1 deraadt 136: if (n == 0) {
137: /* If nargs not set, default to a single argument. */
138: if (nargs == -1)
139: nargs = 1;
140:
1.12 deraadt 141: for (i = 1; i <= nargs; i++) {
1.28 ! tobias 142: snprintf(buf, sizeof(buf), " %c%d", magic, i);
! 143: stradd(buf);
1.12 deraadt 144: }
1.1 deraadt 145:
146: /*
147: * If nargs set to the special value 0, eat a single
148: * argument for each command execution.
149: */
150: if (nargs == 0)
151: nargs = 1;
1.28 ! tobias 152: } else
1.1 deraadt 153: nargs = n;
1.28 ! tobias 154: if ((cmd = strdup(str)) == NULL)
! 155: err(1, "strdup");
1.1 deraadt 156:
157: /*
158: * (argc) and (argv) are still offset by one to make it simpler to
159: * expand %digit references. At the end of the loop check for (argc)
160: * equals 1 means that all the (argv) has been consumed.
161: */
162: for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
1.28 ! tobias 163: strset("exec ");
1.1 deraadt 164:
165: /* Expand command argv references. */
1.28 ! tobias 166: for (p = cmd; *p != '\0'; ++p)
! 167: if (ISMAGICNO(p))
! 168: stradd(argv[*(++p) - '0']);
! 169: else {
! 170: strlcpy(buf, p, 2);
! 171: stradd(buf);
! 172: }
1.1 deraadt 173:
174: /* Run the command. */
175: if (debug)
1.28 ! tobias 176: (void)printf("%s\n", str);
! 177: else if (mysystem(str))
1.25 lum 178: rval = 1;
1.1 deraadt 179: }
180:
181: if (argc != 1)
182: errx(1, "expecting additional argument%s after \"%s\"",
183: (nargs - argc) ? "s" : "", argv[argc - 1]);
184: exit(rval);
185: }
186:
187: /*
1.25 lum 188: * mysystem --
1.1 deraadt 189: * Private version of system(3). Use the user's SHELL environment
190: * variable as the shell to execute.
191: */
1.25 lum 192: static int
1.18 deraadt 193: mysystem(const char *command)
1.1 deraadt 194: {
1.25 lum 195: static const char *name, *shell;
1.1 deraadt 196: pid_t pid;
1.10 millert 197: int pstat;
198: sigset_t mask, omask;
1.1 deraadt 199: sig_t intsave, quitsave;
200:
201: if (shell == NULL) {
202: if ((shell = getenv("SHELL")) == NULL)
203: shell = _PATH_BSHELL;
204: if ((name = strrchr(shell, '/')) == NULL)
205: name = shell;
206: else
207: ++name;
208: }
209: if (!command) /* just checking... */
210: return(1);
211:
1.10 millert 212: sigemptyset(&mask);
213: sigaddset(&mask, SIGCHLD);
214: sigprocmask(SIG_BLOCK, &mask, &omask);
1.4 bitblt 215: switch(pid = fork()) {
1.1 deraadt 216: case -1: /* error */
217: err(1, "fork");
218: case 0: /* child */
1.10 millert 219: sigprocmask(SIG_SETMASK, &omask, NULL);
1.9 deraadt 220: execl(shell, name, "-c", command, (char *)NULL);
1.1 deraadt 221: err(1, "%s", shell);
222: }
223: intsave = signal(SIGINT, SIG_IGN);
224: quitsave = signal(SIGQUIT, SIG_IGN);
1.5 deraadt 225: pid = waitpid(pid, &pstat, 0);
1.10 millert 226: sigprocmask(SIG_SETMASK, &omask, NULL);
1.1 deraadt 227: (void)signal(SIGINT, intsave);
228: (void)signal(SIGQUIT, quitsave);
1.5 deraadt 229: return(pid == -1 ? -1 : pstat);
1.1 deraadt 230: }
231:
1.25 lum 232: __dead void
1.15 deraadt 233: usage(void)
1.1 deraadt 234: {
235: (void)fprintf(stderr,
1.21 jaredy 236: "usage: apply [-#] [-d] [-a magic] command argument ...\n");
1.1 deraadt 237: exit(1);
238: }