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