# 2.11BSD#431 - /usr/src/usr.bin/xargs/xargs.c

##### Functions

    err               X
    main              X
    run               X
    usage             X

##### Variables

    rval              X
    tflag             X

##### Macros

    ARG_MAX           X

       1: /*-
       2:  * Copyright (c) 1990, 1993
       3:  *	The Regents of the University of California.  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: #if defined(DOSCCS) && !defined(lint)
      38: static char copyright[] =
      39: "@(#) Copyright (c) 1990, 1993\n\
      40: 	The Regents of the University of California.  All rights reserved.\n";
      41: #endif
      42:
      43: #if defined(DOSCCS) && !defined(lint)
      44: static char sccsid[] = "@(#)xargs.c	8.1 (Berkeley) 6/6/93";
      45: #endif
      46:
      47: #include <sys/param.h>
      48: #include <sys/types.h>
      49: #include <sys/wait.h>
      50: #include <errno.h>
      51: #include <stdio.h>
      52: #include "pathnames.h"
      53:
      54: extern int errno;
      55: extern char *optarg;
      56: extern int optind;
      57:
      58: /*
      59:  * This is defined for pdp11s.  ARG_MAX is usually defined in
      60:  * an include file.  I have left it here until such times as
      61:  * the system limits stuff in machparam etc is changed to the
      62:  * same names as 4.4. Note that
      63:  * this is much smaller than the normal value cos it's only a
      64:  * small computer (sigh).
      65:  */
      66:
      67: #define ARG_MAX NCARGS
      68:
      69: int tflag, rval;
      70:
      71: void err();
      72: void run();
      73: void usage();
      74:
      75: main(argc, argv)
      76:     int argc;
      77:     char **argv;
      78: {
      79:     register int ch;
      80:     register char *p, *bbp, *ebp, **bxp, **exp, **xp;
      81:     int cnt, indouble, insingle, nargs, nflag, nline, xflag;
      82:     char **av, *argp;
      83:
      84:     /*
      85: 	 * POSIX.2 limits the exec line length to ARG_MAX - 2K.  Running that
      86: 	 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K.  Given
      87: 	 * that the smallest argument is 2 bytes in length, this means that
      88: 	 * the number of arguments is limited to:
      89: 	 *
      90: 	 *	 (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
      91: 	 *
      92: 	 * We arbitrarily limit the number of arguments to 5000.  This is
      93: 	 * allowed by POSIX.2 as long as the resulting minimum exec line is
      94: 	 * at least LINE_MAX.  Realloc'ing as necessary is possible, but
      95: 	 * probably not worthwhile.
      96: 	 */
      97:     nargs = 5000;
      98:     nline = ARG_MAX - 4 * 1024;
      99:     nflag = xflag = 0;
     100:     while ((ch = getopt(argc, argv, "n:s:tx")) != EOF)
     101:         switch(ch) {
     102:         case 'n':
     103:             nflag = 1;
     104:             if ((nargs = atoi(optarg)) <= 0)
     105:                 err("illegal argument count");
     106:             break;
     107:         case 's':
     108:             nline = atoi(optarg);
     109:             break;
     110:         case 't':
     111:             tflag = 1;
     112:             break;
     113:         case 'x':
     114:             xflag = 1;
     115:             break;
     116:         case '?':
     117:         default:
     118:             usage();
     119:     }
     120:     argc -= optind;
     121:     argv += optind;
     122:
     123:     if (xflag && !nflag)
     124:         usage();
     125:
     126:     /*
     127: 	 * Allocate pointers for the utility name, the utility arguments,
     128: 	 * the maximum arguments to be read from stdin and the trailing
     129: 	 * NULL.
     130: 	 */
     131:     if (!(av = bxp =
     132:         (char **)malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **))))
     133:         err("%s", strerror(errno));
     134:
     135:     /*
     136: 	 * Use the user's name for the utility as argv[0], just like the
     137: 	 * shell.  Echo is the default.  Set up pointers for the user's
     138: 	 * arguments.
     139: 	 */
     140:     if (!*argv)
     141:         cnt = strlen(*bxp++ = _PATH_ECHO);
     142:     else {
     143:         cnt = 0;
     144:         do {
     145:             cnt += strlen(*bxp++ = *argv) + 1;
     146:         } while (*++argv);
     147:     }
     148:
     149:     /*
     150: 	 * Set up begin/end/traversing pointers into the array.  The -n
     151: 	 * count doesn't include the trailing NULL pointer, so the malloc
     152: 	 * added in an extra slot.
     153: 	 */
     154:     exp = (xp = bxp) + nargs;
     155:
     156:     /*
     157: 	 * Allocate buffer space for the arguments read from stdin and the
     158: 	 * trailing NULL.  Buffer space is defined as the default or specified
     159: 	 * space, minus the length of the utility name and arguments.  Set up
     160: 	 * begin/end/traversing pointers into the array.  The -s count does
     161: 	 * include the trailing NULL, so the malloc didn't add in an extra
     162: 	 * slot.
     163: 	 */
     164:     nline -= cnt;
     165:     if (nline <= 0)
     166:         err("insufficient space for command");
     167:
     168:     if (!(bbp = (char *)malloc((u_int)nline + 1)))
     169:         err("%s", strerror(errno));
     170:     ebp = (argp = p = bbp) + nline - 1;
     171:
     172:     for (insingle = indouble = 0;;)
     173:         switch(ch = getchar()) {
     174:         case EOF:
     175:             /* No arguments since last exec. */
     176:             if (p == bbp)
     177:                 exit(rval);
     178:
     179:             /* Nothing since end of last argument. */
     180:             if (argp == p) {
     181:                 *xp = NULL;
     182:                 run(av);
     183:                 exit(rval);
     184:             }
     185:             goto arg1;
     186:         case ' ':
     187:         case '\t':
     188:             /* Quotes escape tabs and spaces. */
     189:             if (insingle || indouble)
     190:                 goto addch;
     191:             goto arg2;
     192:         case '\n':
     193:             /* Empty lines are skipped. */
     194:             if (argp == p)
     195:                 continue;
     196:
     197:             /* Quotes do not escape newlines. */
     198: arg1:           if (insingle || indouble)
     199:                  err("unterminated quote");
     200:
     201: arg2:           *p = '\0';
     202:             *xp++ = argp;
     203:
     204:             /*
     205: 			 * If max'd out on args or buffer, or reached EOF,
     206: 			 * run the command.  If xflag and max'd out on buffer
     207: 			 * but not on args, object.
     208: 			 */
     209:             if (xp == exp || p == ebp || ch == EOF) {
     210:                 if (xflag && xp != exp && p == ebp)
     211:                     err("insufficient space for arguments");
     212:                 *xp = NULL;
     213:                 run(av);
     214:                 if (ch == EOF)
     215:                     exit(rval);
     216:                 p = bbp;
     217:                 xp = bxp;
     218:             } else
     219:                 ++p;
     220:             argp = p;
     221:             break;
     222:         case '\'':
     223:             if (indouble)
     224:                 goto addch;
     225:             insingle = !insingle;
     226:             break;
     227:         case '"':
     228:             if (insingle)
     229:                 goto addch;
     230:             indouble = !indouble;
     231:             break;
     232:         case '\\':
     233:             /* Backslash escapes anything, is escaped by quotes. */
     234:             if (!insingle && !indouble && (ch = getchar()) == EOF)
     235:                 err("backslash at EOF");
     236:             /* FALLTHROUGH */
     237:         default:
     238: addch:          if (p < ebp) {
     239:                 *p++ = ch;
     240:                 break;
     241:             }
     242:
     243:             /* If only one argument, not enough buffer space. */
     244:             if (bxp == xp)
     245:                 err("insufficient space for argument");
     246:             /* Didn't hit argument limit, so if xflag object. */
     247:             if (xflag)
     248:                 err("insufficient space for arguments");
     249:
     250:             *xp = NULL;
     251:             run(av);
     252:             xp = bxp;
     253:             cnt = ebp - argp;
     254:             bcopy(argp, bbp, cnt);
     255:             p = (argp = bbp) + cnt;
     256:             *p++ = ch;
     257:             break;
     258:         }
     259:     /* NOTREACHED */
     260: }
     261:
     262: void
     263: run(argv)
     264:     char **argv;
     265: {
     266:     int noinvoke;
     267:     register char **p;
     268:     pid_t pid;
     269:     union wait status;
     270:
     271:     if (tflag) {
     272:         (void)fprintf(stderr, "%s", *argv);
     273:         for (p = argv + 1; *p; ++p)
     274:             (void)fprintf(stderr, " %s", *p);
     275:         (void)fprintf(stderr, "\n");
     276:         (void)fflush(stderr);
     277:     }
     278:     noinvoke = 0;
     279:     switch(pid = vfork()) {
     280:     case -1:
     281:         err("vfork: %s", strerror(errno));
     282:     case 0:
     283:         execvp(argv[0], argv);
     284:         (void)fprintf(stderr,
     285:             "xargs: %s: %s\n", argv[0], strerror(errno));
     286:         noinvoke = 1;
     287:         _exit(1);
     288:     }
     289:     pid = waitpid(pid, &status, 0);
     290:     if (pid == -1)
     291:         err("waitpid: %s", strerror(errno));
     292:     /* If we couldn't invoke the utility, exit 127. */
     293:     if (noinvoke)
     294:         exit(127);
     295:     /* If utility signaled or exited with a value of 255, exit 1-125. */
     296:     if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
     297:         exit(1);
     298:     if (WEXITSTATUS(status))
     299:         rval = 1;
     300: }
     301:
     302: void
     303: usage()
     304: {
     305:     (void)fprintf(stderr,
     306: "usage: xargs [-t] [-n number [-x]] [-s size] [utility [argument ...]]\n");
     307:     exit(1);
     308: }
     309:
     310: #if __STDC__
     311: #include <stdarg.h>
     312: #else
     313: #include <varargs.h>
     314: #endif
     315:
     316: void
     317: #if __STDC__
     318: err(const char *fmt, ...)
     319: #else
     320: err(fmt, va_alist)
     321:     char *fmt;
     322:         va_dcl
     323: #endif
     324: {
     325:     va_list ap;
     326: #if __STDC__
     327:     va_start(ap, fmt);
     328: #else
     329:     va_start(ap);
     330: #endif
     331:     (void)fprintf(stderr, "xargs: ");
     332:     (void)vfprintf(stderr, fmt, ap);
     333:     va_end(ap);
     334:     (void)fprintf(stderr, "\n");
     335:     exit(1);
     336:     /* NOTREACHED */
     337: }

#### Defined functions

err defined in line 316; used 12 times

- in line 71, 105, 133, 166-169(2), 199, 211, 235, 245-248(2), 281, 291

main defined in line 75; never used
run defined in line 262; used 4 times

- in line 72, 182, 213, 251

usage defined in line 302; used 3 times

- in line 73, 118, 124

#### Defined variables

copyright defined in line 38; never used
rval defined in line 69; used 4 times

- in line 177, 183, 215, 299

sccsid defined in line 44; never used
tflag defined in line 69; used 2 times

- in line 111, 271

#### Defined macros

ARG_MAX defined in line 67; used 1 times

- in line 98

Last modified: 1995-06-24 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1488 |