1 /*- 2 * Copyright (c) 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Jan-Simon Pendry. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 04/04/94"; 13 #endif /* not lint */ 14 15 #include <sys/wait.h> 16 17 #include <ctype.h> 18 #include <err.h> 19 #include <paths.h> 20 #include <signal.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 void usage __P((void)); 27 int system __P((const char *)); 28 29 int 30 main(argc, argv) 31 int argc; 32 char *argv[]; 33 { 34 int ch, clen, debug, i, l, magic, n, nargs, rval; 35 char *c, *cmd, *p, *q; 36 37 debug = 0; 38 magic = '%'; /* Default magic char is `%'. */ 39 nargs = -1; 40 while ((ch = getopt(argc, argv, "a:d0123456789")) != EOF) 41 switch (ch) { 42 case 'a': 43 if (optarg[1] != '\0') 44 errx(1, 45 "illegal magic character specification."); 46 magic = optarg[0]; 47 break; 48 case 'd': 49 debug = 1; 50 break; 51 case '0': case '1': case '2': case '3': case '4': 52 case '5': case '6': case '7': case '8': case '9': 53 if (nargs != -1) 54 errx(1, 55 "only one -# argument may be specified."); 56 nargs = optopt - '0'; 57 break; 58 default: 59 usage(); 60 } 61 argc -= optind; 62 argv += optind; 63 64 if (argc < 2) 65 usage(); 66 67 /* 68 * The command to run is argv[0], and the args are argv[1..]. 69 * Look for %digit references in the command, remembering the 70 * largest one. 71 */ 72 for (n = 0, p = argv[0]; *p != '\0'; ++p) 73 if (p[0] == magic && isdigit(p[1]) && p[1] != '0') { 74 ++p; 75 if (p[0] - '0' > n) 76 n = p[0] - '0'; 77 } 78 79 /* 80 * If there were any %digit references, then use those, otherwise 81 * build a new command string with sufficient %digit references at 82 * the end to consume (nargs) arguments each time round the loop. 83 * Allocate enough space to hold the maximum command. 84 */ 85 if ((cmd = malloc(sizeof("exec ") - 1 + 86 strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1)) == NULL) 87 err(1, NULL); 88 89 if (n == 0) { 90 /* If nargs not set, default to a single argument. */ 91 if (nargs == -1) 92 nargs = 1; 93 94 p = cmd; 95 p += sprintf(cmd, "exec %s", argv[0]); 96 for (i = 1; i <= nargs; i++) 97 p += sprintf(p, " %c%d", magic, i); 98 99 /* 100 * If nargs set to the special value 0, eat a single 101 * argument for each command execution. 102 */ 103 if (nargs == 0) 104 nargs = 1; 105 } else { 106 (void)sprintf(cmd, "exec %s", argv[0]); 107 nargs = n; 108 } 109 110 /* 111 * Grab some space in which to build the command. Allocate 112 * as necessary later, but no reason to build it up slowly 113 * for the normal case. 114 */ 115 if ((c = malloc(clen = 1024)) == NULL) 116 err(1, NULL); 117 118 /* 119 * (argc) and (argv) are still offset by one to make it simpler to 120 * expand %digit references. At the end of the loop check for (argc) 121 * equals 1 means that all the (argv) has been consumed. 122 */ 123 for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) { 124 /* 125 * Find a max value for the command length, and ensure 126 * there's enough space to build it. 127 */ 128 for (l = strlen(cmd), i = 0; i < nargs; i++) 129 l += strlen(argv[i]); 130 if (l > clen && (c = realloc(c, clen = l)) == NULL) 131 err(1, NULL); 132 133 /* Expand command argv references. */ 134 for (p = cmd, q = c; *p != '\0'; ++p) 135 if (p[0] == magic && isdigit(p[1]) && p[1] != '0') 136 q += sprintf(q, "%s", argv[(++p)[0] - '0']); 137 else 138 *q++ = *p; 139 140 /* Terminate the command string. */ 141 *q = '\0'; 142 143 /* Run the command. */ 144 if (debug) 145 (void)printf("%s\n", c); 146 else 147 if (system(c)) 148 rval = 1; 149 } 150 151 if (argc != 1) 152 errx(1, "expecting additional argument%s after \"%s\"", 153 (nargs - argc) ? "s" : "", argv[argc - 1]); 154 exit(rval); 155 } 156 157 /* 158 * system -- 159 * Private version of system(3). Use the user's SHELL environment 160 * variable as the shell to execute. 161 */ 162 int 163 system(command) 164 const char *command; 165 { 166 static char *name, *shell; 167 union wait pstat; 168 pid_t pid; 169 int omask; 170 sig_t intsave, quitsave; 171 172 if (shell == NULL) { 173 if ((shell = getenv("SHELL")) == NULL) 174 shell = _PATH_BSHELL; 175 if ((name = strrchr(shell, '/')) == NULL) 176 name = shell; 177 else 178 ++name; 179 } 180 if (!command) /* just checking... */ 181 return(1); 182 183 omask = sigblock(sigmask(SIGCHLD)); 184 switch(pid = vfork()) { 185 case -1: /* error */ 186 err(1, "fork"); 187 case 0: /* child */ 188 (void)sigsetmask(omask); 189 execl(shell, name, "-c", command, NULL); 190 err(1, "%s", shell); 191 } 192 intsave = signal(SIGINT, SIG_IGN); 193 quitsave = signal(SIGQUIT, SIG_IGN); 194 pid = waitpid(pid, (int *)&pstat, 0); 195 (void)sigsetmask(omask); 196 (void)signal(SIGINT, intsave); 197 (void)signal(SIGQUIT, quitsave); 198 return(pid == -1 ? -1 : pstat.w_status); 199 } 200 201 void 202 usage() 203 { 204 205 (void)fprintf(stderr, 206 "usage: apply [-a magic] [-0123456789] command arguments ...\n"); 207 exit(1); 208 } 209