1 /* @(#)builtin.c	1.97 18/08/01 Copyright 1988-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)builtin.c	1.97 18/08/01 Copyright 1988-2018 J. Schilling";
6 #endif
7 /*
8  *	Builtin commands
9  *
10  *	Copyright (c) 1985-2018 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/stdio.h>
27 #include <schily/signal.h>
28 #include <schily/utypes.h>
29 #include <schily/resource.h>
30 #include "bsh.h"
31 #include "str.h"
32 #include "abbrev.h"
33 #include "strsubs.h"
34 #include "btab.h"
35 #include "map.h"
36 #include "node.h"
37 #include <schily/setjmp.h>
38 #include <schily/unistd.h>
39 #include <schily/stdlib.h>
40 #include <schily/fcntl.h>
41 #include <schily/ioctl.h>	/* Need to be before termios.h (BSD botch) */
42 #include <schily/termios.h>
43 #include <schily/utypes.h>
44 #include <schily/getargs.h>
45 #include <schily/time.h>
46 #include <schily/btorder.h>
47 
48 extern int	firstsh;
49 extern int 	delim;
50 extern int 	ex_status;
51 
52 extern	pid_t	opgrp;
53 extern	pid_t	mypgrp;
54 extern	pid_t	mypid;
55 
56 LOCAL jmp_buf	waitjmp;
57 
58 LOCAL	btab	*blook		__PR((char	*name, btab *bt, int n));
59 EXPORT	void	wrong_args	__PR((Argvec * vp, FILE ** std));
60 EXPORT	void	unimplemented	__PR((Argvec * vp, FILE ** std));
61 LOCAL	BOOL	not_loginsh	__PR((FILE ** std));
62 LOCAL	BOOL	helpwanted	__PR((Argvec * vp, FILE ** std));
63 EXPORT	BOOL	busage		__PR((Argvec * vp, FILE ** std));
64 EXPORT	BOOL	toint		__PR((FILE ** std, char *s, int *i));
65 EXPORT	BOOL	tolong		__PR((FILE ** std, char *s, long *l));
66 EXPORT	BOOL	tollong		__PR((FILE ** std, char *s, Llong *ll));
67 LOCAL	BOOL	isbadlpid	__PR((FILE ** std, long	lpid));
68 EXPORT	void	bnallo		__PR((Argvec * vp, FILE ** std, int flag));
69 EXPORT	void	bdummy		__PR((Argvec * vp, FILE ** std, int flag));
70 LOCAL	int	do_oset		__PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
71 LOCAL	int	do_ounset	__PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
72 EXPORT	void	bsetcmd		__PR((Argvec * vp, FILE ** std, int flag));
73 EXPORT	void	bunset		__PR((Argvec * vp, FILE ** std, int flag));
74 EXPORT	void	bsetenv		__PR((Argvec * vp, FILE ** std, int flag));
75 EXPORT	void	bunsetenv	__PR((Argvec * vp, FILE ** std, int flag));
76 EXPORT	void	bconcat		__PR((Argvec * vp, FILE ** std, int flag));
77 EXPORT	void	bmap		__PR((Argvec * vp, FILE ** std, int flag));
78 EXPORT	void	bunmap		__PR((Argvec * vp, FILE ** std, int flag));
79 EXPORT	void	bexit		__PR((Argvec * vp, FILE ** std, int flag));
80 EXPORT	void	beval		__PR((Argvec * vp, FILE ** std, int flag));
81 EXPORT	void	bdo		__PR((Argvec * vp, FILE ** std, int flag));
82 EXPORT	void	benv		__PR((Argvec * vp, FILE ** std, int flag));
83 EXPORT	void	bwait		__PR((Argvec * vp, FILE ** std, int flag));
84 LOCAL	sigret	waitint		__PR((int sig));
85 LOCAL	int	gsig		__PR((char *s, int *sigp));
86 EXPORT	void	bkill		__PR((Argvec * vp, FILE ** std, int flag));
87 LOCAL	void	killp		__PR((FILE ** std, BOOL grpflg, pid_t p, int sig));
88 EXPORT	void	bsuspend	__PR((Argvec * vp, FILE ** std, int flag));
89 EXPORT	void	bresume		__PR((Argvec * vp, FILE ** std, int flag));
90 EXPORT	void	bfg		__PR((Argvec * vp, FILE ** std, int flag));
91 EXPORT	void	bpgrp		__PR((Argvec * vp, FILE ** std, int flag));
92 EXPORT	void	bsync		__PR((Argvec * vp, FILE ** std, int flag));
93 EXPORT	void	bumask		__PR((Argvec * vp, FILE ** std, int flag));
94 EXPORT	void	bsetmask	__PR((Argvec * vp, FILE ** std, int flag));
95 LOCAL	char	*cvmode		__PR((int c, char *cp, char *ep, char *mode));
96 LOCAL	int	mval		__PR((mode_t m));
97 LOCAL	void	pmask		__PR((FILE ** std, BOOL do_posix));
98 EXPORT	void	blogout		__PR((Argvec * vp, FILE ** std, int flag));
99 EXPORT	void	becho		__PR((Argvec * vp, FILE ** std, int flag));
100 EXPORT	void	bshift		__PR((Argvec * vp, FILE ** std, int flag));
101 EXPORT	void	bremap		__PR((Argvec * vp, FILE ** std, int flag));
102 EXPORT	void	bsavehist	__PR((Argvec * vp, FILE ** std, int flag));
103 EXPORT	void	bhistory	__PR((Argvec * vp, FILE ** std, int flag));
104 EXPORT	void	bsource		__PR((Argvec * vp, FILE ** std, int flag));
105 EXPORT	void	brepeat		__PR((Argvec * vp, FILE ** std, int flag));
106 EXPORT	void	bexec		__PR((Argvec * vp, FILE ** std, int flag));
107 EXPORT	void	blogin		__PR((Argvec * vp, FILE ** std, int flag));
108 LOCAL	void	my_exec		__PR((char *name, int first_ac, Argvec *vp, FILE **std));
109 EXPORT	void	berrstr		__PR((Argvec * vp, FILE ** std, int flag));
110 EXPORT	void	btype		__PR((Argvec * vp, FILE ** std, int flag));
111 EXPORT	void	btrue		__PR((Argvec * vp, FILE ** std, int flag));
112 EXPORT	void	bfalse		__PR((Argvec * vp, FILE ** std, int flag));
113 #ifdef	DO_FIND
114 LOCAL	int	quitfun		__PR((void *arg));
115 #endif
116 EXPORT	BOOL	builtin		__PR((Argvec * vp, FILE ** std, int flag));
117 LOCAL	int	suspend		__PR((pid_t p));
118 LOCAL	int	presume		__PR((pid_t p));
119 LOCAL	mode_t	setcmask	__PR((mode_t newmask));
120 LOCAL	mode_t	getcmask	__PR((void));
121 
122 /*
123  * Lookup the builtin command table for a specific function
124  */
125 LOCAL btab *
blook(name,bt,n)126 blook(name, bt, n)
127 	register char	*name;
128 	register btab	*bt;
129 		int	n;
130 {
131 	register char	*s1;
132 	register char	*s2;
133 	register int	mid;
134 	register int	low;
135 	register int	high;
136 
137 	low = 0;
138 	high = n - 1;
139 	while (low <= high) {
140 		mid = (low + high) / 2;
141 		s1 = name;
142 		s2 = bt[mid].b_name;
143 		for (; *s1 == *s2; s1++, s2++) /* viel schneller als strcmp */
144 			if (*s1 == '\0')
145 				return (&bt[mid]);
146 		if (*s1 < *s2) {
147 			high = mid - 1;
148 			continue;
149 		}
150 		low = mid + 1;
151 	}
152 	return ((btab *) NULL);
153 }
154 
155 /*
156  * Generic function used when a builtin is called with a wrong number of args
157  */
158 EXPORT void
wrong_args(vp,std)159 wrong_args(vp, std)
160 	Argvec	*vp;
161 	FILE	*std[];
162 {
163 	fprintf(std[2], "%s: Wrong number of args.\n", vp->av_av[0]);
164 	busage(vp, std);
165 	ex_status = 1;
166 }
167 
168 /*
169  * Generic funtcion used to replace unimplemented funtions
170  */
171 EXPORT void
unimplemented(vp,std)172 unimplemented(vp, std)
173 	Argvec	*vp;
174 	FILE	*std[];
175 {
176 	fprintf(std[2], "%s: unimplemented.\n", vp->av_av[0]);
177 	ex_status = 1;
178 }
179 
180 /*
181  * Error function used when a function which is resereved for a login shell
182  * is used from a non-login shell
183  */
184 LOCAL BOOL
not_loginsh(std)185 not_loginsh(std)
186 	FILE	*std[];
187 {
188 	if (!firstsh) {
189 		fprintf(std[2], "Not login shell.\n");
190 		ex_status = 1;
191 		return (TRUE);
192 	}
193 	return (FALSE);
194 }
195 
196 /*
197  * The generic function to check whether a builtin has been called
198  * with the -help option
199  */
200 LOCAL BOOL
helpwanted(vp,std)201 helpwanted(vp, std)
202 	Argvec	*vp;
203 	FILE	*std[];
204 {
205 	if (vp->av_ac > 1 &&
206 	    (streql(vp->av_av[1], helpname) ||
207 	    (vp->av_av[1][0] == '-' && vp->av_av[1][1] == '-' &&
208 	    streql(&vp->av_av[1][1], helpname)))) {
209 		return (busage(vp, std));
210 	}
211 	return (FALSE);
212 }
213 
214 /*
215  * The generic function to print the usage for a builtin function.
216  */
217 EXPORT BOOL
busage(vp,std)218 busage(vp, std)
219 	Argvec	*vp;
220 	FILE	*std[];
221 {
222 	register btab	*bp;
223 	register char	*name = vp->av_av[0];
224 
225 	if ((bp = blook(name, bitab, n_builtin)) != NULL && bp->b_help) {
226 		if (bp->b_help == (char *)-1)
227 			return (FALSE);
228 		fprintf(std[2], "%s%s [options] %s\n", usage, name, bp->b_help);
229 		return (TRUE);
230 	}
231 	return (FALSE);
232 }
233 
234 EXPORT BOOL
toint(std,s,i)235 toint(std, s, i)
236 	FILE	*std[];
237 	char	*s;
238 	int	*i;
239 {
240 	if (*s == '\0' || *astoi(s, i)) {
241 		fprintf(std[2], "Not a number: %s.\n", s);
242 		ex_status = 1;
243 		return (FALSE);
244 	}
245 	return (TRUE);
246 }
247 
248 EXPORT BOOL
tolong(std,s,l)249 tolong(std, s, l)
250 	FILE	*std[];
251 	char	*s;
252 	long	*l;
253 {
254 	if (*s == '\0' || *astol(s, l)) {
255 		fprintf(std[2], "Not a number: %s.\n", s);
256 		ex_status = 1;
257 		return (FALSE);
258 	}
259 	return (TRUE);
260 }
261 
262 EXPORT BOOL
tollong(std,s,ll)263 tollong(std, s, ll)
264 	FILE	*std[];
265 	char	*s;
266 	Llong	*ll;
267 {
268 	if (*s == '\0' || *astoll(s, ll)) {
269 		fprintf(std[2], "Not a number: %s.\n", s);
270 		ex_status = 1;
271 		return (FALSE);
272 	}
273 	return (TRUE);
274 }
275 
276 LOCAL BOOL
isbadlpid(std,lpid)277 isbadlpid(std, lpid)
278 	FILE	*std[];
279 	long	lpid;
280 {
281 	pid_t	p = lpid;
282 
283 	if (p != lpid) {
284 		fprintf(std[2], "Bad process id: %ld.\n", lpid);
285 		ex_status = 1;
286 		return (TRUE);
287 	}
288 	return (FALSE);
289 }
290 
291 /* ARGSUSED */
292 EXPORT void
bnallo(vp,std,flag)293 bnallo(vp, std, flag)
294 	Argvec	*vp;
295 	FILE	*std[];
296 	int	flag;
297 {
298 	fprintf(std[2], "'%s' not allowed here.\n", vp->av_av[0]);
299 }
300 
301 /* ARGSUSED */
302 EXPORT void
bdummy(vp,std,flag)303 bdummy(vp, std, flag)
304 	Argvec	*vp;
305 	FILE	*std[];
306 	int	flag;
307 {
308 	/* this procedure does nothing */
309 }
310 
311 struct seta {
312 	int	pfshell;
313 	char	*aliasowner;
314 	int	olist;
315 };
316 
317 /* ARGSUSED */
318 LOCAL int
do_oset(arg,valp,pac,pav,opt)319 do_oset(arg, valp, pac, pav, opt)
320 	const char	*arg;
321 	void		*valp;
322 	int		*pac;
323 	char	*const	**pav;
324 	const char	 *opt;
325 {
326 	if (arg[0] == '-' || arg[0] == '+') {
327 		/*
328 		 * Strange Korn Shell rules:
329 		 * If next arg is an option, -o was called without parameter.
330 		 */
331 		if (arg == &opt[2])		/* arg concatenated with -o */
332 			return (BADFLAG);
333 		(*pav)--;
334 		(*pac)++;
335 		*(int *)valp = TRUE;
336 		((struct seta *)valp)->olist = TRUE;
337 		return (1);
338 	}
339 	if (streql(arg, "aliasowner")) {
340 		((struct seta *)valp)->aliasowner = "";
341 		return (1);
342 	} else if (strncmp(arg, "aliasowner=", 11) == 0) {
343 		((struct seta *)valp)->aliasowner = (char *)&arg[11];
344 		return (1);
345 	} else if (streql(arg, "profile")) {
346 		((struct seta *)valp)->pfshell = TRUE;
347 		return (1);
348 	}
349 	((struct seta *)valp)->olist = -1;
350 	return (BADFLAG);
351 }
352 
353 /* ARGSUSED */
354 LOCAL int
do_ounset(arg,valp,pac,pav,opt)355 do_ounset(arg, valp, pac, pav, opt)
356 	const char	*arg;
357 	void		*valp;
358 	int		*pac;
359 	char	*const	**pav;
360 	const char	 *opt;
361 {
362 	if (arg[0] == '-' || arg[0] == '+') {
363 		/*
364 		 * Strange Korn Shell rules:
365 		 * If next arg is an option, +o was called without parameter.
366 		 */
367 		if (arg == &opt[2])		/* arg concatenated with +o */
368 			return (BADFLAG);
369 		(*pav)--;
370 		(*pac)++;
371 		((struct seta *)valp)->olist = TRUE;
372 		return (1);
373 	}
374 	if (streql(arg, "aliasowner")) {
375 		((struct seta *)valp)->aliasowner = "";
376 		return (1);
377 	} else if (streql(arg, "profile")) {
378 		((struct seta *)valp)->pfshell = FALSE;
379 		return (1);
380 	}
381 	((struct seta *)valp)->olist = -1;
382 	return (BADFLAG);
383 }
384 
385 /* ARGSUSED */
386 EXPORT void
bsetcmd(vp,std,flag)387 bsetcmd(vp, std, flag)
388 	register	Argvec	*vp;
389 			FILE	*std[];
390 			int	flag;
391 {
392 	int	ac;
393 	char	* const *av;
394 	BOOL	help	= FALSE;
395 	struct seta	seta;
396 	int	ret;
397 
398 	if (vp->av_ac <= 1) {
399 		ev_list(std[1]);
400 		return;
401 	}
402 	seta.pfshell	= pfshell;
403 	seta.aliasowner	= NULL;
404 	seta.olist	= FALSE;
405 
406 	ac = vp->av_ac - 1;	/* set values */
407 	av = &vp->av_av[1];
408 	ret = getargs(&ac, &av, "help,P%1,+P%0,o&,+o&",
409 			&help,
410 			&seta.pfshell, &seta.pfshell,
411 			do_oset, &seta, do_ounset, &seta);
412 
413 	/*
414 	 * The Korn Shell implements a really strange syntax.
415 	 * set -o uses an optional argument which is hard to parse with a
416 	 * standardized option parser.
417 	 */
418 	if (ret == BADFLAG && ac == 1 && seta.olist >= 0 &&
419 	    ((av[0][0] == '-' || av[0][0] == '+') && av[0][1] == 'o' && av[0][2] == '\0')) {
420 		seta.olist = TRUE;
421 	} else if (ret < 0 &&
422 		    (av[0][0] == '-' || av[0][0] == '+' || seta.olist < 0)) {
423 		fprintf(std[2], "Bad option '%s'\n", av[0]);
424 		busage(vp, std);
425 		ex_status = 1;
426 		return;
427 	}
428 
429 	if (seta.aliasowner != NULL) {
430 		ab_setaltowner(GLOBAL_AB, seta.aliasowner);
431 		ab_setaltowner(LOCAL_AB, seta.aliasowner);
432 	}
433 	if (seta.pfshell != pfshell) {
434 		pfshell = seta.pfshell;
435 		if (pfshell)
436 			pfinit();
437 		else
438 			pfend();
439 	}
440 
441 	if (ret != FLAGDELIM && ac == 1)
442 		ev_insert(makestr(av[0]));
443 	else if (ac > 1)
444 		wrong_args(vp, std);
445 
446 	if (seta.olist) {
447 		uid_t	altuid = ab_getaltowner(GLOBAL_AB);
448 		char	*altuname = "";
449 
450 		if (altuid != (uid_t)-1)
451 			altuname = ab_getaltoname(GLOBAL_AB);
452 
453 		fprintf(std[1], "Current option settings\n");
454 		fprintf(std[1], "profile		%s\n", pfshell ? "on" : "off");
455 		fprintf(std[1], "aliasowner=%s\n", altuname);
456 	}
457 }
458 
459 /* ARGSUSED */
460 EXPORT void
bunset(vp,std,flag)461 bunset(vp, std, flag)
462 	Argvec	*vp;
463 	FILE	*std[];
464 	int	flag;
465 {
466 	ev_delete(vp->av_av[1]);
467 }
468 
469 /* ARGSUSED */
470 EXPORT void
bsetenv(vp,std,flag)471 bsetenv(vp, std, flag)
472 	register Argvec	*vp;
473 		FILE	*std[];
474 		int	flag;
475 {
476 	if (vp->av_ac == 1)
477 		ev_list(std[1]);
478 	else if (vp->av_ac != 3)
479 		wrong_args(vp, std);
480 	else
481 		ev_insert(concat(vp->av_av[1], eql, vp->av_av[2], (char *)NULL));
482 }
483 
484 /* ARGSUSED */
485 EXPORT void
bunsetenv(vp,std,flag)486 bunsetenv(vp, std, flag)
487 	Argvec	*vp;
488 	FILE	*std[];
489 	int	flag;
490 {
491 	ev_delete(vp->av_av[1]);
492 }
493 
494 /* ARGSUSED */
495 EXPORT void
bconcat(vp,std,flag)496 bconcat(vp, std, flag)
497 	register	Argvec	*vp;
498 			FILE	*std[];
499 			int	flag;
500 {
501 	register	char	*args;
502 
503 	if (vp->av_ac < 3) {
504 		wrong_args(vp, std);
505 	} else {
506 		args = concatv(&vp->av_av[2]);
507 		ev_insert(concat(vp->av_av[1], eql, args, (char *)NULL));
508 		free(args);
509 	}
510 }
511 
512 /* ARGSUSED */
513 EXPORT void
bmap(vp,std,flag)514 bmap(vp, std, flag)
515 	register	Argvec	*vp;
516 			FILE	*std[];
517 			int	flag;
518 {
519 #ifdef	INTERACTIVE
520 	if (vp->av_ac == 1)
521 		list_map(std[1]);
522 	else if (vp->av_ac == 2 && streql(vp->av_av[1], "-r"))
523 		remap();
524 	else if (vp->av_ac == 3 && streql(vp->av_av[1], "-u"))
525 		del_map(vp->av_av[2]);
526 	else if (vp->av_ac != 3 && vp->av_ac != 4)
527 		wrong_args(vp, std);
528 	else if (!add_map(vp->av_av[1], vp->av_av[2], vp->av_av[3])) {
529 		ex_status = 1;
530 		fprintf(std[2], "'%s' already defined.\n", vp->av_av[1]);
531 	}
532 #else
533 	unimplemented(vp, std);
534 #endif
535 }
536 
537 /* ARGSUSED */
538 EXPORT void
bunmap(vp,std,flag)539 bunmap(vp, std, flag)
540 	Argvec	*vp;
541 	FILE	*std[];
542 	int	flag;
543 {
544 #ifdef	INTERACTIVE
545 	del_map(vp->av_av[1]);
546 #else
547 	unimplemented(vp, std);
548 #endif
549 }
550 
551 /* ARGSUSED */
552 EXPORT void
bexit(vp,std,flag)553 bexit(vp, std, flag)
554 	register	Argvec	*vp;
555 			FILE	*std[];
556 			int	flag;
557 {
558 	if (vp->av_ac > 2) {
559 		wrong_args(vp, std);
560 		return;
561 	}
562 	if (vp->av_ac == 2 && !toint(std, vp->av_av[1], &ex_status))
563 		return;
564 	exitbsh(ex_status);
565 }
566 
567 /* ARGSUSED */
568 EXPORT void
beval(vp,std,flag)569 beval(vp, std, flag)
570 	register	Argvec	*vp;
571 			FILE	*std[];
572 			int	flag;
573 {
574 	register int i;
575 
576 	delim = ' ';
577 	pushline(nl);
578 	for (i = vp->av_ac; --i > 0; )
579 		pushline(vp->av_av[i]);
580 /*	freetree(cmdline(0|PGRP, std, FALSE));*/
581 	freetree(cmdline(flag, std, FALSE));
582 }
583 
584 /*
585  * Execute a command with new args
586  */
587 /* ARGSUSED */
588 EXPORT void
bdo(vp,std,flag)589 bdo(vp, std, flag)
590 	register	Argvec	*vp;
591 			FILE	*std[];
592 			int	flag;
593 {
594 	int	sac = vac;			/* save old args */
595 	char	**sav = vav;
596 	BOOL	isdosh;
597 
598 	isdosh = streql(vp->av_av[0], "dosh");
599 
600 	if (isdosh) {
601 		/*
602 		 * dosh command_string [command_name [[args]]
603 		 */
604 		if (vp->av_ac <= 1)
605 			return;
606 		vac = vp->av_ac - 2;		/* set new args */
607 		vav = &vp->av_av[2];
608 	} else {
609 		/*
610 		 * do command_string [args]
611 		 */
612 		vac = vp->av_ac - 1;		/* set new args */
613 		vav = &vp->av_av[1];
614 	}
615 #ifdef DEBUGX
616 	printf("        bdo: executing '%s'\n", vp->av_av[1]); flush();
617 #endif
618 	pushline(vp->av_av[1]);
619 /*	freetree(cmdline(0|PGRP, std, FALSE));*/
620 	freetree(cmdline(flag, std, FALSE));
621 	vac = sac;
622 	vav = sav;
623 }
624 
625 /*
626  * Execute a command with new environment.
627  * Also called for "name=value ...", in this case the ENV flag is set.
628  */
629 /* ARGSUSED */
630 EXPORT void
benv(vp,std,flag)631 benv(vp, std, flag)
632 	register	Argvec	*vp;
633 			FILE	*std[];
634 			int	flag;
635 {
636 extern	unsigned evasize;
637 extern	int	evaent;
638 	Argvec	*nvp;
639 	int	len;
640 	int	i;
641 	int	ac;
642 	char	* const *av;
643 	char	*p;
644 	char	*opt = "i";
645 	BOOL	iflag = FALSE;
646 	BOOL	keepenv = FALSE;
647 	pid_t	child;
648 volatile int	cstat;
649 
650 	ac = len = vp->av_ac - 1;	/* set values */
651 	av = &vp->av_av[1];
652 	if (ac < 1) {
653 		ev_list(std[1]);
654 		return;
655 	}
656 	if ((flag & ENV) && strchr(av[ac-1], '=') != NULL) {
657 		for (i = 0; i < ac; i++) {
658 			if (strchr(av[i], '=') == NULL)
659 				break;
660 		}
661 		if (i == ac)
662 			keepenv = TRUE;	/* This is only a list of a=b args */
663 
664 	} else if ((flag & ENV) == 0) {
665 		if (av[0][0] == '-' && av[0][1] == '\0') { /* non std '-' opt */
666 			iflag = TRUE;
667 			ac--;
668 			av++;
669 		}
670 		if (getargs(&ac, &av, opt, &iflag) < 0 && av[0][0] == '-') {
671 			busage(vp, std);
672 			ex_status = 1;
673 			return;
674 		}
675 	}
676 
677 	/*
678 	 * Add new environment entries.
679 	 * This is only a list of a=b args - no real "env" command.
680 	 */
681 	if (keepenv) {
682 		for (; ac > 0 && (p = strchr(av[0], '=')) != NULL; ac--, av++) {
683 			if (ev_set_locked(av[0]))
684 				continue;
685 			ev_insert(makestr(av[0]));
686 		}
687 		return;
688 	}
689 
690 	setstime();
691 	child = shfork(flag);
692 	if (child == 0) {
693 
694 		if (iflag) {
695 			evarray = (char **)NULL;
696 			evasize = 0;
697 			evaent = 0;
698 			ev_inc();
699 		}
700 		/*
701 		 * Add new environment entries.
702 		 */
703 		for (; ac > 0 && (p = strchr(av[0], '=')) != NULL; ac--, av++) {
704 			if (ev_set_locked(av[0]))
705 				continue;
706 			ev_insert(makestr(av[0]));
707 		}
708 		if (ac < 1) {			/* If no args list env */
709 			ev_list(std[1]);
710 			_exit(0);
711 		}
712 
713 
714 		nvp = allocvec(ac);
715 		for (i = 0; i < ac; i++) {
716 			nvp->av_av[i] = vp->av_av[i + (len-ac) + 1];
717 		}
718 		cstat = execcmd(nvp, std, flag | (iflag ? IGNENV : 0));
719 		if (ex_status)
720 			_exit(ex_status);
721 		_exit(cstat);
722 		/*
723 		 * This is a (hidden) background command, so we wo not
724 		 * need to call: free(nvp);
725 		 */
726 	} else if (child != -1) {
727 		if (!(flag & ASYNC))
728 			ewait(child, WALL|NOTMS);
729 	}
730 }
731 
732 /*
733  * Wait for commands that have been previously executed in background.
734  */
735 /* ARGSUSED */
736 EXPORT void
bwait(vp,std,flag)737 bwait(vp, std, flag)
738 	register	Argvec	*vp;
739 			FILE	*std[];
740 			int	flag;
741 {
742 	pid_t	p;
743 	long	lp;
744 	char	**t;
745 	volatile sigtype intsav = SIG_DFL;
746 
747 	if (!setjmp(waitjmp)) {
748 		if (osig2 != (sigtype) SIG_IGN)
749 			intsav = signal(SIGINT, waitint);
750 		/*
751 		 * A longjmp() from the SIGINT handler may leave
752 		 * SIGINT blocked.
753 		 */
754 		unblock_sigs();
755 		if (vp->av_ac == 1) {
756 			ex_status = ewait((pid_t)0, 0);
757 		} else for (t = &vp->av_av[1]; *t != NULL; t++) {
758 			if (!tolong(std, *t, &lp))
759 				return;
760 			p = lp;
761 			if (isbadlpid(std, lp))
762 				return;
763 			ex_status = ewait(p, WALL);
764 		}
765 	}
766 	if (osig2 != (sigtype) SIG_IGN)
767 		signal(SIGINT, intsav);
768 }
769 
770 /* ARGSUSED */
771 LOCAL sigret
waitint(sig)772 waitint(sig)
773 	int	sig;
774 {
775 	extern int sigcount[];
776 
777 	signal(SIGINT, waitint);
778 	sigcount[SIGINT]++;
779 	longjmp(waitjmp, TRUE);
780 }
781 
782 LOCAL int
gsig(s,sigp)783 gsig(s, sigp)
784 	char	*s;
785 	int	*sigp;
786 {
787 	int	sig;
788 
789 	if (*astoi(s, &sig)) {
790 		if (str2sig(s, &sig) != 0) {
791 			if (streql(s, "IOT")) {
792 				sig = SIGABRT;
793 			} else {
794 				return (-1);
795 			}
796 		}
797 	}
798 	*sigp = sig;
799 	if (sig > NSIG || sig < 0)
800 		return (-1);
801 	return (1);
802 }
803 
804 /* ARGSUSED */
805 EXPORT void
bkill(vp,std,flag)806 bkill(vp, std, flag)
807 	register	Argvec	*vp;
808 		FILE	*std[];
809 		int	flag;
810 {
811 	int	ac;
812 	char	* const *av;
813 	char	*opt = "l,&";
814 	BOOL	list = FALSE;
815 	BOOL	kpgrp;
816 	pid_t	p;
817 	long	lp;
818 	int	sig = SIGTERM;
819 	int	i;
820 	register char * const *t;
821 
822 	ac = vp->av_ac - 1;		/* set values */
823 	av = &vp->av_av[1];
824 	if (getargs(&ac, &av, opt, &list, gsig, &sig, &kpgrp) < 0) {
825 		if (sig > NSIG || sig < 0)
826 			fprintf(std[2], "%s: Bad signo: %d.", vp->av_av[0], sig);
827 		else
828 			fprintf(std[2], ebadopt, vp->av_av[0], av[0]);
829 		fprintf(std[2], " kill -l lists signals\n");
830 		busage(vp, std);
831 		ex_status = 1;
832 		return;
833 	}
834 	if (list) {
835 		int	maxsig = NSIG-1;
836 
837 		if (ac > 0) {
838 			char	sname[32];
839 			char	*cp;
840 
841 			for (i = 0; i < ac; i++) {
842 				sig = 0;
843 				cp = astoi(av[i], &sig);
844 				sig &= 0x7F;
845 				if (*cp || sig2str(sig, sname) < 0) {
846 					fprintf(std[2], "%s: Bad sig: '%s'.\n",
847 						vp->av_av[0],
848 						av[i]);
849 					ex_status = 1;
850 					return;
851 				}
852 				fprintf(std[1], "%s\n", sname);
853 			}
854 			return;
855 		}
856 #ifdef	SIGRTMAX
857 		if (SIGRTMAX > maxsig)
858 			maxsig = SIGRTMAX;
859 #endif
860 		for (i = 1; i <= maxsig; i++) {
861 			char	sname[32];
862 
863 			if (sig2str(i, sname) == 0)
864 				fprintf(std[1], "%s ", sname);
865 			else
866 				fprintf(std[1], "%d ", i);
867 			if (i % 8 == 0)
868 				fprintf(std[1], "%s", nl);
869 		}
870 		fprintf(std[1], "%s", nl);
871 		return;
872 	}
873 	if (ac < 1) {
874 		wrong_args(vp, std);
875 		return;
876 	}
877 	kpgrp = streql(vp->av_av[0], "killpg");
878 	for (t = av; *t != NULL; t++) {
879 		if (!tolong(std, *t, &lp))
880 			return;
881 		p = lp;
882 		if (isbadlpid(std, lp))
883 			return;
884 		killp(std, kpgrp, p, sig);
885 	}
886 }
887 
888 #	ifndef	HAVE_KILLPG
889 #		define	killpg(p, s)	kill(-(p), s)
890 #	endif
891 
892 #ifdef	PROTOTYPES
893 LOCAL void
killp(FILE ** std,BOOL grpflg,pid_t p,int sig)894 killp(FILE ** std, BOOL grpflg, pid_t p, int sig)
895 #else
896 LOCAL void
897 killp(std, grpflg, p, sig)
898 	FILE	*std[];
899 	BOOL	grpflg;
900 	pid_t	p;
901 	int	sig;
902 #endif
903 {
904 	if ((grpflg ? killpg(p, sig) : kill(p, sig)) < 0) {
905 		char	sname[32];
906 
907 		ex_status = geterrno();
908 		fprintf(std[2], "Can't send ");
909 		if (sig2str(sig, sname) == 0)
910 			fprintf(std[2], "SIG%s ", sname);
911 		else
912 			fprintf(std[2], "signal %d ", sig);
913 		fprintf(std[2], "to %s %lld. %s\n",
914 			grpflg ? "processgroup" : "process", (Llong)p,
915 			errstr(ex_status));
916 	}
917 #ifdef	SIGCONT
918 	if (sig == SIGHUP || sig == SIGTERM)
919 		grpflg ? killpg(p, SIGCONT) : kill(p, SIGCONT);
920 #endif	/* SIGCONT */
921 }
922 
923 /* ARGSUSED */
924 EXPORT void
bsuspend(vp,std,flag)925 bsuspend(vp, std, flag)
926 	register	Argvec	*vp;
927 			FILE	*std[];
928 			int	flag;
929 {
930 	pid_t	p = (pid_t)-1;
931 	long	lp;
932 	register char **t;
933 	sigtype intsav = (sigtype) SIG_DFL;
934 	int	stop;
935 
936 #if	defined(SIGTSTP) || defined(JOS)
937 
938 	stop = streql("stop", vp->av_av[0]);
939 	if (vp->av_ac == 1) {
940 		if (stop) {
941 			wrong_args(vp, std);
942 			return;
943 		}
944 		p = mypid;
945 		if (firstsh) {
946 			fprintf(std[2], "Can't suspend login shell.\n");
947 			ex_status = 1;
948 			return;
949 		}
950 #ifdef	SIGTSTP
951 		intsav = signal(SIGTSTP, (sigtype) SIG_DFL);
952 #endif
953 		if (suspend(p) < 0)
954 			ex_status = geterrno();
955 	} else for (t = &vp->av_av[1]; *t != NULL; t++) {
956 		if (!tolong(std, *t, &lp))
957 			return;
958 		p = lp;
959 		if (isbadlpid(std, lp))
960 			return;
961 		/* stop == killpg ???? */
962 		if (kill(p, stop ? SIGSTOP : SIGTSTP) < 0) {
963 			ex_status = geterrno();
964 			break;
965 		}
966 	}
967 #ifdef	SIGTSTP
968 	if (intsav != (sigtype) SIG_DFL)
969 		signal(SIGTSTP, intsav);
970 #endif
971 	if (ex_status != 0)
972 		fprintf(std[2], "Can't %s %lld. %s\n",
973 				vp->av_av[0], (Llong)p, errstr(ex_status));
974 #else	/* defined(SIGTSTP) || defined(JOS) */
975 	unimplemented(vp, std);
976 #endif	/* defined(SIGTSTP) || defined(JOS) */
977 }
978 
979 
980 /* ARGSUSED */
981 EXPORT void
bresume(vp,std,flag)982 bresume(vp, std, flag)
983 	register	Argvec	*vp;
984 			FILE	*std[];
985 			int	flag;
986 {
987 	pid_t	p;
988 	long	lp;
989 #ifdef	JOBCONTROL
990 	pid_t	pgrp;
991 #endif	/* JOBCONTROL */
992 
993 #if	defined(SIGCONT) || defined(JOS)
994 
995 	if (!tolong(std, vp->av_av[1], &lp))
996 		return;
997 	p = lp;
998 	if (isbadlpid(std, lp))
999 		return;
1000 #ifdef	JOBCONTROL
1001 	pgrp = getpgid(p);
1002 	tty_setpgrp(0, pgrp);
1003 #endif	/* JOBCONTROL */
1004 	if (presume(p) < 0) {
1005 		ex_status = geterrno();
1006 		fprintf(std[2], "Can't resume %ld. %s\n", (long)p, errstr(ex_status));
1007 	} else if (!(flag & ASYNC)) {
1008 		ewait(p, WALL);
1009 	}
1010 
1011 #else	/* defined(SIGCONT) || defined(JOS) */
1012 
1013 	unimplemented(vp, std);
1014 
1015 #endif	/* defined(SIGCONT) || defined(JOS) */
1016 }
1017 
1018 /* ARGSUSED */
1019 EXPORT void
bfg(vp,std,flag)1020 bfg(vp, std, flag)
1021 	register	Argvec	*vp;
1022 			FILE	*std[];
1023 			int	flag;
1024 {
1025 	int	fg;
1026 	pid_t	p;
1027 	long	lp;
1028 	pid_t	pgrp;
1029 #ifdef	JOBCONTROL
1030 	extern pid_t	lastsusp;	/* XXX Temporary !!! */
1031 #endif
1032 
1033 #if	defined(SIGCONT)
1034 
1035 	fg = streql("fg", vp->av_av[0]);
1036 	if (vp->av_ac > 2) {
1037 		wrong_args(vp, std);
1038 		return;
1039 	} else if (vp->av_ac == 1) {
1040 #ifdef	JOBCONTROL
1041 		if ((lp = lastsusp) == 0)
1042 			return;
1043 #endif
1044 		if (streql("$", vp->av_av[0]))
1045 			fg = TRUE;
1046 	} else if (!tolong(std, vp->av_av[1], &lp))
1047 		return;
1048 
1049 	p = lp;
1050 	if (isbadlpid(std, lp))
1051 		return;
1052 #if	!defined(HAVE_GETPGID) && !defined(HAVE_BSD_GETPGRP)
1053 	if ((pgrp = -1) < 0) {
1054 		seterrno(0);	/* XXX ??? */
1055 		/*
1056 		 * XXX We should have a local process table
1057 		 * XXX to map pid to pgrp.
1058 		 */
1059 #else
1060 	if ((pgrp = getpgid(p)) < 0) {
1061 #endif
1062 		ex_status = geterrno();
1063 		fprintf(std[2], "Can't get processgroup of %ld. %s\n",
1064 						(long)p, errstr(ex_status));
1065 		return;
1066 	}
1067 #ifdef	JOBCONTROL
1068 	if (fg)
1069 		tty_setpgrp(0, pgrp);
1070 #endif	/* JOBCONTROL */
1071 	if (killpg(pgrp, SIGCONT) < 0) {
1072 		ex_status = geterrno();
1073 		fprintf(std[2], "Can't resume %ld. %s\n",
1074 						(long)p, errstr(ex_status));
1075 	}
1076 	/*else*/ if (fg && !(flag & ASYNC))
1077 		ewait(p, WALL);
1078 #else	/* defined(SIGCONT) */
1079 	unimplemented(vp, std);
1080 #endif	/* defined(SIGCONT) */
1081 }
1082 
1083 /* ARGSUSED */
1084 EXPORT void
bpgrp(vp,std,flag)1085 bpgrp(vp, std, flag)
1086 	register	Argvec	*vp;
1087 			FILE	*std[];
1088 			int	flag;
1089 {
1090 	pid_t	p;
1091 	long	lp;
1092 	pid_t	pgrp = 0;
1093 #ifdef	HAVE_GETSID
1094 	pid_t	sgrp;
1095 #endif
1096 
1097 	if (vp->av_ac > 2) {
1098 		wrong_args(vp, std);
1099 		return;
1100 	} else if (vp->av_ac == 1) {
1101 		lp = mypid;
1102 
1103 #ifdef	TIOCGPGRP
1104 		/*
1105 		 * Prefer the ioctl() as the POSIX function tcgetpgrp() limits
1106 		 * access in a way that we cannot accept.
1107 		 */
1108 		if (ioctl(fdown(std[0]), TIOCGPGRP, (char *)&pgrp) < 0)
1109 			pgrp = -1;
1110 #else
1111 		pgrp = tty_getpgrp(fdown(std[0]));
1112 #endif
1113 #if	defined(HAVE_GETSID) && defined(HAVE_TCGETSID)
1114 #ifdef	TIOCGSID
1115 		/*
1116 		 * Prefer the ioctl() as the POSIX function tcgetsid() limits
1117 		 * access in a way that we cannot accept.
1118 		 */
1119 		if (ioctl(fdown(std[0]), TIOCGSID, (char *)&sgrp) < 0)
1120 			sgrp = -1;
1121 #else
1122 		sgrp = tcgetsid(fdown(std[0]));
1123 #endif
1124 		fprintf(std[1], "ttyprocessgroup: %ld ttysessiongroup %ld\n",
1125 				(long)pgrp, (long)sgrp);
1126 #else
1127 		fprintf(std[1], "ttyprocessgroup: %ld\n", (long)pgrp);
1128 #endif
1129 	} else if (!tolong(std, vp->av_av[1], &lp))
1130 		return;
1131 	p = lp;
1132 	if (isbadlpid(std, lp))
1133 		return;
1134 #if	!defined(HAVE_GETPGID) && !defined(HAVE_BSD_GETPGRP)
1135 	if (p != mypid) {
1136 		unimplemented(vp, std);
1137 		return;
1138 	}
1139 #endif
1140 	seterrno(0);
1141 	if ((pgrp = getpgid(p)) < 0 && geterrno() != 0) {
1142 		ex_status = geterrno();
1143 		fprintf(std[2], "Can't get processgroup of %ld. %s\n",
1144 						(long)p, errstr(ex_status));
1145 		return;
1146 	}
1147 	fprintf(std[1], "pid: %ld processgroup: %ld", (long)p, (long)pgrp);
1148 #ifdef	HAVE_GETSID
1149 	sgrp = getsid(p);
1150 	fprintf(std[1], " sessiongroup: %ld", (long)sgrp);
1151 #endif
1152 	fprintf(std[1], "\n");
1153 }
1154 
1155 /* ARGSUSED */
1156 EXPORT void
bsync(vp,std,flag)1157 bsync(vp, std, flag)
1158 	Argvec *vp;
1159 	FILE	*std[];
1160 	int	flag;
1161 {
1162 #ifdef	HAVE_SYNC
1163 	sync();
1164 #else
1165 	unimplemented(vp, std);
1166 #endif
1167 }
1168 
1169 /* ARGSUSED */
1170 EXPORT void
bumask(vp,std,flag)1171 bumask(vp, std, flag)
1172 	register	Argvec *vp;
1173 	register	FILE	*std[];
1174 			int	flag;
1175 {
1176 		int	ac;
1177 		char	* const *av;
1178 		BOOL	symbolic = FALSE;
1179 		mode_t	newmask = 0;
1180 	register char	*cp;
1181 
1182 	ac = vp->av_ac - 1;		/* set values */
1183 	av = &vp->av_av[1];
1184 	if (getargs(&ac, &av, "S", &symbolic) < 0) {
1185 		/*
1186 		 * Let the last argument fail in getperm()
1187 		 * if it is not OK. POSIX requires "umask -r" to fail,
1188 		 * this test catches e.g. "umask a=rwx".
1189 		 */
1190 		if (ac == 1 && vp->av_ac >= 2 && av[0][0] != '-')
1191 			goto ok;
1192 		fprintf(std[2], ebadopt, vp->av_av[0], av[0]);
1193 		fprintf(std[2], "%s", nl);
1194 		busage(vp, std);
1195 		ex_status = 1;
1196 		return;
1197 	}
1198 	if (ac == 0) {
1199 		if (symbolic)
1200 			pmask(std, TRUE);
1201 		else
1202 			fprintf(std[1], "0%llo\n", (ULlong)getcmask());
1203 		return;
1204 	}
1205 	if (ac != 1) {
1206 		wrong_args(vp, std);
1207 		return;
1208 	}
1209 ok:
1210 	if (getperm(std[2], av[0], NULL, &newmask, ~getcmask(),
1211 							GP_UMASK|GP_NOX)) {
1212 		fprintf(std[2], "Improper mask\n");
1213 		ex_status = 1;
1214 		return;
1215 	}
1216 	cp = av[0];
1217 	if (*cp >= '0' && *cp <= '7')
1218 		(void) setcmask(newmask);
1219 	else
1220 		(void) setcmask(~newmask);
1221 }
1222 
1223 /* ARGSUSED */
1224 EXPORT void
bsetmask(vp,std,flag)1225 bsetmask(vp, std, flag)
1226 	register	Argvec *vp;
1227 	register	FILE	*std[];
1228 			int	flag;
1229 {
1230 			char	mstr[64];
1231 			char	*mp;
1232 			mode_t	 oldmask;
1233 			mode_t	 newmask;
1234 	register	char	 **av = vp->av_av;
1235 
1236 	if (vp->av_ac == 1) {
1237 		pmask(std, FALSE);
1238 		return;
1239 	}
1240 	if (vp->av_ac != 4) {
1241 		wrong_args(vp, std);
1242 		return;
1243 	}
1244 	oldmask = ~getcmask();
1245 	mp = mstr;
1246 	mp = cvmode('u', mp, &mstr[sizeof (mstr) - 1], av[1]);
1247 	mp = cvmode('g', mp, &mstr[sizeof (mstr) - 1], av[2]);
1248 	mp = cvmode('o', mp, &mstr[sizeof (mstr) - 1], av[3]);
1249 	if (mp > mstr && mp[-1] == ',')
1250 		mp[-1] = '\0';
1251 	if (mstr[0] == '\0')	/* Keep old mask */
1252 		return;
1253 	if (getperm(std[2], mstr, NULL, &newmask, oldmask, GP_NOX)) {
1254 		fprintf(std[2], "Improper mask\n");
1255 		ex_status = 1;
1256 		return;
1257 	}
1258 	(void) setcmask(~newmask);
1259 }
1260 
1261 LOCAL char *
cvmode(c,cp,ep,mode)1262 cvmode(c, cp, ep, mode)
1263 	int	c;
1264 	char	*cp;
1265 	char	*ep;
1266 	char	*mode;
1267 {
1268 	char	*p = cp;
1269 	char	*mp;
1270 
1271 	for (mp = mode; *mp; mp++) {
1272 		if (*mp == '=') {	/* Keep old mask */
1273 			p = cp;
1274 			mp++;
1275 			if (*mp == '\0')
1276 				break;
1277 		}
1278 		if (p == cp) {		/* Add perm type */
1279 			*p++ = c;
1280 		}
1281 		if (*mp == '.') {	/* Clear mask */
1282 			if ((p+5) >= ep)
1283 				break;
1284 			strcpy(p, "-rwx+");
1285 			p += 5;
1286 			continue;
1287 		} else if (p == &cp[1] && *mp != '-' && *mp != '+') {
1288 			*p++ = '=';
1289 		}
1290 		if (p >= ep)
1291 			break;
1292 		*p++ = *mp;
1293 	}
1294 	if (p > cp)
1295 		*p++ = ',';
1296 	*p = '\0';
1297 	return (p);
1298 }
1299 
1300 
1301 static char *modtab[] =
1302 {"...", "..x", ".w.", ".wx", "r..", "r.x", "rw.", "rwx"};
1303 static char *umodtab[] =
1304 {"", "x", "w", "wx", "r", "rx", "rw", "rwx"};
1305 
1306 
1307 #ifdef	PROTOTYPES
1308 LOCAL int
mval(mode_t m)1309 mval(mode_t m)
1310 #else
1311 LOCAL int
1312 mval(m)
1313 	mode_t	m;
1314 #endif
1315 {
1316 	int	ret = 0;
1317 
1318 	if (m & (S_IRUSR|S_IRGRP|S_IROTH))
1319 		ret |= 4;
1320 	if (m & (S_IWUSR|S_IWGRP|S_IWOTH))
1321 		ret |= 2;
1322 	if (m & (S_IXUSR|S_IXGRP|S_IXOTH))
1323 		ret |= 1;
1324 
1325 	return (ret);
1326 }
1327 
1328 LOCAL void
pmask(std,do_posix)1329 pmask(std, do_posix)
1330 	FILE	*std[];
1331 	BOOL	do_posix;
1332 {
1333 	mode_t	m;
1334 
1335 	m = getcmask();
1336 	m = ~m;
1337 
1338 	if (do_posix)
1339 		fprintf(std[1], "u=%s,g=%s,o=%s\n",
1340 			umodtab[mval(m & S_IRWXU)],
1341 			umodtab[mval(m & S_IRWXG)],
1342 			umodtab[mval(m & S_IRWXO)]);
1343 	else
1344 		fprintf(std[1], "%s %s %s\n",
1345 			modtab[mval(m & S_IRWXU)],
1346 			modtab[mval(m & S_IRWXG)],
1347 			modtab[mval(m & S_IRWXO)]);
1348 }
1349 
1350 /* ARGSUSED */
1351 EXPORT void
blogout(vp,std,flag)1352 blogout(vp, std, flag)
1353 	Argvec	*vp;
1354 	FILE	*std[];
1355 	int	flag;
1356 {
1357 	if (not_loginsh(std)) {
1358 		fprintf(std[2], "use exit to exit.\n");
1359 		ex_status = 1;
1360 		return;
1361 	}
1362 	exitbsh(0);
1363 }
1364 
1365 /* ARGSUSED */
1366 EXPORT void
becho(vp,std,flag)1367 becho(vp, std, flag)
1368 	register Argvec	*vp;
1369 	register FILE	*std[];
1370 		int	flag;
1371 {
1372 	register int	i = 1;
1373 	register int	first = 1;
1374 	register int	ac = vp->av_ac;
1375 	register char **av = vp->av_av;
1376 	register FILE	*output;
1377 		char	buf[4096];
1378 		BOOL	nnl;
1379 		BOOL	glob;
1380 
1381 	glob = streql(av[0], "glob");
1382 	output = streql(av[0], "err") ? std[2] : std[1];
1383 
1384 	if (!glob && std[0] != stdin && ac == 1) {
1385 		file_raise(std[0], FALSE);
1386 		file_raise(output, FALSE);
1387 		do {
1388 			i = fileread(std[0], buf, sizeof (buf));
1389 			if (i > 0)
1390 				filewrite(output, buf, i);
1391 		} while (i > 0 && !ctlc);
1392 	} else {
1393 		nnl = glob;
1394 		if (!glob && ac > 1 && (streql(av[1], "-nnl")||streql(av[1], "-n")))
1395 			i++, nnl = TRUE;
1396 		for (; i < ac && !ctlc; i++) {
1397 			if (first)
1398 				first--;
1399 			else
1400 				glob ? fputc('\0', output) : fprintf(output, " ");
1401 			fprintf(output, "%s", av[i]);
1402 		}
1403 		if (!nnl && ac > 1)
1404 			fprintf(output, "%s", nl);
1405 	}
1406 }
1407 
1408 /* ARGSUSED */
1409 EXPORT void
bshift(vp,std,flag)1410 bshift(vp, std, flag)
1411 	register	Argvec	*vp;
1412 			FILE	*std[];
1413 			int	flag;
1414 {
1415 	register int 	i,
1416 			k;
1417 		int	count = 1;
1418 
1419 	if (vp->av_ac > 2) {
1420 		wrong_args(vp, std);
1421 		return;
1422 	}
1423 	if (vp->av_ac == 2)
1424 		if (!toint(std, vp->av_av[1], &count))
1425 			return;
1426 	for (k = 0; k < count; k++) {
1427 		if (vac <= 1) {
1428 			if (vac)
1429 				fprintf(std[2], "%s: ", vav[0]);
1430 			fprintf(std[2], "cannot shift.\n");
1431 			ex_status = 1;
1432 			return;
1433 		}
1434 		for (i = 1; i <= vac; i++)
1435 			vav[i] = vav[i+1];
1436 		vac--;
1437 	}
1438 }
1439 
1440 /* ARGSUSED */
1441 EXPORT void
bremap(vp,std,flag)1442 bremap(vp, std, flag)
1443 	Argvec	*vp;
1444 	FILE	*std[];
1445 	int	flag;
1446 {
1447 #ifdef	INTERACTIVE
1448 	remap();
1449 #else
1450 	unimplemented(vp, std);
1451 #endif
1452 }
1453 
1454 #ifdef	INTERACTIVE
1455 /* ARGSUSED */
1456 EXPORT void
bsavehist(vp,std,flag)1457 bsavehist(vp, std, flag)
1458 	Argvec	*vp;
1459 	FILE	*std[];
1460 	int	flag;
1461 {
1462 	save_history(HI_INTR);
1463 }
1464 #endif	/* INTERACTIVE */
1465 
1466 /* ARGSUSED */
1467 EXPORT void
bhistory(vp,std,flag)1468 bhistory(vp, std, flag)
1469 	Argvec	*vp;
1470 	FILE	*std[];
1471 	int	flag;
1472 {
1473 	int	ac;
1474 	char	* const *av;
1475 	int	ret;
1476 	BOOL	nflag = FALSE;
1477 	BOOL	rflag = FALSE;
1478 
1479 	ac = vp->av_ac - 1;	/* set values */
1480 	av = &vp->av_av[1];
1481 	ret = getargs(&ac, &av, "n,r", &nflag, &rflag);
1482 	if (ret < 0) {
1483 		fprintf(std[2], "Bad option '%s'\n", av[0]);
1484 		busage(vp, std);
1485 		ex_status = 1;
1486 		return;
1487 	}
1488 
1489 #ifdef	INTERACTIVE
1490 	put_history(std[1],
1491 		HI_INTR|HI_TAB|
1492 		(nflag ? HI_NONUM : 0)|
1493 		(rflag ? HI_REVERSE : 0), 0, 0, NULL);
1494 #else
1495 	hi_list(std[1]);
1496 #endif
1497 }
1498 
1499 /* ARGSUSED */
1500 EXPORT void
bsource(vp,std,flag)1501 bsource(vp, std, flag)
1502 	register	Argvec	*vp;
1503 			FILE	*std[];
1504 			int	flag;
1505 {
1506 	extern	int	do_status;
1507 		int	ac = vp->av_ac;
1508 		char	*name = NULL;	/* Init to make gcc happy */
1509 		char	*pname = NULL;
1510 	register FILE	*f;
1511 
1512 	if (ac < 2) {
1513 #ifndef	NO_STDIN_SOURCE
1514 		if (isatty(fdown(std[0]))) {
1515 			wrong_args(vp, std);
1516 			return;
1517 		}
1518 		doopen(std[0], "stdin", GLOBAL_AB, flag, std, FALSE);
1519 		return;
1520 #else
1521 		wrong_args(vp, std);
1522 		return;
1523 #endif
1524 	}
1525 	if (vp->av_av[0][0] != '.' &&
1526 	    streql(vp->av_av[1], "-h")) {
1527 		if (ac > 3) {
1528 			wrong_args(vp, std);
1529 			return;
1530 		}
1531 		if (ac == 3) {
1532 			/*
1533 			 * Be careful and do no PATH name search when
1534 			 * reading a shell script into the history.
1535 			 * We like to avoid that "source -h ls" fills
1536 			 * the history with junk.
1537 			 */
1538 			name = vp->av_av[2];
1539 			if ((f = fileopen(name, for_read)) == (FILE *) NULL)
1540 				ex_status = geterrno();
1541 		} else {
1542 			name = "stdin";
1543 			f = std[0];
1544 		}
1545 		if (f) {
1546 			readhistory(f);
1547 			if (f == stdin)
1548 				clearerr(f);
1549 			if (f != std[0])
1550 				fclose(f);
1551 		}
1552 	} else {
1553 		pname = name = _findinpath(vp->av_av[1], R_OK, TRUE);
1554 		if (name) {
1555 			dofile(name, GLOBAL_AB, flag, std, FALSE);
1556 			ex_status = do_status;
1557 		} else {
1558 			ex_status = geterrno();
1559 		}
1560 	}
1561 	if (ex_status != 0) {
1562 		fprintf(std[2], ecantread, name, errstr(ex_status));
1563 		fprintf(std[2], "%s", nl);
1564 	}
1565 	if (pname)
1566 		free(pname);
1567 }
1568 
1569 /* repeat command - execute command several times */
1570 /* ARGSUSED */
1571 EXPORT void
brepeat(vp,std,flag)1572 brepeat(vp, std, flag)
1573 	register	Argvec	*vp;
1574 	register	FILE	*std[];
1575 			int	flag;
1576 {
1577 		int	ac;
1578 		char	* const *av;
1579 		long	count	= 0x7FFFFFFF;
1580 		long	dtime	= 0;
1581 	volatile long	sttime	= 0;
1582 		long	d;
1583 	Tnode	* volatile cmd	= (Tnode *) NULL;
1584 		char	*opt	= "delay#L,d#L,count#L,c#L,#L";
1585 		char	*cmdln;
1586 	volatile sigtype intsav = SIG_DFL;
1587 
1588 	ac = vp->av_ac - 1;		/* set values */
1589 	av = &vp->av_av[1];
1590 	if (getargs(&ac, &av, opt, &dtime, &dtime,
1591 						&count, &count, &count) < 0) {
1592 		fprintf(std[2], ebadopt, vp->av_av[0], av[0]);
1593 		fprintf(std[2], "%s", nl);
1594 		busage(vp, std);
1595 		ex_status = 1;
1596 		return;
1597 	}
1598 	if (ac < 1) {
1599 		wrong_args(vp, std);
1600 		return;
1601 	}
1602 	if ((cmdln = cons_args(vp, vp->av_ac - ac)) == NULL) {
1603 		ex_status = 1;
1604 		return;
1605 	}
1606 	if (!setjmp(waitjmp)) {
1607 		if (osig2 != (sigtype) SIG_IGN)
1608 			intsav = signal(SIGINT, waitint);
1609 		/*
1610 		 * A longjmp() from the SIGINT handler may leave
1611 		 * SIGINT blocked.
1612 		 */
1613 		unblock_sigs();
1614 		while (count-- > 0) {
1615 			if (dtime) {
1616 				if (sttime) {
1617 					d = time(0) - sttime;
1618 					if (d < dtime)
1619 						sleep(dtime - d);
1620 				}
1621 				sttime = time(0);
1622 			}
1623 #ifdef DEBUGX
1624 		printf("        brepeat: executing '%s'\n", cmdln); flush();
1625 #endif
1626 			if (!cmd) {
1627 				pushline(cmdln);
1628 /*				cmd = cmdline(0|PGRP, std, TRUE);*/
1629 				cmd = cmdline(flag, std, TRUE);
1630 			}
1631 /*			execute(cmd, 0|PGRP, std);*/
1632 			execute(cmd, flag, std);
1633 #ifdef	JOBCONTROL
1634 			tty_setpgrp(0, mypgrp);
1635 #endif	/* JOBCONTROL */
1636 			if (ctlc)
1637 				ex_status = 1;
1638 			if (ex_status)
1639 				break;
1640 		}
1641 	}
1642 	if (osig2 != (sigtype) SIG_IGN)
1643 		signal(SIGINT, intsav);
1644 	free(cmdln);
1645 	freetree(cmd);
1646 }
1647 
1648 /* ARGSUSED */
1649 EXPORT void
bexec(vp,std,flag)1650 bexec(vp, std, flag)
1651 	Argvec	*vp;
1652 	FILE	*std[];
1653 	int	flag;
1654 {
1655 	my_exec(vp->av_av[1], 1, vp, std);
1656 }
1657 
1658 /* ARGSUSED */
1659 EXPORT void
blogin(vp,std,flag)1660 blogin(vp, std, flag)
1661 	Argvec	*vp;
1662 	FILE	*std[];
1663 	int	flag;
1664 {
1665 	if (!not_loginsh(std)) {
1666 #ifdef	INTERACTIVE
1667 		if (!no_histflg)
1668 			save_history(HI_NOINTR);
1669 #endif	/* INTERACTIVE */
1670 		my_exec(loginname, 0, vp, std);
1671 	}
1672 }
1673 
1674 LOCAL void
my_exec(name,first_ac,vp,std)1675 my_exec(name, first_ac, vp, std)
1676 			char	*name;
1677 			int	first_ac;
1678 	register	Argvec	*vp;
1679 			FILE	*std[];
1680 {
1681 	char	**av = &vp->av_av[first_ac];
1682 	int	ac   = vp->av_ac - first_ac;
1683 	char	*av0 = NULL;
1684 
1685 	if (getargs(&ac, (char * const **)&av, "av0*", &av0) < 0) {
1686 		fprintf(std[2], ebadopt, vp->av_av[0], av[0]);
1687 		fprintf(std[2], "%s", nl);
1688 		busage(vp, std);
1689 		ex_status = 1;
1690 		return;
1691 	}
1692 	if (ac < 1) {
1693 		wrong_args(vp, std);
1694 		return;
1695 	}
1696 	name = makestr(name);
1697 	if (av0) {
1698 		free(name);
1699 		name = makestr(av[0]);
1700 		av0 = makestr(av0);
1701 		free(av[0]);
1702 		av[0] = av0;
1703 	}
1704 	update_cwd();			/* Er koennte sie veraendert haben */
1705 	setpgid(0, opgrp);
1706 #ifdef	JOBCONTROL
1707 	tty_setpgrp(fdown(std[0]), opgrp);
1708 #endif	/* JOBCONTROL */
1709 	ex_status = fexec((char **)NULL, name, std[0], std[1], std[2],
1710 								av, evarray);
1711 	setpgid(0, mypgrp);
1712 #ifdef	JOBCONTROL
1713 	tty_setpgrp(fdown(std[0]), mypgrp);
1714 #endif	/* JOBCONTROL */
1715 	fprintf(std[2], "Can't exec '%s'. %s\n", name, errstr(ex_status));
1716 	free(name);
1717 }
1718 
1719 /* ARGSUSED */
1720 EXPORT void
berrstr(vp,std,flag)1721 berrstr(vp, std, flag)
1722 	Argvec	*vp;
1723 	FILE	*std[];
1724 	int	flag;
1725 {
1726 	int	err;
1727 
1728 	if (!toint(std, vp->av_av[1], &err))
1729 		return;
1730 	fprintf(std[1], "%s", errstr(err));
1731 }
1732 
1733 /* ARGSUSED */
1734 EXPORT void
btype(vp,std,flag)1735 btype(vp, std, flag)
1736 	Argvec	*vp;
1737 	FILE	*std[];
1738 	int	flag;
1739 {
1740 	register int	ac = vp->av_ac;
1741 	register char **av = vp->av_av;
1742 	register int	i;
1743 	register FILE	*output = std[1];
1744 	char		*val	= NULL;
1745 
1746 	if (vp->av_ac < 2) {
1747 		wrong_args(vp, std);
1748 		return;
1749 	}
1750 
1751 	for (i = 1; i < ac && !ctlc; i++) {
1752 		fprintf(output, "%s ", av[i]);
1753 		if ((val = ab_value(LOCAL_AB, av[i], NULL, AB_BEGIN)) != NULL) {
1754 			fprintf(output, "is a local alias to '%s'\n", val);
1755 		} else if ((val = ab_value(GLOBAL_AB, av[i], NULL, AB_BEGIN)) != NULL) {
1756 			fprintf(output, "is a global alias to '%s'\n", val);
1757 		} else if (blook(av[i], bitab, n_builtin) != (btab *) NULL) {
1758 			fprintf(output, "is a shell builtin\n");
1759 		} else if ((val = map_func(av[i])) != NULL) {
1760 			fprintf(output, "is a function '%s'\n", val);
1761 		} else if ((val = _findinpath(av[i], X_OK, TRUE)) != NULL) {
1762 			fprintf(output, "is %s\n", val);
1763 			free(val);
1764 			val = NULL;
1765 		} else {
1766 			fprintf(output, "not found\n");
1767 			ex_status = 1;
1768 		}
1769 	}
1770 }
1771 
1772 /* ARGSUSED */
1773 EXPORT void
btrue(vp,std,flag)1774 btrue(vp, std, flag)
1775 	Argvec	*vp;
1776 	FILE	*std[];
1777 	int	flag;
1778 {
1779 	ex_status = 0;
1780 }
1781 
1782 /* ARGSUSED */
1783 EXPORT void
bfalse(vp,std,flag)1784 bfalse(vp, std, flag)
1785 	Argvec	*vp;
1786 	FILE	*std[];
1787 	int	flag;
1788 {
1789 	ex_status = 1;
1790 }
1791 
1792 #ifdef	DO_FIND
1793 #include <schily/walk.h>
1794 #include <schily/find.h>
1795 
1796 LOCAL int
quitfun(arg)1797 quitfun(arg)
1798 	void	*arg;
1799 {
1800 	return (*((int *)arg) != 0);
1801 }
1802 
1803 /* ARGSUSED */
1804 EXPORT void
bfind(vp,std,flag)1805 bfind(vp, std, flag)
1806 	Argvec	*vp;
1807 	FILE	*std[];
1808 	int	flag;
1809 {
1810 	squit_t	quit;
1811 
1812 	find_sqinit(&quit);
1813 	quit.quitfun = quitfun;
1814 	quit.qfarg = &ctlc;
1815 	quit.flags = 0;
1816 	ex_status = find_main(vp->av_ac, vp->av_av, evarray, std, &quit);
1817 }
1818 #endif
1819 
1820 /* ARGSUSED */
1821 EXPORT BOOL
builtin(vp,std,flag)1822 builtin(vp, std, flag)
1823 	Argvec	*vp;
1824 	FILE	*std[];
1825 	int	flag;
1826 {
1827 	register btab	*bp;
1828 	register char	*name = vp->av_av[0];
1829 		struct rusage	ru1;
1830 		struct rusage	ru2;
1831 		struct rusage	cru1;
1832 		struct rusage	cru2;
1833 
1834 	if (ctlc)
1835 		return (TRUE);
1836 	if ((bp = blook(name, bitab, n_builtin)) == (btab *) NULL)
1837 		return (FALSE);
1838 	setstime();
1839 	getpruself(&ru1);
1840 	getpruchld(&cru1);
1841 	ex_status = 0;
1842 	if (!helpwanted(vp, std)) {
1843 		if (bp->b_argc && vp->av_ac != bp->b_argc)
1844 			wrong_args(vp, std);
1845 		else
1846 			(*bp->b_func)(vp, std, flag);
1847 	}
1848 	fflush(std[1]);
1849 	fflush(std[2]);
1850 	if ((flag & NOTMS) == 0 && getcurenv("TIME")) {
1851 		getpruself(&ru2);
1852 		getpruchld(&cru2);
1853 		rusagesub(&ru1, &ru2);
1854 		rusagesub(&cru1, &cru2);
1855 		rusageadd(&cru2, &ru2);
1856 		prtimes(gstd, &ru2);
1857 	}
1858 	return (TRUE);
1859 }
1860 
1861 #ifdef	PROTOTYPES
1862 LOCAL int
suspend(pid_t p)1863 suspend(pid_t p)
1864 #else
1865 LOCAL int
1866 suspend(p)
1867 	pid_t	p;
1868 #endif
1869 {
1870 #ifdef	SIGSTOP
1871 	return (kill(p, SIGSTOP));
1872 #else
1873 	raisecond("suspend not implemented", 0L);
1874 #endif
1875 }
1876 
1877 #ifdef	PROTOTYPES
1878 LOCAL int
presume(pid_t p)1879 presume(pid_t p)
1880 #else
1881 LOCAL int
1882 presume(p)
1883 	pid_t	p;
1884 #endif
1885 {
1886 #ifdef	SIGCONT
1887 	if (p == getpid()) {
1888 		seterrno(ESRCH);
1889 		return (-1);
1890 	}
1891 	return (kill(p, SIGCONT));
1892 #else
1893 	raisecond("presume not implemented", 0L);
1894 #endif
1895 }
1896 
1897 #ifdef	PROTOTYPES
1898 LOCAL mode_t
setcmask(mode_t newmask)1899 setcmask(mode_t newmask)
1900 #else
1901 LOCAL mode_t
1902 setcmask(newmask)
1903 	mode_t	newmask;
1904 #endif
1905 {
1906 	return (umask(newmask));
1907 }
1908 
1909 LOCAL mode_t
getcmask()1910 getcmask()
1911 {
1912 	mode_t	ret =  umask(0);
1913 
1914 	umask(ret);
1915 	return (ret);
1916 }
1917