|
|
1.1 root 1: /* $Header: /usr/src/sys/i8086/src/RCS/exec.c,v 1.1 88/03/24 17:39:26 src Exp $ */
2: /* (lgl-
3: * The information contained herein is a trade secret of Mark Williams
4: * Company, and is confidential information. It is provided under a
5: * license agreement, and may be copied or disclosed only under the
6: * terms of that agreement. Any reproduction or disclosure of this
7: * material without the express written authorization of Mark Williams
8: * Company or persuant to the license agreement is unlawful.
9: *
10: * COHERENT Version 2.3.37
11: * Copyright (c) 1982, 1983, 1984.
12: * An unpublished work by Mark Williams Company, Chicago.
13: * All rights reserved.
14: -lgl) */
15: /*
16: * This file contains a special version
17: * of "sys exec" for the i8086. This version has
18: * no driver load code in it (save space) and has
19: * special load code so that the text of a shared
20: * and separated image can be shared.
21: * Loadable kernel processes are partially supported:
22: * the process text and data must be ld'ed with the system
23: * and the l.out executed must have no loadable or allocateable
24: * segments.
25: *
26: * $Log: /usr/src/sys/i8086/src/RCS/exec.c,v $
27: * Revision 1.1 88/03/24 17:39:26 src
28: * Initial revision
29: *
30: * 88/01/21 Allan Cornish /usr/src/sys/i8086/src/exec.c
31: * Segments are now de-associated from processes before freeing the segment.
32: *
33: * 87/12/03 Allan Cornish /usr/src/sys/i8086/src/exec.c
34: * ld_start() now reverts to kernel mode [depth=0] from user mode [depth=1].
35: *
36: * 87/11/25 Allan Cornish /usr/src/sys/i8086/src/exec.c
37: * vaddr_t bp->b_vaddr --> faddr_t bp->b_faddr.
38: *
39: * 87/11/14 Allan Cornish /usr/src/sys/i8086/src/exec.c
40: * Init code+data now split into icodep/icodes and idatap/idatas.
41: *
42: * 87/11/05 Allan Cornish /usr/src/sys/i8086/src/exec.c
43: * New seg struct now used to allow extended addressing.
44: *
45: * 87/10/09 Allan Cornish /usr/src/sys/i8086/src/exec.c
46: * pload() now handles new format [separate code] loadable device drivers.
47: *
48: * 87/10/08 Allan Cornish /usr/src/sys/i8086/src/exec.c
49: * Exsread() initializes the (IO).io_flag field to 0.
50: */
51: #include <sys/coherent.h>
52: #include <acct.h>
53: #include <sys/buf.h>
54: #include <canon.h>
55: #include <sys/con.h>
56: #include <errno.h>
57: #include <sys/filsys.h>
58: #include <sys/ino.h>
59: #include <sys/inode.h>
60: #include <l.out.h>
61: #include <sys/proc.h>
62: #include <sys/sched.h>
63: #include <sys/seg.h>
64: #include <signal.h>
65: #include <sys/uproc.h>
66: #include <sys/i8086.h>
67:
68: /*
69: * Sizes.
70: */
71: #define sh ((fsize_t)sizeof(struct ldheader))
72: #define si lssize[L_SHRI]
73: #define pi lssize[L_PRVI]
74: #define bi lssize[L_BSSI]
75: #define sd lssize[L_SHRD]
76: #define pd lssize[L_PRVD]
77: #define bd lssize[L_BSSD]
78:
79: /*
80: * Segments.
81: */
82: #define upsp pp->p_segp[SIUSERP]
83: #define sssp pp->p_segp[SISTACK]
84: #define sisp pp->p_segp[SISTEXT]
85: #define pisp pp->p_segp[SIPTEXT]
86: #define pdsp pp->p_segp[SIPDATA]
87:
88: /*
89: * Loadable driver initiation point.
90: */
91: static
92: ld_start()
93: {
94: register SEG * sp;
95: register int ret;
96:
97: /*
98: * Kernel processes start by default at user level.
99: * Revert to kernel level.
100: */
101: if ( depth == 1 )
102: depth--;
103:
104: /*
105: * Initialize memory references.
106: */
107: u.u_btime = timer.t_time;
108: sproto();
109: segload();
110:
111:
112: /*
113: * Invoke the driver if it has a shared or private code segment.
114: */
115: ret = 100;
116: if ( (sp = SELF->p_segp[SISTEXT]) || (sp = SELF->p_segp[SIPTEXT]) ) {
117: ret = ld_xcall( sp->s_faddr );
118: }
119:
120: uexit( ret );
121: }
122:
123: /*
124: * Set up the first process, a small programme which will exec
125: * the init programme.
126: */
127: eveinit(sp)
128: SEG *sp;
129: {
130: register PROC *pp;
131: SELF = pp = eprocp;
132:
133: /*
134: * Record user area.
135: */
136: pp->p_segp[SIUSERP] = sp;
137:
138: /*
139: * Allocate, record, initialize code segment, make it executable.
140: */
141: if ((sp=salloc((fsize_t)icodes, 0)) == NULL)
142: panic("eveinit(code)");
143: pp->p_segp[SIPTEXT] = sp;
144: kfcopy( icodep, sp->s_faddr, icodes );
145: sp->s_flags |= SFTEXT;
146: vremap(sp);
147:
148: /*
149: * Allocate, record, and initialize data segment.
150: */
151: if ((sp=salloc((fsize_t)idatas, 0)) == NULL)
152: panic("eveinit(data)");
153: pp->p_segp[SIPDATA] = sp;
154: kfcopy( idatap, sp->s_faddr, idatas );
155:
156: /*
157: * Allocate and record stack segment.
158: */
159: if ((sp=salloc((fsize_t)UPASIZE, SFDOWN)) == NULL)
160: panic("eveinit()");
161: pp->p_segp[SISTACK] = sp;
162:
163: /*
164: * Start process.
165: */
166: u.u_argp = 0;
167: if (sproto() == 0)
168: panic("eveinit()");
169: segload();
170: }
171:
172: /*
173: * Load a driver which has already been linked into the system image.
174: */
175: pload( np )
176: char * np;
177: {
178: register INODE * ip;
179: register PROC * cpp;
180: struct seg * sp;
181: fsize_t lssize[NUSEG]; /* Segment sizes */
182: int lflag; /* l_flags from l.out */
183: vaddr_t pc; /* l_entry from l.out */
184: int r; /* Flag for "exload" */
185: int s;
186: extern char end[];
187:
188:
189: if (super() == 0) {
190: return( -1 );
191: }
192:
193: /*
194: * Coalesce memory BEFORE loading driver, since it can't be moved.
195: */
196: krunch(10000);
197:
198: if ((ip=exlopen(np, lssize, &lflag, &pc)) == NULL) {
199: return( -1 );
200: }
201:
202: /*
203: * New format loadable drivers must have separate code/data.
204: * It must have executable code, but no initialized data.
205: * Uninitialized data must match the kernel data size.
206: */
207: if ( ((lflag & (LF_KER|LF_SHR|LF_SEP)) != (LF_SEP|LF_KER))
208: || (si==0) || (sd!=0) || (pd!=0) || (bd != (int)end) ) {
209: u.u_error = EBADFMT;
210: idetach(ip);
211: return( -1 );
212: }
213:
214: /*
215: * Allocate and initialize driver code segment.
216: * NOTE: Must be system segment to prevent relocation.
217: */
218: sp = ssalloc(&r, ip, SFTEXT|SFHIGH|SFNSWP|SFSYST, si+pi+bi, sh, si+pi);
219:
220: /*
221: * Release driver object file.
222: */
223: idetach(ip);
224:
225: if ( r < 0 ) {
226: u.u_error = ENOMEM;
227: return( -1 );
228: }
229:
230: /*
231: * Spawn kernel process to service driver.
232: */
233: if ((cpp = process(ld_start)) == NULL ) {
234: u.u_error = ENOMEM;
235: sfree(sp);
236: return( -1 );
237: }
238:
239: /*
240: * Record the basename of the loaded driver.
241: */
242: kscopy( u.u_direct.d_name, cpp->p_segp[SIUSERP],
243: offset(uproc,u_comm[0]), sizeof(u.u_comm) );
244:
245: /*
246: * Record the driver code segment in the process's private code.
247: */
248: cpp->p_segp[SIPTEXT] = sp;
249: cpp->p_cval = CVCHILD;
250: cpp->p_sval = SVCHILD;
251: cpp->p_rval = RVCHILD;
252: cpp->p_ppid = 1;
253:
254: /*
255: * Make the process executable.
256: */
257: s = sphi();
258: setrun( cpp );
259: spl( s );
260:
261: /*
262: * Return driver process id.
263: */
264: return( cpp->p_pid );
265: }
266:
267: /*
268: * Given a major number, undo the previous function.
269: */
270: puload(m)
271: int m;
272: {
273: register CON *cp;
274: register DRV *dp;
275:
276: dp = &drvl[m];
277: lock(dp->d_gate);
278: if (m>=drvn || (cp=dp->d_conp)==NULL) {
279: u.u_error = ENXIO;
280: goto ret;
281: }
282: (*cp->c_uload)();
283: if ( ! u.u_error)
284: dp->d_conp = NULL;
285: ret:
286: unlock(dp->d_gate);
287: return (0);
288: }
289:
290: /*
291: * Pass control to an image in a file.
292: * Make sure the format is acceptable. Release
293: * the old segments. Read in the new ones. Some special
294: * care is taken so that shared and (more important) shared
295: * and separated images can be run on the 8086.
296: */
297: pexece(np, argp, envp)
298: char *np;
299: char *argp[];
300: char *envp[];
301: {
302: register INODE *ip; /* Load file INODE */
303: register PROC *pp; /* A cheap copy of SELF */
304: register SEG *ssp; /* New stack segment */
305: register SEG *segp;
306: register fsize_t ss; /* Segment size temp. */
307: register int i; /* For looping over segments */
308: int r; /* Flag for "exload" */
309: int lflag; /* l_flags from l.out */
310: vaddr_t pc; /* l_entry from l.out */
311: vaddr_t sp; /* Initial stack pointer */
312: fsize_t lssize[NUSEG]; /* Segment sizes */
313: fsize_t codsize; /* Total if CS segment */
314: fsize_t datsize; /* Total of DS segment */
315: extern fsize_t exround(); /* Paragraph rounder */
316:
317: pp = SELF;
318: if ((ip=exlopen(np, lssize, &lflag, &pc)) == NULL) {
319: return;
320: }
321:
322: if ( (lflag & LF_SEP) == 0 ) {
323: u.u_error = EBADFMT;
324: idetach(ip);
325: return;
326: }
327:
328: /*
329: * Kernel processes are now supported through the sload() system call.
330: * 87/10/09 Allan Cornish.
331: */
332: if ((lflag&LF_KER) != 0) {
333: u.u_error = EBADFMT;
334: idetach(ip);
335: return;
336: }
337:
338: /*
339: * If a shared and separated image
340: * has stuff in segments that makes it impossible
341: * to share, give an error immediately so that we don't
342: * lose the parent.
343: */
344: lflag &= LF_SHR|LF_SEP;
345:
346: if (lflag==(LF_SHR|LF_SEP) && (pi!=0 || bi!=0)) {
347: u.u_error = EBADFMT;
348: idetach(ip);
349: return;
350: }
351:
352: if ((ssp=exstack(&sp, argp, envp)) == NULL) {
353: idetach(ip);
354: return;
355: }
356:
357: switch (lflag) {
358: case LF_SEP:
359: codsize = si+pi+bi;
360: datsize = ssp->s_size+sd+pd+bd;
361: break;
362: case LF_SHR|LF_SEP:
363: codsize = si;
364: datsize = ssp->s_size+exround(sd)+pd+bd;
365: break;
366: }
367: codsize = (codsize+(BSIZE-1)) & ~(BSIZE-1);
368: datsize = (datsize+(BSIZE-1)) & ~(BSIZE-1);
369: if ( (codsize >= MAXU) || (datsize >= MAXU) ) {
370: u.u_error = E2BIG;
371: idetach(ip);
372: return;
373: }
374:
375: /*
376: * At this point the file has been
377: * validated as an object module, and the
378: * argument list has been built. Release all of
379: * the original segments. At this point we have
380: * committed to the new image. A "sys exec" that
381: * gets an I/O error is doomed.
382: * NOTE: User-area segment is NOT released.
383: * Segment pointer in proc is erased BEFORE invoking sfree().
384: */
385: for ( i = 1; i < NUSEG; ++i ) {
386: if ((segp = pp->p_segp[i]) != NULL) {
387: pp->p_segp[i] = NULL;
388: sfree(segp);
389: }
390: }
391:
392: /*
393: * Read in the loadable segments.
394: */
395: sssp = ssp;
396: switch (lflag) {
397: case 0:
398: ss = si+pi+sd+pd;
399: pdsp = ssalloc(&r, ip, 0, ss+bi+bd, sh, ss);
400: if (r < 0)
401: goto out;
402: break;
403:
404: case LF_SHR:
405: ss = exround(si+sd);
406: pdsp = ssalloc(&r, ip, 0, ss+pi+pd+bi+bd, sh, si);
407: if (r < 0)
408: goto out;
409: if (exsread(pdsp, ip, sd, sh+si+pi, si) == NULL)
410: goto out;
411: if (exsread(pdsp, ip, pi, sh+si, ss) == NULL)
412: goto out;
413: if (exsread(pdsp, ip, pd, sh+si+pi+sd, ss+pi) == NULL)
414: goto out;
415: break;
416:
417: case LF_SEP:
418: pisp = ssalloc(&r, ip, SFTEXT, si+pi+bi, sh, si+pi);
419: if (r < 0)
420: goto out;
421: pdsp = ssalloc(&r, ip, 0, sd+pd+bd, sh+si+pi, sd+pd);
422: if (r < 0)
423: goto out;
424: break;
425:
426: case LF_SHR|LF_SEP:
427: /* pi=0, bi=0 */
428: sisp = ssalloc(&r, ip, SFSHRX|SFTEXT, si, sh, si);
429: if (r < 0)
430: goto out;
431: ss = exround(sd);
432: pdsp = ssalloc(&r, ip, 0, ss+pd+bd, sh+si, sd);
433: if (r<0 || exsread(pdsp, ip, pd, sh+si+sd, ss) == NULL)
434: goto out;
435: }
436: if (sproto() == 0)
437: goto out;
438: #if 0
439: if ( (datsize != pdsp->s_size) ||
440: ( (lflag==LF_SEP) && (codsize != pisp->s_size) ) ||
441: ( (lflag==(LF_SEP|LF_SHR)) && (codsize != sisp->s_size) ) ) {
442: printf("\nExec ERROR: codsize: 0x%X datsize: 0x%X\n",
443: codsize, datsize);
444: printf(
445: "pdsp->s_size: 0x%X pisp->s_size: 0x%X sisp->s_size: 0x%X\n",
446: pdsp->s_size, pisp->s_size, sisp->s_size);
447: }
448: #endif
449: /*
450: * The new image is read in
451: * and mapped. Perform the final grunge
452: * (set-uid stuff, accounting, loading up
453: * registers, etc).
454: */
455: u.u_flag &= ~AFORK;
456: kkcopy(u.u_direct.d_name, u.u_comm, sizeof(u.u_comm));
457: if (iaccess(ip, IPR) == 0) { /* Can't read ? no dump or trace */
458: pp->p_flags |= PFNDMP;
459: pp->p_flags &= ~PFTRAC;
460: }
461: if (iaccess(ip, IPW) == 0) /* Can't write ? no trace */
462: pp->p_flags &= ~PFTRAC;
463: if ((ip->i_mode&ISUID) != 0) { /* Set user id ? no trace */
464: pp->p_uid = u.u_uid = ip->i_uid;
465: pp->p_flags &= ~PFTRAC;
466: }
467: if ((ip->i_mode&ISGID) != 0) { /* Set group id ? no trace */
468: u.u_gid = ip->i_gid;
469: pp->p_flags &= ~PFTRAC;
470: }
471: for (i=0; i<NSIG; ++i)
472: if (u.u_sfunc[i] != SIG_IGN)
473: u.u_sfunc[i] = SIG_DFL;
474: if ((pp->p_flags&PFTRAC) != 0) /* Being traced */
475: sendsig(SIGTRAP, pp);
476: idetach(ip);
477: msetusr(pc, sp);
478: segload();
479: return (0);
480:
481: /*
482: * We did not make it.
483: * Release the INODE for the load
484: * file, and return through the "sys exit"
485: * code with a "SIGSYS", or with the signal actually received
486: * if we are aborting due to interrupted exec.
487: */
488: out:
489: idetach(ip);
490: if (u.u_error == EINTR)
491: pexit(nondsig());
492: pexit(SIGSYS);
493: }
494:
495: /*
496: * Open an l.out, make sure it is an l.out and executable and return the
497: * appropriate information.
498: */
499: INODE *
500: exlopen(np, ssizep, flagp, pcp)
501: char *np;
502: fsize_t *ssizep;
503: int *flagp;
504: vaddr_t *pcp;
505: {
506: register INODE *ip;
507: register struct ldheader *ldp;
508: register int n;
509: register BUF *bp;
510: int m;
511:
512: /*
513: * Make sure the file is really an executable l.out and read the
514: * header in.
515: */
516: if (ftoi(np, 'r') != 0)
517: return (NULL);
518: ip = u.u_cdiri;
519: if (iaccess(ip, IPE) == 0) {
520: idetach(ip);
521: return (NULL);
522: }
523: if ((ip->i_mode&(IPE|IPE<<3|IPE<<6))==0 || (ip->i_mode&IFMT)!=IFREG) {
524: u.u_error = EACCES;
525: idetach(ip);
526: return (NULL);
527: }
528: if ((bp=vread(ip, (daddr_t)0)) == NULL) {
529: u.u_error = EBADFMT;
530: idetach(ip);
531: return (NULL);
532: }
533:
534: /*
535: * Copy everything we need from the l.out header and check magic
536: * number and machine type.
537: */
538: ldp = FP_OFF(bp->b_faddr);
539: m = ldp->l_magic;
540: canint(m);
541: if (m != L_MAGIC) {
542: u.u_error = ENOEXEC;
543: brelease(bp);
544: idetach(ip);
545: return (NULL);
546: }
547: m = ldp->l_machine;
548: canint(m);
549: if (m != mactype) {
550: u.u_error = EBADFMT;
551: brelease(bp);
552: idetach(ip);
553: return (NULL);
554: }
555: kkcopy(ldp->l_ssize, ssizep, NXSEG*sizeof(fsize_t));
556: for (n=0; n<NXSEG; n++)
557: cansize(ssizep[n]);
558: *flagp = ldp->l_flag;
559: canint(*flagp);
560: *pcp = ldp->l_entry;
561: canvaddr(*pcp);
562: brelease(bp);
563: return (ip);
564: }
565:
566: /*
567: * Given a segment `sp', read `ss' bytes from the inode `ip' starting
568: * at seek address `sa' into offset `so' in the segment.
569: */
570: SEG *
571: exsread(sp, ip, ss, sa, so)
572: register SEG *sp;
573: INODE *ip;
574: fsize_t ss;
575: fsize_t sa;
576: fsize_t so;
577: {
578: while (ss > 0) {
579: u.u_io.io_seg = IOPHY;
580: u.u_io.io_seek = sa;
581: u.u_io.io_phys = sp->s_paddr + so;
582: u.u_io.io_flag = 0;
583: if (ss >= 4096) {
584: u.u_io.io_ioc = 4096;
585: ss -= 4096;
586: } else {
587: u.u_io.io_ioc = ss;
588: ss = 0;
589: }
590: sp->s_lrefc++;
591: iread(ip, &u.u_io);
592: sp->s_lrefc--;
593: if (nondsig()) {
594: u.u_error = EINTR;
595: break;
596: }
597: sa += 4096;
598: so += 4096;
599: }
600: if (u.u_error == 0)
601: return (sp);
602: return (NULL);
603: }
604:
605: /*
606: * Given a pointer to a list of arguments and a pointer to a list of
607: * environments, return a stack with the arguments and environments on it.
608: */
609: SEG *
610: exstack(iusp, argp, envp)
611: char **iusp; /* Back patch sp value */
612: char *argp[]; /* Arguments for new process */
613: char *envp[]; /* Environments for new process */
614: {
615: SEG *sp; /* Stack segment pointer */
616: struct adata { /* Storage for arg and env data */
617: char **up; /* User vector pointer */
618: int np; /* Number of pointers in vector */
619: int nc; /* Number of characters in strings */
620: } arg, env;
621: struct sdata { /* To keep segment pointers */
622: vaddr_t base; /* Top of segment virtual */
623: vaddr_t ap; /* Argc, argv, envp pointer */
624: vaddr_t vp; /* Argv[i], envp[i] pointer */
625: vaddr_t cp; /* Argv[i][j], envp[i][j] pointer */
626: } aux, stk;
627: aold_t aold; /* Auxiliary map storage */
628: register char **usrvp; /* Vector pointer into user seg */
629: register char *usrcp; /* Character pointer into user seg */
630: register int c; /* Character fetched from user */
631: register int chrsz; /* Size of strings */
632: register struct adata *adp; /* Arg and env scanner */
633: register int vecsz; /* Size of vectors */
634: register int stksz; /* Size of stack argument region */
635:
636: /* Validate and evaluate size of args and envs */
637: arg.up = argp;
638: env.up = envp;
639: chrsz = 0;
640: vecsz = 0;
641: for (adp = &arg; ; adp = &env) {
642: adp->np = 0;
643: adp->nc = 0;
644: if (excount(adp->up, &adp->np, &adp->nc) == 0)
645: return (NULL);
646: chrsz += adp->nc * sizeof(char);
647: vecsz += adp->np * sizeof(char *);
648: if (adp == &env)
649: break;
650: }
651:
652: /* Calculate stack size and allocate it */
653: chrsz = roundu(chrsz, sizeof(int));
654: stksz = sizeof(int) /* argc */
655: + sizeof(char **) /* argv */
656: + sizeof(char **) /* envp */
657: + vecsz /* argv[i] and envp[i] */
658: + chrsz /* *argv[i] and *envp[i] */
659: + sizeof(int) /* Mystery zero word */
660: + sizeof(char *) /* Splimit for z8000 */
661: + sizeof(int); /* errno */
662: stksz += ISTSIZE;
663: if (stksz > MADSIZE) {
664: u.u_error = E2BIG;
665: return (NULL);
666: }
667: if ((sp=salloc((fsize_t)stksz, SFDOWN)) == NULL)
668: return (NULL);
669: stksz -= ISTSIZE;
670:
671: /*
672: * Initialize segment data.
673: */
674: asave(aold);
675:
676: abase(FP_SEL(sp->s_faddr));
677: aux.base = sp->s_size;
678: aux.ap = aux.base - stksz;
679: aux.vp = aux.ap + sizeof(int) + 2*sizeof(char **);
680: aux.cp = aux.vp + vecsz;
681:
682: stk.base = ISTVIRT;
683: stk.ap = stk.base - stksz;
684: stk.vp = stk.ap + sizeof(int) + 2*sizeof(char **);
685: stk.cp = stk.vp + vecsz;
686:
687: /*
688: * Write argc.
689: */
690: aputi((int *)aux.ap, arg.np-1);
691: aux.ap += sizeof(int);
692:
693: /*
694: * Arguments and environments.
695: */
696: for (adp = &arg; ; adp = &env) {
697:
698: /* Write argv or envp */
699: aputp((char ***)aux.ap, (char **)stk.vp);
700: aux.ap += sizeof(char **);
701: if ((usrvp = adp->up) != NULL) {
702:
703: /* Write argv[i] or envp[i] */
704: while ((usrcp = getupd(usrvp++)) != NULL) {
705: aputp((char **)aux.vp, (char *)stk.cp);
706: aux.vp += sizeof(char *);
707: stk.vp += sizeof(char *);
708:
709: /* Write argv[i][j] or envp[i][j] */
710: do {
711: c = getubd(usrcp++);
712: aputc((char *)aux.cp, c);
713: aux.cp += sizeof(char);
714: stk.cp += sizeof(char);
715: } while (c != '\0');
716: }
717: }
718:
719: /* Write argv[argc] or envp[envc] */
720: aputp((char **)aux.vp, NULL);
721: aux.vp += sizeof(char *);
722: stk.vp += sizeof(char *);
723: if (adp == &env)
724: break;
725: }
726:
727: /*
728: * Clear out the slop.
729: */
730: aux.base -= sizeof(int);
731: aputi((int *) aux.base, 0); /* errno */
732: aux.base -= sizeof(char *);
733: aputp((char **) aux.base, (char *)stk.base - sp->s_size + SOVSIZE);
734: aux.base -= sizeof(int);
735: aputi((int *) aux.base, 0); /* mystery word */
736:
737: arest(aold);
738:
739: /*
740: * Patch some values and return.
741: */
742: *iusp = stk.ap; /* Patch initial usp */
743: u.u_argc = arg.np-1;
744: u.u_argp = stk.vp; /* Points after NULL of envs */
745: return (sp);
746: }
747:
748: /*
749: * Given a pointer to a list of arguments, a pointer to an argument count
750: * and a pointer to a byte count, update incrementally the argument count
751: * and the byte count.
752: */
753: excount(usrvp, nap, nbp)
754: register char **usrvp;
755: int *nap;
756: int *nbp;
757: {
758: register char *usrcp;
759: register int c;
760: register unsigned nb;
761: register unsigned na;
762:
763: na = 1;
764: nb = 0;
765: if (usrvp != NULL) {
766: for (;;) {
767: usrcp = getupd(usrvp++);
768: if (u.u_error)
769: return (0);
770: if (usrcp == NULL)
771: break;
772: na++;
773: for (;;) {
774: c = getubd(usrcp++);
775: if (u.u_error)
776: return (0);
777: nb++;
778: if (c == '\0')
779: break;
780: }
781: }
782: }
783: *nap += na;
784: *nbp += nb;
785: return (1);
786: }
787:
788: /*
789: * Round up a size to a paragraph
790: * (mod 16) boundry.
791: * This is really mod 512 to make swapping work
792: */
793: fsize_t
794: exround(s)
795: fsize_t s;
796: {
797: return ((s+15)&~0x0F);
798: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.