8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sh / main.c
blobdf42009b5be9f911ba3e9ca3f1a2302494615bc5
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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 */
30 * UNIX shell
33 #include "defs.h"
34 #include "sym.h"
35 #include "timeout.h"
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/wait.h>
40 #include "dup.h"
42 #ifdef RES
43 #include <sgtty.h>
44 #endif
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;
52 int mailchk = 0;
54 static unsigned char *mailp;
55 static long *mod_time = 0;
56 static BOOL login_shell = FALSE;
58 #if vax
59 char **execargs = (char **)(0x7ffffffc);
60 #endif
62 #if pdp11
63 char **execargs = (char **)(-2);
64 #endif
67 static void exfile();
68 extern unsigned char *simple();
69 static void Ldup(int, int);
70 void settmp(void);
71 void chkmail(void);
72 void setmail(unsigned char *);
74 int
75 main(int c, char *v[], char *e[])
77 int rflag = ttyflg;
78 int rsflag = 1; /* local restricted flag */
79 unsigned char *flagc = flagadr;
80 struct namnod *n;
82 mypid = getpid();
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
95 if (stakbot == 0) {
96 addblok((unsigned)0);
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.
112 login_shell = TRUE;
115 stdsigs();
118 * set names from userenv
121 setup_env();
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 */
137 #endif
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.
144 * is rsh
146 if (n = findnam("SHELL")) {
147 if (eq("rsh", simple(n->namval)))
148 rsflag = 0;
152 * a shell is also restricted if the simple name of argv(0) is
153 * rsh or -rsh in its simple name
156 #ifndef RES
158 if (c > 0 && (eq("rsh", simple(*v)) || eq("-rsh", simple(*v))))
159 rflag = 0;
161 #endif
163 if (eq("jsh", simple(*v)) || eq("-jsh", simple(*v)))
164 flags |= monitorflg;
166 hcreate();
167 set_dotpath();
171 * look for options
172 * dolc is $#
174 dolc = options(c, v);
176 if (dolc < 2) {
177 flags |= stdflg;
180 while (*flagc)
181 flagc++;
182 *flagc++ = STDFLG;
183 *flagc = 0;
186 if ((flags & stdflg) == 0)
187 dolc--;
189 if ((flags & privflg) == 0) {
190 uid_t euid;
191 gid_t egid;
192 uid_t ruid;
193 gid_t rgid;
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
198 * of a fork/exec.
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.
203 euid = geteuid();
204 ruid = getuid();
205 egid = getegid();
206 rgid = getgid();
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;
214 dolc--;
217 * return here for shell file execution
218 * but not for parenthesis subshells
220 if (setjmp(subshell)) {
221 freejobs();
222 flags |= subsh;
226 * number of positional parameters
228 replace(&cmdadr, dolv[0]); /* cmdadr is $0 */
231 * set pidname '$$'
233 assnum(&pidadr, (long)mypid);
236 * set up temp file names
238 settmp();
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
257 * at first character
259 _sp = 1;
261 if ((beenhere++) == FALSE) /* ? profile */
263 if ((login_shell == TRUE) && (flags & privflg) == 0) {
265 /* system profile */
267 #ifndef RES
269 if ((input = pathopen(nullstr, sysprofile)) >= 0)
270 exfile(rflag); /* file exists */
272 #endif
273 /* user profile */
275 if ((input = pathopen(homenod.namval, profile)) >= 0) {
276 exfile(rflag);
277 flags &= ~ttyflg;
280 if (rsflag == 0 || rflag == 0) {
281 if ((flags & rshflg) == 0) {
282 while (*flagc)
283 flagc++;
284 *flagc++ = 'r';
285 *flagc = '\0';
287 flags |= rshflg;
291 * open input file if specified
293 if (comdiv) {
294 estabf(comdiv);
295 input = -1;
297 else
299 if (flags & stdflg) {
300 input = 0;
301 } else {
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
318 * at this stage.
321 flags |= forcexit;
322 input = chkopen(cmdadr, 0);
323 flags &= ~forcexit;
326 #ifdef ACCT
327 if (input != 0)
328 preacct(cmdadr);
329 #endif
330 comdiv--;
333 #ifdef pdp11
334 else
335 *execargs = (char *)dolv; /* for `ps' cmd */
336 #endif
339 exfile(0);
340 done(0);
343 static void
344 exfile(int prof)
346 time_t mailtime = 0; /* Must not be a register variable */
347 time_t curtime = 0;
350 * move input
352 if (input > 0) {
353 Ldup(input, INIO);
354 input = INIO;
358 setmode(prof);
360 if (setjmp(errshell) && prof) {
361 close(input);
362 (void) endjobs(0);
363 return;
366 * error return here
369 loopcnt = peekc = peekn = 0;
370 fndef = 0;
371 nohash = 0;
372 iopend = 0;
374 if (input >= 0)
375 initf(input);
377 * command loop
379 for (;;) {
380 tdystak(0);
381 stakchk(); /* may reduce sbrk */
382 exitset();
384 if ((flags & prompt) && standin->fstak == 0 && !eof) {
386 if (mailp) {
387 time(&curtime);
389 if ((curtime - mailtime) >= mailchk) {
390 chkmail();
391 mailtime = curtime;
395 /* necessary to print jobs in a timely manner */
396 if (trapnote & TRAPSET)
397 chktrap();
399 prs(ps1nod.namval);
401 #ifdef TIME_OUT
402 alarm(TIMEOUT);
403 #endif
407 trapnote = 0;
408 peekc = readwc();
409 if (eof) {
410 if (endjobs(JOB_STOPPED))
411 return;
412 eof = 0;
415 #ifdef TIME_OUT
416 alarm(0);
417 #endif
420 struct trenod *t;
421 t = cmd(NL, MTFLG);
422 if (t == NULL && flags & ttyflg)
423 freejobs();
424 else
425 execute(t, 0, eflag);
428 eof |= (flags & oneflg);
433 void
434 chkpr(void)
436 if ((flags & prompt) && standin->fstak == 0)
437 prs(ps2nod.namval);
440 void
441 settmp(void)
443 int len;
444 serial = 0;
445 if ((len = snprintf((char *)tmpout, TMPOUTSZ, "/tmp/sh%u", mypid)) >=
446 TMPOUTSZ) {
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;
453 } else {
454 tmpout_offset = len;
458 static void
459 Ldup(int fa, int fb)
461 #ifdef RES
463 dup(fa | DUPFLG, fb);
464 close(fa);
465 ioctl(fb, FIOCLEX, 0);
467 #else
469 if (fa >= 0) {
470 if (fa != fb) {
471 close(fb);
472 fcntl(fa, 0, fb); /* normal dup */
473 close(fa);
475 fcntl(fb, 2, 1); /* autoclose for fb */
478 #endif
481 void
482 chkmail(void)
484 unsigned char *s = mailp;
485 unsigned char *save;
487 long *ptr = mod_time;
488 unsigned char *start;
489 BOOL flg;
490 struct stat statb;
492 while (*s) {
493 start = s;
494 save = 0;
495 flg = 0;
497 while (*s) {
498 if (*s != COLON) {
499 if (*s == '%' && save == 0)
500 save = s;
502 s++;
503 } else {
504 flg = 1;
505 *s = 0;
509 if (save)
510 *save = 0;
512 if (*start && stat((const char *)start, &statb) >= 0) {
513 if (statb.st_size && *ptr &&
514 statb.st_mtime != *ptr) {
515 if (save) {
516 prs(save+1);
517 newline();
519 else
520 prs(_gettext(mailmsg));
522 *ptr = statb.st_mtime;
523 } else if (*ptr == 0)
524 *ptr = 1;
526 if (save)
527 *save = '%';
529 if (flg)
530 *s++ = COLON;
532 ptr++;
536 void
537 setmail(unsigned char *mailpath)
539 unsigned char *s = mailpath;
540 int cnt = 1;
542 long *ptr;
544 free(mod_time);
545 if (mailp = mailpath) {
546 while (*s) {
547 if (*s == COLON)
548 cnt += 1;
550 s++;
553 ptr = mod_time = (long *)alloc(sizeof (long) * cnt);
555 while (cnt) {
556 *ptr = 0;
557 ptr++;
558 cnt--;
563 void
564 setmode(int prof)
567 * decide whether interactive
570 if ((flags & intflg) ||
571 ((flags&oneflg) == 0 &&
572 isatty(output) &&
573 isatty(input)))
576 dfault(&ps1nod, (geteuid() ? stdprompt : supprompt));
577 dfault(&ps2nod, readmsg);
578 flags |= ttyflg | prompt;
579 if (mailpnod.namflg != N_DEFAULT)
580 setmail(mailpnod.namval);
581 else
582 setmail(mailnod.namval);
583 startjobs();
585 else
587 flags |= prof;
588 flags &= ~prompt;