1 /* @(#)bsh.c 1.81 21/08/20 Copyright 1984,1985,1988,1989,1991,1994-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)bsh.c 1.81 21/08/20 Copyright 1982,1984,1985,1988,1989,1991,1994-2021 J. Schilling";
6 #endif
7 /*
8 * bsh command interpreter - main Program
9 *
10 * Copyright (c) 1982,1984,1985,1988,1989,1991,1994-2021 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/ctype.h>
28 #include <schily/signal.h>
29 #include <schily/setjmp.h>
30 #include <schily/sigblk.h>
31 #include <schily/pwd.h>
32 #include "bsh.h"
33 #include "node.h"
34 #include "abbrev.h"
35 #include "str.h"
36 #include "strsubs.h"
37 #include <schily/varargs.h>
38 #include <schily/stdlib.h>
39 #include <schily/unistd.h>
40 #include <schily/string.h>
41 #include <schily/fcntl.h>
42 #include <schily/getargs.h>
43 #include <schily/locale.h>
44 #include <schily/nlsdefs.h>
45
46 #ifdef SIGUSR1
47 # define PROTSIG SIGUSR1
48 #else
49 # define PROTSIG 31
50 #endif
51
52 char *prompts[2] = { NULL, NULL};
53
54 /*
55 * Some saved old signal values...
56 */
57 sigtype osig2 = (sigtype) SIG_DFL;
58 sigtype osig3 = (sigtype) SIG_DFL;
59 sigtype osig15 = (sigtype) SIG_DFL;
60 sigtype osig18 = (sigtype) SIG_DFL;
61 sigtype osig21 = (sigtype) SIG_DFL;
62 sigtype osig22 = (sigtype) SIG_DFL;
63
64 int batch = 0;
65 int verbose = FALSE;
66 int cflg = FALSE;
67 int eflg = FALSE;
68 int vflg = FALSE;
69 int iflg = FALSE;
70 int nflg = FALSE;
71 int sflg = FALSE;
72 int tflg = FALSE;
73 int no_closeflg = FALSE;
74 int no_histflg = FALSE;
75 int mailcheck = 600; /* Mail check interval */
76 int qflg = FALSE;
77 int pfshell = FALSE;
78
79 int prflg = FALSE;
80 int ttyflg = FALSE;
81
82 int parseflg = FALSE;
83 int ctlc = 0;
84 int ex_status = 0;
85 int do_status = 0; /* for recognition of readaccess error */
86 pid_t mypid = 0;
87 pid_t opgrp = 0;
88 pid_t mypgrp = 0;
89 Tnode *lastcmd = (Tnode *)NULL; /* Used by ancient #e command */
90 BOOL noslash = FALSE; /* Used for restrictions */
91 char *user = NULL; /* Used for ~ Expansion */
92 char *hostname = NULL;
93 char *cmdfname = NULL; /* Used for #! commands */
94 LOCAL int sig_err_cnt = 0; /* abort on 10.th error */
95
96 #ifdef INTERACTIVE
97 int prompt = 0;
98 #else
99 Tnode **cur_base = 0; /* for use by history */
100 int history = 0;
101 #endif
102
103 int vac = 0;
104 /*char * const *vav = (char * const *)NULL;*/
105 char **vav = (char **)NULL;
106 FILE *cmdfp = (FILE *) NULL;
107 FILE *gstd[3];
108 char **evarray = (char **) NULL;
109 unsigned evasize = 0;
110 int evaent = 0;
111 char *initav0 = NULL;
112
113 BOOL firstsh = FALSE;
114 char *inithome = NULL;
115 FILE *protfile = (FILE *)NULL; /* output file for consprot */
116
117 LOCAL int prompterrs = 0; /* no errors on stderr jet */
118
119 LOCAL jmp_buf jmpblk;
120 LOCAL SIGBLK sb;
121
122 extern abidx_t deftab; /* Default tab for Abbrev/Alias */
123
124 extern int delim;
125 extern int nerrors;
126
127 EXPORT sigret intr __PR((int sig));
128 LOCAL BOOL clearferr __PR((void));
129 LOCAL int sigjmp __PR((const char *signalstr, long j, long arg));
130 LOCAL void printsig __PR((const char *sig, const char *arg));
131 LOCAL sigret proton_off __PR((int sig));
132 EXPORT int main __PR((int ac, char **av, char **ev));
133 EXPORT BOOL dofile __PR((char *s, abidx_t tab, int flag, FILE ** std, BOOL jump));
134 EXPORT void doopen __PR((FILE * fd, char *s, abidx_t tab, int flag, FILE ** std, BOOL jump));
135 EXPORT void process __PR((FILE * f, int flag, FILE ** std, BOOL jump));
136 EXPORT int berror __PR((const char *s, ...));
137 EXPORT char *errstr __PR((int err));
138 EXPORT void close_other_files __PR((FILE ** std));
139 LOCAL char *getgfile __PR((void));
140 EXPORT char *getuname __PR((int uid));
141 EXPORT char *getpwdir __PR((char *name));
142 EXPORT char *mypwhome __PR((void));
143 EXPORT char *myhome __PR((void));
144 LOCAL int get_oopt __PR((const char *arg, void *valp, int *pac, char *const **pav, const char *opt));
145 LOCAL void gargs __PR((int ac, char *const* av, char *opts, int *no_i2flg, int *no_gaflg, int *no_laflg));
146 EXPORT void exitbsh __PR((int excode));
147 LOCAL void bshusage __PR((int flag, char *name, char *s));
148
149 /* ARGSUSED */
150 EXPORT sigret
intr(sig)151 intr(sig)
152 int sig;
153 {
154 extern int sigcount[];
155
156 signal(SIGINT, intr);
157 ctlc++;
158 sigcount[SIGINT]++;
159 #ifdef DEBUG
160 fprintf(stderr,
161 "ctlc: pid: %ld sigcount[%d] %d parseflg: %d jmpblk.ret: 0x%x\n",
162 (long)mypid, SIGINT, sigcount[SIGINT], parseflg, jmpblk[0]);
163 fflush(stderr);
164 #endif
165 /*
166 * XXXY Vielleicht doch wieder lonjmp solange keine ueberall funktionierende
167 * XXXY raisecond() Implementierung vorliegt.
168 * XXXY raisecond geht nur wenn wir USE_SCANSTACK bei der Kompilation von
169 * XXXY raisecond.c definieren.
170 */
171 if (parseflg && !cflg) { /* Kein Jump, wenn bsh -c '' */
172 raisecond(sn_ctlc, (long)NULL); /* raise the condition */
173 }
174 }
175
176 # ifndef _NFILE
177 # define _MAXFILES 20 /* XXX nicht ok */
178 # else
179 # define _MAXFILES _NFILE
180 # endif
181 LOCAL BOOL
clearferr()182 clearferr()
183 {
184 register int i;
185
186 /*
187 * Wenn ein Pseudotty geschloszen wird (quit bei shelltool)
188 * gibt es fortgesetzte write-errors und der bsh beginnt zu
189 * onanieren, wenn auch hier ferror geloescht wird.
190 */
191 if (ferror(stderr)) {
192 if (++prompterrs >= 10) {
193 exitbsh(ex_status);
194 /* NOTREACHED */
195 }
196 }
197
198 for (i = 0; i < 3; i++) {
199 if (ferror(gstd[i])) {
200 clearerr(gstd[i]);
201 return (TRUE);
202 }
203 }
204 return (FALSE);
205 }
206
207 /*
208 * XXXY long j kann erst geaendert werden, wenn raisecond() ein void *
209 * XXXY Argument hat.
210 */
211 LOCAL int
sigjmp(signalstr,j,arg)212 sigjmp(signalstr, j, arg)
213 const char *signalstr;
214 long j; /* (jmp_buf*)j: stack frame information */
215 long arg;
216 {
217 jmp_buf *jp = (jmp_buf *)j;
218
219 printsig(signalstr, (char *)arg);
220
221 if (!(strindex("file", (char *)signalstr) && clearferr()) &&
222 !streql(signalstr, sn_ctlc) && (++sig_err_cnt >= 10)) {
223 #ifdef INTERACTIVE
224 reset_tty_modes();
225 reset_line_disc();
226 reset_tty_pgrp();
227 #endif
228 abort();
229 }
230 longjmp(*jp, TRUE);
231 return (FALSE);
232 }
233
234 LOCAL void
printsig(sig,arg)235 printsig(sig, arg)
236 const char *sig;
237 const char *arg;
238 {
239 char str[80];
240
241 sprintf(str, "Caught %.20s Signal", sig);
242 write(STDERR_FILENO, str, strlen(str));
243 if (arg) {
244 sprintf(str, " from '%.20s'", arg);
245 write(STDERR_FILENO, str, strlen(str));
246 }
247 write(STDERR_FILENO, ".\r\n", 3);
248 }
249
250 /* ARGSUSED */
251 LOCAL sigret
proton_off(sig)252 proton_off(sig)
253 int sig;
254 {
255 char protfname[25];
256
257 signal(PROTSIG, proton_off);
258 if (protfile) {
259 fclose(protfile);
260 protfile = (FILE *) NULL;
261 } else {
262 sprintf(protfname, "%s.%ld", tmpname, (long)mypid);
263 protfile = fileopen(protfname, for_wca);
264 #ifdef F_SETFD
265 fcntl(fdown(protfile), F_SETFD, FD_CLOEXEC);
266 #endif
267 }
268 }
269
270 EXPORT int
main(ac,av,ev)271 main(ac, av, ev)
272 int ac;
273 char *av[];
274 char *ev[];
275 {
276 char *gabbrevs;
277 char *initfname;
278 int no_i2flg = 0;
279 int no_gaflg = 0;
280 int no_laflg = 0;
281
282 save_args(ac, av);
283 initav0 = av[0];
284 vac = ac;
285 vav = av;
286 firstsh = ac > 0 && av[0][0] == '-'; /* see if its a login shell */
287
288 /*
289 * Cygwin32 makes stdin/stdout/stderr non constant expressions
290 * so we cannot do loader initialization.
291 *
292 * XXX May this be a problem?
293 */
294 gstd[0] = stdin;
295 gstd[1] = stdout;
296 gstd[2] = stderr;
297
298 inittime();
299
300 /*error("euid: %d ruid: %d", geteuid(), getuid());*/
301
302 #ifdef HAVE_SETEUID
303 /*
304 * setreuid() ist POSIX aber alte *BSD BS haben kein saved uid.
305 * Hier sollte noch ein Test auf _POSIX_SAVED_IDS hinein.
306 */
307 seteuid(getuid()); /* Ungef�hrlich auf Systemen ohne saved uid */
308 #else
309 #ifdef HAVE_SETREUID /* BSD & POSIX */
310 setreuid(-1, getuid());
311 #else
312 # ifdef HAVE_SETRESUID
313 setresuid(-1, getuid(), -1); /* HP-UX setresuid(ruid, euid, suid)*/
314 # else
315 /*
316 * Hier sollte nur dann eine Warnung/Abbruch kommen, wenn
317 * der bsh tats�chlich suid root installiert ist.
318 */
319 #if !defined(__EMX__) && !defined(__DJGPP__) && \
320 !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BEOS__)
321 error No function to set uid available
322 #endif
323
324 # endif
325 #endif
326 #endif /* HAVE_SETEUID */
327
328 #if defined(HAVE_SIGPROCMASK)
329 {
330 sigset_t set;
331
332 sigemptyset(&set); /* csh macht login falsch */
333 sigprocmask(SIG_SETMASK, &set, 0);
334 }
335 #else
336 # if defined(HAVE_SIGSETMASK)
337 sigsetmask(0); /* csh macht login falsch */
338 # endif
339 #endif
340 signal(PROTSIG, proton_off);
341 mypid = getpid();
342 mypgrp = opgrp = getpgid(0);
343 #ifdef WRONG
344 #ifdef JOBCONTROL
345 setpgid(0, mypid);
346 mypgrp = getpgid(0);
347 #endif
348 #endif /* WRONG */
349 ev_init(ev);
350 if (setlocale(LC_ALL, "") == NULL)
351 error("Bad locale in inital environment.\n");
352 ev_insert(concat(ignoreeofname, eql, off, (char *)NULL));
353
354 #ifdef USE_NLS
355 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
356 #define TEXT_DOMAIN "bsh" /* Use this only if it weren't */
357 #endif
358 { char *dir;
359 dir = searchfileinpath("share/locale", F_OK,
360 SIP_ANY_FILE|SIP_NO_PATH, NULL);
361 if (dir)
362 (void) bindtextdomain(TEXT_DOMAIN, dir);
363 else
364 #if defined(PROTOTYPES) && defined(INS_BASE)
365 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
366 #else
367 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
368 #endif
369 (void) textdomain(TEXT_DOMAIN);
370 }
371 #endif /* USE_NLS */
372
373
374 inituser();
375 inithostname();
376 initprompt();
377 #ifdef INTERACTIVE
378 init_input();
379 #else
380 inithistory();
381 #endif
382 osig2 = signal(SIGINT, (sigtype) SIG_IGN);
383 if (osig2 != (sigtype) SIG_IGN)
384 signal(SIGINT, intr);
385 #ifdef SIGQUIT
386 osig3 = signal(SIGQUIT, (sigtype) SIG_IGN);
387 #endif
388 osig15 = signal(SIGTERM, (sigtype) SIG_IGN);
389 #ifdef SIGTSTP
390 osig18 = signal(SIGTSTP, (sigtype) SIG_IGN);
391 #endif
392 #ifdef SIGTTIN
393 osig21 = signal(SIGTTIN, (sigtype) SIG_IGN);
394 #endif
395 #ifdef SIGTTOU
396 osig22 = signal(SIGTTOU, (sigtype) SIG_IGN);
397 #endif
398 if (firstsh) {
399 signal(SIGINT, intr);
400 osig2 = (sigtype) SIG_DFL;
401 osig3 = (sigtype) SIG_DFL;
402 osig15 = (sigtype) SIG_DFL;
403 osig18 = (sigtype) SIG_DFL;
404 osig21 = (sigtype) SIG_DFL;
405 osig22 = (sigtype) SIG_DFL;
406 }
407
408 #ifdef EXECATTR_FILENAME
409 if (ac > 0) {
410 const char *fn = fbasename(av[0]);
411
412 if (streql(fn, "pfbsh") || streql(fn, "-pfbsh")) {
413 pfshell = TRUE;
414 pfinit();
415 }
416 }
417 #endif
418
419 gargs(ac, av, bshopts, &no_i2flg, &no_gaflg, &no_laflg);
420
421 #ifdef SIGQUIT
422 if (qflg)
423 (void) signal(SIGQUIT, SIG_DFL);
424 #endif
425
426 if (batch) {
427 vac -= ac - batch;
428 vav += ac - batch;
429 if (vac <= 1)
430 sflg++;
431 }
432 #ifdef XXX
433 /* XXX solange setreuid() am Anfang steht ungefaehrlich !! */
434 else if (getuid() != geteuid() || getgid() != getegid()) {
435 berror("%s: %s", fbasename(initav0), errstr(EACCES));
436 exit(EACCES);
437 }
438 #endif
439
440
441 if (!no_closeflg)
442 close_other_files(gstd);
443
444 setinput((FILE *) NULL); /* Create input stream */
445 gabbrevs = getgfile(); /* Get .globals file name */
446 inithome = concat(getcurenv(homename), (char *)NULL);
447
448 if (firstsh) {
449 /* Run /etc/initbsh file */
450 dofile(sysinitname, GLOBAL_AB, 0, gstd, TRUE);
451
452 /* Run /etc/initrbsh file */
453 if (strchr(fbasename(initav0), 'r'))
454 dofile(sysrinitname, GLOBAL_AB, 0, gstd, TRUE);
455 }
456
457 if (!no_gaflg) { /* Read in .globals */
458 ab_use(GLOBAL_AB, gabbrevs);
459 }
460
461 if (!no_laflg) { /* Read in .locals */
462 ab_use(LOCAL_AB, localname);
463 }
464
465 if (firstsh) {
466 /* Run .init script */
467 initfname = concat(inithome, slash, initname, (char *)NULL);
468 dofile(initfname, GLOBAL_AB, 0, gstd, TRUE);
469 } else {
470 /* Run .init2 script */
471 initfname = concat(inithome, slash, init2name, (char *)NULL);
472 if (!no_i2flg)
473 dofile(initfname, GLOBAL_AB, NOTMS, gstd, TRUE);
474 }
475 free(initfname);
476 if (verbose)
477 vflg++;
478
479 vav++;
480 vac--;
481 if (!sflg && !batch &&
482 getfiles(&vac, (char * const **)&vav, bshopts) <= 0)
483 sflg++;
484
485 if (!sflg) {
486 if (cflg) {
487 /*
488 * -c Option: force "one line" command.
489 */
490 pushline(vav[0]);
491 do {
492 freetree(cmdline(0, gstd, FALSE));
493 } while (delim != EOF);
494 } else if (!dofile(vav[0], GLOBAL_AB, 0, gstd, TRUE)) {
495 berror(ecantopen, vav[0], errstr(ex_status = do_status));
496 }
497 } else {
498 cflg = FALSE;
499 #ifdef INTERACTIVE
500 if (!no_histflg)
501 read_init_history();
502 #endif
503 #ifdef JOBCONTROL
504 setpgid(0, mypid);
505 mypgrp = getpgid(0);
506 #endif
507 do
508 process(stdin, 0, gstd, TRUE);
509 while (delim != EOF && !tflg);
510 }
511 exitbsh(ex_status);
512 return (ex_status); /* Keep lint happy */
513 }
514
515 EXPORT BOOL
dofile(s,tab,flag,std,jump)516 dofile(s, tab, flag, std, jump)
517 char *s;
518 abidx_t tab;
519 int flag;
520 FILE *std[];
521 BOOL jump;
522 {
523 FILE *fd;
524
525 #ifdef DEBUG
526 fprintf(stderr, "dofile(%s,%d,..%sjump) ", s, tab, jump?nullstr:"no");
527 #endif
528 if ((fd = fileopen(s, for_read)) != (FILE *) NULL) {
529 #ifdef DEBUG
530 fprintf(stderr, "(ok)\n");
531 fflush(stderr);
532 #endif
533 #ifdef F_SETFD
534 fcntl(fdown(fd), F_SETFD, FD_CLOEXEC);
535 #endif
536 doopen(fd, s, tab, flag, std, jump);
537 fclose(fd);
538 return (TRUE);
539 } else {
540 do_status = geterrno();
541 #ifdef DEBUG
542 fprintf(stderr, "(error) %s\n", errstr(do_status));
543 fflush(stderr);
544 #endif
545 return (FALSE);
546 }
547 }
548
549 EXPORT void
doopen(fd,s,tab,flag,std,jump)550 doopen(fd, s, tab, flag, std, jump)
551 FILE *fd;
552 char *s;
553 abidx_t tab;
554 int flag;
555 FILE *std[];
556 BOOL jump;
557 {
558 abidx_t savetab; /* abbrev tab */
559 int prsave; /* Promptflag */
560 int ttysave; /* ttyflag */
561 int ssave; /* sflag */
562
563 #ifdef DEBUG
564 fprintf(stderr, "doopen(%d,%s,%d,..%sjump) ",
565 fdown(fd), s, tab, jump?nullstr:"no");
566 #endif
567 do_status = 0;
568 cmdfname = s;
569 cmdfp = fd;
570 savetab = deftab;
571 deftab = tab;
572 prsave = prflg;
573 ttysave = ttyflg;
574 ssave = sflg;
575 sflg = FALSE;
576 process(fd, flag, std, jump);
577 cmdfp = (FILE *)NULL;
578 cmdfname = NULL;
579 deftab = savetab;
580 prflg = prsave; /* process setzt prflg um */
581 ttyflg = ttysave; /* process setzt ttyflg um */
582 sflg = ssave;
583 }
584
585 EXPORT void
process(f,flag,std,jump)586 process(f, flag, std, jump)
587 FILE *f;
588 int flag;
589 FILE *std[];
590 BOOL jump; /* Damit dofile und process auch von hoeherer*/
591 /* Ebene aufgerufen werden kann */
592 {
593 FILE *old;
594 int save = delim;
595 Tnode *cmd;
596 SIGBLK sigfirst;
597 #ifndef INTERACTIVE
598 int i, found, max;
599 #endif
600
601 ttyflg = isatty(fdown(f));
602 prflg = ttyflg || iflg;
603
604 if (ttyflg) {
605 setbuf(std[0], NULL); /* XXX ist das die richtige Stelle ? */
606 osig18 = (sigtype) SIG_DFL;
607 osig21 = (sigtype) SIG_DFL;
608 osig22 = (sigtype) SIG_DFL;
609 }
610 old = setinput(f);
611 starthandlecond(&sigfirst);
612 if (jump) {
613 if (setjmp(jmpblk)) {
614 /*
615 * A longjmp() from the SIGINT handler may leave
616 * SIGINT blocked.
617 */
618 unblock_sigs();
619 eatline();
620 if (!prflg || delim == EOF) {
621 setinput(old);
622 unhandlecond(&sigfirst);
623 delim = save;
624 return;
625 }
626 } else {
627 handlecond(sn_any_other, &sb, sigjmp, (long)jmpblk);
628 }
629 }
630 do {
631 ctlc = 0;
632 if (prflg)
633 testmail();
634 #ifdef INTERACTIVE
635 prompt = 0;
636 #else
637 if (prflg) {
638 #ifdef JOBCONTROL
639 tty_setpgrp(fdown(f), mypgrp);
640 #endif
641 fprintf(stderr, prompts[0]);
642 prompterrs = 0; /* diesmal kein write-error */
643 }
644 #endif
645 cmd = cmdline(flag, std, FALSE); /* Parse / execute next line */
646 #ifndef INTERACTIVE
647 if (cmd && history > 0) {
648 max = high_hist();
649 found = -1;
650 for (i = max; i >= 0 && found == -1; i--)
651 if (treeequal(cmd, cur_base[i]))
652 found = i;
653 if (found == -1)
654 h_append(cmd);
655 else
656 lr_used(found);
657 /* no freetree(lastcmd) h_append() free's it */
658 lastcmd = cmd;
659 }
660 if (cmd && history == 0) {
661 freetree(lastcmd);
662 lastcmd = cmd;
663 }
664 #else
665 if (cmd) {
666 freetree(lastcmd);
667 lastcmd = cmd;
668 }
669 #endif
670 } while (delim != EOF &&
671 ((nerrors == 0 && !ctlc) || prflg) &&
672 !(ttyflg && tflg));
673 setinput(old);
674 unhandlecond(&sigfirst);
675 delim = save;
676 }
677
678 #ifdef PROTOTYPES
679 EXPORT int
berror(const char * s,...)680 berror(const char *s, ...)
681 #else
682 /* VARARGS1 */
683 EXPORT int
684 berror(s, va_alist)
685 char *s;
686 va_dcl
687 #endif
688 {
689 va_list args;
690 int ret;
691
692 #ifdef PROTOTYPES
693 va_start(args, s);
694 #else
695 va_start(args);
696 #endif
697 ret = fprintf(stderr, "%r\n", s, args);
698 va_end(args);
699 fflush(stderr);
700 return (ret);
701 }
702
703 /*
704 * Return system error message string for arg 'err'.
705 */
706
707 #if defined(__BEOS__) || defined(__HAIKU__)
708 #define silent_error(e) ((e) < 0 && (e) >= -1024)
709 #else
710 #define silent_error(e) ((e) < 0)
711 #endif
712
713 EXPORT char *
errstr(err)714 errstr(err)
715 int err;
716 {
717 static char errbuf[12];
718 char *estr;
719
720 if (silent_error(err)) {
721 return (nullstr);
722 } else {
723 estr = errmsgstr(err);
724 if (estr == NULL) {
725 sprintf(errbuf, "%d", err);
726 estr = errbuf;
727 }
728 return (estr);
729 }
730 }
731
732 EXPORT void
close_other_files(std)733 close_other_files(std)
734 FILE *std[3];
735 {
736 #ifdef HAVE_CLOSEFROM
737 closefrom(STDERR_FILENO+1);
738 #else
739 register int s0 = fdown(std[0]);
740 register int s1 = fdown(std[1]);
741 register int s2 = fdown(std[2]);
742 register int i;
743 #ifdef _SC_OPEN_MAX
744 register int max = sysconf(_SC_OPEN_MAX);
745 #else
746 #ifdef HAVE_GETDTABLESIZE
747 register int max = getdtablesize();
748 #else
749 register int max = _MAXFILES;
750 #endif
751 #endif
752
753 for (i = 0; i++ < max; ) {
754 if (i == STDIN_FILENO || i == STDOUT_FILENO ||
755 i == STDERR_FILENO) {
756 continue;
757 }
758 if (i != s0 && i != s1 && i != s2)
759 close(i);
760 }
761 #endif /* HAVE_CLOSEFROM */
762 }
763
764 LOCAL char *
getgfile()765 getgfile()
766 {
767 char *gname;
768 char *hdir;
769 char buf[10];
770 struct passwd *pw;
771 /* extern struct passwd *getpwuid();*/
772
773 hdir = getcurenv(homename);
774 if (hdir) {
775 gname = concat(hdir, slash, globalname, (char *)NULL);
776 } else {
777 sprintf(buf, "%ld", (long)geteuid());
778 /*
779 * First search for user in passwd file. If user can be found,
780 * look in his home directory for .globals file.
781 * If the user is not in the passwd file then search
782 * current directory for .globals file.
783 */
784 pw = getpwuid(geteuid());
785 endpwent();
786 if (!pw)
787 return (concat(globalname, (char *)NULL));
788 gname = concat(pw->pw_dir, slash, globalname, (char *)NULL);
789 ev_insert(concat(homename, eql, pw->pw_dir, (char *)NULL));
790 }
791 return (gname);
792 }
793
794 EXPORT char *
getuname(uid)795 getuname(uid)
796 int uid;
797 {
798 char buf[12];
799 register struct passwd *pw;
800
801 pw = getpwuid(uid);
802 endpwent();
803 if (pw)
804 return (makestr(pw->pw_name));
805 sprintf(buf, "%d", uid);
806 return (makestr(buf));
807 }
808
809 EXPORT char *
getpwdir(name)810 getpwdir(name)
811 char *name;
812 {
813 register struct passwd *pw;
814 /* extern struct passwd *getpwnam();*/
815
816 pw = getpwnam(name);
817 endpwent();
818
819 if (!pw)
820 return (NULL);
821 return (makestr(pw->pw_dir));
822 }
823
824 EXPORT char *
mypwhome()825 mypwhome()
826 {
827 static char *my_pwhome = 0;
828
829 if (!my_pwhome)
830 my_pwhome = getpwdir(user);
831 if (!my_pwhome) {
832 my_pwhome = getcurenv(homename);
833 if (my_pwhome)
834 my_pwhome = makestr(my_pwhome);
835 }
836 if (!my_pwhome)
837 return (NULL);
838 return (makestr(my_pwhome));
839 }
840
841 EXPORT char *
myhome()842 myhome()
843 {
844 char *my_home;
845
846 my_home = getcurenv(homename);
847 if (!my_home)
848 return (NULL);
849 return (makestr(my_home));
850 }
851
852 /* ARGSUSED */
853 LOCAL int
get_oopt(arg,valp,pac,pav,opt)854 get_oopt(arg, valp, pac, pav, opt)
855 const char *arg;
856 void *valp;
857 int *pac;
858 char *const **pav;
859 const char *opt;
860 {
861 if (arg[0] == '-' || arg[0] == '+') {
862 /*
863 * Strange Korn Shell rules:
864 * If next arg is an option, -o was called without parameter.
865 */
866 if (arg == &opt[2]) /* arg concatenated with -o */
867 return (BADFLAG);
868 (*pav)--;
869 (*pac)++;
870 return (1);
871 }
872 if (streql(arg, "aliasowner")) {
873 ab_setaltowner(GLOBAL_AB, "");
874 ab_setaltowner(LOCAL_AB, "");
875 return (1);
876 } else if (strncmp(arg, "aliasowner=", 11) == 0) {
877 ab_setaltowner(GLOBAL_AB, (char *)&arg[11]);
878 ab_setaltowner(LOCAL_AB, (char *)&arg[11]);
879 return (1);
880 }
881 return (BADFLAG);
882 }
883
884 LOCAL void
gargs(ac,av,opts,no_i2flg,no_gaflg,no_laflg)885 gargs(ac, av, opts, no_i2flg, no_gaflg, no_laflg)
886 int ac;
887 char *const *av;
888 char *opts;
889 int *no_i2flg, *no_gaflg, *no_laflg;
890 {
891 BOOL hflg = FALSE;
892 BOOL be_fast = FALSE;
893 BOOL be_xfast = FALSE;
894 BOOL prversion = FALSE;
895 char *aliasowner = NULL;
896 /* char bshopts[] = "v,V,i,c,e,h,2,g,l,n,s,t,f,F,o&,q,alias-owner*,noclose,help,version";*/
897
898 av++;
899 ac--;
900 if (getargs(&ac, &av, opts,
901 &verbose,
902 &vflg,
903 &iflg,
904 &cflg,
905 &eflg,
906 &no_histflg,
907 no_i2flg,
908 no_gaflg,
909 no_laflg,
910 &nflg,
911 &sflg,
912 &tflg,
913 &be_fast,
914 &be_xfast,
915 get_oopt, NULL,
916 &qflg, /* Undoc' d .. don't ignore SIGQUIT */
917 &aliasowner,
918 &no_closeflg,
919 &hflg, &prversion) < 0) {
920 if (av[0][0] != '-') { /* Be careful, cmd args may have '=' */
921 batch = ac+1;
922 } else {
923 bshusage(TRUE, fbasename(initav0), av[0]);
924 }
925 }
926 if (av[0] != NULL && streql(av[0], "-"))
927 batch = ac;
928 #ifdef ODEBUG
929 error("-v%d -V%d -i%d -c%d -e%d -h%d -2%d -g%d -l%d -n%d -s%d -t%d -f%d -F%d -o%d -q%d -help%d -version%d\n",
930 verbose, vflg, iflg, cflg, eflg, no_histflg,
931 *no_i2flg, *no_gaflg, *no_laflg, nflg, sflg, tflg,
932 be_fast, be_xfast, no_closeflg, qflg, hflg, prversion);
933 #endif
934 if (hflg)
935 bshusage(FALSE, fbasename(initav0), (char *) NULL);
936 if (prversion) {
937 extern int MVERSION;
938 extern int mVERSION;
939 extern char dVERSION[];
940
941 printf("bsh %d.%02d %s (%s-%s-%s)\n\n", MVERSION, mVERSION, dVERSION,
942 HOST_CPU, HOST_VENDOR, HOST_OS);
943 printf("Copyright (C) 1982, 1984, 1985, 1988-1989, 1991, 1994-2021 %s\n",
944 _("J�rg Schilling"));
945 printf("This is free software; see the source for copying conditions. There is NO\n");
946 printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
947 exit(0);
948 }
949 if (be_fast)
950 (*no_i2flg)++, no_histflg++;
951 if (be_xfast)
952 (*no_i2flg)++, no_histflg++, (*no_gaflg)++, (*no_laflg)++;
953 if (cflg && streql(fbasename(initav0), commandname))
954 (*no_i2flg)++;
955 if (aliasowner) {
956 ab_setaltowner(GLOBAL_AB, aliasowner);
957 ab_setaltowner(LOCAL_AB, aliasowner);
958 }
959 }
960
961 EXPORT void
exitbsh(excode)962 exitbsh(excode)
963 int excode;
964 {
965 if (sflg) {
966 /* see if its a top level */
967 /* run final file */
968 #ifdef INTERACTIVE
969 if (!no_histflg)
970 save_history(HI_NOINTR);
971 #endif
972 if (firstsh)
973 dofile(concat(inithome, slash, finalname, (char *)NULL),
974 GLOBAL_AB, 0, gstd, TRUE);
975 }
976
977 #ifdef INTERACTIVE
978 reset_tty_modes();
979 reset_line_disc(); /* Line discipline */
980 reset_tty_pgrp();
981 #endif
982 exit(excode);
983 }
984
985 LOCAL void
bshusage(flag,name,s)986 bshusage(flag, name, s)
987 int flag;
988 char *name;
989 char *s;
990 {
991 if (flag)
992 berror(ebadopt, name, s);
993 berror("%s%s %s", usage, name, ubsh);
994 if (flag)
995 exit(1);
996 else
997 exit(0);
998 }
999