1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <stdio.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 36*7c478bd9Sstevel@tonic-gate #include <unistd.h> 37*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 38*7c478bd9Sstevel@tonic-gate #include <string.h> 39*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 40*7c478bd9Sstevel@tonic-gate #include <libgen.h> 41*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 42*7c478bd9Sstevel@tonic-gate #include <limits.h> 43*7c478bd9Sstevel@tonic-gate #include <wchar.h> 44*7c478bd9Sstevel@tonic-gate #include <locale.h> 45*7c478bd9Sstevel@tonic-gate #include <langinfo.h> 46*7c478bd9Sstevel@tonic-gate #include <stropts.h> 47*7c478bd9Sstevel@tonic-gate #include <poll.h> 48*7c478bd9Sstevel@tonic-gate #include <errno.h> 49*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #define HEAD 0 52*7c478bd9Sstevel@tonic-gate #define TAIL 1 53*7c478bd9Sstevel@tonic-gate #define FALSE 0 54*7c478bd9Sstevel@tonic-gate #define TRUE 1 55*7c478bd9Sstevel@tonic-gate #define MAXSBUF 255 56*7c478bd9Sstevel@tonic-gate #define MAXIBUF 512 57*7c478bd9Sstevel@tonic-gate #define MAXINSERTS 5 58*7c478bd9Sstevel@tonic-gate #define BUFSIZE LINE_MAX 59*7c478bd9Sstevel@tonic-gate #define MAXARGS 255 60*7c478bd9Sstevel@tonic-gate #define INSPAT_STR "{}" /* default replstr string for -[Ii] */ 61*7c478bd9Sstevel@tonic-gate #define FORK_RETRY 5 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #define QBUF_STARTLEN 255 /* start size of growable string buffer */ 64*7c478bd9Sstevel@tonic-gate #define QBUF_INC 100 /* how much to grow a growable string by */ 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate static wctype_t blank; 67*7c478bd9Sstevel@tonic-gate static char *arglist[MAXARGS+1]; 68*7c478bd9Sstevel@tonic-gate static char argbuf[BUFSIZE+1]; 69*7c478bd9Sstevel@tonic-gate static char *next = argbuf; 70*7c478bd9Sstevel@tonic-gate static char *lastarg = ""; 71*7c478bd9Sstevel@tonic-gate static char **ARGV = arglist; 72*7c478bd9Sstevel@tonic-gate static char *LEOF = "_"; 73*7c478bd9Sstevel@tonic-gate static char *INSPAT = INSPAT_STR; 74*7c478bd9Sstevel@tonic-gate static char ins_buf[MAXIBUF]; 75*7c478bd9Sstevel@tonic-gate static char *p_ibuf; 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate static struct inserts { 78*7c478bd9Sstevel@tonic-gate char **p_ARGV; /* where to put newarg ptr in arg list */ 79*7c478bd9Sstevel@tonic-gate char *p_skel; /* ptr to arg template */ 80*7c478bd9Sstevel@tonic-gate } saveargv[MAXINSERTS]; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate static off_t file_offset = 0; 83*7c478bd9Sstevel@tonic-gate static int PROMPT = -1; 84*7c478bd9Sstevel@tonic-gate static int BUFLIM = BUFSIZE; 85*7c478bd9Sstevel@tonic-gate static int N_ARGS = 0; 86*7c478bd9Sstevel@tonic-gate static int N_args = 0; 87*7c478bd9Sstevel@tonic-gate static int N_lines = 0; 88*7c478bd9Sstevel@tonic-gate static int DASHX = FALSE; 89*7c478bd9Sstevel@tonic-gate static int MORE = TRUE; 90*7c478bd9Sstevel@tonic-gate static int PER_LINE = FALSE; 91*7c478bd9Sstevel@tonic-gate static int ERR = FALSE; 92*7c478bd9Sstevel@tonic-gate static int OK = TRUE; 93*7c478bd9Sstevel@tonic-gate static int LEGAL = FALSE; 94*7c478bd9Sstevel@tonic-gate static int TRACE = FALSE; 95*7c478bd9Sstevel@tonic-gate static int INSERT = FALSE; 96*7c478bd9Sstevel@tonic-gate static int linesize = 0; 97*7c478bd9Sstevel@tonic-gate static int ibufsize = 0; 98*7c478bd9Sstevel@tonic-gate static char *yesstr; /* the string contains int'l for "yes" */ 99*7c478bd9Sstevel@tonic-gate static int exitstat = 0; /* our exit status */ 100*7c478bd9Sstevel@tonic-gate static int mac; /* modified argc, after parsing */ 101*7c478bd9Sstevel@tonic-gate static char **mav; /* modified argv, after parsing */ 102*7c478bd9Sstevel@tonic-gate static int n_inserts; /* # of insertions. */ 103*7c478bd9Sstevel@tonic-gate static int inquote = 0; /* processing a quoted string */ 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * the pio structure is used to save any pending input before the 107*7c478bd9Sstevel@tonic-gate * user replies to a prompt. the pending input is saved here, 108*7c478bd9Sstevel@tonic-gate * for the appropriate processing later. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate typedef struct pio { 111*7c478bd9Sstevel@tonic-gate struct pio *next; /* next in stack */ 112*7c478bd9Sstevel@tonic-gate char *start; /* starting addr of the buffer */ 113*7c478bd9Sstevel@tonic-gate char *cur; /* ptr to current char in buf */ 114*7c478bd9Sstevel@tonic-gate size_t length; /* number of bytes remaining */ 115*7c478bd9Sstevel@tonic-gate } pio; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate static pio *queued_data = NULL; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* our usage message: */ 120*7c478bd9Sstevel@tonic-gate #define USAGEMSG "Usage: xargs: [-t] [-p] [-e[eofstr]] [-E eofstr] "\ 121*7c478bd9Sstevel@tonic-gate "[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-s size] "\ 122*7c478bd9Sstevel@tonic-gate "[cmd [args ...]]\n" 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate static int echoargs(); 125*7c478bd9Sstevel@tonic-gate static int getchr(void); 126*7c478bd9Sstevel@tonic-gate static wchar_t getwchr(void); 127*7c478bd9Sstevel@tonic-gate static void ungetwchr(wchar_t); 128*7c478bd9Sstevel@tonic-gate static int lcall(char *sub, char **subargs); 129*7c478bd9Sstevel@tonic-gate static int xindex(char *as1, char *as2); 130*7c478bd9Sstevel@tonic-gate static void addibuf(struct inserts *p); 131*7c478bd9Sstevel@tonic-gate static void ermsg(char *messages, ...); 132*7c478bd9Sstevel@tonic-gate static char *addarg(char *arg); 133*7c478bd9Sstevel@tonic-gate static char *checklen(char *arg); 134*7c478bd9Sstevel@tonic-gate static size_t store_wchr(char **, size_t *, size_t, wchar_t); 135*7c478bd9Sstevel@tonic-gate static char *getarg(); 136*7c478bd9Sstevel@tonic-gate static char *insert(char *pattern, char *subst); 137*7c478bd9Sstevel@tonic-gate static void usage(); 138*7c478bd9Sstevel@tonic-gate static void parseargs(); 139*7c478bd9Sstevel@tonic-gate static void saveinput(); 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate void 143*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 144*7c478bd9Sstevel@tonic-gate { 145*7c478bd9Sstevel@tonic-gate int j; 146*7c478bd9Sstevel@tonic-gate struct inserts *psave; 147*7c478bd9Sstevel@tonic-gate int c; 148*7c478bd9Sstevel@tonic-gate int initsize; 149*7c478bd9Sstevel@tonic-gate char *cmdname, *initbuf, **initlist; 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* initialization */ 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate blank = wctype("blank"); 155*7c478bd9Sstevel@tonic-gate n_inserts = 0; 156*7c478bd9Sstevel@tonic-gate psave = saveargv; 157*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 158*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 159*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 160*7c478bd9Sstevel@tonic-gate #endif 161*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * now we get the appropriate "yes" string for our locale. 165*7c478bd9Sstevel@tonic-gate * since this may be a multibyte character, we store the 166*7c478bd9Sstevel@tonic-gate * string which is returned. later on, when we're looking for 167*7c478bd9Sstevel@tonic-gate * a "y" in response to our prompt, we'll use the first 168*7c478bd9Sstevel@tonic-gate * multibyte character of yesstr as a comparision. 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate initbuf = nl_langinfo(YESSTR); /* initbuf is a tmp placeholder here */ 171*7c478bd9Sstevel@tonic-gate if ((yesstr = malloc(strlen(initbuf) + 1)) == NULL) { 172*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 173*7c478bd9Sstevel@tonic-gate exit(1); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate (void) strcpy(yesstr, initbuf); 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate parseargs(argc, argv); 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* handling all of xargs arguments: */ 180*7c478bd9Sstevel@tonic-gate while ((c = getopt(mac, mav, "tpe:E:I:i:L:l:n:s:x")) != EOF) { 181*7c478bd9Sstevel@tonic-gate switch (c) { 182*7c478bd9Sstevel@tonic-gate case 't': /* -t: turn trace mode on */ 183*7c478bd9Sstevel@tonic-gate TRACE = TRUE; 184*7c478bd9Sstevel@tonic-gate break; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate case 'p': /* -p: turn on prompt mode. */ 187*7c478bd9Sstevel@tonic-gate if ((PROMPT = open("/dev/tty", O_RDONLY)) == -1) { 188*7c478bd9Sstevel@tonic-gate perror(gettext("can't read from tty for -p")); 189*7c478bd9Sstevel@tonic-gate } else { 190*7c478bd9Sstevel@tonic-gate TRACE = TRUE; 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate break; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate case 'e': 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * -e[eofstr]: set/disable end-of-file. 197*7c478bd9Sstevel@tonic-gate * N.B. that an argument *isn't* required here; but 198*7c478bd9Sstevel@tonic-gate * parseargs forced an argument if not was given. The 199*7c478bd9Sstevel@tonic-gate * forced argument is the default... 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate LEOF = optarg; /* can be empty */ 202*7c478bd9Sstevel@tonic-gate break; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate case 'E': 205*7c478bd9Sstevel@tonic-gate /* 206*7c478bd9Sstevel@tonic-gate * -E eofstr: change end-of-file string. 207*7c478bd9Sstevel@tonic-gate * eofstr *is* required here: 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate LEOF = optarg; 210*7c478bd9Sstevel@tonic-gate #ifdef XPG6 211*7c478bd9Sstevel@tonic-gate if (LEOF == NULL) { 212*7c478bd9Sstevel@tonic-gate #else 213*7c478bd9Sstevel@tonic-gate if ((LEOF == NULL) || (*LEOF == NULL)) { 214*7c478bd9Sstevel@tonic-gate #endif 215*7c478bd9Sstevel@tonic-gate ermsg(gettext("Must specify subargment to -E " 216*7c478bd9Sstevel@tonic-gate " flag\n")); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate break; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate case 'I': 221*7c478bd9Sstevel@tonic-gate /* -I replstr: Insert mode. replstr *is* required. */ 222*7c478bd9Sstevel@tonic-gate INSERT = PER_LINE = LEGAL = TRUE; 223*7c478bd9Sstevel@tonic-gate N_ARGS = 0; 224*7c478bd9Sstevel@tonic-gate if (*optarg) { 225*7c478bd9Sstevel@tonic-gate INSPAT = optarg; 226*7c478bd9Sstevel@tonic-gate } else { 227*7c478bd9Sstevel@tonic-gate ermsg(gettext("Must specify subargment " 228*7c478bd9Sstevel@tonic-gate "for -I\n")); 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate break; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate case 'i': 233*7c478bd9Sstevel@tonic-gate /* 234*7c478bd9Sstevel@tonic-gate * -i [replstr]: insert mode, with *optional* replstr. 235*7c478bd9Sstevel@tonic-gate * N.B. that an argument *isn't* required here; if 236*7c478bd9Sstevel@tonic-gate * it's not given, then the string INSPAT_STR will 237*7c478bd9Sstevel@tonic-gate * be assumed. 238*7c478bd9Sstevel@tonic-gate * 239*7c478bd9Sstevel@tonic-gate * Since getopts(3C) doesn't handle the case of an 240*7c478bd9Sstevel@tonic-gate * optional variable argument at all, we have to 241*7c478bd9Sstevel@tonic-gate * parse this by hand: 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate INSERT = PER_LINE = LEGAL = TRUE; 245*7c478bd9Sstevel@tonic-gate N_ARGS = 0; 246*7c478bd9Sstevel@tonic-gate if (optarg[0] != NULL) { 247*7c478bd9Sstevel@tonic-gate INSPAT = optarg; 248*7c478bd9Sstevel@tonic-gate } else { 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * here, there is no next argument. so 251*7c478bd9Sstevel@tonic-gate * we reset INSPAT to the INSPAT_STR. 252*7c478bd9Sstevel@tonic-gate * we *have* to do this, as -i/I may have 253*7c478bd9Sstevel@tonic-gate * been given previously, and XCU4 requires 254*7c478bd9Sstevel@tonic-gate * that only "the last one specified takes 255*7c478bd9Sstevel@tonic-gate * effect". 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate INSPAT = INSPAT_STR; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate break; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate case 'L': 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate * -L number: # of times cmd is executed 264*7c478bd9Sstevel@tonic-gate * number *is* required here: 265*7c478bd9Sstevel@tonic-gate */ 266*7c478bd9Sstevel@tonic-gate PER_LINE = TRUE; 267*7c478bd9Sstevel@tonic-gate N_ARGS = 0; 268*7c478bd9Sstevel@tonic-gate INSERT = FALSE; 269*7c478bd9Sstevel@tonic-gate if (optarg && (PER_LINE = atoi(optarg)) <= 0) { 270*7c478bd9Sstevel@tonic-gate ermsg(gettext("#lines must be positive " 271*7c478bd9Sstevel@tonic-gate "int: %s\n"), optarg); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate break; 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate case 'l': 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * -l [number]: # of times cmd is executed 278*7c478bd9Sstevel@tonic-gate * N.B. that an argument *isn't* required here; if 279*7c478bd9Sstevel@tonic-gate * it's not given, then 1 is assumed. 280*7c478bd9Sstevel@tonic-gate * 281*7c478bd9Sstevel@tonic-gate * parseargs handles the optional arg processing. 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate PER_LINE = LEGAL = TRUE; /* initialization */ 285*7c478bd9Sstevel@tonic-gate N_ARGS = 0; 286*7c478bd9Sstevel@tonic-gate INSERT = FALSE; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate if (optarg[0] != NULL) { 289*7c478bd9Sstevel@tonic-gate if ((PER_LINE = atoi(optarg)) <= 0) 290*7c478bd9Sstevel@tonic-gate PER_LINE = 1; 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate break; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate case 'n': /* -n number: # stdin args */ 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * -n number: # stdin args. 297*7c478bd9Sstevel@tonic-gate * number *is* required here: 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate if ((N_ARGS = atoi(optarg)) <= 0) { 300*7c478bd9Sstevel@tonic-gate ermsg(gettext("#args must be positive " 301*7c478bd9Sstevel@tonic-gate "int: %s\n"), optarg); 302*7c478bd9Sstevel@tonic-gate } else { 303*7c478bd9Sstevel@tonic-gate LEGAL = DASHX || N_ARGS == 1; 304*7c478bd9Sstevel@tonic-gate INSERT = PER_LINE = FALSE; 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate break; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate case 's': /* -s size: set max size of each arg list */ 309*7c478bd9Sstevel@tonic-gate BUFLIM = atoi(optarg); 310*7c478bd9Sstevel@tonic-gate if (BUFLIM > BUFSIZE || BUFLIM <= 0) { 311*7c478bd9Sstevel@tonic-gate ermsg(gettext("0 < max-cmd-line-size <= %d: " 312*7c478bd9Sstevel@tonic-gate "%s\n"), BUFSIZE, optarg); 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate break; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate case 'x': /* -x: terminate if args > size limit */ 317*7c478bd9Sstevel@tonic-gate DASHX = LEGAL = TRUE; 318*7c478bd9Sstevel@tonic-gate break; 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate default: 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * bad argument. complain and get ready to die. 323*7c478bd9Sstevel@tonic-gate */ 324*7c478bd9Sstevel@tonic-gate ERR = TRUE; 325*7c478bd9Sstevel@tonic-gate usage(); 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate exit(2); 328*7c478bd9Sstevel@tonic-gate break; 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * if anything called ermsg(), something screwed up, so 334*7c478bd9Sstevel@tonic-gate * we exit early. 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate if (OK == FALSE) { 337*7c478bd9Sstevel@tonic-gate ERR = TRUE; 338*7c478bd9Sstevel@tonic-gate usage(); 339*7c478bd9Sstevel@tonic-gate exit(2); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * we're finished handling xargs's options, so now pick up 344*7c478bd9Sstevel@tonic-gate * the command name (if any), and it's options. 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate mac -= optind; /* dec arg count by what we've processed */ 349*7c478bd9Sstevel@tonic-gate mav += optind; /* inc to current mav */ 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if (mac <= 0) { /* if there're no more args to process, */ 352*7c478bd9Sstevel@tonic-gate cmdname = "/usr/bin/echo"; /* our default command */ 353*7c478bd9Sstevel@tonic-gate *ARGV++ = addarg(cmdname); /* use the default cmd. */ 354*7c478bd9Sstevel@tonic-gate } else { /* otherwise keep parsing rest of the string. */ 355*7c478bd9Sstevel@tonic-gate /* 356*7c478bd9Sstevel@tonic-gate * note that we can't use getopts(3C), and *must* parse 357*7c478bd9Sstevel@tonic-gate * this by hand, as we don't know apriori what options the 358*7c478bd9Sstevel@tonic-gate * command will take. 359*7c478bd9Sstevel@tonic-gate */ 360*7c478bd9Sstevel@tonic-gate cmdname = *mav; /* get the command name */ 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* pick up the remaining args from the command line: */ 364*7c478bd9Sstevel@tonic-gate while ((OK == TRUE) && (mac-- > 0)) { 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * while we haven't crapped out, and there's 367*7c478bd9Sstevel@tonic-gate * work to do: 368*7c478bd9Sstevel@tonic-gate */ 369*7c478bd9Sstevel@tonic-gate if (INSERT && ! ERR) { 370*7c478bd9Sstevel@tonic-gate if (xindex(*mav, INSPAT) != -1) { 371*7c478bd9Sstevel@tonic-gate if (++n_inserts > MAXINSERTS) { 372*7c478bd9Sstevel@tonic-gate ermsg(gettext("too many args " 373*7c478bd9Sstevel@tonic-gate "with %s\n"), INSPAT); 374*7c478bd9Sstevel@tonic-gate ERR = TRUE; 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate psave->p_ARGV = ARGV; 377*7c478bd9Sstevel@tonic-gate (psave++)->p_skel = *mav; 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate *ARGV++ = addarg(*mav++); 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate /* pick up args from standard input */ 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate initbuf = next; 387*7c478bd9Sstevel@tonic-gate initlist = ARGV; 388*7c478bd9Sstevel@tonic-gate initsize = linesize; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate while (OK && MORE) { 391*7c478bd9Sstevel@tonic-gate N_args = 0; 392*7c478bd9Sstevel@tonic-gate N_lines = 0; 393*7c478bd9Sstevel@tonic-gate next = initbuf; 394*7c478bd9Sstevel@tonic-gate ARGV = initlist; 395*7c478bd9Sstevel@tonic-gate linesize = initsize; 396*7c478bd9Sstevel@tonic-gate if (*lastarg) { 397*7c478bd9Sstevel@tonic-gate *ARGV++ = addarg(lastarg); 398*7c478bd9Sstevel@tonic-gate lastarg = ""; 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate while (((ARGV - arglist) < MAXARGS) && 402*7c478bd9Sstevel@tonic-gate ((*ARGV++ = getarg()) != NULL) && OK) 403*7c478bd9Sstevel@tonic-gate ; 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate /* insert arg if requested */ 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate if (!ERR && INSERT) { 408*7c478bd9Sstevel@tonic-gate if ((!MORE) && (N_lines == 0)) { 409*7c478bd9Sstevel@tonic-gate exit(exitstat); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate /* no more input lines */ 412*7c478bd9Sstevel@tonic-gate p_ibuf = ins_buf; 413*7c478bd9Sstevel@tonic-gate ARGV--; 414*7c478bd9Sstevel@tonic-gate j = ibufsize = 0; 415*7c478bd9Sstevel@tonic-gate for (psave = saveargv; ++j <= n_inserts; ++psave) { 416*7c478bd9Sstevel@tonic-gate addibuf(psave); 417*7c478bd9Sstevel@tonic-gate if (ERR) 418*7c478bd9Sstevel@tonic-gate break; 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate *ARGV = 0; 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate if (n_inserts > 0) { 424*7c478bd9Sstevel@tonic-gate int t_ninserts; 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* 427*7c478bd9Sstevel@tonic-gate * if we've done any insertions, re-calculate the 428*7c478bd9Sstevel@tonic-gate * linesize. bomb out if we've exceeded our length. 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate t_ninserts = n_inserts; 431*7c478bd9Sstevel@tonic-gate n_inserts = 0; /* inserts have been done */ 432*7c478bd9Sstevel@tonic-gate linesize = 0; /* recalculate this */ 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate /* for each current argument in the list: */ 435*7c478bd9Sstevel@tonic-gate for (ARGV = arglist; *ARGV != NULL; ARGV++) { 436*7c478bd9Sstevel@tonic-gate /* recalculate everything. */ 437*7c478bd9Sstevel@tonic-gate if (checklen(*ARGV) != 0) { 438*7c478bd9Sstevel@tonic-gate if (N_ARGS && (N_args >= N_ARGS)) { 439*7c478bd9Sstevel@tonic-gate N_lines = N_args = 0; 440*7c478bd9Sstevel@tonic-gate OK = FALSE; 441*7c478bd9Sstevel@tonic-gate ERR = TRUE; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate n_inserts = t_ninserts; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate /* exec command */ 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate if (!ERR) { 451*7c478bd9Sstevel@tonic-gate if (!MORE && 452*7c478bd9Sstevel@tonic-gate (PER_LINE && N_lines == 0 || N_ARGS && N_args == 0)) 453*7c478bd9Sstevel@tonic-gate exit(exitstat); 454*7c478bd9Sstevel@tonic-gate OK = TRUE; 455*7c478bd9Sstevel@tonic-gate j = TRACE ? echoargs() : TRUE; 456*7c478bd9Sstevel@tonic-gate if (j) { 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * for xcu4, all invocations of cmdname must 459*7c478bd9Sstevel@tonic-gate * return 0, in order for us to return 0. 460*7c478bd9Sstevel@tonic-gate * so if we have a non-zero status here, 461*7c478bd9Sstevel@tonic-gate * quit immediately. 462*7c478bd9Sstevel@tonic-gate */ 463*7c478bd9Sstevel@tonic-gate if ((exitstat |= lcall(cmdname, arglist)) == 0) 464*7c478bd9Sstevel@tonic-gate continue; 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate (void) lseek(0, file_offset, SEEK_SET); 470*7c478bd9Sstevel@tonic-gate if (OK) { 471*7c478bd9Sstevel@tonic-gate exit(exitstat); 472*7c478bd9Sstevel@tonic-gate } else { 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * if exitstat was set, to match XCU4 complience, 475*7c478bd9Sstevel@tonic-gate * return that value, otherwise, return 1. 476*7c478bd9Sstevel@tonic-gate */ 477*7c478bd9Sstevel@tonic-gate exit(exitstat ? exitstat : 1); 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate static void 482*7c478bd9Sstevel@tonic-gate queue(char *buffer, int len, int where) 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate pio *new, *element; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate if ((new = malloc(sizeof (pio))) == NULL) { 487*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 488*7c478bd9Sstevel@tonic-gate exit(1); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate new->cur = new->start = buffer; 491*7c478bd9Sstevel@tonic-gate new->length = len; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate if (where == TAIL) { 494*7c478bd9Sstevel@tonic-gate new->next = NULL; 495*7c478bd9Sstevel@tonic-gate if (queued_data == NULL) { 496*7c478bd9Sstevel@tonic-gate queued_data = new; 497*7c478bd9Sstevel@tonic-gate } else { 498*7c478bd9Sstevel@tonic-gate element = queued_data; 499*7c478bd9Sstevel@tonic-gate while (element->next != NULL) { 500*7c478bd9Sstevel@tonic-gate element = element->next; 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate element->next = new; 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate } else { 505*7c478bd9Sstevel@tonic-gate file_offset -= len; 506*7c478bd9Sstevel@tonic-gate new->next = queued_data; 507*7c478bd9Sstevel@tonic-gate queued_data = new; 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate static char * 512*7c478bd9Sstevel@tonic-gate checklen(char *arg) 513*7c478bd9Sstevel@tonic-gate { 514*7c478bd9Sstevel@tonic-gate int oklen; 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate oklen = TRUE; 517*7c478bd9Sstevel@tonic-gate linesize += strlen(arg) + 1; 518*7c478bd9Sstevel@tonic-gate if (linesize >= BUFLIM) { 519*7c478bd9Sstevel@tonic-gate /* 520*7c478bd9Sstevel@tonic-gate * we skip this if there're inserts. we'll handle the 521*7c478bd9Sstevel@tonic-gate * argument counting after all the insertions have 522*7c478bd9Sstevel@tonic-gate * been done. 523*7c478bd9Sstevel@tonic-gate */ 524*7c478bd9Sstevel@tonic-gate if (n_inserts == 0) { 525*7c478bd9Sstevel@tonic-gate lastarg = arg; 526*7c478bd9Sstevel@tonic-gate oklen = OK = FALSE; 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate if (LEGAL) { 529*7c478bd9Sstevel@tonic-gate ERR = TRUE; 530*7c478bd9Sstevel@tonic-gate ermsg(gettext("arg list too long\n")); 531*7c478bd9Sstevel@tonic-gate } else if (N_args > 1) { 532*7c478bd9Sstevel@tonic-gate N_args = 1; 533*7c478bd9Sstevel@tonic-gate } else { 534*7c478bd9Sstevel@tonic-gate ermsg(gettext("a single arg was greater than " 535*7c478bd9Sstevel@tonic-gate "the max arglist size of %d characters\n"), 536*7c478bd9Sstevel@tonic-gate BUFLIM); 537*7c478bd9Sstevel@tonic-gate ERR = TRUE; 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate return (oklen ? arg : 0); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate static char * 545*7c478bd9Sstevel@tonic-gate addarg(char *arg) 546*7c478bd9Sstevel@tonic-gate { 547*7c478bd9Sstevel@tonic-gate if (checklen(arg) != 0) { 548*7c478bd9Sstevel@tonic-gate (void) strcpy(next, arg); 549*7c478bd9Sstevel@tonic-gate arg = next; 550*7c478bd9Sstevel@tonic-gate next += strlen(arg) + 1; 551*7c478bd9Sstevel@tonic-gate return (arg); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate return ((char *)0); 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate /* 557*7c478bd9Sstevel@tonic-gate * store_wchr() : append a wchar_t to a char buffer, resize buffer if required. 558*7c478bd9Sstevel@tonic-gate * 559*7c478bd9Sstevel@tonic-gate * Given a pointer to the beginning of a string buffer, the length of the 560*7c478bd9Sstevel@tonic-gate * buffer and an offset indicating the next place to write within that 561*7c478bd9Sstevel@tonic-gate * buffer, the passed wchar_t will be appended to the buffer if there is 562*7c478bd9Sstevel@tonic-gate * enough space. If there is not enough space, an attempt to reallocate the 563*7c478bd9Sstevel@tonic-gate * buffer will be made and if successful the passed pointer and size will be 564*7c478bd9Sstevel@tonic-gate * updated to describe the reallocated block. Returns the new value for 565*7c478bd9Sstevel@tonic-gate * 'offset' (it will be incremented by the number of bytes written). 566*7c478bd9Sstevel@tonic-gate */ 567*7c478bd9Sstevel@tonic-gate static size_t 568*7c478bd9Sstevel@tonic-gate store_wchr(char **buffer, size_t *buflen, size_t offset, wchar_t c) 569*7c478bd9Sstevel@tonic-gate { 570*7c478bd9Sstevel@tonic-gate int bytes; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate /* 573*7c478bd9Sstevel@tonic-gate * Make sure that there is enough room in the buffer to store the 574*7c478bd9Sstevel@tonic-gate * maximum length of c. 575*7c478bd9Sstevel@tonic-gate */ 576*7c478bd9Sstevel@tonic-gate if ((offset + MB_CUR_MAX) > *buflen) { 577*7c478bd9Sstevel@tonic-gate /* 578*7c478bd9Sstevel@tonic-gate * Not enough room so attempt to reallocate. Add 'MB_CUR_MAX' to 579*7c478bd9Sstevel@tonic-gate * buffer length to ensure that there is always enough room to 580*7c478bd9Sstevel@tonic-gate * store 'c' if realloc succeeds, no matter what QBUF_INC is 581*7c478bd9Sstevel@tonic-gate * defined as. 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate *buflen += (QBUF_INC + MB_CUR_MAX); 584*7c478bd9Sstevel@tonic-gate if ((*buffer = realloc(*buffer, *buflen)) == NULL) { 585*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 586*7c478bd9Sstevel@tonic-gate exit(1); 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate /* store bytes from wchar into buffer */ 590*7c478bd9Sstevel@tonic-gate bytes = wctomb(*buffer + offset, c); 591*7c478bd9Sstevel@tonic-gate if (bytes == -1) { 592*7c478bd9Sstevel@tonic-gate /* char was invalid */ 593*7c478bd9Sstevel@tonic-gate bytes = 1; 594*7c478bd9Sstevel@tonic-gate *(*buffer + offset) = (char)c; 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* return new value for offset */ 598*7c478bd9Sstevel@tonic-gate return (offset + bytes); 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate static char * 602*7c478bd9Sstevel@tonic-gate getarg() 603*7c478bd9Sstevel@tonic-gate { 604*7c478bd9Sstevel@tonic-gate int bytes; 605*7c478bd9Sstevel@tonic-gate wchar_t c; 606*7c478bd9Sstevel@tonic-gate char *arg; 607*7c478bd9Sstevel@tonic-gate char *retarg, *requeue_buf; 608*7c478bd9Sstevel@tonic-gate size_t requeue_offset = 0, requeue_len; 609*7c478bd9Sstevel@tonic-gate char mbc[MB_LEN_MAX]; 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate while (iswspace(c = getwchr()) || c == '\n') 612*7c478bd9Sstevel@tonic-gate ; 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate if (c == '\0') { 615*7c478bd9Sstevel@tonic-gate MORE = FALSE; 616*7c478bd9Sstevel@tonic-gate return (0); 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate /* 620*7c478bd9Sstevel@tonic-gate * While we are reading in an argument, it is possible that we will 621*7c478bd9Sstevel@tonic-gate * reach the maximum length of the overflow buffer and we'll have to 622*7c478bd9Sstevel@tonic-gate * requeue what we have read so far. To handle this we allocate an 623*7c478bd9Sstevel@tonic-gate * initial buffer here which will keep an unprocessed copy of the data 624*7c478bd9Sstevel@tonic-gate * that we read in (this buffer will grow as required). 625*7c478bd9Sstevel@tonic-gate */ 626*7c478bd9Sstevel@tonic-gate requeue_len = (size_t)QBUF_STARTLEN; 627*7c478bd9Sstevel@tonic-gate if ((requeue_buf = (char *)malloc(requeue_len)) == NULL) { 628*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 629*7c478bd9Sstevel@tonic-gate exit(1); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate for (arg = next; ; c = getwchr()) { 633*7c478bd9Sstevel@tonic-gate bytes = wctomb(mbc, c); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate * Store the char that we have read before processing it in case 637*7c478bd9Sstevel@tonic-gate * the current argument needs to be requeued. 638*7c478bd9Sstevel@tonic-gate */ 639*7c478bd9Sstevel@tonic-gate requeue_offset = store_wchr(&requeue_buf, &requeue_len, 640*7c478bd9Sstevel@tonic-gate requeue_offset, c); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate /* Check for overflow the input buffer */ 643*7c478bd9Sstevel@tonic-gate if ((next + ((bytes == -1) ? 1 : bytes)) >= &argbuf[BUFLIM]) { 644*7c478bd9Sstevel@tonic-gate /* 645*7c478bd9Sstevel@tonic-gate * It's only an error if there are no Args in buffer 646*7c478bd9Sstevel@tonic-gate * already. 647*7c478bd9Sstevel@tonic-gate */ 648*7c478bd9Sstevel@tonic-gate if ((N_ARGS || PER_LINE) && LEGAL) { 649*7c478bd9Sstevel@tonic-gate ERR = TRUE; 650*7c478bd9Sstevel@tonic-gate ermsg(gettext("Argument list too long\n")); 651*7c478bd9Sstevel@tonic-gate free(requeue_buf); 652*7c478bd9Sstevel@tonic-gate return (0); 653*7c478bd9Sstevel@tonic-gate } else if (N_args == 0) { 654*7c478bd9Sstevel@tonic-gate lastarg = ""; 655*7c478bd9Sstevel@tonic-gate ERR = TRUE; 656*7c478bd9Sstevel@tonic-gate ermsg(gettext("A single arg was greater than " 657*7c478bd9Sstevel@tonic-gate "the max arglist size of %d characters\n"), 658*7c478bd9Sstevel@tonic-gate BUFSIZE); 659*7c478bd9Sstevel@tonic-gate free(requeue_buf); 660*7c478bd9Sstevel@tonic-gate return (0); 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * Otherwise we put back the current argument 664*7c478bd9Sstevel@tonic-gate * and use what we have collected so far... 665*7c478bd9Sstevel@tonic-gate */ 666*7c478bd9Sstevel@tonic-gate queue(requeue_buf, requeue_offset, HEAD); 667*7c478bd9Sstevel@tonic-gate /* reset inquote because we have requeued the quotes */ 668*7c478bd9Sstevel@tonic-gate inquote = 0; 669*7c478bd9Sstevel@tonic-gate return (NULL); 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate if (iswctype(c, blank) && inquote == 0) { 674*7c478bd9Sstevel@tonic-gate if (INSERT) { 675*7c478bd9Sstevel@tonic-gate if (bytes == -1) { 676*7c478bd9Sstevel@tonic-gate *next++ = (char)c; 677*7c478bd9Sstevel@tonic-gate } else { 678*7c478bd9Sstevel@tonic-gate (void) wctomb(next, c); 679*7c478bd9Sstevel@tonic-gate next += bytes; 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate continue; 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate /* skip over trailing whitespace till next arg */ 685*7c478bd9Sstevel@tonic-gate while (iswctype((c = getwchr()), blank) && 686*7c478bd9Sstevel@tonic-gate (c != '\n') && (c != '\0')) 687*7c478bd9Sstevel@tonic-gate ; 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate /* 690*7c478bd9Sstevel@tonic-gate * if there was space till end of line then the last 691*7c478bd9Sstevel@tonic-gate * character was really a newline... 692*7c478bd9Sstevel@tonic-gate */ 693*7c478bd9Sstevel@tonic-gate if (c == L'\n' || c == L'\0') { 694*7c478bd9Sstevel@tonic-gate ungetwchr(L'\n'); 695*7c478bd9Sstevel@tonic-gate } else { 696*7c478bd9Sstevel@tonic-gate /* later code needs to know this was a space */ 697*7c478bd9Sstevel@tonic-gate ungetwchr(c); 698*7c478bd9Sstevel@tonic-gate c = L' '; 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate goto end_arg; 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate switch (c) { 703*7c478bd9Sstevel@tonic-gate case L'\0': 704*7c478bd9Sstevel@tonic-gate case L'\n': 705*7c478bd9Sstevel@tonic-gate if (inquote) { 706*7c478bd9Sstevel@tonic-gate *next++ = '\0'; 707*7c478bd9Sstevel@tonic-gate ermsg(gettext("Missing quote: %s\n"), arg); 708*7c478bd9Sstevel@tonic-gate ERR = TRUE; 709*7c478bd9Sstevel@tonic-gate free(requeue_buf); 710*7c478bd9Sstevel@tonic-gate return (0); 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate N_lines++; 714*7c478bd9Sstevel@tonic-gate end_arg: *next++ = '\0'; 715*7c478bd9Sstevel@tonic-gate /* we finished without requeuing so free requeue_buf */ 716*7c478bd9Sstevel@tonic-gate free(requeue_buf); 717*7c478bd9Sstevel@tonic-gate if (strcmp(arg, LEOF) == 0 || (c == '\0' && 718*7c478bd9Sstevel@tonic-gate strlen(arg) == 0)) { 719*7c478bd9Sstevel@tonic-gate MORE = FALSE; 720*7c478bd9Sstevel@tonic-gate /* absorb the rest of the line */ 721*7c478bd9Sstevel@tonic-gate if ((c != '\n') && (c != '\0')) 722*7c478bd9Sstevel@tonic-gate while (c = getwchr()) 723*7c478bd9Sstevel@tonic-gate if ((c == '\n') || (c == '\0')) 724*7c478bd9Sstevel@tonic-gate break; 725*7c478bd9Sstevel@tonic-gate return (0); 726*7c478bd9Sstevel@tonic-gate } else { 727*7c478bd9Sstevel@tonic-gate ++N_args; 728*7c478bd9Sstevel@tonic-gate if (retarg = checklen(arg)) { 729*7c478bd9Sstevel@tonic-gate if ((PER_LINE && 730*7c478bd9Sstevel@tonic-gate N_lines >= PER_LINE && 731*7c478bd9Sstevel@tonic-gate (c == '\0' || c == '\n')) || 732*7c478bd9Sstevel@tonic-gate (N_ARGS && N_args >= N_ARGS)) { 733*7c478bd9Sstevel@tonic-gate N_lines = N_args = 0; 734*7c478bd9Sstevel@tonic-gate lastarg = ""; 735*7c478bd9Sstevel@tonic-gate OK = FALSE; 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate return (retarg); 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate case '"': 742*7c478bd9Sstevel@tonic-gate if (inquote == 1) /* in single quoted string */ 743*7c478bd9Sstevel@tonic-gate goto is_default; 744*7c478bd9Sstevel@tonic-gate if (inquote == 2) /* terminating double quote */ 745*7c478bd9Sstevel@tonic-gate inquote = 0; 746*7c478bd9Sstevel@tonic-gate else /* starting quoted string */ 747*7c478bd9Sstevel@tonic-gate inquote = 2; 748*7c478bd9Sstevel@tonic-gate break; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate case '\'': 751*7c478bd9Sstevel@tonic-gate if (inquote == 2) /* in double quoted string */ 752*7c478bd9Sstevel@tonic-gate goto is_default; 753*7c478bd9Sstevel@tonic-gate if (inquote == 1) /* terminating single quote */ 754*7c478bd9Sstevel@tonic-gate inquote = 0; 755*7c478bd9Sstevel@tonic-gate else /* starting quoted string */ 756*7c478bd9Sstevel@tonic-gate inquote = 1; 757*7c478bd9Sstevel@tonic-gate break; 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate case L'\\': 760*7c478bd9Sstevel@tonic-gate c = getwchr(); 761*7c478bd9Sstevel@tonic-gate /* store quoted char for potential requeueing */ 762*7c478bd9Sstevel@tonic-gate requeue_offset = store_wchr(&requeue_buf, &requeue_len, 763*7c478bd9Sstevel@tonic-gate requeue_offset, c); 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate default: 766*7c478bd9Sstevel@tonic-gate is_default: if (bytes == -1) { 767*7c478bd9Sstevel@tonic-gate *next++ = (char)c; 768*7c478bd9Sstevel@tonic-gate } else { 769*7c478bd9Sstevel@tonic-gate (void) wctomb(next, c); 770*7c478bd9Sstevel@tonic-gate next += bytes; 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate break; 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* 779*7c478bd9Sstevel@tonic-gate * ermsg(): print out an error message, and indicate failure globally. 780*7c478bd9Sstevel@tonic-gate * 781*7c478bd9Sstevel@tonic-gate * Assumes that message has already been gettext()'d. It would be 782*7c478bd9Sstevel@tonic-gate * nice if we could just do the gettext() here, but we can't, since 783*7c478bd9Sstevel@tonic-gate * since xgettext(1M) wouldn't be able to pick up our error message. 784*7c478bd9Sstevel@tonic-gate */ 785*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */ 786*7c478bd9Sstevel@tonic-gate static void 787*7c478bd9Sstevel@tonic-gate ermsg(char *messages, ...) 788*7c478bd9Sstevel@tonic-gate { 789*7c478bd9Sstevel@tonic-gate va_list ap; 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate va_start(ap, messages); 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "xargs: "); 794*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, messages, ap); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate va_end(ap); 797*7c478bd9Sstevel@tonic-gate OK = FALSE; 798*7c478bd9Sstevel@tonic-gate } 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate /* 802*7c478bd9Sstevel@tonic-gate * Function: int rpmatch(char *) 803*7c478bd9Sstevel@tonic-gate * 804*7c478bd9Sstevel@tonic-gate * Description: 805*7c478bd9Sstevel@tonic-gate * 806*7c478bd9Sstevel@tonic-gate * Internationalized get yes / no answer. 807*7c478bd9Sstevel@tonic-gate * 808*7c478bd9Sstevel@tonic-gate * Inputs: 809*7c478bd9Sstevel@tonic-gate * s -> Pointer to answer to compare against. 810*7c478bd9Sstevel@tonic-gate * 811*7c478bd9Sstevel@tonic-gate * Returns: 812*7c478bd9Sstevel@tonic-gate * TRUE -> Answer was affirmative 813*7c478bd9Sstevel@tonic-gate * FALSE -> Answer was negative 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate static int 817*7c478bd9Sstevel@tonic-gate rpmatch(char *s) 818*7c478bd9Sstevel@tonic-gate { 819*7c478bd9Sstevel@tonic-gate static char *default_yesexpr = "^[Yy].*"; 820*7c478bd9Sstevel@tonic-gate static char *compiled_yesexpr = (char *)NULL; 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate /* Execute once to initialize */ 823*7c478bd9Sstevel@tonic-gate if (compiled_yesexpr == (char *)NULL) { 824*7c478bd9Sstevel@tonic-gate char *yesexpr; 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate /* get yes expression according to current locale */ 827*7c478bd9Sstevel@tonic-gate yesexpr = nl_langinfo(YESEXPR); 828*7c478bd9Sstevel@tonic-gate /* 829*7c478bd9Sstevel@tonic-gate * If the was no expression or if there is a compile error 830*7c478bd9Sstevel@tonic-gate * use default yes expression. Anchor 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate if ((yesexpr == (char *)NULL) || (*yesexpr == (char)NULL) || 833*7c478bd9Sstevel@tonic-gate ((compiled_yesexpr = 834*7c478bd9Sstevel@tonic-gate regcmp(yesexpr, 0)) == NULL)) 835*7c478bd9Sstevel@tonic-gate compiled_yesexpr = regcmp(default_yesexpr, 0); 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* match yesexpr */ 839*7c478bd9Sstevel@tonic-gate if (regex(compiled_yesexpr, s) == NULL) { 840*7c478bd9Sstevel@tonic-gate return (FALSE); 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate return (TRUE); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate static int 846*7c478bd9Sstevel@tonic-gate echoargs() 847*7c478bd9Sstevel@tonic-gate { 848*7c478bd9Sstevel@tonic-gate char **anarg; 849*7c478bd9Sstevel@tonic-gate char **tanarg; /* tmp ptr */ 850*7c478bd9Sstevel@tonic-gate int i; 851*7c478bd9Sstevel@tonic-gate char reply[LINE_MAX]; 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate tanarg = anarg = arglist-1; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate /* 856*7c478bd9Sstevel@tonic-gate * write out each argument, separated by a space. the tanarg 857*7c478bd9Sstevel@tonic-gate * nonsense is for xcu4 testsuite compliance - so that an 858*7c478bd9Sstevel@tonic-gate * extra space isn't echoed after the last argument. 859*7c478bd9Sstevel@tonic-gate */ 860*7c478bd9Sstevel@tonic-gate while (*++anarg) { /* while there's an argument */ 861*7c478bd9Sstevel@tonic-gate ++tanarg; /* follow anarg */ 862*7c478bd9Sstevel@tonic-gate (void) write(2, *anarg, strlen(*anarg)); 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate if (*++tanarg) { /* if there's another argument: */ 865*7c478bd9Sstevel@tonic-gate (void) write(2, " ", 1); /* add a space */ 866*7c478bd9Sstevel@tonic-gate --tanarg; /* reset back to anarg */ 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate if (PROMPT == -1) { 870*7c478bd9Sstevel@tonic-gate (void) write(2, "\n", 1); 871*7c478bd9Sstevel@tonic-gate return (TRUE); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* 875*7c478bd9Sstevel@tonic-gate * at this point, there may be unexpected input pending on stdin, 876*7c478bd9Sstevel@tonic-gate * if one has used the -n flag. this presents a problem, because 877*7c478bd9Sstevel@tonic-gate * if we simply do a read(), we'll get the extra input, instead 878*7c478bd9Sstevel@tonic-gate * of our desired y/n input. so, we see if there's any extra 879*7c478bd9Sstevel@tonic-gate * input, and if there is, then we will store it. 880*7c478bd9Sstevel@tonic-gate */ 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate saveinput(); 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate (void) write(2, "?...", 4); /* ask the user for input */ 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate for (i = 0; i < LINE_MAX && read(PROMPT, &reply[i], 1) > 0; i++) { 887*7c478bd9Sstevel@tonic-gate if (reply[i] == '\n') { 888*7c478bd9Sstevel@tonic-gate if (i == 0) 889*7c478bd9Sstevel@tonic-gate return (FALSE); 890*7c478bd9Sstevel@tonic-gate break; 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate reply[i] = 0; 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate /* flush remainder of line if necessary */ 896*7c478bd9Sstevel@tonic-gate if (i == LINE_MAX) { 897*7c478bd9Sstevel@tonic-gate char bitbucket; 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate while ((read(PROMPT, &bitbucket, 1) > 0) && (bitbucket != '\n')) 900*7c478bd9Sstevel@tonic-gate ; 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate /* 904*7c478bd9Sstevel@tonic-gate * now we have to figure out whether the user typed an 905*7c478bd9Sstevel@tonic-gate * internationalized version of 'y' for yes. note that in some 906*7c478bd9Sstevel@tonic-gate * countries, they've gotten used to typing an ASCII 'y'! so 907*7c478bd9Sstevel@tonic-gate * even if our int'l version fails, we will check for an ASCII 908*7c478bd9Sstevel@tonic-gate * 'y', in order to be backwards compatible. 909*7c478bd9Sstevel@tonic-gate */ 910*7c478bd9Sstevel@tonic-gate return (rpmatch(reply)); 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate static char * 915*7c478bd9Sstevel@tonic-gate insert(char *pattern, char *subst) 916*7c478bd9Sstevel@tonic-gate { 917*7c478bd9Sstevel@tonic-gate static char buffer[MAXSBUF+1]; 918*7c478bd9Sstevel@tonic-gate int len, ipatlen; 919*7c478bd9Sstevel@tonic-gate char *pat; 920*7c478bd9Sstevel@tonic-gate char *bufend; 921*7c478bd9Sstevel@tonic-gate char *pbuf; 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate len = strlen(subst); 924*7c478bd9Sstevel@tonic-gate ipatlen = strlen(INSPAT) - 1; 925*7c478bd9Sstevel@tonic-gate pat = pattern - 1; 926*7c478bd9Sstevel@tonic-gate pbuf = buffer; 927*7c478bd9Sstevel@tonic-gate bufend = &buffer[MAXSBUF]; 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate while (*++pat) { 930*7c478bd9Sstevel@tonic-gate if (xindex(pat, INSPAT) == 0) { 931*7c478bd9Sstevel@tonic-gate if (pbuf + len >= bufend) { 932*7c478bd9Sstevel@tonic-gate break; 933*7c478bd9Sstevel@tonic-gate } else { 934*7c478bd9Sstevel@tonic-gate (void) strcpy(pbuf, subst); 935*7c478bd9Sstevel@tonic-gate pat += ipatlen; 936*7c478bd9Sstevel@tonic-gate pbuf += len; 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate } else { 939*7c478bd9Sstevel@tonic-gate *pbuf++ = *pat; 940*7c478bd9Sstevel@tonic-gate if (pbuf >= bufend) 941*7c478bd9Sstevel@tonic-gate break; 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate } 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate if (!*pat) { 946*7c478bd9Sstevel@tonic-gate *pbuf = '\0'; 947*7c478bd9Sstevel@tonic-gate return (buffer); 948*7c478bd9Sstevel@tonic-gate } else { 949*7c478bd9Sstevel@tonic-gate ermsg(gettext("Maximum argument size with insertion via %s's " 950*7c478bd9Sstevel@tonic-gate "exceeded\n"), INSPAT); 951*7c478bd9Sstevel@tonic-gate ERR = TRUE; 952*7c478bd9Sstevel@tonic-gate return (0); 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate static void 958*7c478bd9Sstevel@tonic-gate addibuf(struct inserts *p) 959*7c478bd9Sstevel@tonic-gate { 960*7c478bd9Sstevel@tonic-gate char *newarg, *skel, *sub; 961*7c478bd9Sstevel@tonic-gate int l; 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate skel = p->p_skel; 964*7c478bd9Sstevel@tonic-gate sub = *ARGV; 965*7c478bd9Sstevel@tonic-gate linesize -= strlen(skel) + 1; 966*7c478bd9Sstevel@tonic-gate newarg = insert(skel, sub); 967*7c478bd9Sstevel@tonic-gate if (ERR) 968*7c478bd9Sstevel@tonic-gate return; 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate if (checklen(newarg)) { 971*7c478bd9Sstevel@tonic-gate if ((ibufsize += (l = strlen(newarg) + 1)) > MAXIBUF) { 972*7c478bd9Sstevel@tonic-gate ermsg(gettext("Insert buffer overflow\n")); 973*7c478bd9Sstevel@tonic-gate ERR = TRUE; 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate (void) strcpy(p_ibuf, newarg); 976*7c478bd9Sstevel@tonic-gate *(p->p_ARGV) = p_ibuf; 977*7c478bd9Sstevel@tonic-gate p_ibuf += l; 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate /* 983*7c478bd9Sstevel@tonic-gate * getchr(): get the next character. 984*7c478bd9Sstevel@tonic-gate * description: 985*7c478bd9Sstevel@tonic-gate * we get the next character from pio.structure, if there's a character 986*7c478bd9Sstevel@tonic-gate * to get. this may happen when we've had to flush stdin=/dev/tty, 987*7c478bd9Sstevel@tonic-gate * but still wanted to preserve the characters for later processing. 988*7c478bd9Sstevel@tonic-gate * 989*7c478bd9Sstevel@tonic-gate * otherwise we just get the character from stdin. 990*7c478bd9Sstevel@tonic-gate */ 991*7c478bd9Sstevel@tonic-gate static int 992*7c478bd9Sstevel@tonic-gate getchr(void) 993*7c478bd9Sstevel@tonic-gate { 994*7c478bd9Sstevel@tonic-gate char c; 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate do { 997*7c478bd9Sstevel@tonic-gate if (queued_data == NULL) { 998*7c478bd9Sstevel@tonic-gate char *buffer; 999*7c478bd9Sstevel@tonic-gate int len; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate if ((buffer = malloc(BUFSIZE)) == NULL) { 1002*7c478bd9Sstevel@tonic-gate perror(gettext( 1003*7c478bd9Sstevel@tonic-gate "xargs: Memory allocation failure")); 1004*7c478bd9Sstevel@tonic-gate exit(1); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate if ((len = read(0, buffer, BUFSIZE)) == 0) 1008*7c478bd9Sstevel@tonic-gate return (0); 1009*7c478bd9Sstevel@tonic-gate if (len == -1) { 1010*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Read failure")); 1011*7c478bd9Sstevel@tonic-gate exit(1); 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate queue(buffer, len, TAIL); 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate file_offset++; 1018*7c478bd9Sstevel@tonic-gate c = *queued_data->cur++; /* get the next character */ 1019*7c478bd9Sstevel@tonic-gate if (--queued_data->length == 0) { /* at the end of buffer? */ 1020*7c478bd9Sstevel@tonic-gate pio *nxt = queued_data->next; 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate free(queued_data->start); 1023*7c478bd9Sstevel@tonic-gate free(queued_data); 1024*7c478bd9Sstevel@tonic-gate queued_data = nxt; 1025*7c478bd9Sstevel@tonic-gate } 1026*7c478bd9Sstevel@tonic-gate } while (c == '\0'); 1027*7c478bd9Sstevel@tonic-gate return (c); 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate static wchar_t 1032*7c478bd9Sstevel@tonic-gate getwchr(void) 1033*7c478bd9Sstevel@tonic-gate { 1034*7c478bd9Sstevel@tonic-gate int i; 1035*7c478bd9Sstevel@tonic-gate wchar_t wch; 1036*7c478bd9Sstevel@tonic-gate unsigned char buffer[MB_LEN_MAX + 1]; 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate for (i = 0; i < (int)MB_CUR_MAX; ) { 1039*7c478bd9Sstevel@tonic-gate if ((buffer[i++] = getchr()) == NULL) { 1040*7c478bd9Sstevel@tonic-gate /* We have reached EOF */ 1041*7c478bd9Sstevel@tonic-gate if (i == 1) { 1042*7c478bd9Sstevel@tonic-gate /* TRUE EOF has been reached */ 1043*7c478bd9Sstevel@tonic-gate return (NULL); 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate /* 1046*7c478bd9Sstevel@tonic-gate * We have some characters in our buffer still so it 1047*7c478bd9Sstevel@tonic-gate * must be an invalid character right before EOF. 1048*7c478bd9Sstevel@tonic-gate */ 1049*7c478bd9Sstevel@tonic-gate break; 1050*7c478bd9Sstevel@tonic-gate } 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate /* If this succeeds then we are done */ 1053*7c478bd9Sstevel@tonic-gate if (mbtowc(&wch, (char *)buffer, i) != -1) 1054*7c478bd9Sstevel@tonic-gate return (wch); 1055*7c478bd9Sstevel@tonic-gate } 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* 1058*7c478bd9Sstevel@tonic-gate * We have now encountered an illegal character sequence. 1059*7c478bd9Sstevel@tonic-gate * There is nothing much we can do at this point but 1060*7c478bd9Sstevel@tonic-gate * return an error. If we attempt to recover we may in fact 1061*7c478bd9Sstevel@tonic-gate * return garbage as arguments, from the customer's point 1062*7c478bd9Sstevel@tonic-gate * of view. After all what if they are feeding us a file 1063*7c478bd9Sstevel@tonic-gate * generated in another locale? 1064*7c478bd9Sstevel@tonic-gate */ 1065*7c478bd9Sstevel@tonic-gate errno = EILSEQ; 1066*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Corrupt input file")); 1067*7c478bd9Sstevel@tonic-gate exit(1); 1068*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate static void 1073*7c478bd9Sstevel@tonic-gate ungetwchr(wchar_t wch) 1074*7c478bd9Sstevel@tonic-gate { 1075*7c478bd9Sstevel@tonic-gate char *buffer; 1076*7c478bd9Sstevel@tonic-gate int bytes; 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate if ((buffer = malloc(MB_LEN_MAX)) == NULL) { 1079*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 1080*7c478bd9Sstevel@tonic-gate exit(1); 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate bytes = wctomb(buffer, wch); 1083*7c478bd9Sstevel@tonic-gate queue(buffer, bytes, HEAD); 1084*7c478bd9Sstevel@tonic-gate } 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate 1087*7c478bd9Sstevel@tonic-gate static int 1088*7c478bd9Sstevel@tonic-gate lcall(char *sub, char **subargs) 1089*7c478bd9Sstevel@tonic-gate { 1090*7c478bd9Sstevel@tonic-gate int retcode, retry = 0; 1091*7c478bd9Sstevel@tonic-gate pid_t iwait, child; 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate for (; ; ) { 1094*7c478bd9Sstevel@tonic-gate switch (child = fork()) { 1095*7c478bd9Sstevel@tonic-gate default: 1096*7c478bd9Sstevel@tonic-gate while ((iwait = wait(&retcode)) != child && 1097*7c478bd9Sstevel@tonic-gate iwait != (pid_t)-1) 1098*7c478bd9Sstevel@tonic-gate ; 1099*7c478bd9Sstevel@tonic-gate if (iwait == (pid_t)-1) { 1100*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Wait failure")); 1101*7c478bd9Sstevel@tonic-gate exit(122); 1102*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate if (WIFSIGNALED(retcode)) { 1105*7c478bd9Sstevel@tonic-gate ermsg(gettext("Child killed with signal %d\n"), 1106*7c478bd9Sstevel@tonic-gate WTERMSIG(retcode)); 1107*7c478bd9Sstevel@tonic-gate exit(125); 1108*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate if ((WEXITSTATUS(retcode) & 0377) == 0377) { 1111*7c478bd9Sstevel@tonic-gate ermsg(gettext("Command could not continue " 1112*7c478bd9Sstevel@tonic-gate "processing data\n")); 1113*7c478bd9Sstevel@tonic-gate exit(124); 1114*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate return (WEXITSTATUS(retcode)); 1117*7c478bd9Sstevel@tonic-gate case 0: 1118*7c478bd9Sstevel@tonic-gate (void) execvp(sub, subargs); 1119*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Could not exec command")); 1120*7c478bd9Sstevel@tonic-gate if (errno == EACCES) 1121*7c478bd9Sstevel@tonic-gate exit(126); 1122*7c478bd9Sstevel@tonic-gate exit(127); 1123*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1124*7c478bd9Sstevel@tonic-gate case -1: 1125*7c478bd9Sstevel@tonic-gate if (errno != EAGAIN && retry++ < FORK_RETRY) { 1126*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Could not fork child")); 1127*7c478bd9Sstevel@tonic-gate exit(123); 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate (void) sleep(1); 1130*7c478bd9Sstevel@tonic-gate } 1131*7c478bd9Sstevel@tonic-gate } 1132*7c478bd9Sstevel@tonic-gate } 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate /* 1136*7c478bd9Sstevel@tonic-gate * If `s2' is a substring of `s1' return the offset of the first 1137*7c478bd9Sstevel@tonic-gate * occurrence of `s2' in `s1', else return -1. 1138*7c478bd9Sstevel@tonic-gate */ 1139*7c478bd9Sstevel@tonic-gate static int 1140*7c478bd9Sstevel@tonic-gate xindex(char *as1, char *as2) 1141*7c478bd9Sstevel@tonic-gate { 1142*7c478bd9Sstevel@tonic-gate char *s1, *s2, c; 1143*7c478bd9Sstevel@tonic-gate int offset; 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate s1 = as1; 1146*7c478bd9Sstevel@tonic-gate s2 = as2; 1147*7c478bd9Sstevel@tonic-gate c = *s2; 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate while (*s1) { 1150*7c478bd9Sstevel@tonic-gate if (*s1++ == c) { 1151*7c478bd9Sstevel@tonic-gate offset = s1 - as1 - 1; 1152*7c478bd9Sstevel@tonic-gate s2++; 1153*7c478bd9Sstevel@tonic-gate while ((c = *s2++) == *s1++ && c) 1154*7c478bd9Sstevel@tonic-gate ; 1155*7c478bd9Sstevel@tonic-gate if (c == 0) 1156*7c478bd9Sstevel@tonic-gate return (offset); 1157*7c478bd9Sstevel@tonic-gate s1 = offset + as1 + 1; 1158*7c478bd9Sstevel@tonic-gate s2 = as2; 1159*7c478bd9Sstevel@tonic-gate c = *s2; 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate return (-1); 1163*7c478bd9Sstevel@tonic-gate } 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate static void 1167*7c478bd9Sstevel@tonic-gate usage() 1168*7c478bd9Sstevel@tonic-gate { 1169*7c478bd9Sstevel@tonic-gate ermsg(gettext(USAGEMSG)); 1170*7c478bd9Sstevel@tonic-gate OK = FALSE; 1171*7c478bd9Sstevel@tonic-gate } 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate /* 1176*7c478bd9Sstevel@tonic-gate * parseargs(): modify the args 1177*7c478bd9Sstevel@tonic-gate * since the -e, -i and -l flags all take optional subarguments, 1178*7c478bd9Sstevel@tonic-gate * and getopts(3C) is clueless about this nonsense, we change the 1179*7c478bd9Sstevel@tonic-gate * our local argument count and strings to separate this out, 1180*7c478bd9Sstevel@tonic-gate * and make it easier to handle via getopts(3c). 1181*7c478bd9Sstevel@tonic-gate * 1182*7c478bd9Sstevel@tonic-gate * -e -> "-e "" 1183*7c478bd9Sstevel@tonic-gate * -e3 -> "-e "3" 1184*7c478bd9Sstevel@tonic-gate * -Estr -> "-E "str" 1185*7c478bd9Sstevel@tonic-gate * -i -> "-i "{}" 1186*7c478bd9Sstevel@tonic-gate * -irep -> "-i "rep" 1187*7c478bd9Sstevel@tonic-gate * -l -> "-i "1" 1188*7c478bd9Sstevel@tonic-gate * -l10 -> "-i "10" 1189*7c478bd9Sstevel@tonic-gate * 1190*7c478bd9Sstevel@tonic-gate * since the -e, -i and -l flags all take optional subarguments, 1191*7c478bd9Sstevel@tonic-gate */ 1192*7c478bd9Sstevel@tonic-gate static void 1193*7c478bd9Sstevel@tonic-gate parseargs(int ac, char **av) 1194*7c478bd9Sstevel@tonic-gate { 1195*7c478bd9Sstevel@tonic-gate int i; /* current argument */ 1196*7c478bd9Sstevel@tonic-gate int cflag; /* 0 = not processing cmd arg */ 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate if ((mav = malloc((ac * 2 + 1) * sizeof (char *))) == NULL) { 1199*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 1200*7c478bd9Sstevel@tonic-gate exit(1); 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate /* for each argument, see if we need to change things: */ 1204*7c478bd9Sstevel@tonic-gate for (i = mac = cflag = 0; (av[i] != NULL) && i < ac; i++, mac++) { 1205*7c478bd9Sstevel@tonic-gate if ((mav[mac] = strdup(av[i])) == NULL) { 1206*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 1207*7c478bd9Sstevel@tonic-gate exit(1); 1208*7c478bd9Sstevel@tonic-gate } 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate /* -- has been found or argument list is fully processes */ 1211*7c478bd9Sstevel@tonic-gate if (cflag) 1212*7c478bd9Sstevel@tonic-gate continue; 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate /* 1215*7c478bd9Sstevel@tonic-gate * if we're doing special processing, and we've got a flag 1216*7c478bd9Sstevel@tonic-gate */ 1217*7c478bd9Sstevel@tonic-gate else if ((av[i][0] == '-') && (av[i][1] != NULL)) { 1218*7c478bd9Sstevel@tonic-gate char *def; 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate switch (av[i][1]) { 1221*7c478bd9Sstevel@tonic-gate case 'e': 1222*7c478bd9Sstevel@tonic-gate def = ""; /* -e with no arg turns off eof */ 1223*7c478bd9Sstevel@tonic-gate goto process_special; 1224*7c478bd9Sstevel@tonic-gate case 'i': 1225*7c478bd9Sstevel@tonic-gate def = INSPAT_STR; 1226*7c478bd9Sstevel@tonic-gate goto process_special; 1227*7c478bd9Sstevel@tonic-gate case 'l': 1228*7c478bd9Sstevel@tonic-gate def = "1"; 1229*7c478bd9Sstevel@tonic-gate process_special: 1230*7c478bd9Sstevel@tonic-gate /* 1231*7c478bd9Sstevel@tonic-gate * if there's no sub-option, we *must* add 1232*7c478bd9Sstevel@tonic-gate * a default one. this is because xargs must 1233*7c478bd9Sstevel@tonic-gate * be able to distinguish between a valid 1234*7c478bd9Sstevel@tonic-gate * suboption, and a command name. 1235*7c478bd9Sstevel@tonic-gate */ 1236*7c478bd9Sstevel@tonic-gate if (av[i][2] == NULL) { 1237*7c478bd9Sstevel@tonic-gate mav[++mac] = strdup(def); 1238*7c478bd9Sstevel@tonic-gate } else { 1239*7c478bd9Sstevel@tonic-gate /* clear out our version: */ 1240*7c478bd9Sstevel@tonic-gate mav[mac][2] = NULL; 1241*7c478bd9Sstevel@tonic-gate mav[++mac] = strdup(&av[i][2]); 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate if (mav[mac] == NULL) { 1244*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory" 1245*7c478bd9Sstevel@tonic-gate " allocation failure")); 1246*7c478bd9Sstevel@tonic-gate exit(1); 1247*7c478bd9Sstevel@tonic-gate } 1248*7c478bd9Sstevel@tonic-gate break; 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate /* flags with required subarguments: */ 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate /* 1253*7c478bd9Sstevel@tonic-gate * there are two separate cases here. either the 1254*7c478bd9Sstevel@tonic-gate * flag can have the normal XCU4 handling 1255*7c478bd9Sstevel@tonic-gate * (of the form: -X subargument); or it can have 1256*7c478bd9Sstevel@tonic-gate * the old solaris 2.[0-4] handling (of the 1257*7c478bd9Sstevel@tonic-gate * form: -Xsubargument). in order to maintain 1258*7c478bd9Sstevel@tonic-gate * backwards compatibility, we must support the 1259*7c478bd9Sstevel@tonic-gate * latter case. we handle the latter possibility 1260*7c478bd9Sstevel@tonic-gate * first so both the old solaris way of handling 1261*7c478bd9Sstevel@tonic-gate * and the new XCU4 way of handling things are allowed. 1262*7c478bd9Sstevel@tonic-gate */ 1263*7c478bd9Sstevel@tonic-gate case 'n': /* FALLTHROUGH */ 1264*7c478bd9Sstevel@tonic-gate case 's': /* FALLTHROUGH */ 1265*7c478bd9Sstevel@tonic-gate case 'E': /* FALLTHROUGH */ 1266*7c478bd9Sstevel@tonic-gate case 'I': /* FALLTHROUGH */ 1267*7c478bd9Sstevel@tonic-gate case 'L': 1268*7c478bd9Sstevel@tonic-gate /* 1269*7c478bd9Sstevel@tonic-gate * if the second character isn't null, then 1270*7c478bd9Sstevel@tonic-gate * the user has specified the old syntax. 1271*7c478bd9Sstevel@tonic-gate * we move the subargument into our 1272*7c478bd9Sstevel@tonic-gate * mod'd argument list. 1273*7c478bd9Sstevel@tonic-gate */ 1274*7c478bd9Sstevel@tonic-gate if (av[i][2] != NULL) { 1275*7c478bd9Sstevel@tonic-gate /* first clean things up: */ 1276*7c478bd9Sstevel@tonic-gate mav[mac][2] = NULL; 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate /* now add the separation: */ 1279*7c478bd9Sstevel@tonic-gate ++mac; /* inc to next mod'd arg */ 1280*7c478bd9Sstevel@tonic-gate if ((mav[mac] = strdup(&av[i][2])) == 1281*7c478bd9Sstevel@tonic-gate NULL) { 1282*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory" 1283*7c478bd9Sstevel@tonic-gate " allocation failure")); 1284*7c478bd9Sstevel@tonic-gate exit(1); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate break; 1287*7c478bd9Sstevel@tonic-gate } 1288*7c478bd9Sstevel@tonic-gate i++; 1289*7c478bd9Sstevel@tonic-gate mac++; 1290*7c478bd9Sstevel@tonic-gate #ifdef XPG6 1291*7c478bd9Sstevel@tonic-gate if (av[i] != NULL) { 1292*7c478bd9Sstevel@tonic-gate if ((mav[mac] = strdup(av[i])) 1293*7c478bd9Sstevel@tonic-gate == NULL) { 1294*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory" 1295*7c478bd9Sstevel@tonic-gate " allocation failure")); 1296*7c478bd9Sstevel@tonic-gate exit(1); 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate } 1299*7c478bd9Sstevel@tonic-gate #else 1300*7c478bd9Sstevel@tonic-gate if (av[i] == NULL) { 1301*7c478bd9Sstevel@tonic-gate if ((mav[mac++] = strdup("")) == NULL) { 1302*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory " 1303*7c478bd9Sstevel@tonic-gate " allocation failure")); 1304*7c478bd9Sstevel@tonic-gate exit(1); 1305*7c478bd9Sstevel@tonic-gate } 1306*7c478bd9Sstevel@tonic-gate mav[mac] = NULL; 1307*7c478bd9Sstevel@tonic-gate return; 1308*7c478bd9Sstevel@tonic-gate } 1309*7c478bd9Sstevel@tonic-gate if ((mav[mac] = strdup(av[i])) == NULL) { 1310*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory" 1311*7c478bd9Sstevel@tonic-gate " allocation failure")); 1312*7c478bd9Sstevel@tonic-gate exit(1); 1313*7c478bd9Sstevel@tonic-gate } 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate #endif 1316*7c478bd9Sstevel@tonic-gate break; 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate /* flags */ 1319*7c478bd9Sstevel@tonic-gate case 'p' : 1320*7c478bd9Sstevel@tonic-gate case 't' : 1321*7c478bd9Sstevel@tonic-gate case 'x' : 1322*7c478bd9Sstevel@tonic-gate break; 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate case '-' : 1325*7c478bd9Sstevel@tonic-gate default: 1326*7c478bd9Sstevel@tonic-gate /* 1327*7c478bd9Sstevel@tonic-gate * here we've hit the cmd argument. so 1328*7c478bd9Sstevel@tonic-gate * we'll stop special processing, as the 1329*7c478bd9Sstevel@tonic-gate * cmd may have a "-i" etc., argument, 1330*7c478bd9Sstevel@tonic-gate * and we don't want to add a "" to it. 1331*7c478bd9Sstevel@tonic-gate */ 1332*7c478bd9Sstevel@tonic-gate cflag = 1; 1333*7c478bd9Sstevel@tonic-gate break; 1334*7c478bd9Sstevel@tonic-gate } 1335*7c478bd9Sstevel@tonic-gate } else if (i > 0) { /* if we're not the 1st arg */ 1336*7c478bd9Sstevel@tonic-gate /* 1337*7c478bd9Sstevel@tonic-gate * if it's not a flag, then it *must* be the cmd. 1338*7c478bd9Sstevel@tonic-gate * set cflag, so we don't mishandle the -[eil] flags. 1339*7c478bd9Sstevel@tonic-gate */ 1340*7c478bd9Sstevel@tonic-gate cflag = 1; 1341*7c478bd9Sstevel@tonic-gate } 1342*7c478bd9Sstevel@tonic-gate } 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate mav[mac] = NULL; 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate /* 1349*7c478bd9Sstevel@tonic-gate * saveinput(): pick up any pending input, so it can be processed later. 1350*7c478bd9Sstevel@tonic-gate * 1351*7c478bd9Sstevel@tonic-gate * description: 1352*7c478bd9Sstevel@tonic-gate * the purpose of this routine is to allow us to handle the user 1353*7c478bd9Sstevel@tonic-gate * typing in a 'y' or 'n', when there's existing characters already 1354*7c478bd9Sstevel@tonic-gate * in stdin. this happens when one gives the "-n" option along with 1355*7c478bd9Sstevel@tonic-gate * "-p". the problem occurs when the user first types in more arguments 1356*7c478bd9Sstevel@tonic-gate * than specified by the -n number. echoargs() wants to read stdin 1357*7c478bd9Sstevel@tonic-gate * in order to get the user's response, but if there's already stuff 1358*7c478bd9Sstevel@tonic-gate * there, echoargs() won't read the proper character. 1359*7c478bd9Sstevel@tonic-gate * 1360*7c478bd9Sstevel@tonic-gate * the solution provided by this routine is to pick up all characters 1361*7c478bd9Sstevel@tonic-gate * (if any), and store them for later processing. 1362*7c478bd9Sstevel@tonic-gate */ 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate void 1365*7c478bd9Sstevel@tonic-gate saveinput() 1366*7c478bd9Sstevel@tonic-gate { 1367*7c478bd9Sstevel@tonic-gate char *buffer; /* ptr to the floating data buffer */ 1368*7c478bd9Sstevel@tonic-gate struct strpeek speek; /* to see what's on the queue */ 1369*7c478bd9Sstevel@tonic-gate struct strpeek *ps; 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate /* if we're not in -p mode, skip */ 1372*7c478bd9Sstevel@tonic-gate if (PROMPT == -1) { 1373*7c478bd9Sstevel@tonic-gate return; 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate /* now see if there's any activity pending: */ 1378*7c478bd9Sstevel@tonic-gate ps = &speek; 1379*7c478bd9Sstevel@tonic-gate ps->ctlbuf.maxlen = 0; 1380*7c478bd9Sstevel@tonic-gate ps->ctlbuf.len = 0; 1381*7c478bd9Sstevel@tonic-gate ps->ctlbuf.buf = NULL; 1382*7c478bd9Sstevel@tonic-gate ps->flags = 0; 1383*7c478bd9Sstevel@tonic-gate ps->databuf.maxlen = MAX_INPUT; 1384*7c478bd9Sstevel@tonic-gate ps->databuf.len = 0; 1385*7c478bd9Sstevel@tonic-gate if ((buffer = malloc((size_t)MAX_INPUT)) == NULL) { 1386*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: Memory allocation failure")); 1387*7c478bd9Sstevel@tonic-gate exit(1); 1388*7c478bd9Sstevel@tonic-gate } 1389*7c478bd9Sstevel@tonic-gate ps->databuf.buf = (char *)buffer; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate if (ioctl(PROMPT, I_PEEK, ps) == -1) { 1392*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: I_PEEK failure")); 1393*7c478bd9Sstevel@tonic-gate exit(1); 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate if (ps->databuf.len > 0) { 1397*7c478bd9Sstevel@tonic-gate int len; 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate if ((len = read(PROMPT, buffer, ps->databuf.len)) == -1) { 1400*7c478bd9Sstevel@tonic-gate perror(gettext("xargs: read failure")); 1401*7c478bd9Sstevel@tonic-gate exit(1); 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate queue(buffer, len, TAIL); 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate } 1406