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