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