Annotation of src/usr.bin/apply/apply.c, Revision 1.15
1.15 ! deraadt 1: /* $OpenBSD: apply.c,v 1.14 2003/06/03 02:56:05 millert 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: #ifndef lint
37: #if 0
38: static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94";
39: #else
1.15 ! deraadt 40: static char rcsid[] = "$OpenBSD: apply.c,v 1.14 2003/06/03 02:56:05 millert Exp $";
1.1 deraadt 41: #endif
42: #endif /* not lint */
43:
44: #include <sys/wait.h>
45:
46: #include <ctype.h>
47: #include <err.h>
48: #include <paths.h>
49: #include <signal.h>
50: #include <stdio.h>
51: #include <stdlib.h>
52: #include <string.h>
53: #include <unistd.h>
54:
1.11 millert 55: void usage(void);
56: int system(const char *);
1.1 deraadt 57:
58: int
1.15 ! deraadt 59: main(int argc, char *argv[])
1.1 deraadt 60: {
61: int ch, clen, debug, i, l, magic, n, nargs, rval;
62: char *c, *cmd, *p, *q;
1.12 deraadt 63: size_t len;
1.1 deraadt 64:
65: debug = 0;
66: magic = '%'; /* Default magic char is `%'. */
67: nargs = -1;
1.3 millert 68: while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
1.1 deraadt 69: switch (ch) {
70: case 'a':
71: if (optarg[1] != '\0')
72: errx(1,
73: "illegal magic character specification.");
74: magic = optarg[0];
75: break;
76: case 'd':
77: debug = 1;
78: break;
79: case '0': case '1': case '2': case '3': case '4':
80: case '5': case '6': case '7': case '8': case '9':
81: if (nargs != -1)
82: errx(1,
83: "only one -# argument may be specified.");
84: nargs = optopt - '0';
85: break;
86: default:
87: usage();
88: }
89: argc -= optind;
90: argv += optind;
91:
92: if (argc < 2)
93: usage();
94:
95: /*
96: * The command to run is argv[0], and the args are argv[1..].
97: * Look for %digit references in the command, remembering the
98: * largest one.
99: */
100: for (n = 0, p = argv[0]; *p != '\0'; ++p)
101: if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
102: ++p;
103: if (p[0] - '0' > n)
104: n = p[0] - '0';
105: }
106:
107: /*
108: * If there were any %digit references, then use those, otherwise
109: * build a new command string with sufficient %digit references at
110: * the end to consume (nargs) arguments each time round the loop.
111: * Allocate enough space to hold the maximum command.
112: */
1.12 deraadt 113: len = sizeof("exec ") - 1 +
114: strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1;
115: if ((cmd = malloc(len)) == NULL)
1.1 deraadt 116: err(1, NULL);
117:
118: if (n == 0) {
1.12 deraadt 119: size_t l;
120:
1.1 deraadt 121: /* If nargs not set, default to a single argument. */
122: if (nargs == -1)
123: nargs = 1;
124:
1.12 deraadt 125: l = snprintf(cmd, len, "exec %s", argv[0]);
126: if (l >= len)
127: err(1, "snprintf");
128: len -= l;
129: p = cmd + l;
130:
131: for (i = 1; i <= nargs; i++) {
132: l = snprintf(p, len, " %c%d", magic, i);
133: if (l >= len)
134: err(1, "snprintf");
135: len -= l;
136: p += l;
137: }
1.1 deraadt 138:
139: /*
140: * If nargs set to the special value 0, eat a single
141: * argument for each command execution.
142: */
143: if (nargs == 0)
144: nargs = 1;
145: } else {
1.12 deraadt 146: (void)snprintf(cmd, len, "exec %s", argv[0]);
1.1 deraadt 147: nargs = n;
148: }
149:
150: /*
151: * Grab some space in which to build the command. Allocate
152: * as necessary later, but no reason to build it up slowly
153: * for the normal case.
154: */
155: if ((c = malloc(clen = 1024)) == NULL)
156: err(1, NULL);
157:
158: /*
159: * (argc) and (argv) are still offset by one to make it simpler to
160: * expand %digit references. At the end of the loop check for (argc)
161: * equals 1 means that all the (argv) has been consumed.
162: */
163: for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
164: /*
165: * Find a max value for the command length, and ensure
166: * there's enough space to build it.
167: */
168: for (l = strlen(cmd), i = 0; i < nargs; i++)
1.6 deraadt 169: l += strlen(argv[i+1]);
1.1 deraadt 170: if (l > clen && (c = realloc(c, clen = l)) == NULL)
171: err(1, NULL);
172:
173: /* Expand command argv references. */
174: for (p = cmd, q = c; *p != '\0'; ++p)
1.12 deraadt 175: if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
1.13 deraadt 176: strlcpy(q, argv[(++p)[0] - '0'], c + clen - q);
1.12 deraadt 177: q += strlen(q);
178: } else
1.1 deraadt 179: *q++ = *p;
180:
181: /* Terminate the command string. */
182: *q = '\0';
183:
184: /* Run the command. */
185: if (debug)
186: (void)printf("%s\n", c);
187: else
188: if (system(c))
189: rval = 1;
190: }
191:
192: if (argc != 1)
193: errx(1, "expecting additional argument%s after \"%s\"",
194: (nargs - argc) ? "s" : "", argv[argc - 1]);
195: exit(rval);
196: }
197:
198: /*
199: * system --
200: * Private version of system(3). Use the user's SHELL environment
201: * variable as the shell to execute.
202: */
203: int
1.15 ! deraadt 204: system(const char *command)
1.1 deraadt 205: {
206: static char *name, *shell;
207: pid_t pid;
1.10 millert 208: int pstat;
209: sigset_t mask, omask;
1.1 deraadt 210: sig_t intsave, quitsave;
211:
212: if (shell == NULL) {
213: if ((shell = getenv("SHELL")) == NULL)
214: shell = _PATH_BSHELL;
215: if ((name = strrchr(shell, '/')) == NULL)
216: name = shell;
217: else
218: ++name;
219: }
220: if (!command) /* just checking... */
221: return(1);
222:
1.10 millert 223: sigemptyset(&mask);
224: sigaddset(&mask, SIGCHLD);
225: sigprocmask(SIG_BLOCK, &mask, &omask);
1.4 bitblt 226: switch(pid = fork()) {
1.1 deraadt 227: case -1: /* error */
228: err(1, "fork");
229: case 0: /* child */
1.10 millert 230: sigprocmask(SIG_SETMASK, &omask, NULL);
1.9 deraadt 231: execl(shell, name, "-c", command, (char *)NULL);
1.1 deraadt 232: err(1, "%s", shell);
233: }
234: intsave = signal(SIGINT, SIG_IGN);
235: quitsave = signal(SIGQUIT, SIG_IGN);
1.5 deraadt 236: pid = waitpid(pid, &pstat, 0);
1.10 millert 237: sigprocmask(SIG_SETMASK, &omask, NULL);
1.1 deraadt 238: (void)signal(SIGINT, intsave);
239: (void)signal(SIGQUIT, quitsave);
1.5 deraadt 240: return(pid == -1 ? -1 : pstat);
1.1 deraadt 241: }
242:
243: void
1.15 ! deraadt 244: usage(void)
1.1 deraadt 245: {
246: (void)fprintf(stderr,
1.8 aaron 247: "usage: apply [-#] [-a magic] [-d] command argument [...]\n");
1.1 deraadt 248: exit(1);
249: }