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