Annotation of src/usr.bin/apply/apply.c, Revision 1.22
1.22 ! deraadt 1: /* $OpenBSD: apply.c,v 1.21 2005/05/15 16:22:12 jaredy 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.22 ! deraadt 40: static const char rcsid[] = "$OpenBSD: apply.c,v 1.21 2005/05/15 16:22:12 jaredy 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);
1.18 deraadt 56: int mysystem(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.");
1.20 jaredy 84: nargs = ch - '0';
1.1 deraadt 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: */
113: if (n == 0) {
1.19 jsg 114: int l;
1.12 deraadt 115:
1.22 ! deraadt 116: len = sizeof("exec ") - 1 +
! 117: strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1;
! 118: if ((cmd = malloc(len)) == NULL)
! 119: err(1, NULL);
! 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]);
1.19 jsg 126: if (l >= len || l == -1)
127: errx(1, "error building exec string");
1.12 deraadt 128: len -= l;
129: p = cmd + l;
130:
131: for (i = 1; i <= nargs; i++) {
132: l = snprintf(p, len, " %c%d", magic, i);
1.19 jsg 133: if (l >= len || l == -1)
134: errx(1, "error numbering arguments");
1.12 deraadt 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.22 ! deraadt 146: if (asprintf(&cmd, "exec %s", argv[0]) == -1)
! 147: err(1, NULL);
1.1 deraadt 148: nargs = n;
149: }
150:
151: /*
152: * Grab some space in which to build the command. Allocate
153: * as necessary later, but no reason to build it up slowly
154: * for the normal case.
155: */
156: if ((c = malloc(clen = 1024)) == NULL)
157: err(1, NULL);
158:
159: /*
160: * (argc) and (argv) are still offset by one to make it simpler to
161: * expand %digit references. At the end of the loop check for (argc)
162: * equals 1 means that all the (argv) has been consumed.
163: */
164: for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
165: /*
166: * Find a max value for the command length, and ensure
167: * there's enough space to build it.
168: */
169: for (l = strlen(cmd), i = 0; i < nargs; i++)
1.6 deraadt 170: l += strlen(argv[i+1]);
1.16 tedu 171: if (l > clen) {
172: if ((c2 = realloc(c, l)) == NULL)
173: err(1, NULL);
174: c = c2;
175: clen = l;
176: }
1.1 deraadt 177:
178: /* Expand command argv references. */
179: for (p = cmd, q = c; *p != '\0'; ++p)
1.12 deraadt 180: if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
1.13 deraadt 181: strlcpy(q, argv[(++p)[0] - '0'], c + clen - q);
1.12 deraadt 182: q += strlen(q);
183: } else
1.1 deraadt 184: *q++ = *p;
185:
186: /* Terminate the command string. */
187: *q = '\0';
188:
189: /* Run the command. */
190: if (debug)
191: (void)printf("%s\n", c);
192: else
1.18 deraadt 193: if (mysystem(c))
1.1 deraadt 194: rval = 1;
195: }
196:
197: if (argc != 1)
198: errx(1, "expecting additional argument%s after \"%s\"",
199: (nargs - argc) ? "s" : "", argv[argc - 1]);
200: exit(rval);
201: }
202:
203: /*
204: * system --
205: * Private version of system(3). Use the user's SHELL environment
206: * variable as the shell to execute.
207: */
208: int
1.18 deraadt 209: mysystem(const char *command)
1.1 deraadt 210: {
211: static char *name, *shell;
212: pid_t pid;
1.10 millert 213: int pstat;
214: sigset_t mask, omask;
1.1 deraadt 215: sig_t intsave, quitsave;
216:
217: if (shell == NULL) {
218: if ((shell = getenv("SHELL")) == NULL)
219: shell = _PATH_BSHELL;
220: if ((name = strrchr(shell, '/')) == NULL)
221: name = shell;
222: else
223: ++name;
224: }
225: if (!command) /* just checking... */
226: return(1);
227:
1.10 millert 228: sigemptyset(&mask);
229: sigaddset(&mask, SIGCHLD);
230: sigprocmask(SIG_BLOCK, &mask, &omask);
1.4 bitblt 231: switch(pid = fork()) {
1.1 deraadt 232: case -1: /* error */
233: err(1, "fork");
234: case 0: /* child */
1.10 millert 235: sigprocmask(SIG_SETMASK, &omask, NULL);
1.9 deraadt 236: execl(shell, name, "-c", command, (char *)NULL);
1.1 deraadt 237: err(1, "%s", shell);
238: }
239: intsave = signal(SIGINT, SIG_IGN);
240: quitsave = signal(SIGQUIT, SIG_IGN);
1.5 deraadt 241: pid = waitpid(pid, &pstat, 0);
1.10 millert 242: sigprocmask(SIG_SETMASK, &omask, NULL);
1.1 deraadt 243: (void)signal(SIGINT, intsave);
244: (void)signal(SIGQUIT, quitsave);
1.5 deraadt 245: return(pid == -1 ? -1 : pstat);
1.1 deraadt 246: }
247:
248: void
1.15 deraadt 249: usage(void)
1.1 deraadt 250: {
251: (void)fprintf(stderr,
1.21 jaredy 252: "usage: apply [-#] [-d] [-a magic] command argument ...\n");
1.1 deraadt 253: exit(1);
254: }