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  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
32  *
33  * Sccsid @(#)main.c	1.10 (gritter) 7/3/05
34  */
35 
36 
37 /* from OpenSolaris "main.c	1.34	05/06/08 SMI" */
38 
39 /*
40  * UNIX shell
41  */
42 
43 #include	"defs.h"
44 #include	"sym.h"
45 #include	"hash.h"
46 #include	"timeout.h"
47 #include	<sys/types.h>
48 #include	<sys/stat.h>
49 #include	<sys/wait.h>
50 #include	<fcntl.h>
51 #include	<time.h>
52 #include	"dup.h"
53 
54 #ifdef RES
55 #include	<sgtty.h>
56 #endif
57 
58 #define	setmode	sh_setmode
59 
60 pid_t mypid, mypgid, mysid;
61 
62 static BOOL	beenhere = FALSE;
63 unsigned char		tmpout[20] = "/tmp/sh-";
64 struct fileblk	stdfile;
65 struct fileblk *standin = &stdfile;
66 int mailchk = 0;
67 
68 static unsigned char	*mailp;
69 static long	*mod_time = 0;
70 static BOOL login_shell = FALSE;
71 
72 #if vax
73 char **execargs = (char **)(0x7ffffffc);
74 #endif
75 
76 #if pdp11
77 char **execargs = (char **)(-2);
78 #endif
79 
80 
81 static void exfile(int);
82 
83 
84 int
main(int c,char * v[],char * e[])85 main(int c, char *v[], char *e[])
86 {
87 	register int	rflag = ttyflg;
88 	int		rsflag = 1;	/* local restricted flag */
89 	register unsigned char *flagc = flagadr;
90 	struct namnod	*n;
91 
92 	init_sigval();
93 	mypid = getpid();
94 	mypgid = getpgid(mypid);
95 	mysid = getsid(mypid);
96 
97 	/*
98 	 * initialize storage allocation
99 	 */
100 
101 	if (stakbot == 0) {
102 	addblok((unsigned)0);
103 	}
104 
105 	/*
106 	 * If the first character of the last path element of v[0] is "-"
107 	 * (ex. -sh, or /bin/-sh), this is a login shell
108 	 */
109 	if (*simple(v[0]) == '-') {
110 		signal(SIGXCPU, SIG_DFL);
111 		signal(SIGXFSZ, SIG_DFL);
112 
113 		/*
114 		 * As the previous comment states, this is a login shell.
115 		 * Therefore, we set the login_shell flag to explicitly
116 		 * indicate this condition.
117 		 */
118 		login_shell = TRUE;
119 	}
120 
121 	stdsigs();
122 
123 	/*
124 	 * set names from userenv
125 	 */
126 
127 	setup_env();
128 
129 	/*
130 	 * Do locale processing.
131 	 */
132 	setlocale(LC_CTYPE, "");
133 
134 	/*
135 	 * 'rsflag' is zero if SHELL variable is
136 	 *  set in environment and
137 	 *  the simple file part of the value.
138 	 *  is rsh
139 	 */
140 	if (n = findnam("SHELL"))
141 	{
142 		if (eq("rsh", simple(n->namval)))
143 			rsflag = 0;
144 	}
145 
146 	/*
147 	 * a shell is also restricted if the simple name of argv(0) is
148 	 * rsh or -rsh in its simple name
149 	 */
150 
151 #ifndef RES
152 
153 	if (c > 0 && (eq("rsh", simple(*v)) || eq("-rsh", simple(*v))))
154 		rflag = 0;
155 
156 #endif
157 
158 	if (eq("jsh", simple(*v)) || eq("-jsh", simple(*v)))
159 		flags |= monitorflg;
160 
161 	hcreate();
162 	set_dotpath();
163 
164 
165 	/*
166 	 * look for options
167 	 * dolc is $#
168 	 */
169 	dolc = options(c, (unsigned char **)v);
170 
171 	if (dolc < 2)
172 	{
173 		flags |= stdflg;
174 		{
175 
176 			while (*flagc)
177 				flagc++;
178 			*flagc++ = STDFLG;
179 			*flagc = 0;
180 		}
181 	}
182 	if ((flags & stdflg) == 0)
183 		dolc--;
184 
185 	if ((flags & privflg) == 0) {
186 		register uid_t euid;
187 		register gid_t egid;
188 		register uid_t ruid;
189 		register gid_t rgid;
190 
191 		/*
192 		 * Determine all of the user's id #'s for this process and
193 		 * then decide if this shell is being entered as a result
194 		 * of a fork/exec.
195 		 * If the effective uid/gid do NOT match and the euid/egid
196 		 * is < 100 and the egid is NOT 1, reset the uid and gid to
197 		 * the user originally calling this process.
198 		 */
199 		euid = geteuid();
200 		ruid = getuid();
201 		egid = getegid();
202 		rgid = getgid();
203 		if ((euid != ruid) && (euid < 100))
204 			setuid(ruid);   /* reset the uid to the orig user */
205 		if ((egid != rgid) && ((egid < 100) && (egid != 1)))
206 			setgid(rgid);   /* reset the gid to the orig user */
207 	}
208 
209 	dolv = (unsigned char **)v + c - dolc;
210 	dolc--;
211 
212 	/*
213 	 * return here for shell file execution
214 	 * but not for parenthesis subshells
215 	 */
216 	if (setjmp(subshell)) {
217 		freejobs();
218 		flags |= subsh;
219 	}
220 
221 	/*
222 	 * number of positional parameters
223 	 */
224 	replace(&cmdadr, dolv[0]);	/* cmdadr is $0 */
225 
226 	/*
227 	 * set pidname '$$'
228 	 */
229 	assnum(&pidadr, (long)mypid);
230 
231 	/*
232 	 * set up temp file names
233 	 */
234 	settmp();
235 
236 	/*
237 	 * default internal field separators
238 	 * Do not allow importing of IFS from parent shell.
239 	 * setup_env() may have set anything from parent shell to IFS.
240 	 * Always set the default ifs to IFS.
241 	 */
242 	assign(&ifsnod, sptbnl);
243 
244 	dfault(&timeoutnod, "0");
245 	timeoutnod.namflg |= N_RDONLY;
246 
247 	dfault(&mchknod, MAILCHECK);
248 	mailchk = stoi(mchknod.namval);
249 
250 	/* initialize OPTIND for getopt */
251 
252 	n = lookup("OPTIND");
253 	assign(n, "1");
254 	/*
255 	 * make sure that option parsing starts
256 	 * at first character
257 	 */
258 	getopt_sp = 1;
259 
260 	/* initialize multibyte information */
261 	setwidth();
262 
263 	if ((beenhere++) == FALSE)	/* ? profile */
264 	{
265 		if ((login_shell == TRUE) && (flags & privflg) == 0) {
266 
267 			/* system profile */
268 
269 #ifndef RES
270 
271 			if ((input = pathopen(nullstr, sysprofile)) >= 0)
272 				exfile(rflag);		/* file exists */
273 
274 #endif
275 			/* user profile */
276 
277 			if ((input = pathopen(homenod.namval, profile)) >= 0)
278 			{
279 				exfile(rflag);
280 				flags &= ~ttyflg;
281 			}
282 		}
283 		if (rsflag == 0 || rflag == 0) {
284 			if ((flags & rshflg) == 0) {
285 				while (*flagc)
286 					flagc++;
287 				*flagc++ = 'r';
288 				*flagc = '\0';
289 			}
290 			flags |= rshflg;
291 		}
292 
293 		/*
294 		 * open input file if specified
295 		 */
296 		if (comdiv)
297 		{
298 			estabf(comdiv);
299 			input = -1;
300 		}
301 		else
302 		{
303 			if (flags & stdflg) {
304 				input = 0;
305 			} else {
306 			/*
307 			 * If the command file specified by 'cmdadr'
308 			 * doesn't exist, chkopen() will fail calling
309 			 * exitsh(). If this is a login shell and
310 			 * the $HOME/.profile file does not exist, the
311 			 * above statement "flags &= ~ttyflg" does not
312 			 * get executed and this makes exitsh() call
313 			 * longjmp() instead of exiting. longjmp() will
314 			 * return to the location specified by the last
315 			 * active jmpbuffer, which is the one set up in
316 			 * the function exfile() called after the system
317 			 * profile file is executed (see lines above).
318 			 * This would cause an infinite loop, because
319 			 * chkopen() will continue to fail and exitsh()
320 			 * to call longjmp(). To make exitsh() exit instead
321 			 * of calling longjmp(), we then set the flag forcexit
322 			 * at this stage.
323 			 */
324 
325 				flags |= forcexit;
326 				input = chkopen(cmdadr, 0);
327 				flags &= ~forcexit;
328 			}
329 
330 #ifdef ACCT
331 			if (input != 0)
332 				preacct(cmdadr);
333 #endif
334 			comdiv--;
335 		}
336 	}
337 #ifdef pdp11
338 	else
339 		*execargs = (char *)dolv;	/* for `ps' cmd */
340 #endif
341 
342 
343 	exfile(0);
344 	done(0);
345 	/*NOTREACHED*/
346 	return 0;
347 }
348 
349 static void
exfile(prof)350 exfile(prof)
351 BOOL	prof;
352 {
353 	time_t	mailtime = 0;	/* Must not be a register variable */
354 	time_t 	curtime = 0;
355 	long	timeout = 0;
356 
357 	/*
358 	 * move input
359 	 */
360 	if (input > 0)
361 	{
362 		Ldup(input, INIO);
363 		input = INIO;
364 	}
365 
366 
367 	setmode(prof);
368 
369 	if (setjmp(errshell) && prof)
370 	{
371 		close(input);
372 		endjobs(0);
373 		return;
374 	}
375 	/*
376 	 * error return here
377 	 */
378 
379 	loopcnt = peekc = peekn = 0;
380 	fndef = 0;
381 	nohash = 0;
382 	iopend = 0;
383 
384 	if (input >= 0)
385 		initf(input);
386 	/*
387 	 * command loop
388 	 */
389 	for (;;)
390 	{
391 		tdystak(0);
392 		stakchk();	/* may reduce sbrk */
393 		exitset();
394 
395 		if ((flags & prompt) && standin->fstak == 0 && !eof)
396 		{
397 
398 			if (mailp)
399 			{
400 				time(&curtime);
401 
402 				if ((curtime - mailtime) >= mailchk)
403 				{
404 					chkmail();
405 					mailtime = curtime;
406 				}
407 			}
408 
409 			/* necessary to print jobs in a timely manner */
410 			if (trapnote & TRAPSET)
411 				chktrap();
412 
413 			prs(ps1nod.namval);
414 
415 			if ((timeout = atol(timeoutnod.namval)) > 0)
416 				alarm(timeout);
417 
418 #ifdef TIME_OUT
419 			alarm(TIMEOUT);
420 #endif
421 			flags |= waiting;
422 
423 		}
424 
425 		trapnote = 0;
426 		peekc = readwc();
427 		if (eof) {
428 			if (endjobs(JOB_STOPPED))
429 				return;
430 			eof = 0;
431 		}
432 
433 		if (timeout > 0) {
434 			alarm(0);
435 			timeout = 0;
436 		}
437 #ifdef TIME_OUT
438 		alarm(0);
439 #endif
440 		flags &= ~waiting;
441 
442 		{
443 			register struct trenod *t;
444 			t = cmd(NL, MTFLG);
445 			if (t == NULL && flags & ttyflg)
446 				freejobs();
447 			else
448 				execute(t, 0, eflag, NULL, NULL);
449 		}
450 
451 		eof |= (flags & oneflg);
452 
453 	}
454 }
455 
456 void
chkpr(void)457 chkpr(void)
458 {
459 	if ((flags & prompt) && standin->fstak == 0)
460 		prs(ps2nod.namval);
461 }
462 
463 void
settmp(void)464 settmp(void)
465 {
466 	int i;
467 	i = ltos(mypid);
468 	serial = 0;
469 	tmpname = movstr(numbuf + i, &tmpout[TMPNAM]);
470 }
471 
472 void
Ldup(register int fa,register int fb)473 Ldup(register int fa, register int fb)
474 {
475 #ifdef RES
476 
477 	dup(fa | DUPFLG, fb);
478 	close(fa);
479 	ioctl(fb, FIOCLEX, 0);
480 
481 #else
482 
483 	if (fa >= 0) {
484 		if (fa != fb)
485 		{
486 			close(fb);
487 			fcntl(fa, 0, fb); /* normal dup */
488 			close(fa);
489 		}
490 		fcntl(fb, 2, 1);	/* autoclose for fb */
491 	}
492 
493 #endif
494 }
495 
496 
497 void
chkmail(void)498 chkmail(void)
499 {
500 	register unsigned char 	*s = mailp;
501 	register unsigned char	*save;
502 
503 	long	*ptr = mod_time;
504 	unsigned char	*start;
505 	BOOL	flg;
506 	struct stat	statb;
507 
508 	while (*s) {
509 		start = s;
510 		save = 0;
511 		flg = 0;
512 
513 		while (*s) {
514 			if (*s != COLON) {
515 				if (*s == '%' && save == 0)
516 					save = s;
517 
518 				s++;
519 			} else {
520 				flg = 1;
521 				*s = 0;
522 			}
523 		}
524 
525 		if (save)
526 			*save = 0;
527 
528 		if (*start && stat((const char *)start, &statb) >= 0) {
529 			if (statb.st_size && *ptr &&
530 			    statb.st_mtime != *ptr) {
531 				if (save) {
532 					prs(save+1);
533 					newline();
534 				}
535 				else
536 					prs(mailmsg);
537 			}
538 			*ptr = statb.st_mtime;
539 		} else if (*ptr == 0)
540 			*ptr = 1;
541 
542 		if (save)
543 			*save = '%';
544 
545 		if (flg)
546 			*s++ = COLON;
547 
548 		ptr++;
549 	}
550 }
551 
552 
553 void
setmail(unsigned char * mailpath)554 setmail(unsigned char *mailpath)
555 {
556 	register unsigned char	*s = mailpath;
557 	register int 	cnt = 1;
558 
559 	long	*ptr;
560 
561 	free(mod_time);
562 	if (mailp = mailpath)
563 	{
564 		while (*s)
565 		{
566 			if (*s == COLON)
567 				cnt += 1;
568 
569 			s++;
570 		}
571 
572 		ptr = mod_time = (long *)alloc(sizeof (long) * cnt);
573 
574 		while (cnt)
575 		{
576 			*ptr = 0;
577 			ptr++;
578 			cnt--;
579 		}
580 	}
581 }
582 
583 void
setwidth(void)584 setwidth(void)
585 {
586 	unsigned char *name = lookup("LC_ALL")->namval;
587 	if (!name || !*name)
588 		name = lookup("LC_CTYPE")->namval;
589 	if (!name || !*name)
590 		name = lookup("LANG")->namval;
591 	if (!name || !*name)
592 		setlocale(LC_CTYPE, "C");
593 	else
594 		setlocale(LC_CTYPE, (const char *)name);
595 	mb_cur_max = MB_CUR_MAX;
596 }
597 
598 void
setmode(int prof)599 setmode(int prof)
600 {
601 	/*
602 	 * decide whether interactive
603 	 */
604 
605 	if ((flags & intflg) ||
606 	    ((flags&oneflg) == 0 &&
607 	    isatty(output) &&
608 	    isatty(input)))
609 
610 	{
611 		dfault(&ps1nod, (geteuid() ? stdprompt : supprompt));
612 		dfault(&ps2nod, readmsg);
613 		flags |= ttyflg | prompt;
614 		if (mailpnod.namflg != N_DEFAULT)
615 			setmail(mailpnod.namval);
616 		else
617 			setmail(mailnod.namval);
618 		startjobs();
619 	}
620 	else
621 	{
622 		flags |= prof;
623 		flags &= ~prompt;
624 	}
625 }
626