1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #if defined(sun)
32 #pragma ident	"@(#)args.c	1.11	05/09/14 SMI"
33 #endif
34 
35 #include "defs.h"
36 #ifdef	DO_SYSALIAS
37 #include "abbrev.h"
38 #endif
39 #include "version.h"
40 
41 /*
42  * Copyright 2008-2021 J. Schilling
43  *
44  * @(#)args.c	1.96 21/02/27 2008-2021 J. Schilling
45  */
46 #ifndef lint
47 static	UConst char sccsid[] =
48 	"@(#)args.c	1.96 21/02/27 2008-2021 J. Schilling";
49 #endif
50 
51 /*
52  *	UNIX shell
53  */
54 
55 #include	"sh_policy.h"
56 
57 #if !defined(DO_SET_O)
58 #undef	DO_GLOBALALIASES
59 #undef	DO_LOCALALIASES
60 #endif
61 
62 	void		prversion	__PR((void));
63 	int		options		__PR((int argc, unsigned char **argv));
64 	void		setopts		__PR((void));
65 	void		setargs		__PR((unsigned char *argi[]));
66 static void		freedolh	__PR((void));
67 	struct dolnod	*freeargs	__PR((struct dolnod *blk));
68 static struct dolnod	*copyargs	__PR((unsigned char *[], int));
69 static	struct dolnod	*clean_args	__PR((struct dolnod *blk));
70 	void		clearup		__PR((void));
71 	struct dolnod	*savargs	__PR((int funcntp));
72 	void		restorargs	__PR((struct dolnod *olddolh,
73 							int funcntp));
74 	struct dolnod	*useargs	__PR((void));
75 static	unsigned char	*lookcopt	__PR((int wc));
76 #if	defined(DO_SYSALIAS) && \
77 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
78 static	void		listaliasowner	__PR((int parse, int flagidx));
79 #endif
80 #ifdef	DO_SET_O
81 static	void		listopts	__PR((int parse));
82 #ifdef	DO_HOSTPROMPT
83 static	void		hostprompt	__PR((int on));
84 #endif
85 #ifdef	DO_PS34
86 static	void		ps_reset	__PR((void));
87 #endif
88 #endif
89 
90 static struct dolnod *dolh;
91 
92 /* Used to save outermost positional parameters */
93 static struct dolnod *globdolh;
94 static unsigned char **globdolv;
95 static int globdolc;
96 
97 unsigned char	flagadr[20];
98 
99 unsigned char	flagchar[] =
100 {
101 #if	defined(DO_SYSALIAS) && \
102 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
103 	0,			/* set -o aliasowner= */
104 #endif
105 	'a',			/* -a / -o allexport */
106 #ifdef	DO_BGNICE
107 	0,			/* -o bgnice */
108 #endif
109 	'e',
110 #ifdef	DO_FDPIPE
111 	0,			/* set -o fdpipe */
112 #endif
113 #ifdef	DO_FULLEXCODE
114 	0,			/* set -o fullexitcode */
115 #endif
116 #if	defined(DO_SYSALIAS) && defined(DO_GLOBALALIASES)
117 	0,			/* set -o globalaliases */
118 #endif
119 #ifdef	DO_GLOBSKIPDOT
120 	0,			/* set -o globskipdot */
121 #endif
122 	'h',
123 #ifdef	DO_HASHCMDS
124 	0,			/* -o hashcmds, enable # commands */
125 #endif
126 #ifdef	DO_HOSTPROMPT
127 	0,			/* -o hostprompt, "<host> <user>> " prompt */
128 #endif
129 #ifdef	INTERACTIVE
130 	0,			/* -o ignoreeof POSIX name */
131 #endif
132 	'i',
133 	'k',			/* -k / -o keyword */
134 #if	defined(DO_SYSALIAS) && defined(DO_LOCALALIASES)
135 	0,			/* set -o localaliases */
136 #endif
137 	'm',
138 #ifdef	DO_NOCLOBBER
139 	'C',			/* -C, set -o noclobber */
140 #endif
141 	'n',
142 	'f',			/* -f / -o noglob */
143 #ifdef	DO_NOTIFY
144 	'b',			/* -b / -o notify */
145 #endif
146 	'u',			/* -u / -o nounset */
147 	't',			/* -t / -o onecmd */
148 	'P',
149 #ifdef	DO_SET_O
150 	0,			/* -o posix */
151 #endif
152 	'p',
153 #ifdef	DO_PS34
154 	0,			/* -o promptcmdsubst */
155 #endif
156 	'r',
157 	STDFLG,			/* -s / -o stdin */
158 	'V',
159 #ifdef	DO_TIME
160 	0,			/* set -o time */
161 #endif
162 #ifdef	INTERACTIVE
163 	0,			/* set -o ved */
164 #endif
165 	'v',
166 #ifdef	INTERACTIVE
167 	0,			/* set -o vi */
168 #endif
169 	'x',
170 	0
171 };
172 #define	NFLAGCHAR	((sizeof (flagchar) / sizeof (flagchar[0])) - 1)
173 
174 #ifdef	DO_SET_O
175 char	*flagname[] =
176 {
177 #if	defined(DO_SYSALIAS) && \
178 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
179 	"aliasowner",
180 #endif
181 	"allexport",		/* -a POSIX */
182 #ifdef	DO_BGNICE
183 	"bgnice",		/* -o bgnice */
184 #endif
185 	"errexit",		/* -e POSIX */
186 #ifdef	DO_FDPIPE
187 	"fdpipe",		/* e.g. 2| for pipe from stderr */
188 #endif
189 #ifdef	DO_FULLEXCODE
190 	"fullexitcode",		/* -o fullexitcode, do not mask $? */
191 #endif
192 #if	defined(DO_SYSALIAS) && defined(DO_GLOBALALIASES)
193 	"globalaliases",
194 #endif
195 #ifdef	DO_GLOBSKIPDOT
196 	"globskipdot",
197 #endif
198 	"hashall",		/* -h bash name (ksh93 uses "trackall") */
199 #ifdef	DO_HASHCMDS
200 	"hashcmds",		/* -o hashcmds, enable # commands */
201 #endif
202 #ifdef	DO_HOSTPROMPT
203 	"hostprompt",		/* -o hostprompt, "<host> <user>> " prompt */
204 #endif
205 #ifdef	INTERACTIVE
206 	"ignoreeof",		/* -o ignoreeof POSIX name */
207 #endif
208 	"interactive",		/* -i ksh93 name */
209 	"keyword",		/* -k bash/ksh93 name */
210 #if	defined(DO_SYSALIAS) && defined(DO_LOCALALIASES)
211 	"localaliases",
212 #endif
213 	"monitor",		/* -m POSIX */
214 #ifdef	DO_NOCLOBBER
215 	"noclobber",		/* -C, set -o noclobber */
216 #endif
217 	"noexec",		/* -n POSIX */
218 	"noglob",		/* -f POSIX */
219 #ifdef	DO_NOTIFY
220 	"notify",		/* -b POSIX */
221 #endif
222 	"nounset",		/* -u POSIX */
223 	"onecmd",		/* -t bash name */
224 	"pfsh",			/* -P Schily Bourne Shell */
225 #ifdef	DO_SET_O
226 	"posix",		/* -o posix */
227 #endif
228 	"privileged",		/* -p ksh93: only if really privileged */
229 #ifdef	DO_PS34
230 	"promptcmdsubst",	/* -o promptcmdsubst */
231 #endif
232 	"restricted",		/* -r ksh93 name */
233 	"stdin",		/* -s Schily name */
234 	"version",		/* -V Schily Bourne Shell */
235 #ifdef	DO_TIME
236 	"time",			/* -o time, enable timing */
237 #endif
238 #ifdef	INTERACTIVE
239 	"ved",
240 #endif
241 	"verbose",		/* -v POSIX */
242 #ifdef	INTERACTIVE
243 	"vi",
244 #endif
245 	"xtrace",		/* -x POSIX */
246 	0
247 };
248 #endif
249 
250 unsigned long	flagval[]  =
251 {
252 #if	defined(DO_SYSALIAS) && \
253 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
254 	fl2 | aliasownerflg,	/* -o aliasowner= */
255 #endif
256 	exportflg,		/* -a / -o allexport */
257 #ifdef	DO_BGNICE
258 	fl2 | bgniceflg,	/* -o bgnice */
259 #endif
260 	errflg,			/* -e */
261 #ifdef	DO_FDPIPE
262 	fl2 | fdpipeflg,	/* -o fdpipe */
263 #endif
264 #ifdef	DO_FULLEXCODE
265 	fl2 | fullexitcodeflg,	/* -o fullexitcode */
266 #endif
267 #if	defined(DO_SYSALIAS) && defined(DO_GLOBALALIASES)
268 	fl2 | globalaliasflg,	/* -o globalaliases */
269 #endif
270 #ifdef	DO_GLOBSKIPDOT
271 	fl2 | globskipdot,	/* -o globskipdot */
272 #endif
273 	hashflg,		/* -h / -o hashall */
274 #ifdef	DO_HASHCMDS
275 	fl2 | hashcmdsflg,	/* -o hashcmds, enable # commands */
276 #endif
277 #ifdef	DO_HOSTPROMPT
278 	fl2 | hostpromptflg,	/* -o hostprompt, "<host> <user>> " prompt */
279 #endif
280 #ifdef	INTERACTIVE
281 	fl2 | ignoreeofflg,	/* -o ignoreeof POSIX name */
282 #endif
283 	intflg,			/* -i / -o interactive */
284 	keyflg,			/* -k / -o keyword */
285 #if	defined(DO_SYSALIAS) && defined(DO_LOCALALIASES)
286 	fl2 | localaliasflg,	/* -o localaliases */
287 #endif
288 	monitorflg,		/* -m / -o monitor */
289 #ifdef	DO_NOCLOBBER
290 	fl2 | noclobberflg,	/* -C, set -o noclobber */
291 #endif
292 	noexec,			/* -n / -o noexec */
293 	nofngflg,		/* -f / -o noglob */
294 #ifdef	DO_NOTIFY
295 	notifyflg,		/* -b / -o notify */
296 #endif
297 	setflg,			/* -u / -o nounset */
298 	oneflg,			/* -t / -o onecmd */
299 	pfshflg,		/* -P */
300 #ifdef	DO_SET_O
301 	fl2 | posixflg,		/* -o posix */
302 #endif
303 	privflg,		/* -p */
304 #ifdef	DO_PS34
305 	fl2 | promptcmdsubst,	/* -o promptcmdsubst */
306 #endif
307 	rshflg,			/* -r / -o restrictive */
308 	stdflg,			/* -s / -o stdin */
309 	fl2 | versflg,		/* -V */
310 #ifdef	DO_TIME
311 	fl2 | timeflg,		/* -o time */
312 #endif
313 #ifdef	INTERACTIVE
314 	fl2 | vedflg,		/* -o ved */
315 #endif
316 	readpr,			/* -v / -o verbose */
317 #ifdef	INTERACTIVE
318 	fl2 | viflg,		/* -o vi */
319 #endif
320 	execpr,			/* -x / -o xtrace */
321 	0
322 };
323 
324 unsigned char *shvers;
325 
326 /* ========	option handling	======== */
327 
328 #ifndef	VSHNAME
329 #define	VSHNAME	"sh"
330 #endif
331 
332 void
prversion()333 prversion()
334 {
335 	char	vbuf[BUFFERSIZE];
336 
337 	snprintf(vbuf, sizeof (vbuf),
338 	    "%s %s\n",
339 	    shname, shvers);
340 	prs(UC vbuf);
341 	if (dolv == NULL) {
342 		/*
343 		 * We have been called as a result of a sh command line flag.
344 		 * Print the version information and exit.
345 		 */
346 		prs(UC "\n");
347 		prs(UC "Copyright (C) 1984-1989 AT&T\n");
348 		prs(UC "Copyright (C) 1989-2009 Sun Microsystems\n");
349 #ifdef	INTERACTIVE
350 		prs(UC "Copyright (C) 1982-2021 Joerg Schilling\n");
351 #else
352 		prs(UC "Copyright (C) 1985-2021 Joerg Schilling\n");
353 #endif
354 		exitsh(0);
355 	}
356 }
357 
358 int
options(argc,argv)359 options(argc, argv)
360 	int		argc;
361 	unsigned char	**argv;
362 {
363 	unsigned char *cp;
364 	unsigned char **argp = argv;
365 	unsigned char *flagc;
366 	int		len;
367 	wchar_t		wc;
368 	unsigned long	fv;
369 
370 	if (shvers == NULL) {
371 		char	vbuf[BUFFERSIZE];
372 		size_t	vlen;
373 
374 		vlen = snprintf(vbuf, sizeof (vbuf),
375 			    "version %s %s %s (%s-%s-%s)",
376 			    VSHNAME,
377 			    VERSION_DATE, VERSION_STR,
378 			    HOST_CPU, HOST_VENDOR, HOST_OS);
379 		shvers = alloc(vlen + 1);
380 		strcpy((char *)shvers, vbuf);
381 	}
382 
383 #ifdef	DO_POSIX_SET
384 	dashdash = 0;
385 #endif
386 #ifdef	DO_MULTI_OPT
387 again:
388 #endif
389 	if (argc > 1 && *argp[1] == '-') {
390 		cp = argp[1];
391 		/*
392 		 * Allow "--version" by mapping it to "-V".
393 		 */
394 		if ((strcmp((char *)&cp[1], "version") == 0) ||
395 		    (cp[1] == '-' && strcmp((char *)&cp[2], "version") == 0)) {
396 			cp = UC "-V";
397 		} else if (cp[1] == '-' && cp[2] == '\0') {
398 			/*
399 			 * if first argument is "--" then options are not
400 			 * to be changed. Fix for problems getting
401 			 * $1 starting with a "-"
402 			 */
403 			argp[1] = argp[0];
404 			argc--;
405 #ifdef	DO_POSIX_SET
406 			if (comdiv == cp) {
407 				/*
408 				 * Support sh -c -- command
409 				 */
410 				if ((comdiv = argp[2]) == NULL) {
411 					failed(argv[1], mssgargn);
412 					return (-1);
413 				} else {
414 					argp[2] = argp[3]?argp[3]:argp[0];
415 					argc--;
416 				}
417 			}
418 			dashdash++;
419 #endif
420 #ifdef	DO_MULTI_OPT
421 			setopts();
422 #endif
423 			return (argc);
424 		}
425 #ifdef	DO_MULTI_OPT
426 		/*
427 		 * Mark that we will later need to correct comdiv.
428 		 */
429 		if (comdiv && dolv == NULL)
430 			comdiv = UC -1;
431 #endif
432 		if (cp[1] == '\0')
433 			flags &= ~(execpr|readpr);
434 
435 		/*
436 		 * Step along 'flagchar[]' looking for matches.
437 		 * 'sicrp' are not legal with 'set' command.
438 		 */
439 		(void) mbtowc(NULL, NULL, 0);
440 		cp++;
441 		while (*cp) {
442 			if ((len = mbtowc(&wc, (char *)cp, MB_LEN_MAX)) <= 0) {
443 				(void) mbtowc(NULL, NULL, 0);
444 				len = 1;
445 				wc = (unsigned char)*cp;
446 				failed(argv[1], badopt);
447 				return (-1);
448 			}
449 			cp += len;
450 
451 #ifdef	DO_SET_O
452 			if (wc == 'o') {		/* set set -o */
453 				unsigned char *argarg;
454 				int	dolistopts = argc <= 2 ||
455 						argp[2][0] == '-' ||
456 						argp[2][0] == '+';
457 
458 				if (dolistopts) {
459 					listopts(0);
460 					continue;
461 				}
462 				argarg = UC strchr((char *)argp[2], '=');
463 				if (argarg != NULL)
464 					*argarg = '\0';
465 				if ((flagc = lookopt(argp[2])) != NULL) {
466 						argp[1] = argp[0];
467 						argp++;
468 						argc--;
469 						wc = *flagc;
470 #if	defined(DO_SYSALIAS) && \
471 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
472 							/* LINTED */
473 						if (flagval[flagc-flagchar] ==
474 						    (fl2 | aliasownerflg)) {
475 							char *owner;
476 
477 							if (argarg != NULL)
478 								owner = (char *)
479 								    &argarg[1];
480 							else
481 								owner = "";
482 							ab_setaltowner(
483 							    GLOBAL_AB, owner);
484 							ab_setaltowner(
485 							    LOCAL_AB, owner);
486 						}
487 #endif
488 				}
489 				if (argarg != NULL)
490 					*argarg = '=';
491 				if (flagc == NULL || wc != *flagc) {
492 					if (argc > 2) {
493 						failed(argp[2], badopt);
494 						return (-1);
495 					}
496 					continue;
497 				}
498 			} else {		/* Not set -o, but: set -c */
499 #else	/* !DO_SET_O */
500 			{
501 #endif
502 				flagc = lookcopt(wc);
503 			}
504 			if (wc == *flagc) {
505 				if (eq(argv[0], "set") &&
506 				    wc && any(wc, UC "sicrp")) {
507 					failed(argv[1], badopt);
508 					return (-1);
509 				} else {
510 					unsigned long *fp = &flags;
511 #ifdef	DO_PS34
512 					unsigned long oflags;
513 #endif
514 
515 							/* LINTED */
516 					fv = flagval[flagc-flagchar];
517 					if (fv & fl2)
518 						fp = &flags2;
519 #ifdef	DO_PS34
520 					oflags = *fp;
521 #endif
522 					*fp |= fv & ~fl2;
523 					/*
524 					 * Disallow to set -n on an interactive
525 					 * shell as this cannot be reset.
526 					 */
527 					if (flags & intflg)
528 						flags &= ~noexec;
529 #ifdef	INTERACTIVE
530 					flags2 &= ~viflg;
531 #endif
532 					if (fv == errflg)
533 						eflag = errflg;
534 
535 #ifdef	DO_MONITOR_SCRIPT
536 					if (fv == monitorflg &&
537 					    (flags & jcflg) == 0) {
538 						startjobs();
539 					}
540 #endif
541 
542 #ifdef	EXECATTR_FILENAME		/* from <exec_attr.h> */
543 					if (fv == pfshflg)
544 						secpolicy_init();
545 #endif
546 					if (fv == (fl2 | versflg)) {
547 						flags2 &= ~versflg;
548 						prversion();
549 					}
550 #if	defined(DO_SYSALIAS) && defined(DO_GLOBALALIASES)
551 					if (fv == (fl2 | globalaliasflg)) {
552 						if (homenod.namval) {
553 						    catpath(homenod.namval,
554 						    UC globalname);
555 						    ab_use(GLOBAL_AB,
556 						    (char *)make(curstak()));
557 						}
558 					}
559 #endif
560 #if	defined(DO_SYSALIAS) && defined(DO_LOCALALIASES)
561 					if (fv == (fl2 | localaliasflg)) {
562 						ab_use(LOCAL_AB,
563 							(char *)localname);
564 					}
565 #endif
566 #ifdef	DO_HOSTPROMPT
567 					if (fv == (fl2 | hostpromptflg))
568 						hostprompt(TRUE);
569 #endif
570 #ifdef	DO_PS34
571 					if (fv == (fl2 | promptcmdsubst) &&
572 					    (oflags & promptcmdsubst) == 0)
573 						ps_reset();
574 #endif
575 #ifdef	DO_POSIX_EXPORT_ENV
576 					if (fv == (fl2 | posixflg))
577 						namscan(exportenv);
578 #endif
579 				}
580 			} else if (wc == 'c' && argc > 2 && comdiv == 0) {
581 				comdiv = argp[2];
582 				argp[1] = argp[0];
583 				argp++;
584 				argc--;
585 #ifdef	DO_POSIX_SET
586 				if (*argp[1] == '-' ||	/* Check for --    */
587 				    *argp[1] == '+')	/* or more options */
588 					goto again;
589 #endif
590 			} else {
591 				failed(argv[1], badopt);
592 				return (-1);
593 			}
594 		}
595 		argp[1] = argp[0];
596 		argc--;
597 		argp++;
598 	} else if (argc > 1 &&
599 		    *argp[1] == '+') { /* unset flags x, k, t, n, v, e, u */
600 #ifdef	DO_MULTI_OPT
601 		/*
602 		 * Mark that we will later need to correct comdiv.
603 		 */
604 		if (comdiv && dolv == NULL)
605 			comdiv = UC -1;
606 #endif
607 		(void) mbtowc(NULL, NULL, 0);
608 		cp = argp[1];
609 		cp++;
610 		while (*cp) {
611 			if ((len = mbtowc(&wc, (char *)cp, MB_LEN_MAX)) <= 0) {
612 				(void) mbtowc(NULL, NULL, 0);
613 				cp++;
614 				continue;
615 			}
616 			cp += len;
617 
618 #ifdef	DO_SET_O
619 			if (wc == 'o') {		/* set +o */
620 				int	dolistopts = argc <= 2 ||
621 						argp[2][0] == '-' ||
622 						argp[2][0] == '+';
623 
624 				if (dolistopts) {
625 					listopts(1);
626 					continue;
627 				}
628 				if ((flagc = lookopt(argp[2])) != NULL) {
629 						argp[1] = argp[0];
630 						argp++;
631 						argc--;
632 						wc = *flagc;
633 				}
634 				if (flagc == NULL || wc != *flagc) {
635 					if (argc > 2) {
636 						failed(argp[2], badopt);
637 						return (-1);
638 					}
639 					continue;
640 				}
641 			} else {		/* Not set +o, but: set +c */
642 #else	/* !DO_SET_O */
643 			{
644 #endif
645 				flagc = lookcopt(wc);
646 			}
647 			/*
648 			 * step through flags
649 			 */
650 			if (wc == 0 ||
651 			    (!any(wc, UC "sicrp") && wc == *flagc)) {
652 				unsigned long *fp = &flags;
653 							/* LINTED */
654 				fv = flagval[flagc-flagchar];
655 				if (fv & fl2)
656 					fp = &flags2;
657 				*fp &= ~fv;
658 				if (wc == 'e')
659 					eflag = 0;
660 #ifdef	EXECATTR_FILENAME
661 				if (fv == pfshflg)
662 					secpolicy_end();
663 #endif
664 #if	defined(DO_SYSALIAS) && defined(DO_GLOBALALIASES)
665 				if (fv == (fl2 | globalaliasflg)) {
666 					ab_use(GLOBAL_AB, NULL);
667 				}
668 #endif
669 #if	defined(DO_SYSALIAS) && defined(DO_LOCALALIASES)
670 				if (fv == (fl2 | localaliasflg)) {
671 					ab_use(LOCAL_AB, NULL);
672 				}
673 #endif
674 #if	defined(DO_SYSALIAS) && \
675 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
676 				if (fv == (fl2 | aliasownerflg)) {
677 					ab_setaltowner(GLOBAL_AB, "");
678 					ab_setaltowner(LOCAL_AB, "");
679 				}
680 #endif
681 #ifdef	DO_HOSTPROMPT
682 				if (fv == (fl2 | hostpromptflg))
683 					hostprompt(FALSE);
684 #endif
685 #ifdef	DO_POSIX_EXPORT_ENV
686 				if (fv == (fl2 | posixflg))
687 					namscan(deexportenv);
688 #endif
689 			} else {
690 				failed(argv[1], badopt);
691 				return (-1);
692 			}
693 		}
694 		argp[1] = argp[0];
695 		argc--;
696 		argp++;
697 	}
698 #ifdef	DO_MULTI_OPT
699 	if ((comdiv == NULL || dolv != NULL) &&
700 	    argc > 1 && (*argp[1] == '-' || *argp[1] == '+'))
701 		goto again;
702 
703 	if (comdiv == UC -1 && dolv == NULL) {
704 		/*
705 		 * Correct comdiv to point past last option.
706 		 */
707 		if (argc > 1) {
708 			comdiv = argp[1];
709 			argp[1] = argp[0];
710 			argv++;
711 			argc--;
712 		} else {
713 			failed(argv[1], mssgargn);
714 			return (-1);
715 		}
716 	}
717 #endif
718 
719 	setopts();
720 	return (argc);
721 }
722 
723 /*
724  * set up $-
725  * $- is only constructed from flag values in the basic "flags"
726  */
727 void
setopts()728 setopts()
729 {
730 	unsigned char	*flagc;
731 	unsigned char	*flagp;
732 	unsigned long	oflags = flags;
733 
734 	flagp = flagadr;
735 	flags |= eflag;
736 	if (flags) {
737 		flagc = flagchar;
738 		while (flagc < &flagchar[NFLAGCHAR]) {
739 			if (*flagc && optval(flagc))
740 				*flagp++ = *flagc;
741 			flagc++;
742 		}
743 	}
744 	*flagp = 0;
745 	flags = oflags;
746 }
747 
748 /*
749  * sets up positional parameters
750  */
751 void
setargs(argi)752 setargs(argi)
753 	unsigned char	*argi[];
754 {
755 	unsigned char **argp = argi;	/* count args */
756 	int argn = 0;
757 
758 	while (*argp++ != UC ENDARGS)
759 		argn++;
760 	/*
761 	 * free old ones unless on for loop chain
762 	 */
763 	freedolh();
764 	dolh = copyargs(argi, argn);
765 	dolc = argn - 1;
766 }
767 
768 
769 static void
freedolh()770 freedolh()
771 {
772 	unsigned char **argp;
773 	struct dolnod *argblk;
774 
775 	if ((argblk = dolh) != NULL) {
776 		if ((--argblk->doluse) == 0) {
777 			for (argp = argblk->dolarg; *argp != UC ENDARGS; argp++)
778 				free(*argp);
779 			free(argblk->dolarg);
780 			free(argblk);
781 		}
782 	}
783 }
784 
785 struct dolnod *
freeargs(blk)786 freeargs(blk)
787 	struct dolnod *blk;
788 {
789 	unsigned char **argp;
790 	struct dolnod *argr = 0;
791 	struct dolnod *argblk;
792 	int cnt;
793 
794 	if ((argblk = blk) != NULL) {
795 		argr = argblk->dolnxt;
796 		cnt  = --argblk->doluse;
797 
798 		if (argblk == dolh) {
799 			if (cnt == 1)
800 				return (argr);
801 			else
802 				return (argblk);
803 		} else {
804 			if (cnt == 0) {
805 				for (argp = argblk->dolarg;
806 				    *argp != UC ENDARGS; argp++) {
807 					free(*argp);
808 				}
809 				free(argblk->dolarg);
810 				free(argblk);
811 			}
812 		}
813 	}
814 	return (argr);
815 }
816 
817 static struct dolnod *
copyargs(from,n)818 copyargs(from, n)
819 	unsigned char	*from[];
820 	int		n;
821 {
822 	struct dolnod *np = (struct dolnod *)alloc(sizeof (struct dolnod));
823 	unsigned char **fp = from;
824 	unsigned char **pp;
825 
826 	np -> dolnxt = 0;
827 	np->doluse = 1;	/* use count */
828 	pp = np->dolarg = (unsigned char **)alloc((n+1)*sizeof (char *));
829 	dolv = pp;
830 
831 	while (n--)
832 		*pp++ = make(*fp++);
833 	*pp++ = ENDARGS;
834 	return (np);
835 }
836 
837 
838 static struct dolnod *
clean_args(blk)839 clean_args(blk)
840 	struct dolnod *blk;
841 {
842 	unsigned char **argp;
843 	struct dolnod *argr = 0;
844 	struct dolnod *argblk;
845 
846 	if ((argblk = blk) != NULL) {
847 		argr = argblk->dolnxt;
848 
849 		if (argblk == dolh) {
850 			argblk->doluse = 1;
851 		} else {
852 			for (argp = argblk->dolarg; *argp != UC ENDARGS; argp++)
853 				free(*argp);
854 			free(argblk->dolarg);
855 			free(argblk);
856 		}
857 	}
858 	return (argr);
859 }
860 
861 void
clearup()862 clearup()
863 {
864 	/*
865 	 * force `for' $* lists to go away
866 	 */
867 	if (globdolv)
868 		dolv = globdolv;
869 	if (globdolc)
870 		dolc = globdolc;
871 	if (globdolh)
872 		dolh = globdolh;
873 	globdolv = 0;
874 	globdolc = 0;
875 	globdolh = 0;
876 	while ((argfor = clean_args(argfor)) != NULL)
877 		/* LINTED */
878 		;
879 	/*
880 	 * clean up io files
881 	 */
882 	while (pop())
883 		/* LINTED */
884 		;
885 
886 	/*
887 	 * Clean up pipe file descriptor
888 	 * from command substitution
889 	 */
890 
891 	if (savpipe != -1) {
892 		close(savpipe);
893 		savpipe = -1;
894 	}
895 
896 	/*
897 	 * clean up tmp files
898 	 */
899 	while (poptemp())
900 		/* LINTED */
901 		;
902 }
903 
904 /*
905  * Save positiional parameters before outermost function invocation
906  * in case we are interrupted.
907  * Increment use count for current positional parameters so that they aren't
908  * thrown away.
909  */
910 
911 struct dolnod *
savargs(funcntp)912 savargs(funcntp)
913 	int	funcntp;
914 {
915 	if (!funcntp) {
916 		globdolh = dolh;
917 		globdolv = dolv;
918 		globdolc = dolc;
919 	}
920 	useargs();
921 	return (dolh);
922 }
923 
924 /*
925  * After function invocation, free positional parameters,
926  * restore old positional parameters, and restore
927  * use count.
928  */
929 
930 void
restorargs(olddolh,funcntp)931 restorargs(olddolh, funcntp)
932 	struct dolnod	*olddolh;
933 	int		funcntp;
934 {
935 	if (argfor != olddolh)
936 		while ((argfor = clean_args(argfor)) != olddolh && argfor)
937 			/* LINTED */
938 			;
939 	if (!argfor)
940 		return;
941 	freedolh();
942 	dolh = olddolh;
943 
944 	/*
945 	 * increment use count so arguments aren't freed
946 	 */
947 	if (dolh)
948 		dolh -> doluse++;
949 	argfor = freeargs(dolh);
950 	if (funcntp == 1) {
951 		globdolh = 0;
952 		globdolv = 0;
953 		globdolc = 0;
954 	}
955 }
956 
957 struct dolnod *
useargs()958 useargs()
959 {
960 	if (dolh) {
961 		if (dolh->doluse++ == 1) {
962 			dolh->dolnxt = argfor;
963 			argfor = dolh;
964 		}
965 	}
966 	return (dolh);
967 }
968 
969 static unsigned char *
lookcopt(wc)970 lookcopt(wc)
971 	int		wc;
972 {
973 	unsigned char *flagc;
974 
975 	flagc = flagchar;
976 	while (flagc < &flagchar[NFLAGCHAR]) {
977 		if (*flagc && wc == *flagc)
978 			break;
979 		flagc++;
980 	}
981 	return (flagc);
982 }
983 
984 int
optval(flagc)985 optval(flagc)
986 	unsigned char *flagc;
987 {
988 	unsigned long	fv;
989 	unsigned long	*fp;
990 
991 	if (flagc == NULL)
992 		return (0);
993 
994 				/* LINTED */
995 	fv = flagval[flagc-flagchar];
996 	fp = &flags;
997 	if (fv & fl2) {
998 		fp = &flags2;
999 		fv &= ~fl2;
1000 	}
1001 	return (*fp & fv ? 1:0);
1002 }
1003 
1004 #ifdef	DO_SET_O
1005 unsigned char *
lookopt(name)1006 lookopt(name)
1007 	unsigned char	*name;
1008 {
1009 	unsigned char *flagc;
1010 
1011 	for (flagc = flagchar;
1012 				/* LINTED */
1013 	    flagname[flagc-flagchar]; flagc++) {
1014 				/* LINTED */
1015 		if (eq(name,
1016 		    flagname[flagc-flagchar])) {
1017 			return (flagc);
1018 		}
1019 	}
1020 	return (NULL);
1021 }
1022 
1023 #if	defined(DO_SYSALIAS) && \
1024 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
1025 static void
listaliasowner(parse,flagidx)1026 listaliasowner(parse, flagidx)
1027 	int	parse;
1028 	int	flagidx;
1029 {
1030 	uid_t	altuid = ab_getaltowner(GLOBAL_AB);
1031 
1032 	if (parse) {
1033 		prs_buff(UC "set ");
1034 		if (altuid == (uid_t)-1)
1035 			prs_buff(UC "+o ");
1036 		else
1037 			prs_buff(UC "-o ");
1038 	}
1039 	prs_buff(UC flagname[flagidx]);
1040 	if (altuid == (uid_t)-1 && parse) {
1041 		prc_buff(NL);
1042 		return;
1043 	}
1044 	prs_buff(UC "=");
1045 	if (altuid != (uid_t)-1)
1046 		prs_buff(UC ab_getaltoname(GLOBAL_AB));
1047 	prc_buff(NL);
1048 }
1049 #endif
1050 
1051 static void
listopts(parse)1052 listopts(parse)
1053 	int	parse;
1054 {
1055 	unsigned char *flagc;
1056 	int		len;
1057 	unsigned long	fv;
1058 
1059 					/* LINTED */
1060 	for (flagc = flagchar; flagname[flagc-flagchar]; flagc++) {
1061 		if (*flagc == 'V')
1062 			continue;
1063 					/* LINTED */
1064 		fv = flagval[flagc-flagchar];
1065 #if	defined(DO_SYSALIAS) && \
1066 	(defined(DO_GLOBALALIASES) || defined(DO_LOCALALIASES))
1067 		if (fv == (fl2 | aliasownerflg)) {
1068 					/* LINTED */
1069 			listaliasowner(parse, flagc-flagchar);
1070 			continue;
1071 		}
1072 #endif
1073 		fv = optval(flagc);
1074 		if (parse) {
1075 			if (any(*flagc, UC "sicrp"))	/* Unsettable?    */
1076 				continue;		/* so do not list */
1077 			prs_buff(UC "set ");
1078 			prs_buff(UC(fv ? "-":"+"));
1079 			prs_buff(UC "o ");
1080 		}
1081 					/* LINTED */
1082 		prs_buff(UC flagname[flagc-flagchar]);
1083 		if (parse) {
1084 			prc_buff(NL);
1085 			continue;
1086 		}
1087 					/* LINTED */
1088 		len = length(UC flagname[flagc-flagchar]);
1089 		while (++len <= 16)
1090 			prc_buff(SPACE);
1091 		prc_buff(TAB);
1092 		prs_buff(UC(fv ? "on":"off"));
1093 		prc_buff(NL);
1094 	}
1095 }
1096 
1097 #ifdef	DO_HOSTPROMPT
1098 #include <schily/utsname.h>
1099 #include <schily/pwd.h>
1100 static void
hostprompt(on)1101 hostprompt(on)
1102 	int	on;
1103 {
1104 #ifdef	HAVE_UNAME
1105 	struct utsname	un;
1106 	struct passwd	*pw;
1107 	unsigned char	pr[1000];
1108 	unsigned char	*p;
1109 	uid_t		euid = geteuid();
1110 
1111 	if (on) {
1112 		if (ps1nod.namval != NULL &&
1113 		    !eq(ps1nod.namval, (euid ? stdprompt : supprompt)))
1114 			return;
1115 	}
1116 	uname(&un);
1117 	pw = getpwuid(euid);
1118 	if (pw == NULL)
1119 		return;
1120 	if ((length(UC un.nodename) + length(UC pw->pw_name) + 3) >
1121 	    sizeof (pr))
1122 		return;
1123 	p = movstr(UC un.nodename, pr);
1124 	*p++ = ' ';
1125 	p = movstr(UC pw->pw_name, p);
1126 	*p++ = '>';
1127 	*p++ = ' ';
1128 	*p++ = '\0';
1129 	if (!on) {
1130 		if (ps1nod.namval != NULL &&
1131 		    !eq(ps1nod.namval, pr))
1132 			return;
1133 	}
1134 	if (on)
1135 		assign(&ps1nod, pr);
1136 	else
1137 		assign(&ps1nod, UC(euid ? stdprompt : supprompt));
1138 #endif
1139 }
1140 #endif	/* DO_HOSTPROMPT */
1141 
1142 #ifdef	DO_PS34
1143 /*
1144  * Reset user specific prompts to their default values.
1145  */
1146 static void
ps_reset()1147 ps_reset()
1148 {
1149 	assign(&ps1nod, UC(geteuid() ? stdprompt : supprompt));
1150 	assign(&ps2nod, UC readmsg);
1151 #ifdef	__needed_
1152 	assign(&ps3nod, UC selectmsg);
1153 #endif
1154 	assign(&ps4nod, UC execpmsg);
1155 #ifdef	DO_HOSTPROMPT
1156 	if (flags2 & hostpromptflg)
1157 		hostprompt(TRUE);
1158 #endif
1159 }
1160 #endif	/* DO_PS34 */
1161 #endif	/* DO_SET_O */
1162