|
|
1.1 root 1: From uucp Thu Jan 10 01:37:58 1980
2: >From dmr Thu Jan 10 04:25:49 1980 remote from research
3: The system has been changed so that if a file being executed
4: begins with the magic characters #! , the rest of the line is understood
5: to be the name of an interpreter for the executed file.
6: Previously (and in fact still) the shell did much of this job;
7: it automatically executed itself on a text file with executable mode
8: when the text file's name was typed as a command.
9: Putting the facility into the system gives the following
10: benefits.
11:
12: 1) It makes shell scripts more like real executable files,
13: because they can be the subject of 'exec.'
14:
15: 2) If you do a 'ps' while such a command is running, its real
16: name appears instead of 'sh'.
17: Likewise, accounting is done on the basis of the real name.
18:
19: 3) Shell scripts can be set-user-ID.
20:
21: 4) It is simpler to have alternate shells available;
22: e.g. if you like the Berkeley csh there is no question about
23: which shell is to interpret a file.
24:
25: 5) It will allow other interpreters to fit in more smoothly.
26:
27: To take advantage of this wonderful opportunity,
28: put
29:
30: #! /bin/sh
31:
32: at the left margin of the first line of your shell scripts.
33: Blanks after ! are OK. Use a complete pathname (no search is done).
34: At the moment the whole line is restricted to 16 characters but
35: this limit will be raised.
36:
37:
38: From uucp Thu Jan 10 01:37:49 1980
39: >From dmr Thu Jan 10 04:23:53 1980 remote from research
40: #include "../h/param.h"
41: #include "../h/systm.h"
42: #include "../h/map.h"
43: #include "../h/dir.h"
44: #include "../h/user.h"
45: #include "../h/proc.h"
46: #include "../h/buf.h"
47: #include "../h/reg.h"
48: #include "../h/inode.h"
49: #include "../h/seg.h"
50: #include "../h/acct.h"
51:
52:
53: /*
54: * exec system call, with and without environments.
55: */
56: struct execa {
57: char *fname;
58: char **argp;
59: char **envp;
60: };
61:
62: exec()
63: {
64: ((struct execa *)u.u_ap)->envp = NULL;
65: exece();
66: }
67:
68: exece()
69: {
70: register nc;
71: register char *cp;
72: register struct buf *bp;
73: register struct execa *uap;
74: int na, ne, bno, ucp, ap, c, indir, uid, gid;
75: struct inode *ip;
76:
77: bno = 0;
78: bp = 0;
79: indir = 0;
80: if ((ip = namei(uchar, 0)) == NULL)
81: return;
82: uid = u.u_uid;
83: gid = u.u_gid;
84: if (ip->i_mode&ISUID)
85: uid = ip->i_uid;
86: if (ip->i_mode&ISGID)
87: gid = ip->i_gid;
88: again:
89: if(access(ip, IEXEC))
90: goto bad;
91: if((ip->i_mode & IFMT) != IFREG ||
92: (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
93: u.u_error = EACCES;
94: goto bad;
95: }
96: /*
97: * read in first few bytes
98: * of file for segment
99: * types and sizes:
100: * ux_mag = 407/410/411/405
101: * 407 is plain executable
102: * 410 is RO text
103: * 411 is separated ID
104: * 405 is overlaid text
105: *
106: * Also, an ascii line beginning
107: * with '#!' is the file name of a shell.
108: */
109: u.u_base = (caddr_t)&u.u_exdata;
110: u.u_count = sizeof(u.u_exdata);
111: u.u_offset = 0;
112: u.u_segflg = 1;
113: readi(ip);
114: u.u_segflg = 0;
115: if(u.u_error)
116: goto bad;
117: if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.A)
118: && u.u_exdata.S[0] != '#') {
119: u.u_error = ENOEXEC;
120: goto bad;
121: }
122: if(u.u_exdata.A.ux_mag == 0407)
123: ;
124: else if (u.u_exdata.A.ux_mag == 0411)
125: ;
126: else if (u.u_exdata.A.ux_mag == 0405)
127: ;
128: else if (u.u_exdata.A.ux_mag == 0410)
129: ;
130: else if (u.u_exdata.S[0]=='#' && u.u_exdata.S[1]=='!' && indir==0) {
131: cp = &u.u_exdata.S[2];
132: while (*cp==' ' && cp<&u.u_exdata.S[SHSIZ])
133: cp++;
134: u.u_dirp = cp;
135: while (cp < &u.u_exdata.S[SHSIZ-1] && *cp != '\n')
136: cp++;
137: *cp = '\0';
138: indir++;
139: iput(ip);
140: ip = namei(schar, 0);
141: if (ip==NULL)
142: return;
143: goto again;
144: } else {
145: u.u_error = ENOEXEC;
146: goto bad;
147: }
148: /*
149: * Collect arguments on "file" in swap space.
150: */
151: na = 0;
152: ne = 0;
153: nc = 0;
154: uap = (struct execa *)u.u_ap;
155: while ((bno = malloc(argmap,(NCARGS+BSIZE-1)/BSIZE)) == 0)
156: sleep((caddr_t)&argmap, PRIBIO);
157: if (uap->argp) for (;;) {
158: ap = NULL;
159: if (indir && na==1)
160: ap = uap->fname;
161: else if (uap->argp) {
162: ap = fuword((caddr_t)uap->argp);
163: uap->argp++;
164: }
165: if (ap==NULL && uap->envp) {
166: uap->argp = NULL;
167: if ((ap = fuword((caddr_t)uap->envp)) == NULL)
168: break;
169: uap->envp++;
170: ne++;
171: }
172: if (ap==NULL)
173: break;
174: na++;
175: if(ap == -1)
176: u.u_error = EFAULT;
177: do {
178: if (nc >= NCARGS-1)
179: u.u_error = E2BIG;
180: if ((c = fubyte((caddr_t)ap++)) < 0)
181: u.u_error = EFAULT;
182: if (u.u_error)
183: goto bad;
184: if ((nc&BMASK) == 0) {
185: if (bp)
186: bawrite(bp);
187: bp = getblk(swapdev, swplo+bno+(nc>>BSHIFT));
188: cp = bp->b_un.b_addr;
189: }
190: nc++;
191: *cp++ = c;
192: } while (c>0);
193: }
194: if (bp)
195: bawrite(bp);
196: bp = 0;
197: nc = (nc + NBPW-1) & ~(NBPW-1);
198: getxfile(ip, nc, uid, gid);
199: if (u.u_error || u.u_exdata.A.ux_mag==0405)
200: goto bad;
201:
202: /*
203: * copy back arglist
204: */
205: ucp = -nc - NBPW;
206: ap = ucp - na*NBPW - 3*NBPW;
207: u.u_ar0[R6] = ap;
208: suword((caddr_t)ap, na-ne);
209: nc = 0;
210: for (;;) {
211: ap += NBPW;
212: if (na==ne) {
213: suword((caddr_t)ap, 0);
214: ap += NBPW;
215: }
216: if (--na < 0)
217: break;
218: suword((caddr_t)ap, ucp);
219: do {
220: if ((nc&BMASK) == 0) {
221: if (bp)
222: brelse(bp);
223: bp = bread(swapdev, swplo+bno+(nc>>BSHIFT));
224: bp->b_flags &= ~B_DELWRI;
225: cp = bp->b_un.b_addr;
226: if (nc==0 && indir)
227: bcopy(cp, (caddr_t)u.u_dbuf, DIRSIZ);
228: }
229: subyte((caddr_t)ucp++, (c = *cp++));
230: nc++;
231: } while(c&0377);
232: }
233: suword((caddr_t)ap, 0);
234: suword((caddr_t)ucp, 0);
235: setregs();
236: bad:
237: if (bp)
238: brelse(bp);
239: if(bno) {
240: mfree(argmap, (NCARGS+BSIZE-1)/BSIZE, bno);
241: wakeup((caddr_t)&argmap);
242: }
243: iput(ip);
244: }
245:
246: /*
247: * Read in and set up memory for executed file.
248: */
249: getxfile(ip, nargc, uid, gid)
250: register struct inode *ip;
251: {
252: register unsigned ds;
253: register sep;
254: register unsigned ts, ss;
255: int i;
256: long lsize;
257:
258: sep = 0;
259: if(u.u_exdata.A.ux_mag == 0407) {
260: lsize = (long)u.u_exdata.A.ux_dsize + u.u_exdata.A.ux_tsize;
261: u.u_exdata.A.ux_dsize = lsize;
262: if (lsize != u.u_exdata.A.ux_dsize) { /* check overflow */
263: u.u_error = ENOMEM;
264: return;
265: }
266: u.u_exdata.A.ux_tsize = 0;
267: } else if (u.u_exdata.A.ux_mag == 0411)
268: sep++;
269: if(u.u_exdata.A.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
270: u.u_error = ETXTBSY;
271: return;
272: }
273:
274: /*
275: * find text and data sizes
276: * try them out for possible
277: * overflow of max sizes
278: */
279: ts = btoc(u.u_exdata.A.ux_tsize);
280: lsize = (long)u.u_exdata.A.ux_dsize + u.u_exdata.A.ux_bsize;
281: if (lsize != (unsigned)lsize) {
282: u.u_error = ENOMEM;
283: return;
284: }
285: ds = btoc(lsize);
286: ss = SSIZE + btoc(nargc);
287: if (u.u_exdata.A.ux_mag==0405) {
288: if (u.u_sep==0 && ctos(ts) != ctos(u.u_tsize) || nargc) {
289: u.u_error = ENOMEM;
290: return;
291: }
292: ds = u.u_dsize;
293: ss = u.u_ssize;
294: sep = u.u_sep;
295: xfree();
296: xalloc(ip);
297: u.u_ar0[PC] = u.u_exdata.A.ux_entloc & ~01;
298: } else {
299: if(estabur(ts, ds, ss, sep, RO))
300: return;
301:
302: /*
303: * allocate and clear core
304: * at this point, committed
305: * to the new image
306: */
307: u.u_prof.pr_scale = 0;
308: xfree();
309: i = USIZE+ds+ss;
310: expand(i);
311: while(--i >= USIZE)
312: clearseg(u.u_procp->p_addr+i);
313: xalloc(ip);
314:
315: /*
316: * read in data segment
317: */
318: estabur((unsigned)0, ds, (unsigned)0, 0, RO);
319: u.u_base = 0;
320: u.u_offset = sizeof(u.u_exdata.A)+u.u_exdata.A.ux_tsize;
321: u.u_count = u.u_exdata.A.ux_dsize;
322: readi(ip);
323: /*
324: * set SUID/SGID protections, if no tracing
325: */
326: if ((u.u_procp->p_flag&STRC)==0) {
327: u.u_uid = uid;
328: u.u_gid = gid;
329: } else
330: psignal(u.u_procp, SIGTRC);
331: }
332: u.u_tsize = ts;
333: u.u_dsize = ds;
334: u.u_ssize = ss;
335: u.u_sep = sep;
336: estabur(ts, ds, ss, sep, RO);
337: }
338:
339: /*
340: * Clear registers on exec
341: */
342: setregs()
343: {
344: register int *rp;
345: register char *cp;
346: register i;
347:
348: for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++)
349: if((*rp & 1) == 0)
350: *rp = 0;
351: for(cp = ®loc[0]; cp < ®loc[6];)
352: u.u_ar0[*cp++] = 0;
353: u.u_ar0[PC] = u.u_exdata.A.ux_entloc & ~01;
354: for(rp = (int *)&u.u_fps; rp < (int *)&u.u_fps.u_fpregs[6];)
355: *rp++ = 0;
356: for(i=0; i<NOFILE; i++) {
357: if (u.u_pofile[i]&EXCLOSE) {
358: closef(u.u_ofile[i]);
359: u.u_ofile[i] = NULL;
360: u.u_pofile[i] &= ~EXCLOSE;
361: }
362: }
363: /*
364: * Remember file name for accounting.
365: */
366: u.u_acflag &= ~AFORK;
367: bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ);
368: }
369:
370: /*
371: * exit system call:
372: * pass back caller's arg
373: */
374: rexit()
375: {
376: register struct a {
377: int rval;
378: } *uap;
379:
380: uap = (struct a *)u.u_ap;
381: exit((uap->rval & 0377) << 8);
382: }
383:
384: /*
385: * Release resources.
386: * Save u. area for parent to look at.
387: * Enter zombie state.
388: * Wake up parent and init processes,
389: * and dispose of children.
390: */
391: exit(rv)
392: {
393: register int i;
394: register struct proc *p, *q;
395: register struct file *f;
396:
397: p = u.u_procp;
398: p->p_flag &= ~(STRC|SULOCK);
399: p->p_clktim = 0;
400: for(i=0; i<NSIG; i++)
401: u.u_signal[i] = 1;
402: for(i=0; i<NOFILE; i++) {
403: f = u.u_ofile[i];
404: u.u_ofile[i] = NULL;
405: closef(f);
406: }
407: plock(u.u_cdir);
408: iput(u.u_cdir);
409: if (u.u_rdir) {
410: plock(u.u_rdir);
411: iput(u.u_rdir);
412: }
413: xfree();
414: acct();
415: mfree(coremap, p->p_size, p->p_addr);
416: p->p_stat = SZOMB;
417: ((struct xproc *)p)->xp_xstat = rv;
418: ((struct xproc *)p)->xp_utime = u.u_cutime + u.u_utime;
419: ((struct xproc *)p)->xp_stime = u.u_cstime + u.u_stime;
420: for(q = &proc[0]; q < &proc[NPROC]; q++)
421: if(q->p_ppid == p->p_pid) {
422: wakeup((caddr_t)&proc[1]);
423: q->p_ppid = 1;
424: if (q->p_stat==SSTOP)
425: setrun(q);
426: }
427: for(q = &proc[0]; q < &proc[NPROC]; q++)
428: if(p->p_ppid == q->p_pid) {
429: wakeup((caddr_t)q);
430: swtch();
431: /* no return */
432: }
433: swtch();
434: }
435:
436: /*
437: * Wait system call.
438: * Search for a terminated (zombie) child,
439: * finally lay it to rest, and collect its status.
440: * Look also for stopped (traced) children,
441: * and pass back status from them.
442: */
443: wait()
444: {
445: register f;
446: register struct proc *p;
447:
448: f = 0;
449:
450: loop:
451: for(p = &proc[0]; p < &proc[NPROC]; p++)
452: if(p->p_ppid == u.u_procp->p_pid) {
453: f++;
454: if(p->p_stat == SZOMB) {
455: u.u_r.V.r_val1 = p->p_pid;
456: u.u_r.V.r_val2 = ((struct xproc *)p)->xp_xstat;
457: u.u_cutime += ((struct xproc *)p)->xp_utime;
458: u.u_cstime += ((struct xproc *)p)->xp_stime;
459: p->p_pid = 0;
460: p->p_ppid = 0;
461: p->p_pgrp = 0;
462: p->p_sig = 0;
463: p->p_flag = 0;
464: p->p_wchan = 0;
465: p->p_stat = NULL;
466: return;
467: }
468: if(p->p_stat == SSTOP) {
469: if((p->p_flag&SWTED) == 0) {
470: p->p_flag |= SWTED;
471: u.u_r.V.r_val1 = p->p_pid;
472: u.u_r.V.r_val2 = (fsig(p)<<8) | 0177;
473: return;
474: }
475: continue;
476: }
477: }
478: if(f) {
479: sleep((caddr_t)u.u_procp, PWAIT);
480: goto loop;
481: }
482: u.u_error = ECHILD;
483: }
484:
485: /*
486: * fork system call.
487: */
488: fork()
489: {
490: register struct proc *p1, *p2;
491: register a;
492:
493: /*
494: * Make sure there's enough swap space for max
495: * core image, thus reducing chances of running out
496: */
497: if ((a = malloc(swapmap, ctod(MAXMEM))) == 0) {
498: u.u_error = ENOMEM;
499: goto out;
500: }
501: mfree(swapmap, ctod(MAXMEM), a);
502: a = 0;
503: p2 = NULL;
504: for(p1 = &proc[0]; p1 < &proc[NPROC]; p1++) {
505: if (p1->p_stat==NULL && p2==NULL)
506: p2 = p1;
507: else {
508: if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
509: a++;
510: }
511: }
512: /*
513: * Disallow if
514: * No processes at all;
515: * not su and too many procs owned; or
516: * not su and would take last slot.
517: */
518: if (p2==NULL || (u.u_uid!=0 && (p2==&proc[NPROC-1] || a>MAXUPRC))) {
519: u.u_error = EAGAIN;
520: goto out;
521: }
522: p1 = u.u_procp;
523: if(newproc()) {
524: u.u_r.V.r_val1 = p1->p_pid;
525: u.u_start = time;
526: u.u_cstime = 0;
527: u.u_stime = 0;
528: u.u_cutime = 0;
529: u.u_utime = 0;
530: u.u_acflag = AFORK;
531: return;
532: }
533: u.u_r.V.r_val1 = p2->p_pid;
534:
535: out:
536: u.u_ar0[R7] += NBPW;
537: }
538:
539: /*
540: * break system call.
541: * -- bad planning: "break" is a dirty word in C.
542: */
543: sbreak()
544: {
545: struct a {
546: char *nsiz;
547: };
548: register a, n, d;
549: int i;
550:
551: /*
552: * set n to new data size
553: * set d to new-old
554: * set n to new total size
555: */
556:
557: n = btoc((int)((struct a *)u.u_ap)->nsiz);
558: if(!u.u_sep)
559: n -= ctos(u.u_tsize) * stoc(1);
560: if(n < 0)
561: n = 0;
562: d = n - u.u_dsize;
563: n += USIZE+u.u_ssize;
564: if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep, RO))
565: return;
566: u.u_dsize += d;
567: if(d > 0)
568: goto bigger;
569: a = u.u_procp->p_addr + n - u.u_ssize;
570: i = n;
571: n = u.u_ssize;
572: while(n--) {
573: copyseg(a-d, a);
574: a++;
575: }
576: expand(i);
577: return;
578:
579: bigger:
580: expand(n);
581: a = u.u_procp->p_addr + n;
582: n = u.u_ssize;
583: while(n--) {
584: a--;
585: copyseg(a-d, a);
586: }
587: while(d--)
588: clearseg(--a);
589: }
590:
591:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.