Annotation of src/usr.bin/apply/apply.c, Revision 1.17
1.17 ! mickey 1: /* $OpenBSD: apply.c,v 1.16 2003/09/26 21:26:05 tedu 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
1.17 ! mickey 38: static const char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94";
1.1 deraadt 39: #else
1.17 ! mickey 40: static const char rcsid[] = "$OpenBSD: apply.c,v 1.16 2003/09/26 21:26:05 tedu 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;
1.17 ! mickey 62: char *c, *c2, *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.16 tedu 170: if (l > clen) {
171: if ((c2 = realloc(c, l)) == NULL)
172: err(1, NULL);
173: c = c2;
174: clen = l;
175: }
1.1 deraadt 176:
177: /* Expand command argv references. */
178: for (p = cmd, q = c; *p != '\0'; ++p)
1.12 deraadt 179: if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
1.13 deraadt 180: strlcpy(q, argv[(++p)[0] - '0'], c + clen - q);
1.12 deraadt 181: q += strlen(q);
182: } else
1.1 deraadt 183: *q++ = *p;
184:
185: /* Terminate the command string. */
186: *q = '\0';
187:
188: /* Run the command. */
189: if (debug)
190: (void)printf("%s\n", c);
191: else
192: if (system(c))
193: rval = 1;
194: }
195:
196: if (argc != 1)
197: errx(1, "expecting additional argument%s after \"%s\"",
198: (nargs - argc) ? "s" : "", argv[argc - 1]);
199: exit(rval);
200: }
201:
202: /*
203: * system --
204: * Private version of system(3). Use the user's SHELL environment
205: * variable as the shell to execute.
206: */
207: int
1.15 deraadt 208: system(const char *command)
1.1 deraadt 209: {
210: static char *name, *shell;
211: pid_t pid;
1.10 millert 212: int pstat;
213: sigset_t mask, omask;
1.1 deraadt 214: sig_t intsave, quitsave;
215:
216: if (shell == NULL) {
217: if ((shell = getenv("SHELL")) == NULL)
218: shell = _PATH_BSHELL;
219: if ((name = strrchr(shell, '/')) == NULL)
220: name = shell;
221: else
222: ++name;
223: }
224: if (!command) /* just checking... */
225: return(1);
226:
1.10 millert 227: sigemptyset(&mask);
228: sigaddset(&mask, SIGCHLD);
229: sigprocmask(SIG_BLOCK, &mask, &omask);
1.4 bitblt 230: switch(pid = fork()) {
1.1 deraadt 231: case -1: /* error */
232: err(1, "fork");
233: case 0: /* child */
1.10 millert 234: sigprocmask(SIG_SETMASK, &omask, NULL);
1.9 deraadt 235: execl(shell, name, "-c", command, (char *)NULL);
1.1 deraadt 236: err(1, "%s", shell);
237: }
238: intsave = signal(SIGINT, SIG_IGN);
239: quitsave = signal(SIGQUIT, SIG_IGN);
1.5 deraadt 240: pid = waitpid(pid, &pstat, 0);
1.10 millert 241: sigprocmask(SIG_SETMASK, &omask, NULL);
1.1 deraadt 242: (void)signal(SIGINT, intsave);
243: (void)signal(SIGQUIT, quitsave);
1.5 deraadt 244: return(pid == -1 ? -1 : pstat);
1.1 deraadt 245: }
246:
247: void
1.15 deraadt 248: usage(void)
1.1 deraadt 249: {
250: (void)fprintf(stderr,
1.8 aaron 251: "usage: apply [-#] [-a magic] [-d] command argument [...]\n");
1.1 deraadt 252: exit(1);
253: }