1 /* $NetBSD: xargs.c,v 1.7 1994/11/14 06:51:41 jtc Exp $ */ 2 3 /*- 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * John B. Roll Jr. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #ifndef lint 40 static char copyright[] = 41 "@(#) Copyright (c) 1990, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n"; 43 #endif /* not lint */ 44 45 #ifndef lint 46 #if 0 47 static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93"; 48 #endif 49 static char rcsid[] = "$NetBSD: xargs.c,v 1.7 1994/11/14 06:51:41 jtc Exp $"; 50 #endif /* not lint */ 51 52 #include <sys/types.h> 53 #include <sys/wait.h> 54 #include <errno.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 #include <limits.h> 60 #include <locale.h> 61 #include <err.h> 62 #include "pathnames.h" 63 64 int tflag, rval; 65 66 void run __P((char **)); 67 void usage __P((void)); 68 69 int 70 main(argc, argv) 71 int argc; 72 char **argv; 73 { 74 register int ch; 75 register char *p, *bbp, *ebp, **bxp, **exp, **xp; 76 int cnt, indouble, insingle, nargs, nflag, nline, xflag; 77 char **av, *argp; 78 79 setlocale(LC_ALL, ""); 80 81 /* 82 * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that 83 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given 84 * that the smallest argument is 2 bytes in length, this means that 85 * the number of arguments is limited to: 86 * 87 * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2. 88 * 89 * We arbitrarily limit the number of arguments to 5000. This is 90 * allowed by POSIX.2 as long as the resulting minimum exec line is 91 * at least LINE_MAX. Realloc'ing as necessary is possible, but 92 * probably not worthwhile. 93 */ 94 nargs = 5000; 95 nline = ARG_MAX - 4 * 1024; 96 nflag = xflag = 0; 97 while ((ch = getopt(argc, argv, "n:s:tx")) != EOF) 98 switch(ch) { 99 case 'n': 100 nflag = 1; 101 if ((nargs = atoi(optarg)) <= 0) 102 errx(1, "illegal argument count"); 103 break; 104 case 's': 105 nline = atoi(optarg); 106 break; 107 case 't': 108 tflag = 1; 109 break; 110 case 'x': 111 xflag = 1; 112 break; 113 case '?': 114 default: 115 usage(); 116 } 117 argc -= optind; 118 argv += optind; 119 120 if (xflag && !nflag) 121 usage(); 122 123 /* 124 * Allocate pointers for the utility name, the utility arguments, 125 * the maximum arguments to be read from stdin and the trailing 126 * NULL. 127 */ 128 if (!(av = bxp = 129 malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **)))) 130 err(1, NULL); 131 132 /* 133 * Use the user's name for the utility as argv[0], just like the 134 * shell. Echo is the default. Set up pointers for the user's 135 * arguments. 136 */ 137 if (!*argv) 138 cnt = strlen(*bxp++ = _PATH_ECHO); 139 else { 140 cnt = 0; 141 do { 142 cnt += strlen(*bxp++ = *argv) + 1; 143 } while (*++argv); 144 } 145 146 /* 147 * Set up begin/end/traversing pointers into the array. The -n 148 * count doesn't include the trailing NULL pointer, so the malloc 149 * added in an extra slot. 150 */ 151 exp = (xp = bxp) + nargs; 152 153 /* 154 * Allocate buffer space for the arguments read from stdin and the 155 * trailing NULL. Buffer space is defined as the default or specified 156 * space, minus the length of the utility name and arguments. Set up 157 * begin/end/traversing pointers into the array. The -s count does 158 * include the trailing NULL, so the malloc didn't add in an extra 159 * slot. 160 */ 161 nline -= cnt; 162 if (nline <= 0) 163 errx(1, "insufficient space for command"); 164 165 if (!(bbp = malloc((u_int)nline + 1))) 166 err(1, NULL); 167 ebp = (argp = p = bbp) + nline - 1; 168 169 for (insingle = indouble = 0;;) 170 switch(ch = getchar()) { 171 case EOF: 172 /* No arguments since last exec. */ 173 if (p == bbp) 174 exit(rval); 175 176 /* Nothing since end of last argument. */ 177 if (argp == p) { 178 *xp = NULL; 179 run(av); 180 exit(rval); 181 } 182 goto arg1; 183 case ' ': 184 case '\t': 185 /* Quotes escape tabs and spaces. */ 186 if (insingle || indouble) 187 goto addch; 188 goto arg2; 189 case '\n': 190 /* Empty lines are skipped. */ 191 if (argp == p) 192 continue; 193 194 /* Quotes do not escape newlines. */ 195 arg1: if (insingle || indouble) 196 errx(1, "unterminated quote"); 197 198 arg2: *p = '\0'; 199 *xp++ = argp; 200 201 /* 202 * If max'd out on args or buffer, or reached EOF, 203 * run the command. If xflag and max'd out on buffer 204 * but not on args, object. 205 */ 206 if (xp == exp || p == ebp || ch == EOF) { 207 if (xflag && xp != exp && p == ebp) 208 errx(1, "insufficient space for arguments"); 209 *xp = NULL; 210 run(av); 211 if (ch == EOF) 212 exit(rval); 213 p = bbp; 214 xp = bxp; 215 } else 216 ++p; 217 argp = p; 218 break; 219 case '\'': 220 if (indouble) 221 goto addch; 222 insingle = !insingle; 223 break; 224 case '"': 225 if (insingle) 226 goto addch; 227 indouble = !indouble; 228 break; 229 case '\\': 230 /* Backslash escapes anything, is escaped by quotes. */ 231 if (!insingle && !indouble && (ch = getchar()) == EOF) 232 errx(1, "backslash at EOF"); 233 /* FALLTHROUGH */ 234 default: 235 addch: if (p < ebp) { 236 *p++ = ch; 237 break; 238 } 239 240 /* If only one argument, not enough buffer space. */ 241 if (bxp == xp) 242 errx(1, "insufficient space for argument"); 243 /* Didn't hit argument limit, so if xflag object. */ 244 if (xflag) 245 errx(1, "insufficient space for arguments"); 246 247 *xp = NULL; 248 run(av); 249 xp = bxp; 250 cnt = ebp - argp; 251 bcopy(argp, bbp, cnt); 252 p = (argp = bbp) + cnt; 253 *p++ = ch; 254 break; 255 } 256 /* NOTREACHED */ 257 } 258 259 void 260 run(argv) 261 char **argv; 262 { 263 volatile int noinvoke; 264 register char **p; 265 pid_t pid; 266 int status; 267 268 if (tflag) { 269 (void)fprintf(stderr, "%s", *argv); 270 for (p = argv + 1; *p; ++p) 271 (void)fprintf(stderr, " %s", *p); 272 (void)fprintf(stderr, "\n"); 273 (void)fflush(stderr); 274 } 275 noinvoke = 0; 276 switch(pid = vfork()) { 277 case -1: 278 err(1, "vfork"); 279 case 0: 280 execvp(argv[0], argv); 281 noinvoke = (errno == ENOENT) ? 127 : 126; 282 warn("%s", argv[0]);; 283 _exit(1); 284 } 285 pid = waitpid(pid, &status, 0); 286 if (pid == -1) 287 err(1, "waitpid"); 288 289 /* 290 * If we couldn't invoke the utility or the utility didn't exit 291 * properly, quit with 127 or 126 respectively. 292 */ 293 if (noinvoke) 294 exit(noinvoke); 295 296 /* 297 * According to POSIX, we have to exit if the utility exits with 298 * a 255 status, or is interrupted by a signal. xargs is allowed 299 * to return any exit status between 1 and 125 in these cases, but 300 * we'll use 124 and 125, the same values used by GNU xargs. 301 */ 302 if (WIFEXITED(status)) { 303 if (WEXITSTATUS (status) == 255) { 304 warnx ("%s exited with status 255", argv[0]); 305 exit(124); 306 } else if (WEXITSTATUS (status) != 0) { 307 rval = 123; 308 } 309 } else if (WIFSIGNALED (status)) { 310 warnx ("%s terminated by signal %d", argv[0], WTERMSIG(status)); 311 exit(125); 312 } 313 } 314 315 void 316 usage() 317 { 318 (void)fprintf(stderr, 319 "usage: xargs [-t] [-n number [-x]] [-s size] [utility [argument ...]]\n"); 320 exit(1); 321 } 322