|
|
1.1 root 1: /*
2: * sh/main.c
3: * The Bourne shell.
4: * Main program, initialization and miscellaneous routines.
5: */
6:
7: #include <assert.h>
8: #include <stdarg.h>
9: #include "sh.h"
10: #include <fcntl.h>
11:
12: void fakearg ();
13: void reset ();
14: void ecantopen ();
15: void panic ();
16: void printe ();
17: void syntax ();
18:
19:
20: int
21: main(argc, argv, envp)
22: char *argv[];
23: char *envp[];
24: {
25:
26: sarg0 = argc > 0 ? argv [0] : "";
27: fakearg (0, argc, argv, envp);
28:
29: if (argc > 0 && argv [0][0] == '-') {
30: lgnflag = 1;
31: umask (ufmask = 022);
32: } else if (argc > 0 && argv [0][0] == '+') {
33: lgnflag = 2;
34: umask (ufmask = 022);
35: } else
36: umask (ufmask = umask (ufmask));
37:
38: /*
39: * NIGEL: we must *force* stdin to be unbuffered to defeat some
40: * excessive cleverness in the stdio library. Note that line-buffering
41: * is a mode that only applies to output.
42: */
43:
44: if (setvbuf (stdin, NULL, _IONBF, BUFSIZ) != 0)
45: printe ("Cannot set stdin buffering\n");
46:
47: if (setjmp (restart) != 0) {
48: /* reentry for shell command file execution */
49: fakearg (1, nargc, nargv, nenvp);
50: argc = nargc;
51: argv = nargv;
52: envp = nenvp;
53: cmdflag ++;
54: nllflag = 0;
55: }
56:
57: shpid = getpid ();
58: initvar (envp);
59:
60: if (set (argc, argv, 1))
61: return 1;
62:
63: if (cflag) {
64: if (sargp [0] == NULL) {
65: printe ("No string for -c?");
66: return 1;
67: }
68: -- sargc;
69: session (SARGS, * sargp ++);
70: } else if (! sflag && ! iflag && sargc != 0) {
71: sarg0 = * sargp ++;
72: --sargc;
73: if (scmdp == NULL)
74: scmdp = sarg0;
75: session (SFILE, scmdp);
76: } else
77: session (SSTR, stdin);
78:
79: cleanup_shell_fns ();
80: unlink_temp (capture_temp ());
81: return slret;
82: }
83:
84:
85: /*
86: * Make the arg listing of ps come out right.
87: * f == 0, first entry, determine buffer limits.
88: * f != 0, later entry, fill buffer with lies.
89: */
90:
91: void
92: fakearg(f, argc, argv, envp)
93: int f, argc;
94: char **argv, **envp;
95: {
96: static char *fbuf;
97: static int nbuf;
98: register int n;
99:
100: if (f == 0) {
101: fbuf = argv [0];
102: nbuf = 0;
103: if (envp != NULL && envp [0] != NULL) {
104: while (envp [1] != NULL)
105: envp += 1;
106: nbuf = envp [0] - fbuf + strlen (envp [0]) - 1;
107: } else if (argc > 0)
108: nbuf = argv [argc - 1] - fbuf +
109: strlen (argv [argc - 1]) - 1;
110: } else {
111: if (fbuf == NULL || nbuf == 0)
112: return;
113: n = 0;
114: fbuf [0] = 0;
115: while (-- argc > 0) {
116: argv += 1;
117: n += strlen (argv [0]) + 1;
118: if (n >= nbuf)
119: break;
120: strcat (fbuf, argv [0]);
121: strcat (fbuf, " ");
122: }
123: strcat (fbuf, "\1"); /* non-ascii terminator */
124: }
125: }
126:
127:
128: /*
129: * Push a session of the indicated type. A non-zero return value is the
130: * appropriate return value for the session, but offset by one.
131: */
132:
133: int
134: push_session (type, info, session)
135: int type;
136: __VOID__ * info;
137: SES * session;
138: {
139: session->s_next = sesp;
140: sesp = session;
141: session->s_bpp = savebuf ();
142:
143: switch (session->s_type = type) {
144: case SARGS:
145: session->s_strp = (char *) info;
146: session->s_flag = 0;
147: break;
148:
149: case SARGV:
150: session->s_argv = (char **) info;
151: if ((session->s_strp = session->s_argv [0]) == NULL)
152: return 1;
153: session->s_flag = 0;
154: break;
155:
156: case SFILE:
157: session->s_strp = (char *) info;
158:
159: /*
160: * NIGEL: We should take steps to ensure that the file
161: * descriptors created for these input files lie above the
162: * range that can be redirected in scripts!
163: */
164:
165: if ((type = open (session->s_strp, O_RDONLY)) < 0) {
166: ecantopen (session->s_strp);
167: return 2;
168: }
169: if (type > 9) {
170: int scan;
171: for (scan = 10 ; scan < FOPEN_MAX ; scan ++) {
172: if (fcntl (scan, F_GETFD) == -1) {
173: /*
174: * Move the new FD to the new place.
175: */
176:
177: dup2 (type, scan);
178: close (type);
179: type = scan;
180:
181: break;
182: }
183: }
184: }
185: if ((session->s_ifp = fdopen (type, "r")) == NULL) {
186: ecantopen (session->s_strp);
187: return 2;
188: }
189: session->s_flag = isatty (fileno (session->s_ifp)) &&
190: isatty (2);
191: break;
192:
193: case SSTR:
194: session->s_strp = NULL;
195: session->s_ifp = (FILE *) info;
196: session->s_flag = isatty (fileno (session->s_ifp)) &&
197: isatty (2);
198: break;
199: }
200:
201: return 0;
202: }
203:
204:
205: /*
206: * Pop the passed-in session, which must be the current session.
207: */
208:
209: void
210: pop_session (session)
211: SES * session;
212: {
213: assert (sesp == session);
214:
215: freebuf (session->s_bpp);
216:
217: if (session->s_type == SFILE)
218: fclose (session->s_ifp);
219:
220: if (session->s_next == NULL) {
221: sigintr (0);
222: recover (IRDY);
223: }
224:
225: sesp = session->s_next;
226: }
227:
228:
229: /*
230: * Loop on input.
231: */
232:
233: int
234: session(t, p)
235: register char *p;
236: {
237: SES s;
238: register int rcode;
239:
240: if ((rcode = push_session (t, p, & s)) > 0)
241: return rcode - 1;
242:
243: if (s.s_next == NULL) { /* Initial entry */
244: if (iflag)
245: s.s_flag = iflag;
246: else
247: iflag = s.s_flag;
248: dflttrp (IRDY);
249: }
250:
251: /* Loop on input */
252: for (;;) {
253: unlink_temp (capture_temp ());
254:
255: rcode = setjmp (s.s_envl);
256: switch (rcode) {
257: case RSET: /* initial setjmp call */
258: switch (lgnflag) {
259: case 1: /* - sign invocation */
260: lgnflag = 0;
261: if (ffind ("/etc", "profile", 4))
262: session (SFILE, duplstr (strt, 0));
263: recover (IPROF);
264: if (* vhome && ffind (vhome, ".profile", 4))
265: session (SFILE, duplstr (strt, 0));
266: break;
267:
268: case 2: /* + sign invocation */
269: lgnflag = 0;
270: if (ffind ("/etc", "profile", 4))
271: session (SFILE, duplstr (strt, 0));
272: recover (IPROF);
273: return exshell (findvar ("SHELL"));
274: }
275: checkmail ();
276: comflag = 1;
277: errflag = 0;
278: recover (IRDY);
279: freebuf (s.s_bpp);
280: s.s_bpp = savebuf ();
281: if (yyparse () != 0)
282: syntax ();
283:
284: case REOF:
285: recover (IRDY);
286: break;
287:
288: case RCMD:
289: recover (IRDY);
290: s.s_con = NULL;
291: command (s.s_node);
292: if (tflag && tflag ++ >= 2)
293: break;
294: continue;
295:
296: case RERR:
297: recover (IRDY);
298: if (! errflag)
299: syntax ();
300: if (! iflag || (tflag && tflag ++ >= 2))
301: break;
302: continue;
303:
304: case RINT:
305: if (s.s_next != NULL) {
306: sesp = s.s_next;
307: reset (RINT);
308: NOTREACHED;
309: }
310: prpflag = 2;
311: if (! iflag || (tflag && tflag ++ >= 2))
312: break;
313: continue;
314:
315: case RUEXITS:
316: case RUABORT:
317: if (s.s_next != NULL) {
318: sesp = s.s_next;
319: reset (rcode);
320: NOTREACHED;
321: }
322: if (rcode == RUEXITS || ! iflag ||
323: (tflag && tflag ++ >= 2))
324: break;
325: continue;
326:
327: case RNOSBRK:
328: case RSYSER:
329: case RBRKCON:
330: case RNOWAY:
331: default:
332: if (s.s_next != NULL)
333: break;
334: if (! iflag || (tflag && tflag ++ >= 2))
335: break;
336: continue;
337: }
338: break;
339: }
340:
341: pop_session (& s);
342: return (slret);
343: }
344:
345:
346: void
347: reset (f)
348: {
349: longjmp (sesp->s_envl, f);
350: NOTREACHED;
351: }
352:
353:
354: /*
355: * Global head of list of temporary files.
356: */
357:
358: static TEMP_FILE * temp_list;
359:
360: ALLOC_COUNT (temp)
361:
362: /*
363: * Remember the name of a temporary file.
364: */
365:
366: void
367: remember_temp (filename)
368: char * filename;
369: {
370: TEMP_FILE * temp = (TEMP_FILE *) salloc (sizeof (* temp));
371:
372: temp->tf_name = duplstr (filename, 1);
373: temp->tf_next = temp_list;
374: temp_list = temp;
375:
376: ALLOC_ALLOC (temp)
377: }
378:
379:
380: /*
381: * Return a pointer to the current global list of temporary files and clear
382: * the global pointer to that list.
383: */
384:
385: TEMP_FILE *
386: capture_temp ()
387: {
388: TEMP_FILE * temp = temp_list;
389:
390: temp_list = NULL;
391: return temp;
392: }
393:
394:
395: /*
396: * Deallocate a list of temporary files.
397: */
398:
399: void
400: forget_temp (templist)
401: TEMP_FILE * templist;
402: {
403: TEMP_FILE * temp;
404:
405: while ((temp = templist) != NULL) {
406:
407: templist = temp->tf_next;
408:
409: ALLOC_FREE (temp);
410: sfree (temp->tf_name);
411: sfree (temp);
412: }
413: }
414:
415:
416: /*
417: * Walk over a list of temporary files, unlinking the files and deallocating
418: * the list nodes.
419: */
420:
421: void
422: unlink_temp (templist)
423: TEMP_FILE * templist;
424: {
425: TEMP_FILE * temp;
426:
427: while ((temp = templist) != NULL) {
428:
429: templist = temp->tf_next;
430: unlink (temp->tf_name);
431:
432: ALLOC_FREE (temp)
433: sfree (temp->tf_name);
434: sfree (temp);
435: }
436: }
437:
438:
439: /*
440: * Make a temp file name.
441: */
442:
443: char *
444: shtmp ()
445: {
446: static char tmpfile [] = "/tmp/shXXXXXXX";
447: static int tmpflag = 0;
448:
449: tmpflag ++;
450: sprintf (tmpfile + 6, "%05d%c%c", shpid, tmpflag % 26 + 'a',
451: (tmpflag / 26) % 26 + 'a');
452: return tmpfile;
453: }
454:
455:
456: /*
457: * Print formatted.
458: */
459:
460: void
461: prints (format /* , ... */)
462: char * format;
463: {
464: va_list args;
465:
466: va_start (args, format);
467: vfprintf (stderr, format, args);
468: va_end (args);
469: }
470:
471:
472: /*
473: * Make a core dump in /tmp and longjmp back to session -
474: * there's a possibility we'll die horribly.
475: */
476:
477: void
478: panic (i)
479: int i;
480: {
481: #ifdef PARANOID
482: register int f;
483:
484: if ((f = fork ()) == 0) {
485: abort ();
486: NOTREACHED;
487: }
488: waitc (f);
489: #endif
490: printe ("Internal shell assertion %d failed", i);
491: reset (RNOWAY);
492: NOTREACHED;
493: }
494:
495:
496: /*
497: * Print out an error message.
498: */
499:
500: void
501: printe (format /* , ... */)
502: char * format;
503: {
504: errflag += 1;
505: if (! noeflag) {
506: va_list args;
507:
508: va_start (args, format);
509: vfprintf (stderr, format, args);
510: va_end (args);
511: fprintf (stderr, "\n");
512: }
513: }
514:
515: /*
516: * Some familiar errors.
517: */
518:
519: void ecantopen(s) char *s; { printe ("Cannot open %s", s); }
520: void ecantfind(s) char *s; { printe ("Cannot find %s", s); }
521: void e2big(s) char *s; { printe ("File to big to execute: %s", s); }
522: void ecantmake(s) char *s; { printe ("Cannot create %s", s); }
523: void emisschar(c) { printe ("Missing `%c'", c); }
524: void ecantfdop() { printe ("Fdopen failed"); }
525: void enotdef(s) char *s; { printe ("Cannot find variable %s", s); }
526: void eillvar(s) char *s; { printe ("Illegal variable name: %s", s); }
527: void eredir() { printe ("Illegal redirection"); }
528: void etoolong(s) char *s; {
529: printe ("Argument too long %s: %.*s", s, STRSIZE, strt);
530: }
531: void eredirundo() {
532: printe ("Unable to preserve redirection state when redirecting builtin");
533: }
534:
535:
536: /*
537: * Don't print out an error message.
538: */
539:
540: void
541: yyerror()
542: {
543: }
544:
545:
546: /*
547: * print out the prompt given the prompt to write
548: */
549:
550: void
551: prompt(vps)
552: char *vps;
553: {
554: prints ("%s", vps);
555: #if RSX
556: fflush (stdout);
557: #endif
558: }
559:
560:
561: /*
562: * Syntax error message - print line number and file if
563: * not interactive.
564: */
565:
566: void
567: syntax()
568: {
569: if (sesp->s_type == SFILE) {
570: if (feof (sesp->s_ifp))
571: printe ("%s: Syntax error at EOF", sesp->s_strp);
572: else
573: printe ("%s: Syntax error in line %d", sesp->s_strp,
574: yyline);
575: } else
576: printe ("Syntax error");
577: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.