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