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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)xargs.c 5.3 (Berkeley) 05/15/90"; 19 #endif /* not lint */ 20 21 #include <sys/types.h> 22 #include <sys/wait.h> 23 #include <errno.h> 24 #include <stdio.h> 25 #include <string.h> 26 #include <limits.h> 27 #include "pathnames.h" 28 29 #define DEF_ARGC 255 30 31 int tflag; 32 33 main(argc, argv) 34 int argc; 35 char **argv; 36 { 37 extern int errno, optind; 38 extern char *optarg; 39 register int ch; 40 register char *p, *bp, *endbp, **bxp, **endxp, **xp; 41 int cnt, indouble, insingle, nargs, nline; 42 char *mark, *prog, **xargs, *malloc(); 43 44 nargs = DEF_ARGC; 45 nline = LINE_MAX; 46 47 while ((ch = getopt(argc, argv, "n:s:t")) != EOF) 48 switch(ch) { 49 case 'n': 50 if ((nargs = atoi(optarg)) <= 0) { 51 (void)fprintf(stderr, 52 "xargs: bad argument count.\n"); 53 exit(1); 54 } 55 break; 56 case 's': 57 if ((nline = atoi(optarg)) <= 0) { 58 (void)fprintf(stderr, 59 "xargs: bad command length.\n"); 60 exit(1); 61 } 62 break; 63 case 't': 64 tflag = 1; 65 break; 66 case '?': 67 default: 68 usage(); 69 } 70 argc -= optind; 71 argv += optind; 72 73 /* room for the command, leftover arguments and trailing NULL */ 74 if (!(xargs = 75 (char **)malloc((u_int)(nargs + argc + 2) * sizeof(char **)))) 76 enomem(); 77 78 if (!(bp = malloc((u_int)nline + 1))) 79 enomem(); 80 81 xp = xargs + 1; 82 if (!*argv) 83 prog = _PATH_ECHO; 84 else { 85 prog = *argv; 86 while (*++argv) 87 *xp++ = *argv; 88 } 89 90 if (xargs[0] = rindex(prog, '/')) 91 ++xargs[0]; 92 else 93 xargs[0] = prog; 94 95 /* set up the pointers into the buffer and the arguments */ 96 *(endxp = (bxp = xp) + nargs) = NULL; 97 endbp = (mark = p = bp) + nline; 98 99 insingle = indouble = 0; 100 for (;;) 101 switch(ch = getchar()) { 102 case EOF: 103 if (p == bp) /* nothing to display */ 104 exit(0); 105 if (mark == p) { /* nothing since last arg end */ 106 run(prog, xargs); 107 exit(0); 108 } 109 goto addarg; 110 case ' ': 111 case '\t': 112 if (insingle || indouble) 113 goto addch; 114 goto addarg; 115 case '\n': 116 if (mark == p) /* empty line */ 117 continue; 118 addarg: *xp++ = mark; 119 *p++ = '\0'; 120 if (xp == endxp || p >= endbp || ch == EOF) { 121 if (insingle || indouble) { 122 (void)fprintf(stderr, 123 "xargs: unterminated quote.\n"); 124 exit(1); 125 } 126 run(prog, xargs); 127 if (ch == EOF) 128 exit(0); 129 p = bp; 130 xp = bxp; 131 } 132 mark = p; 133 break; 134 case '\'': 135 if (indouble) 136 goto addch; 137 insingle = !insingle; 138 break; 139 case '"': 140 if (insingle) 141 goto addch; 142 indouble = !indouble; 143 break; 144 case '\\': 145 if ((ch = getchar()) == EOF) 146 ch = '\\'; 147 if (ch == '\n') { 148 (void)fprintf(stderr, 149 "xargs: newline may not be escaped.\n"); 150 exit(1); 151 } 152 /* FALLTHROUGH */ 153 default: 154 addch: if (p != endbp) { 155 *p++ = ch; 156 continue; 157 } 158 if (xp == bxp) { 159 (void)fprintf(stderr, 160 "xargs: argument too large.\n"); 161 exit(1); 162 } 163 *xp = NULL; 164 run(prog, xargs); 165 cnt = endbp - mark; 166 bcopy(mark, bp, cnt); 167 p = (mark = bp) + cnt; 168 *p++ = ch; 169 xp = bxp; 170 break; 171 } 172 /* NOTREACHED */ 173 } 174 175 run(prog, argv) 176 char *prog, **argv; 177 { 178 union wait pstat; 179 pid_t pid, waitpid(); 180 char **p; 181 182 if (tflag) { 183 (void)fprintf(stderr, "%s", *argv); 184 for (p = argv + 1; *p; ++p) 185 (void)fprintf(stderr, " %s", *p); 186 (void)fprintf(stderr, "\n"); 187 (void)fflush(stderr); 188 } 189 switch(pid = vfork()) { 190 case -1: 191 (void)fprintf(stderr, 192 "xargs: vfork: %s.\n", strerror(errno)); 193 exit(1); 194 case 0: 195 execvp(prog, argv); 196 (void)fprintf(stderr, 197 "xargs: %s: %s.\n", prog, strerror(errno)); 198 _exit(1); 199 } 200 pid = waitpid(pid, &pstat, 0); 201 if (pid == -1) { 202 (void)fprintf(stderr, 203 "xargs: waitpid: %s.\n", strerror(errno)); 204 exit(1); 205 } 206 if (pstat.w_status) 207 exit(1); 208 } 209 210 enomem() 211 { 212 (void)fprintf(stderr, "xargs: %s.\n", strerror(ENOMEM)); 213 exit(1); 214 } 215 216 usage() 217 { 218 (void)fprintf(stderr, 219 "xargs: [-t] [-n number] [-s size] [utility [argument ...]]\n"); 220 exit(1); 221 } 222