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