4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
37 #include <sys/types.h>
46 pid_t mypid
, mypgid
, mysid
;
48 static BOOL beenhere
= FALSE
;
49 unsigned char tmpout
[TMPOUTSZ
];
50 struct fileblk stdfile
;
51 struct fileblk
*standin
= &stdfile
;
54 static unsigned char *mailp
;
55 static long *mod_time
= 0;
56 static BOOL login_shell
= FALSE
;
59 char **execargs
= (char **)(0x7ffffffc);
63 char **execargs
= (char **)(-2);
68 extern unsigned char *simple();
69 static void Ldup(int, int);
72 void setmail(unsigned char *);
75 main(int c
, char *v
[], char *e
[])
78 int rsflag
= 1; /* local restricted flag */
79 unsigned char *flagc
= flagadr
;
83 mypgid
= getpgid(mypid
);
84 mysid
= getsid(mypid
);
87 * Do locale processing only if /usr is mounted.
89 localedir_exists
= (access(localedir
, F_OK
) == 0);
92 * initialize storage allocation
100 * If the first character of the last path element of v[0] is "-"
101 * (ex. -sh, or /bin/-sh), this is a login shell
103 if (*simple(v
[0]) == '-') {
104 signal(SIGXCPU
, SIG_DFL
);
105 signal(SIGXFSZ
, SIG_DFL
);
108 * As the previous comment states, this is a login shell.
109 * Therefore, we set the login_shell flag to explicitly
110 * indicate this condition.
118 * set names from userenv
124 * LC_MESSAGES is set here so that early error messages will
125 * come out in the right style.
126 * Note that LC_CTYPE is done later on and is *not*
127 * taken from the previous environ
131 * Do locale processing only if /usr is mounted.
133 if (localedir_exists
)
134 (void) setlocale(LC_ALL
, "");
135 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
136 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
138 (void) textdomain(TEXT_DOMAIN
);
141 * 'rsflag' is zero if SHELL variable is
142 * set in environment and
143 * the simple file part of the value.
146 if (n
= findnam("SHELL")) {
147 if (eq("rsh", simple(n
->namval
)))
152 * a shell is also restricted if the simple name of argv(0) is
153 * rsh or -rsh in its simple name
158 if (c
> 0 && (eq("rsh", simple(*v
)) || eq("-rsh", simple(*v
))))
163 if (eq("jsh", simple(*v
)) || eq("-jsh", simple(*v
)))
174 dolc
= options(c
, v
);
186 if ((flags
& stdflg
) == 0)
189 if ((flags
& privflg
) == 0) {
196 * Determine all of the user's id #'s for this process and
197 * then decide if this shell is being entered as a result
199 * If the effective uid/gid do NOT match and the euid/egid
200 * is < 100 and the egid is NOT 1, reset the uid and gid to
201 * the user originally calling this process.
207 if ((euid
!= ruid
) && (euid
< 100))
208 setuid(ruid
); /* reset the uid to the orig user */
209 if ((egid
!= rgid
) && ((egid
< 100) && (egid
!= 1)))
210 setgid(rgid
); /* reset the gid to the orig user */
213 dolv
= (unsigned char **)v
+ c
- dolc
;
217 * return here for shell file execution
218 * but not for parenthesis subshells
220 if (setjmp(subshell
)) {
226 * number of positional parameters
228 replace(&cmdadr
, dolv
[0]); /* cmdadr is $0 */
233 assnum(&pidadr
, (long)mypid
);
236 * set up temp file names
241 * default internal field separators
242 * Do not allow importing of IFS from parent shell.
243 * setup_env() may have set anything from parent shell to IFS.
244 * Always set the default ifs to IFS.
246 assign(&ifsnod
, (unsigned char *)sptbnl
);
248 dfault(&mchknod
, MAILCHECK
);
249 mailchk
= stoi(mchknod
.namval
);
251 /* initialize OPTIND for getopt */
253 n
= lookup("OPTIND");
254 assign(n
, (unsigned char *)"1");
256 * make sure that option parsing starts
261 if ((beenhere
++) == FALSE
) /* ? profile */
263 if ((login_shell
== TRUE
) && (flags
& privflg
) == 0) {
269 if ((input
= pathopen(nullstr
, sysprofile
)) >= 0)
270 exfile(rflag
); /* file exists */
275 if ((input
= pathopen(homenod
.namval
, profile
)) >= 0) {
280 if (rsflag
== 0 || rflag
== 0) {
281 if ((flags
& rshflg
) == 0) {
291 * open input file if specified
299 if (flags
& stdflg
) {
303 * If the command file specified by 'cmdadr'
304 * doesn't exist, chkopen() will fail calling
305 * exitsh(). If this is a login shell and
306 * the $HOME/.profile file does not exist, the
307 * above statement "flags &= ~ttyflg" does not
308 * get executed and this makes exitsh() call
309 * longjmp() instead of exiting. longjmp() will
310 * return to the location specified by the last
311 * active jmpbuffer, which is the one set up in
312 * the function exfile() called after the system
313 * profile file is executed (see lines above).
314 * This would cause an infinite loop, because
315 * chkopen() will continue to fail and exitsh()
316 * to call longjmp(). To make exitsh() exit instead
317 * of calling longjmp(), we then set the flag forcexit
322 input
= chkopen(cmdadr
, 0);
335 *execargs
= (char *)dolv
; /* for `ps' cmd */
346 time_t mailtime
= 0; /* Must not be a register variable */
360 if (setjmp(errshell
) && prof
) {
369 loopcnt
= peekc
= peekn
= 0;
381 stakchk(); /* may reduce sbrk */
384 if ((flags
& prompt
) && standin
->fstak
== 0 && !eof
) {
389 if ((curtime
- mailtime
) >= mailchk
) {
395 /* necessary to print jobs in a timely manner */
396 if (trapnote
& TRAPSET
)
410 if (endjobs(JOB_STOPPED
))
422 if (t
== NULL
&& flags
& ttyflg
)
425 execute(t
, 0, eflag
);
428 eof
|= (flags
& oneflg
);
436 if ((flags
& prompt
) && standin
->fstak
== 0)
445 if ((len
= snprintf((char *)tmpout
, TMPOUTSZ
, "/tmp/sh%u", mypid
)) >=
448 * TMPOUTSZ should be big enough, but if it isn't,
449 * we'll at least try to create tmp files with
450 * a truncated tmpfile name at tmpout.
452 tmpout_offset
= TMPOUTSZ
- 1;
463 dup(fa
| DUPFLG
, fb
);
465 ioctl(fb
, FIOCLEX
, 0);
472 fcntl(fa
, 0, fb
); /* normal dup */
475 fcntl(fb
, 2, 1); /* autoclose for fb */
484 unsigned char *s
= mailp
;
487 long *ptr
= mod_time
;
488 unsigned char *start
;
499 if (*s
== '%' && save
== 0)
512 if (*start
&& stat((const char *)start
, &statb
) >= 0) {
513 if (statb
.st_size
&& *ptr
&&
514 statb
.st_mtime
!= *ptr
) {
520 prs(_gettext(mailmsg
));
522 *ptr
= statb
.st_mtime
;
523 } else if (*ptr
== 0)
537 setmail(unsigned char *mailpath
)
539 unsigned char *s
= mailpath
;
545 if (mailp
= mailpath
) {
553 ptr
= mod_time
= (long *)alloc(sizeof (long) * cnt
);
567 * decide whether interactive
570 if ((flags
& intflg
) ||
571 ((flags
&oneflg
) == 0 &&
576 dfault(&ps1nod
, (geteuid() ? stdprompt
: supprompt
));
577 dfault(&ps2nod
, readmsg
);
578 flags
|= ttyflg
| prompt
;
579 if (mailpnod
.namflg
!= N_DEFAULT
)
580 setmail(mailpnod
.namval
);
582 setmail(mailnod
.namval
);