1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23
24 /*
25 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32 #if defined(sun)
33 #pragma ident "@(#)main.c 1.37 06/06/16 SMI"
34 #endif
35
36 #include "defs.h"
37
38 /*
39 * Copyright 2008-2020 J. Schilling
40 *
41 * @(#)main.c 1.80 20/10/07 2008-2020 J. Schilling
42 */
43 #ifndef lint
44 static UConst char sccsid[] =
45 "@(#)main.c 1.80 20/10/07 2008-2020 J. Schilling";
46 #endif
47
48 /*
49 * UNIX shell
50 */
51 #ifdef SCHILY_INCLUDES
52 #include "sym.h"
53 #include "hash.h"
54 #include "timeout.h"
55 #include <schily/types.h>
56 #include <schily/stat.h>
57 #include <schily/fcntl.h>
58 #include <schily/wait.h>
59 #ifdef INTERACTIVE
60 #include <schily/shedit.h>
61 #endif
62 #include "dup.h"
63 #include "sh_policy.h"
64 #ifdef DO_SYSALIAS
65 #include "abbrev.h"
66 #endif
67 #undef feof
68 #else
69 #include "sym.h"
70 #include "hash.h"
71 #include "timeout.h"
72 #include <stdio.h>
73 #include <sys/types.h>
74 #include <sys/stat.h>
75 #include <fcntl.h>
76 #include <sys/wait.h>
77 #include "dup.h"
78 #include "sh_policy.h"
79 #ifdef DO_SYSALIAS
80 #include "abbrev.h"
81 #endif
82 #endif
83
84 #ifdef RES
85 #include <sgtty.h>
86 #endif
87
88 #define no_pipe (int *)0
89
90 pid_t mypid, mypgid, mysid;
91
92 static BOOL beenhere = FALSE;
93 unsigned char tmpout[TMPOUTSZ];
94 struct fileblk stdfile;
95 struct fileblk *standin = &stdfile;
96 int mailchk = 0;
97
98 static int posix = 0;
99
100 static unsigned char *mailp;
101 static long *mod_time = 0;
102 static BOOL login_shell = FALSE;
103
104 #if vax
105 char **execargs = (char **)(0x7ffffffc);
106 #endif
107
108 #if pdp11
109 char **execargs = (char **)(-2);
110 #endif
111
112 int main __PR((int c, char *v[], char *e[]));
113 static void exfile __PR((int prof));
114 void chkpr __PR((void));
115 #ifdef INTERACTIVE
116 static void editpr __PR((int idx));
117 #endif
118 void settmp __PR((void));
119 static void Ldup __PR((int, int));
120 void chkmail __PR((void));
121 void setmail __PR((unsigned char *));
122 void setmode __PR((int prof));
123 void secpolicy_print __PR((int level, const char *msg));
124 static void bosh_init __PR((void));
125
126 int
main(c,v,e)127 main(c, v, e)
128 int c;
129 char *v[];
130 char *e[];
131 {
132 int rflag = ttyflg;
133 int rsflag = 1; /* local restricted flag */
134 struct namnod *n;
135
136 init_sigval();
137 mypid = getpid();
138 mypgid = getpgid(mypid); /* get process group for this shell */
139 mysid = getsid(mypid); /* get process group id of leader */
140
141 #if defined(IS_SUN) || defined(DO_SPLIT_ROOT)
142 /*
143 * Do locale processing only if /usr is mounted.
144 * This is to help the single user shell to work.
145 * Since localedir may not be the same for all target architectures
146 * we just disable this check for a non-Solaris environment.
147 */
148 localedir_exists = (access(localedir, F_OK) == 0);
149 #else
150 localedir_exists = TRUE;
151 #endif
152
153 /*
154 * initialize storage allocation
155 */
156
157 if (stakbot == 0) {
158 addblok((unsigned)0);
159 }
160
161 /*
162 * Initialize global data structure.
163 */
164 bosh_init();
165
166 /*
167 * If the first character of the last path element of v[0] is "-"
168 * (ex. -sh, or /bin/-sh), this is a login shell
169 */
170 if (*simple((unsigned char *)v[0]) == '-') {
171 #ifdef SIGXCPU
172 signal(SIGXCPU, SIG_DFL);
173 #endif
174 #ifdef SIGXFSZ
175 signal(SIGXFSZ, SIG_DFL);
176 #endif
177 /*
178 * As the previous comment states, this is a login shell.
179 * Therefore, we set the login_shell flag to explicitly
180 * indicate this condition.
181 */
182 login_shell = TRUE;
183 }
184
185 stdsigs();
186
187 /*
188 * set names from userenv
189 */
190
191 setup_env();
192
193 /*
194 * LC_MESSAGES is set here so that early error messages will
195 * come out in the right style.
196 * Note that LC_CTYPE is done later on and is *not*
197 * taken from the previous environ
198 */
199
200 /*
201 * Do locale processing only if /usr is mounted.
202 */
203 if (localedir_exists)
204 (void) setlocale(LC_ALL, "");
205 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
206 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
207 #endif
208 (void) textdomain(TEXT_DOMAIN);
209
210 /*
211 * This is a profile shell if the simple name of argv[0] is
212 * pfsh or -pfsh
213 */
214 #ifdef EXECATTR_FILENAME
215 if (c > 0 && (eq("pfsh", simple((unsigned char *)*v)) ||
216 eq("-pfsh", simple((unsigned char *)*v)) ||
217 eq("pfbosh", simple((unsigned char *)*v)) ||
218 eq("-pfbosh", simple((unsigned char *)*v)))) {
219 flags |= pfshflg;
220 secpolicy_init();
221 }
222 #endif
223
224 /*
225 * 'rsflag' is zero if SHELL variable is
226 * set in environment and
227 * the simple file part of the value.
228 * is rsh
229 */
230 if ((n = findnam((unsigned char *)"SHELL")) != NULL) {
231 if (eq("rsh", simple(n->namval)) ||
232 eq("rbosh", simple(n->namval)))
233 rsflag = 0;
234 }
235
236 /*
237 * a shell is also restricted if the simple name of argv(0) is
238 * rsh or -rsh in its simple name
239 */
240
241 #ifndef RES
242
243 if (c > 0 && (eq("rsh", simple((unsigned char *)*v)) ||
244 eq("-rsh", simple((unsigned char *)*v)) ||
245 eq("rbosh", simple((unsigned char *)*v)) ||
246 eq("-rbosh", simple((unsigned char *)*v))))
247 rflag = 0;
248
249 #endif
250
251 if (eq("jsh", simple((unsigned char *)*v)) ||
252 eq("-jsh", simple((unsigned char *)*v)) ||
253 eq("jbosh", simple((unsigned char *)*v)) ||
254 eq("-jbosh", simple((unsigned char *)*v)))
255 flags |= monitorflg;
256
257 #ifdef DO_GLOBSKIPDOT_DEF
258 flags2 |= globskipdot;
259 #endif
260 #ifdef DO_ALWAYS_POSIX_SH
261 flags2 |= posixflg;
262 #else
263 #ifdef DO_POSIX_SH
264 /*
265 * If the last path name component is "sh", set -o posix by default.
266 * This may be the right way for Linux, but probably not for Solaris.
267 */
268 if (eq("sh", simple((unsigned char *)*v)))
269 flags2 |= posixflg;
270 #else
271 #ifdef DO_POSIX_PATH
272 /*
273 * If the last path name component is not "sh", it may behave different.
274 */
275 if (eq("sh", simple((unsigned char *)*v))) {
276 #ifdef HAVE_GETEXECNAME
277 const char *exname = getexecname();
278 #else
279 char *exname = getexecpath();
280 #endif
281 if (exname) {
282 if (strstr(exname, "/xpg4")) /* X-Open interface? */
283 flags2 |= posixflg;
284
285 #ifdef POSIX_BOSH_PATH
286 if (eq(POSIX_BOSH_PATH, exname)) {
287 flags2 |= posixflg;
288 } else if (**v == '/' &&
289 eq(POSIX_BOSH_PATH, (unsigned char *)*v)) {
290 flags2 |= posixflg;
291 } else {
292 char *p;
293
294 /*
295 * We like to recognise symlinks as well,
296 * so we cannot base results on getexecname() or
297 * getexecpath(). Use SIP_ONLY_PATH to only do
298 * a PATH based search.
299 */
300 p = searchfileinpath(*v, X_OK,
301 SIP_PLAIN_FILE |
302 SIP_ONLY_PATH |
303 SIP_NO_STRIPBIN, NULL);
304 if (p && eq(POSIX_BOSH_PATH, p))
305 flags2 |= posixflg;
306 if (p)
307 libc_free(p);
308 }
309 #endif /* POSIX_BOSH_PATH */
310 #ifndef HAVE_GETEXECNAME
311 libc_free(exname);
312 #endif
313 }
314 }
315 #endif /* DO_POSIX_PATH */
316 #endif /* DO_POSIX_SH */
317 #endif /* DO_ALWAYS_POSIX_SH */
318 posix = flags2 & posixflg; /* remember "auto-posix" value */
319
320 hcreate();
321 set_dotpath();
322 #ifdef DO_DOL_SLASH
323 shmcreate();
324 #endif
325
326 /*
327 * look for options
328 * dolc is $#
329 */
330 dolc = options(c, (unsigned char **)v);
331
332 if (dolc < 2) {
333 flags |= stdflg;
334 setopts(); /* set flagadr */
335 }
336 if ((flags & stdflg) == 0)
337 dolc--;
338
339 #ifdef DO_EXPORT_ENV
340 namscan(exportenv);
341 #else
342 #ifdef DO_POSIX_EXPORT_ENV
343 if (flags2 & posixflg)
344 namscan(exportenv);
345 #endif
346 #endif
347
348 if ((flags & privflg) == 0) {
349 uid_t euid;
350 gid_t egid;
351 uid_t ruid;
352 gid_t rgid;
353
354 /*
355 * Determine all of the user's id #'s for this process and
356 * then decide if this shell is being entered as a result
357 * of a fork/exec.
358 * If the effective uid/gid do NOT match and the euid/egid
359 * is < 100 and the egid is NOT 1, reset the uid and gid to
360 * the user originally calling this process.
361 */
362 euid = geteuid();
363 ruid = getuid();
364 egid = getegid();
365 rgid = getgid();
366 if ((euid != ruid) && (euid < 100))
367 setuid(ruid); /* reset the uid to the orig user */
368 if ((egid != rgid) && ((egid < 100) && (egid != 1)))
369 setgid(rgid); /* reset the gid to the orig user */
370 }
371
372 dolv = (unsigned char **)v + c - dolc;
373 dolc--;
374
375 /*
376 * return here for shell file execution
377 * but not for parenthesis subshells
378 */
379 if (setjmp(subshell)) {
380 freejobs();
381 #ifdef DO_SYSALIAS
382 /*
383 * Shell scripts start with empty alias definitions.
384 * Turn off all aliases and disable persistent aliases.
385 */
386 ab_use(GLOBAL_AB, NULL);
387 ab_use(LOCAL_AB, NULL);
388 #endif
389 flags |= subsh;
390 flags2 |= posix; /* restore "auto-posix" value */
391 #ifdef DO_GLOBSKIPDOT_DEF
392 flags2 |= globskipdot;
393 #endif
394
395 mypgid = getpgid(0); /* get process group of script */
396 }
397
398 /*
399 * number of positional parameters
400 */
401 replace(&cmdadr, dolv[0]); /* cmdadr is $0 */
402
403 /*
404 * set pidname '$$'
405 */
406 assnum(&pidadr, (long)mypid);
407
408 /*
409 * set up temp file names
410 */
411 settmp();
412
413 /*
414 * default internal field separators
415 * Do not allow importing of IFS from parent shell.
416 * setup_env() may have set anything from parent shell to IFS.
417 * Always set the default ifs to IFS.
418 */
419 assign(&ifsnod, (unsigned char *)sptbnl);
420
421 dfault(&mchknod, (unsigned char *)MAILCHECK);
422 mailchk = stoi(mchknod.namval);
423 #ifdef DO_SYSFC
424 dfault(&fcenod, (unsigned char *)fcedit);
425 #endif
426 #ifdef DO_PS34
427 dfault(&ps3nod, (unsigned char *)selectmsg);
428 dfault(&ps4nod, (unsigned char *)execpmsg);
429 #endif
430 #ifdef DO_PPID
431 itos(getppid());
432 dfault(&ppidnod, numbuf);
433 #ifdef __readonly_ppid__
434 attrib((&ppidnod), N_RDONLY);
435 #endif
436 #endif
437 #ifdef DO_POSIX_CD
438 /*
439 * XXX Should we set a timeout here in order to allow people to log in
440 * XXX when the home directory hangs?
441 * XXX Root should not have these problems as root's homedir is local.
442 */
443 cwdget(CHDIR_P); /* Verify/set PWD as with pwd -P */
444 attrib(&pwdnod, N_EXPORT); /* Speedup nested "sh" calls */
445 #endif
446
447 /* initialize OPTIND for getopt */
448
449 n = lookup((unsigned char *)"OPTIND");
450 #ifdef DO_GETOPT_POSIX
451 optindnodep = n;
452 #endif
453 assign(n, (unsigned char *)"1");
454 /*
455 * make sure that option parsing starts
456 * at first character
457 */
458 _sp = 1;
459
460 if ((beenhere++) == FALSE) { /* ? profile */
461 if ((login_shell == TRUE) && (flags & privflg) == 0) {
462
463 /* system profile */
464
465 #ifndef RES
466
467 if ((input = pathopen((unsigned char *)nullstr,
468 (unsigned char *)sysprofile)) >= 0)
469 exfile(rflag); /* file exists */
470
471 #endif
472 /* user profile */
473
474 if ((input = pathopen(homenod.namval?
475 homenod.namval:UC "",
476 (unsigned char *)profile)) >= 0) {
477 exfile(rflag);
478 flags &= ~ttyflg;
479 }
480 }
481 if (rsflag == 0 || rflag == 0) {
482 if ((flags & rshflg) == 0) {
483 flags |= rshflg;
484 setopts(); /* set flagadr */
485 }
486 }
487 #if defined(INT_DOLMINUS) || defined(INTERACTIVE)
488 if ((flags & stdflg) && (flags & oneflg) == 0 && comdiv == 0) {
489 /*
490 * This is an interactive shell, mark it as interactive.
491 */
492 if ((flags & intflg) == 0) {
493 /*
494 * Do not switch on interactive mode in case
495 * "sh < file" was called.
496 */
497 if (isatty(STDIN_FILENO))
498 flags |= intflg;
499 }
500 #ifdef DO_BGNICE
501 flags2 |= bgniceflg;
502 #endif
503 #ifdef INTERACTIVE
504 flags2 |= vedflg;
505 #endif
506 #ifdef DO_POSIX_M
507 /*
508 * POSIX requires to auto-enable -m when
509 * in interactive mode.
510 */
511 if ((flags & intflg) != 0)
512 flags |= monitorflg;
513 #endif
514 setopts(); /* set flagadr */
515 }
516 #endif
517 if ((flags & intflg) && (flags & privflg) == 0) {
518 #ifdef DO_SHRCFILES
519 unsigned char *env = envnod.namval;
520 BOOL dosysrc = TRUE;
521
522 if (env == NULL)
523 envnod.namval = env = UC rcfile;
524 env = make(macro(env));
525
526 if (env[0] == '/' && env[1] == '.' && env[2] == '/')
527 dosysrc = FALSE;
528 else if (env[0] == '.' && env[1] == '/')
529 dosysrc = FALSE;
530
531 flags &= ~intflg; /* rcfiles: non-interactive */
532 /* system rcfile */
533 if (dosysrc &&
534 (input = pathopen((unsigned char *)nullstr,
535 (unsigned char *)sysrcfile)) >= 0)
536 exfile(rflag); /* file exists */
537
538 /* user rcfile */
539 if ((input = pathopen((unsigned char *)nullstr,
540 env)) >= 0) {
541 exfile(rflag);
542 flags &= ~ttyflg;
543 }
544 flags |= intflg; /* restore interactive */
545 setopts(); /* and flagadr */
546 free(env);
547 #endif
548 #ifdef DO_SYSALIAS
549 #ifdef __never__
550 /*
551 * The only way to have the global and local alias flag
552 * set is via the set(1) command and the set command
553 * code already reads the global and local alias files
554 * when the related flags are set.
555 */
556 if ((flags2 & globalaliasflg) && homenod.namval) {
557 catpath(homenod.namval, UC globalname);
558 ab_use(GLOBAL_AB, (char *)make(curstak()));
559 }
560 if (flags2 & localaliasflg) {
561 ab_use(LOCAL_AB, (char *)localname);
562 }
563 #endif
564 #endif
565 }
566
567 /*
568 * open input file if specified
569 */
570 if (comdiv) { /* comdiv is -c arg */
571 estabf(comdiv);
572 input = -1;
573 } else {
574 if (flags & stdflg) {
575 input = 0;
576 } else {
577 /*
578 * If the command file specified by 'cmdadr'
579 * doesn't exist, chkopen() will fail calling
580 * exitsh(). If this is a login shell and
581 * the $HOME/.profile file does not exist, the
582 * above statement "flags &= ~ttyflg" does not
583 * get executed and this makes exitsh() call
584 * longjmp() instead of exiting. longjmp() will
585 * return to the location specified by the last
586 * active jmpbuffer, which is the one set up in
587 * the function exfile() called after the system
588 * profile file is executed (see lines above).
589 * This would cause an infinite loop, because
590 * chkopen() will continue to fail and exitsh()
591 * to call longjmp(). To make exitsh() exit instead
592 * of calling longjmp(), we then set the flag forcexit
593 * at this stage.
594 */
595
596 flags |= forcexit;
597 input = chkopen(cmdadr, O_RDONLY);
598 flags &= ~forcexit;
599 }
600
601 #ifdef ACCT
602 if (input != 0)
603 preacct(cmdadr);
604 #endif
605 comdiv = UC -1; /* disable "set -c cmd" */
606 }
607 }
608 #ifdef pdp11
609 else
610 *execargs = (char *)dolv; /* for `ps' cmd */
611 #endif
612
613
614 exfile(0);
615 done(0);
616 return (exitval); /* Keep lint happy */
617 }
618
619 static void
exfile(prof)620 exfile(prof)
621 int prof;
622 {
623 time_t mailtime = 0; /* Must not be a register variable */
624 time_t curtime = 0;
625
626 /*
627 * move input
628 */
629 if (input > 0) {
630 Ldup(input, INIO);
631 input = INIO;
632 }
633
634
635 setmode(prof);
636
637 if (setjmp(errshell)) {
638 /*
639 * clear special "command -p" flag.
640 */
641 flags &= ~ppath;
642 #ifdef DO_SYSLOCAL
643 if (localp) {
644 localp = NULL;
645 poplvars();
646 }
647 #endif
648 if (prof) {
649 close(input);
650 /*
651 * Reset process group to saved value.
652 */
653 (void) endjobs(0);
654 return;
655 }
656 }
657 /*
658 * error return here
659 */
660
661 loopcnt = peekc = peekn = 0;
662 fndef = 0;
663 nohash = 0;
664 iopend = 0;
665
666 /*
667 * initf() initializes the input filehdr or flushes the content of the
668 * buffer. Flushing is needed when we come from the errshell longjmp().
669 */
670 if (input >= 0)
671 initf(input);
672
673 #ifdef DO_CHECKBINARY
674 /*
675 * Check wether the script may be a binary file, e.g. from a different
676 * architecture and caused a ENOEXEC error.
677 */
678 if (isbinary(standin))
679 failedx(ERR_NOEXEC, cmdadr, badexec);
680 #endif
681
682 /*
683 * command loop
684 */
685 for (;;) {
686 bosh.intrcnt = 0; /* Reset interrupt counter */
687 tdystak(0, 0);
688 stakchk(); /* may reduce sbrk */
689 clearcurjob(); /* clear thisjob */
690 exitset();
691
692 if ((flags & prompt) && standin->fstak == 0 && !eof) {
693
694 if (mailp) {
695 time(&curtime);
696
697 if ((curtime - mailtime) >= mailchk) {
698 chkmail();
699 mailtime = curtime;
700 }
701 }
702
703 /* necessary to print jobs in a timely manner */
704 if (trapnote & TRAPSET)
705 chktrap();
706
707 #ifdef INTERACTIVE
708 /*
709 * Make sure not to use variables from a shared
710 * library. This will not work on Mac OS X and
711 * on Solaris, it will pull in libshedit even
712 * when linked with -zlazyload.
713 * This is why we set up the prompt in libshedit
714 * indirectly here.
715 */
716 #define EDIT_RPOMPTS 2
717 if (flags2 & vedflg) {
718 editpr(0);
719 } else {
720 #endif
721 #ifdef DO_PS34
722 prs(ps_macro(ps1nod.namval, FALSE));
723 #else
724 prs(ps1nod.namval); /* Ignores NULL ptr */
725 #endif
726 #ifdef INTERACTIVE
727 }
728 #endif
729
730 #ifdef TIME_OUT
731 alarm(TIMEOUT);
732 #endif
733
734 }
735
736 trapnote = 0;
737 traprecurse = 0;
738 peekc = readwc();
739 if (eof) {
740 /*
741 * Reset process group to saved value.
742 */
743 if (endjobs(JOB_STOPPED))
744 return;
745 eof = 0;
746 }
747
748 #ifdef TIME_OUT
749 alarm(0);
750 #endif
751
752 #ifdef DO_HASHCMDS
753 if (peekc == '#' && (flags2 & hashcmdsflg)) {
754 peekc = 0;
755 hashcmd();
756 } else
757 #endif
758 {
759 struct trenod *t;
760 t = cmd(NL, MTFLG | SEMIFLG);
761 #ifdef PARSE_DEBUG
762 prtree(t, "Commandline: ");
763 #endif
764 if (t == NULL && flags & ttyflg) {
765 freejobs();
766 } else {
767 execbrk = dotbrk = 0;
768 execute(t, 0, eflag, no_pipe, no_pipe);
769 }
770 }
771
772 eof |= (flags & oneflg);
773
774 }
775 }
776
777 /*
778 * Print secondary prompt if not using the history editor.
779 */
780 void
chkpr()781 chkpr()
782 {
783 if ((flags & prompt) && standin->fstak == 0) {
784 #ifdef INTERACTIVE
785 if (flags2 & vedflg) {
786 editpr(1);
787 } else {
788 #endif
789 #ifdef DO_PS34
790 prs(ps_macro(ps2nod.namval, FALSE));
791 #else
792 prs(ps2nod.namval); /* Ignores NULL ptr */
793 #endif
794 #ifdef INTERACTIVE
795 }
796 #endif
797 }
798 }
799
800 #ifdef INTERACTIVE
801 static void
editpr(idx)802 editpr(idx)
803 int idx;
804 {
805 if (flags2 & vedflg) {
806 static char *prompts[EDIT_RPOMPTS];
807 static char palloc[EDIT_RPOMPTS];
808
809 if (palloc[idx])
810 free(prompts[idx]);
811
812 if (idx == 0 || prompts[0] == NULL) {
813 if ((prompts[0] = C ps1nod.namval) == NULL)
814 prompts[0] = C nullstr;
815 palloc[0] = FALSE;
816 }
817 if (idx == 1 || prompts[1] == NULL) {
818 if ((prompts[1] = C ps2nod.namval) == NULL)
819 prompts[1] = C nullstr;
820 palloc[1] = FALSE;
821 }
822 #ifdef DO_PS34
823 prompts[idx] = C ps_macro(UC prompts[idx], TRUE);
824 palloc[idx] = TRUE;
825 #endif
826 shedit_setprompts(idx, EDIT_RPOMPTS, prompts);
827 }
828 }
829 #endif
830
831 void
settmp()832 settmp()
833 {
834 int len;
835 serial = 0;
836 /*
837 * Should better use %ju and cast to maxint_t,
838 * but then we need to call js_snprintf() for portability.
839 */
840 if ((len = snprintf((char *)tmpout, TMPOUTSZ, "/tmp/sh%lu",
841 (unsigned long)mypid)) >= TMPOUTSZ) {
842 /*
843 * TMPOUTSZ should be big enough, but if it isn't,
844 * we'll at least try to create tmp files with
845 * a truncated tmpfile name at tmpout.
846 */
847 tmpout_offset = TMPOUTSZ - 1;
848 } else {
849 tmpout_offset = len;
850 }
851 }
852
853 /*
854 * dup file descriptor fa to fb, close fa and set fb to close-on-exec
855 */
856 static void
Ldup(fa,fb)857 Ldup(fa, fb)
858 int fa;
859 int fb;
860 {
861 #ifdef RES
862
863 dup(fa | DUPFLG, fb);
864 close(fa);
865 ioctl(fb, FIOCLEX, 0);
866
867 #else
868
869 if (fa >= 0) {
870 if (fa != fb) {
871 close(fb);
872 (void) fcntl(fa, F_DUPFD, fb); /* normal dup */
873 close(fa);
874 }
875 (void) fcntl(fb, F_SETFD, FD_CLOEXEC); /* autoclose for fb */
876 }
877
878 #endif
879 }
880
881 void
chkmail()882 chkmail()
883 {
884 unsigned char *s = mailp;
885 unsigned char *save;
886
887 long *ptr = mod_time;
888 unsigned char *start;
889 BOOL flg;
890 struct stat statb;
891
892 while (*s) {
893 start = s;
894 save = 0;
895 flg = 0;
896
897 while (*s) {
898 if (*s != COLON) {
899 if (*s == '%' && save == 0)
900 save = s;
901
902 s++;
903 } else {
904 flg = 1;
905 *s = 0;
906 }
907 }
908
909 if (save)
910 *save = 0;
911
912 if (*start && stat((const char *)start, &statb) >= 0) {
913 if (statb.st_size && *ptr &&
914 statb.st_mtime != *ptr) {
915 if (save) {
916 prs(save+1);
917 newline();
918 }
919 else
920 prs(_gettext(mailmsg));
921 }
922 *ptr = statb.st_mtime;
923 } else if (*ptr == 0)
924 *ptr = 1;
925
926 if (save)
927 *save = '%';
928
929 if (flg)
930 *s++ = COLON;
931
932 ptr++;
933 }
934 }
935
936 void
setmail(mailpath)937 setmail(mailpath)
938 unsigned char *mailpath;
939 {
940 unsigned char *s = mailpath;
941 int cnt = 1;
942
943 long *ptr;
944
945 free(mod_time);
946 if ((mailp = mailpath) != NULL) {
947 while (*s) {
948 if (*s == COLON)
949 cnt += 1;
950
951 s++;
952 }
953
954 ptr = mod_time = (long *)alloc(sizeof (long) * cnt);
955
956 while (cnt) {
957 *ptr = 0;
958 ptr++;
959 cnt--;
960 }
961 }
962 }
963
964 void
setmode(prof)965 setmode(prof)
966 int prof;
967 {
968 /*
969 * decide whether interactive
970 */
971
972 if ((flags & intflg) ||
973 ((flags&oneflg) == 0 &&
974 isatty(output) &&
975 isatty(input))) {
976 dfault(&ps1nod, (unsigned char *)(geteuid() ?
977 stdprompt : supprompt));
978 dfault(&ps2nod, (unsigned char *)readmsg);
979 flags |= ttyflg | prompt;
980 if (mailpnod.namflg != N_DEFAULT)
981 setmail(mailpnod.namval);
982 else
983 setmail(mailnod.namval);
984 /*
985 * Set job control and make me a process group leader
986 */
987 startjobs();
988 } else {
989 flags |= prof;
990 flags &= ~prompt;
991 }
992 }
993
994 /*
995 * A generic call back routine to output error messages from the
996 * policy backing functions called by pfsh.
997 *
998 * msg must contain '\n' if a new line is to be printed.
999 */
1000 void
secpolicy_print(level,msg)1001 secpolicy_print(level, msg)
1002 int level;
1003 const char *msg;
1004 {
1005 switch (level) {
1006 case SECPOLICY_WARN:
1007 default:
1008 prs(_gettext(msg));
1009 return;
1010 case SECPOLICY_ERROR:
1011 error(msg);
1012 break;
1013 }
1014 }
1015
1016 static void
bosh_init()1017 bosh_init()
1018 {
1019 bosh.intrcnt = 0;
1020 bosh.flagsp = &flags;
1021 bosh.flagsp2 = &flags2;
1022 bosh.get_envptr = get_envptr;
1023 bosh.callsh = callsh;
1024 }
1025