Start development on BSD 2
[unix-history] / .ref-BSD-1 / ashell / sh.c
CommitLineData
1a5078b8
BJ
1#include "sh.h"
2/*
3 * Shell
4 *
5 * Modified by Bill Joy
6 * UC Berkeley 1976/1977
7 *
8
9 Features remaining to be fixed up and/or implemented
10 ======== ========= == == ===== == === == ===========
11
12 * Commands insert and delete on argument lists should be
13 * implemented also set 3= when have 2 arguments should be
14 * handled somehow (perhaps optionally valid).
15 * Also note that $12 should really be done correctly.
16
17 * A notion of terse ?
18
19 * time time ... time time date etc. are funny
20 * These should be implemented correctly with the internal versions
21 * of exit repeat if goto etc. Probably want to maintain a timed
22 * process number list and check this when processes die (this uses
23 * less processes than forking a time).
24
25 * Better facilities for string manipulation ?
26
27 * The exit status variable should be implemented (status)
28 * and set too by the internal commands. When do this get
29 * rid of kludge about prompt not set for exit on error or
30 * fix up in some way. Also should rewrite the argument
31 * processing section to be cleaner and make some sense.
32
33 * Do verbose more cleanly.
34
35 * Implement next (recursively!)
36
37 * Implement shell filters and <<. This probably involves some more
38 * modularization of the scanner and deciphering of the two different
39 * options available in the bell shell.
40
41 * Other stuff from Bell shell -
42 *
43 * Any more control facilities ?
44 * || &&
45 * <>, ><, >2, 2 >, etc.
46 * Terminate
47 * Can we build high level commands out of gotos which have
48 * optional defaults and ifs that set variables which one
49 * can test ? Think so !
50 * but what about "for" ?
51 * Prompt for more input ?
52 * Command substitution ` ` ?
53 * Trap ?
54 * Exec ?
55 * Eval ?
56 * .acct ?
57 * Some way to set stdin to be input when filters can happen.
58
59 * What about file name substitution and quoting in set.
60
61 * Conditional expressions should be fixed up with set name@
62 * and to allow quoting at least between ? ... : ... }.
63
64 * internal if, repeat, nohup, goto, exit, echo, echononl
65 * Repeat, time, nohup, etc. should allow
66 *
67 * repeat 10 { sleep 5; echo hi } &
68 * time { pc -l *.p ; obj }
69 * or perhaps with ('s since that is illegal now anyways
70 * although the above is more like if.
71
72 * Changes to glob to allow ~, prevent too long path, and prevent
73 * perhaps running out of directories. Also change it so it doesn't
74 * exit so ungracefully, i.e. on:
75 * chdir /asdf/adfas/a*
76 * In error diagnostics the command name is often not set or set
77 * wrong on calls to bferr. Could have more calls to bferr2.
78 * Should be able to distinguish between ``No more processes'' and
79 * ``Too many processes.''
80
81 * Shell flags to exit on error, make undefined variables an error.
82
83 * Interrupted waits and errors in glob cost storage.
84 * Scratch should go away.
85 * Set a="abc" should print back similarly.
86
87 * Last, but certainly not least, some of the INTERLISP redo etc features.
88
89 */
90
91char prompt[] "prompt";
92char pcs[] "pcs";
93char shell[] "shell";
94char pid[] "pid";
95char home[] "home";
96char path[] "path";
97char n_args[] "nargs";
98char tim[] "time";
99
100char *narginp, nonelflg, nverbose;
101
102main(c, av)
103 int c;
104 char **av;
105{
106 register f;
107 register char **v, *cp;
108
109 settimes();
110 v = av;
111 uid = getuid();
112 loginsh = **v == '-';
113 set(home, gethome() == 0 ? savestr(hentry.home) : ".");
114 set1("0404", "/usr/bin/px", &interps);
115 set(prompt, uid == 0 ? "#\240" : "\246\240");
116 set(shell, "/usr/bin/ashell");
117 set(pid, putn(getpid()));
118 set1(tim, "tyme", &aliases);
119 for (f = 3; f < 15; f++)
120 close(f);
121 if (c > 1) {
122 if (*(cp = v[1]) == '-') {
123 do
124 switch (*cp++) {
125 case 'V':
126 verbose = 1;
127 case 'v':
128 nverbose = 1;
129 break;
130 case 'c':
131 if (c > 2)
132 narginp = v[2];
133 goto l1;
134 case 't':
135 nonelflg = 2;
136 case '\0':
137l1:
138 set(prompt, "");
139 unsetv(prompt);
140 case 'i':
141 **v = '-';
142 nofile++;
143 break;
144 }
145 while (*cp);
146 v++;
147 c--;
148 }
149 if (nofile == 0 && c > 1) {
150 set(prompt, "");
151 unsetv(prompt);
152 close(0);
153 if (open(cp = v[1], 0) < 0) {
154 prs(v[1]);
155 err(": Cannot open");
156 exit(1);
157 }
158 }
159 }
160 if (gtty(0, scratch) == 0 && gtty(1, scratch) == 0)
161 **v = '-';
162 c--;
163 v++;
164 if (c == 0) {
165 c = 1;
166 v = av;
167 }
168 setargs(c, v);
169 set(path, "-/bin-/usr/bin");
170 pfile("/.profile");
171 if (loginsh)
172 pfile("/.login");
173 arginp = narginp;
174 onelflg = nonelflg;
175 verbose = nverbose;
176 if (**av == '-') {
177 setintr++;
178 signal(QUIT, 1);
179 signal(INTR, 1);
180 }
181 /* mask the name ?? */
182 process(1);
183 if (loginsh)
184 prs("logout\n");
185 goodbye(loginsh);
186}
187
188pfile(cp)
189 char *cp;
190{
191 int oldinput, c;
192
193 strcpy(scratch, hentry.home);
194 strcat(scratch, cp);
195 oldinput = dup(0);
196 close(0);
197 c = open(scratch, 0);
198 if (c == 0) {
199 process(0);
200 close(0);
201 }
202 dup(oldinput);
203 close(oldinput);
204}
205
206goodbye(f)
207 int f;
208{
209
210 if (f) {
211 signal(QUIT, 1);
212 signal(INTR, 1);
213 setintr = 0;
214 pfile("/.logout");
215 }
216 exit(0);
217}
218
219process(pro)
220{
221 register char *cp;
222
223 setexit();
224 if (doneinp) {
225 doneinp = 0;
226 return;
227 }
228 for (;;) {
229 cp = value(prompt);
230 if (pro)
231 prs(cp);
232 for (; *cp; cp++)
233 echo(*cp);
234 main1();
235 }
236}
237
238main1()
239{
240 register int *t;
241
242 error = 0;
243 lex(&paraml);
244 if (error) {
245 err(error);
246 freelex(&paraml);
247 return;
248 }
249 t = syntax(paraml.next, &paraml);
250 if (error)
251 err(error);
252 else
253 execute(t);
254 freesyn(t);
255 freelex(&paraml);
256}
257
258echo(c)
259 char c;
260{
261
262 c =& 0177;
263 if (verbose)
264 write(2, &c, 1);
265 return (c);
266}
267
268err(s)
269 char *s;
270{
271
272 prs(s);
273 prs("\n");
274 s = value(prompt);
275 if (*s == 0) {
276 seek(0, 0, 2);
277 exit(1);
278 }
279}
280
281prs(os)
282 register char *os;
283{
284 register char *s;
285
286 s = os;
287 if (s != 0) {
288 while (*s)
289 s++;
290 write(2, os, s-os);
291 }
292}
293
294digit(c)
295 char c;
296{
297 c =& 0177;
298 return (c >= '0' && c <= '9');
299}
300
301letter(c)
302 char c;
303{
304 c =& 0177;
305 return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
306}
307
308any(c, s)
309 int c;
310 register char *s;
311{
312
313 while (*s)
314 if (*s++ == c)
315 return(1);
316 return(0);
317}
318
319char htmp[] "/etc/htmp";
320int tty;
321
322gethome()
323{
324 char buf[100];
325 register int i;
326 register char *bufp, *cp;
327
328 if (loginsh)
329 exechome();
330 tty = ttyn(2);
331 if (readhome() == 0 && hentry.uid == uid)
332 return (0);
333 if (getpw(uid, buf) && sleep(15), getpw(uid, buf))
334 return (-1);
335 bufp = buf;
336 for (i = 1; i < 6; i++) {
337 while (*bufp != ':')
338 if (*bufp++ == 0)
339 return (-1);
340 bufp++;
341 }
342/* printf("buf %s bufp %s", buf, bufp); */
343 for (cp = bufp; *cp && *cp != ':'; cp++)
344 continue;
345 *cp = 0;
346/* printf("bufp %s\n", bufp); */
347 hentry.uid == uid;
348 for (i = 0; i < (sizeof hentry.home - 1); i++)
349 hentry.home[i] = *bufp ? *bufp++ : 0;
350 return (0);
351}
352
353readhome()
354{
355 int htmpf;
356
357 htmpf = open(htmp, 0);
358 if (htmpf < 0)
359 return (-1);
360 if (seek(htmpf, tty * sizeof hentry, 0) < 0) {
361 close(htmpf);
362 return (-1);
363 }
364 if (read(htmpf, &hentry, sizeof hentry) != sizeof hentry) {
365 close(htmpf);
366 return (-1);
367 }
368 close (htmpf);
369 return (0);
370}
371
372exechome()
373{
374 int status;
375 static reenter;
376
377 if (reenter)
378 return;
379 reenter = 1;
380/*
381 if (fork()) {
382 wait(&status);
383 if (tty == 'x')
384 tty = status >> 8;
385 } else {
386 execl("/usr/bin/sethome", loginsh ? "-" : "x", 0);
387 exit(0177);
388 }
389*/
390}
391
392getpw(uid, buf)
393 int uid;
394 char buf[];
395{
396 char pbuf[512];
397 register int n;
398 register char *bp, *pbufp;
399 int pwf, m, pbufc;
400
401 pwf = open("/etc/passwd", 0);
402 if (pwf < 0)
403 return (1);
404 pbufc = 0;
405 for (;;) {
406 bp = buf;
407 do {
408 if (pbufc == 0) {
409 pbufc = read(pwf, &pbuf, 512);
410 if (pbufc <= 0)
411 return (1);
412 pbufp = pbuf;
413 }
414 pbufc--;
415 } while ((*bp++ = *pbufp++) != '\n');
416 *bp++ = '\0';
417/* printf("uid %d xid %d buf %s", uid, xid(buf), buf); */
418 if (xid(buf) == uid)
419 return (0);
420 }
421}
422
423xid(buf)
424 char buf[];
425{
426 register int i;
427 int uid;
428 register char *bp;
429 register c;
430
431 bp = buf;
432 for (i = 1; i < 3; i++) {
433 while (*bp != ':')
434 if (*bp++ == 0)
435 return (-1);
436 bp++;
437 }
438 i = 0;
439 while ((c = *bp++) != ':')
440 if (c == 0)
441 return (-1);
442 else if (digit(c))
443 i = i * 10 + c - '0';
444 uid = i;
445 i = 0;
446 while ((c = *bp++) != ':')
447 if (c == 0)
448 return (-1);
449 else if (digit(c))
450 i = i * 10 + c - '0';
451 return (i << 8 | uid);
452}