Annotation of src/usr.bin/apply/apply.c, Revision 1.29
1.29 ! bluhm 1: /* $OpenBSD: apply.c,v 1.28 2018/03/27 10:00:16 tobias 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);
1.29 ! bluhm 62: if (str == NULL) {
! 63: sz = (n / 1024 + 1) * 1024;
! 64: if ((str = malloc(sz)) == NULL)
! 65: err(1, "malloc");
! 66: *str = '\0';
! 67: } else if (sz - strlen(str) <= n) {
1.28 tobias 68: sz += (n / 1024 + 1) * 1024;
69: if ((str = realloc(str, sz)) == NULL)
70: err(1, "realloc");
71: }
72: strlcat(str, p, sz);
73: }
74:
75: void
76: strset(char *p)
77: {
78: if (str != NULL)
79: str[0] = '\0';
80: stradd(p);
81: }
82:
1.1 deraadt 83: int
1.15 deraadt 84: main(int argc, char *argv[])
1.1 deraadt 85: {
1.28 tobias 86: int ch, debug, i, magic, n, nargs, rval;
87: char buf[4], *cmd, *p;
1.27 deraadt 88:
89: if (pledge("stdio proc exec", NULL) == -1)
90: err(1, "pledge");
1.1 deraadt 91:
92: debug = 0;
93: magic = '%'; /* Default magic char is `%'. */
94: nargs = -1;
1.3 millert 95: while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
1.1 deraadt 96: switch (ch) {
97: case 'a':
1.28 tobias 98: if (optarg[0] == '\0' || optarg[1] != '\0')
1.1 deraadt 99: errx(1,
100: "illegal magic character specification.");
101: magic = optarg[0];
102: break;
103: case 'd':
104: debug = 1;
105: break;
106: case '0': case '1': case '2': case '3': case '4':
107: case '5': case '6': case '7': case '8': case '9':
108: if (nargs != -1)
109: errx(1,
110: "only one -# argument may be specified.");
1.20 jaredy 111: nargs = ch - '0';
1.1 deraadt 112: break;
113: default:
114: usage();
115: }
116: argc -= optind;
117: argv += optind;
118:
119: if (argc < 2)
120: usage();
121:
122: /*
123: * The command to run is argv[0], and the args are argv[1..].
124: * Look for %digit references in the command, remembering the
125: * largest one.
126: */
127: for (n = 0, p = argv[0]; *p != '\0'; ++p)
1.28 tobias 128: if (ISMAGICNO(p)) {
1.1 deraadt 129: ++p;
130: if (p[0] - '0' > n)
131: n = p[0] - '0';
132: }
133:
134: /*
135: * If there were any %digit references, then use those, otherwise
136: * build a new command string with sufficient %digit references at
137: * the end to consume (nargs) arguments each time round the loop.
138: * Allocate enough space to hold the maximum command.
139: */
1.28 tobias 140: strset(argv[0]);
1.1 deraadt 141: if (n == 0) {
142: /* If nargs not set, default to a single argument. */
143: if (nargs == -1)
144: nargs = 1;
145:
1.12 deraadt 146: for (i = 1; i <= nargs; i++) {
1.28 tobias 147: snprintf(buf, sizeof(buf), " %c%d", magic, i);
148: stradd(buf);
1.12 deraadt 149: }
1.1 deraadt 150:
151: /*
152: * If nargs set to the special value 0, eat a single
153: * argument for each command execution.
154: */
155: if (nargs == 0)
156: nargs = 1;
1.28 tobias 157: } else
1.1 deraadt 158: nargs = n;
1.28 tobias 159: if ((cmd = strdup(str)) == NULL)
160: err(1, "strdup");
1.1 deraadt 161:
162: /*
163: * (argc) and (argv) are still offset by one to make it simpler to
164: * expand %digit references. At the end of the loop check for (argc)
165: * equals 1 means that all the (argv) has been consumed.
166: */
167: for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
1.28 tobias 168: strset("exec ");
1.1 deraadt 169:
170: /* Expand command argv references. */
1.28 tobias 171: for (p = cmd; *p != '\0'; ++p)
172: if (ISMAGICNO(p))
173: stradd(argv[*(++p) - '0']);
174: else {
175: strlcpy(buf, p, 2);
176: stradd(buf);
177: }
1.1 deraadt 178:
179: /* Run the command. */
180: if (debug)
1.28 tobias 181: (void)printf("%s\n", str);
182: else if (mysystem(str))
1.25 lum 183: rval = 1;
1.1 deraadt 184: }
185:
186: if (argc != 1)
187: errx(1, "expecting additional argument%s after \"%s\"",
188: (nargs - argc) ? "s" : "", argv[argc - 1]);
189: exit(rval);
190: }
191:
192: /*
1.25 lum 193: * mysystem --
1.1 deraadt 194: * Private version of system(3). Use the user's SHELL environment
195: * variable as the shell to execute.
196: */
1.25 lum 197: static int
1.18 deraadt 198: mysystem(const char *command)
1.1 deraadt 199: {
1.25 lum 200: static const char *name, *shell;
1.1 deraadt 201: pid_t pid;
1.10 millert 202: int pstat;
203: sigset_t mask, omask;
1.1 deraadt 204: sig_t intsave, quitsave;
205:
206: if (shell == NULL) {
207: if ((shell = getenv("SHELL")) == NULL)
208: shell = _PATH_BSHELL;
209: if ((name = strrchr(shell, '/')) == NULL)
210: name = shell;
211: else
212: ++name;
213: }
214: if (!command) /* just checking... */
215: return(1);
216:
1.10 millert 217: sigemptyset(&mask);
218: sigaddset(&mask, SIGCHLD);
219: sigprocmask(SIG_BLOCK, &mask, &omask);
1.4 bitblt 220: switch(pid = fork()) {
1.1 deraadt 221: case -1: /* error */
222: err(1, "fork");
223: case 0: /* child */
1.10 millert 224: sigprocmask(SIG_SETMASK, &omask, NULL);
1.9 deraadt 225: execl(shell, name, "-c", command, (char *)NULL);
1.1 deraadt 226: err(1, "%s", shell);
227: }
228: intsave = signal(SIGINT, SIG_IGN);
229: quitsave = signal(SIGQUIT, SIG_IGN);
1.5 deraadt 230: pid = waitpid(pid, &pstat, 0);
1.10 millert 231: sigprocmask(SIG_SETMASK, &omask, NULL);
1.1 deraadt 232: (void)signal(SIGINT, intsave);
233: (void)signal(SIGQUIT, quitsave);
1.5 deraadt 234: return(pid == -1 ? -1 : pstat);
1.1 deraadt 235: }
236:
1.25 lum 237: __dead void
1.15 deraadt 238: usage(void)
1.1 deraadt 239: {
240: (void)fprintf(stderr,
1.21 jaredy 241: "usage: apply [-#] [-d] [-a magic] command argument ...\n");
1.1 deraadt 242: exit(1);
243: }