1 /* $NetBSD: xargs.c,v 1.9 1997/10/20 03:30:16 lukem 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 #include <sys/cdefs.h> 40 #ifndef lint 41 __COPYRIGHT("@(#) 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 __RCSID("$NetBSD: xargs.c,v 1.9 1997/10/20 03:30:16 lukem 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, zflag, rval; 65 66 void run __P((char **)); 67 int main __P((int, char **)); 68 void usage __P((void)); 69 70 int 71 main(argc, argv) 72 int argc; 73 char **argv; 74 { 75 int ch; 76 char *p, *bbp, *ebp, **bxp, **exp, **xp; 77 int cnt, indouble, insingle, nargs, nflag, nline, xflag; 78 char **av, *argp; 79 80 setlocale(LC_ALL, ""); 81 82 /* 83 * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that 84 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given 85 * that the smallest argument is 2 bytes in length, this means that 86 * the number of arguments is limited to: 87 * 88 * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2. 89 * 90 * We arbitrarily limit the number of arguments to 5000. This is 91 * allowed by POSIX.2 as long as the resulting minimum exec line is 92 * at least LINE_MAX. Realloc'ing as necessary is possible, but 93 * probably not worthwhile. 94 */ 95 nargs = 5000; 96 nline = ARG_MAX - 4 * 1024; 97 nflag = xflag = 0; 98 while ((ch = getopt(argc, argv, "0n:s:tx")) != -1) 99 switch(ch) { 100 case '0': 101 zflag = 1; 102 break; 103 case 'n': 104 nflag = 1; 105 if ((nargs = atoi(optarg)) <= 0) 106 errx(1, "illegal argument count"); 107 break; 108 case 's': 109 nline = atoi(optarg); 110 break; 111 case 't': 112 tflag = 1; 113 break; 114 case 'x': 115 xflag = 1; 116 break; 117 case '?': 118 default: 119 usage(); 120 } 121 argc -= optind; 122 argv += optind; 123 124 if (xflag && !nflag) 125 usage(); 126 127 /* 128 * Allocate pointers for the utility name, the utility arguments, 129 * the maximum arguments to be read from stdin and the trailing 130 * NULL. 131 */ 132 if (!(av = bxp = 133 malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **)))) 134 err(1, "malloc"); 135 136 /* 137 * Use the user's name for the utility as argv[0], just like the 138 * shell. Echo is the default. Set up pointers for the user's 139 * arguments. 140 */ 141 if (!*argv) 142 cnt = strlen(*bxp++ = _PATH_ECHO); 143 else { 144 cnt = 0; 145 do { 146 cnt += strlen(*bxp++ = *argv) + 1; 147 } while (*++argv); 148 } 149 150 /* 151 * Set up begin/end/traversing pointers into the array. The -n 152 * count doesn't include the trailing NULL pointer, so the malloc 153 * added in an extra slot. 154 */ 155 exp = (xp = bxp) + nargs; 156 157 /* 158 * Allocate buffer space for the arguments read from stdin and the 159 * trailing NULL. Buffer space is defined as the default or specified 160 * space, minus the length of the utility name and arguments. Set up 161 * begin/end/traversing pointers into the array. The -s count does 162 * include the trailing NULL, so the malloc didn't add in an extra 163 * slot. 164 */ 165 nline -= cnt; 166 if (nline <= 0) 167 errx(1, "insufficient space for command"); 168 169 if (!(bbp = malloc((u_int)nline + 1))) 170 err(1, "malloc"); 171 ebp = (argp = p = bbp) + nline - 1; 172 173 for (insingle = indouble = 0;;) 174 switch(ch = getchar()) { 175 case EOF: 176 /* No arguments since last exec. */ 177 if (p == bbp) 178 exit(rval); 179 180 /* Nothing since end of last argument. */ 181 if (argp == p) { 182 *xp = NULL; 183 run(av); 184 exit(rval); 185 } 186 goto arg1; 187 case ' ': 188 case '\t': 189 /* Quotes escape tabs and spaces. */ 190 if (insingle || indouble || zflag) 191 goto addch; 192 goto arg2; 193 case '\0': 194 if (zflag) 195 goto arg2; 196 goto addch; 197 case '\n': 198 if (zflag) 199 goto addch; 200 /* Empty lines are skipped. */ 201 if (argp == p) 202 continue; 203 204 /* Quotes do not escape newlines. */ 205 arg1: if (insingle || indouble) 206 errx(1, "unterminated quote"); 207 208 arg2: *p = '\0'; 209 *xp++ = argp; 210 211 /* 212 * If max'd out on args or buffer, or reached EOF, 213 * run the command. If xflag and max'd out on buffer 214 * but not on args, object. 215 */ 216 if (xp == exp || p == ebp || ch == EOF) { 217 if (xflag && xp != exp && p == ebp) 218 errx(1, "insufficient space for arguments"); 219 *xp = NULL; 220 run(av); 221 if (ch == EOF) 222 exit(rval); 223 p = bbp; 224 xp = bxp; 225 } else 226 ++p; 227 argp = p; 228 break; 229 case '\'': 230 if (indouble || zflag) 231 goto addch; 232 insingle = !insingle; 233 break; 234 case '"': 235 if (insingle || zflag) 236 goto addch; 237 indouble = !indouble; 238 break; 239 case '\\': 240 if (zflag) 241 goto addch; 242 /* Backslash escapes anything, is escaped by quotes. */ 243 if (!insingle && !indouble && (ch = getchar()) == EOF) 244 errx(1, "backslash at EOF"); 245 /* FALLTHROUGH */ 246 default: 247 addch: if (p < ebp) { 248 *p++ = ch; 249 break; 250 } 251 252 /* If only one argument, not enough buffer space. */ 253 if (bxp == xp) 254 errx(1, "insufficient space for argument"); 255 /* Didn't hit argument limit, so if xflag object. */ 256 if (xflag) 257 errx(1, "insufficient space for arguments"); 258 259 *xp = NULL; 260 run(av); 261 xp = bxp; 262 cnt = ebp - argp; 263 memmove(bbp, argp, cnt); 264 p = (argp = bbp) + cnt; 265 *p++ = ch; 266 break; 267 } 268 /* NOTREACHED */ 269 } 270 271 void 272 run(argv) 273 char **argv; 274 { 275 volatile int noinvoke; 276 char **p; 277 pid_t pid; 278 int status; 279 280 if (tflag) { 281 (void)fprintf(stderr, "%s", *argv); 282 for (p = argv + 1; *p; ++p) 283 (void)fprintf(stderr, " %s", *p); 284 (void)fprintf(stderr, "\n"); 285 (void)fflush(stderr); 286 } 287 noinvoke = 0; 288 switch(pid = vfork()) { 289 case -1: 290 err(1, "vfork"); 291 case 0: 292 execvp(argv[0], argv); 293 noinvoke = (errno == ENOENT) ? 127 : 126; 294 warn("%s", argv[0]);; 295 _exit(1); 296 } 297 pid = waitpid(pid, &status, 0); 298 if (pid == -1) 299 err(1, "waitpid"); 300 301 /* 302 * If we couldn't invoke the utility or the utility didn't exit 303 * properly, quit with 127 or 126 respectively. 304 */ 305 if (noinvoke) 306 exit(noinvoke); 307 308 /* 309 * According to POSIX, we have to exit if the utility exits with 310 * a 255 status, or is interrupted by a signal. xargs is allowed 311 * to return any exit status between 1 and 125 in these cases, but 312 * we'll use 124 and 125, the same values used by GNU xargs. 313 */ 314 if (WIFEXITED(status)) { 315 if (WEXITSTATUS (status) == 255) { 316 warnx ("%s exited with status 255", argv[0]); 317 exit(124); 318 } else if (WEXITSTATUS (status) != 0) { 319 rval = 123; 320 } 321 } else if (WIFSIGNALED (status)) { 322 warnx ("%s terminated by signal %d", argv[0], WTERMSIG(status)); 323 exit(125); 324 } 325 } 326 327 void 328 usage() 329 { 330 (void)fprintf(stderr, 331 "usage: xargs [-0t] [-n number [-x]] [-s size] [utility [argument ...]]\n"); 332 exit(1); 333 } 334