kern_exec.c revision 1.128 1 /* $NetBSD: kern_exec.c,v 1.128 2000/12/01 19:41:49 jdolecek Exp $ */
2
3 /*-
4 * Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
5 * Copyright (C) 1992 Wolfgang Solfrank.
6 * Copyright (C) 1992 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "opt_ktrace.h"
36 #include "opt_syscall_debug.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/filedesc.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/mount.h>
44 #include <sys/malloc.h>
45 #include <sys/namei.h>
46 #include <sys/vnode.h>
47 #include <sys/file.h>
48 #include <sys/acct.h>
49 #include <sys/exec.h>
50 #include <sys/ktrace.h>
51 #include <sys/resourcevar.h>
52 #include <sys/wait.h>
53 #include <sys/mman.h>
54 #include <sys/signalvar.h>
55 #include <sys/stat.h>
56 #include <sys/syscall.h>
57
58 #include <sys/syscallargs.h>
59
60 #include <uvm/uvm_extern.h>
61
62 #include <machine/cpu.h>
63 #include <machine/reg.h>
64
65 extern char sigcode[], esigcode[];
66 #ifdef SYSCALL_DEBUG
67 extern const char * const syscallnames[];
68 #endif
69
70 const struct emul emul_netbsd = {
71 "netbsd",
72 NULL, /* emulation path */
73 NULL,
74 sendsig,
75 SYS_syscall,
76 SYS_MAXSYSCALL,
77 sysent,
78 #ifdef SYSCALL_DEBUG
79 syscallnames,
80 #else
81 NULL,
82 #endif
83 sigcode,
84 esigcode,
85 NULL,
86 NULL,
87 NULL,
88 EMUL_HAS_SYS___syscall,
89 };
90
91 /*
92 * check exec:
93 * given an "executable" described in the exec package's namei info,
94 * see what we can do with it.
95 *
96 * ON ENTRY:
97 * exec package with appropriate namei info
98 * proc pointer of exec'ing proc
99 * NO SELF-LOCKED VNODES
100 *
101 * ON EXIT:
102 * error: nothing held, etc. exec header still allocated.
103 * ok: filled exec package, executable's vnode (unlocked).
104 *
105 * EXEC SWITCH ENTRY:
106 * Locked vnode to check, exec package, proc.
107 *
108 * EXEC SWITCH EXIT:
109 * ok: return 0, filled exec package, executable's vnode (unlocked).
110 * error: destructive:
111 * everything deallocated execept exec header.
112 * non-destructive:
113 * error code, executable's vnode (unlocked),
114 * exec header unmodified.
115 */
116 int
117 check_exec(struct proc *p, struct exec_package *epp)
118 {
119 int error, i;
120 struct vnode *vp;
121 struct nameidata *ndp;
122 size_t resid;
123
124 ndp = epp->ep_ndp;
125 ndp->ni_cnd.cn_nameiop = LOOKUP;
126 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | SAVENAME;
127 /* first get the vnode */
128 if ((error = namei(ndp)) != 0)
129 return error;
130 epp->ep_vp = vp = ndp->ni_vp;
131
132 /* check access and type */
133 if (vp->v_type != VREG) {
134 error = EACCES;
135 goto bad1;
136 }
137 if ((error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) != 0)
138 goto bad1;
139
140 /* get attributes */
141 if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 0)
142 goto bad1;
143
144 /* Check mount point */
145 if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
146 error = EACCES;
147 goto bad1;
148 }
149 if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
150 epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID);
151
152 /* try to open it */
153 if ((error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) != 0)
154 goto bad1;
155
156 /* unlock vp, since we need it unlocked from here on out. */
157 VOP_UNLOCK(vp, 0);
158
159 /* now we have the file, get the exec header */
160 uvn_attach(vp, VM_PROT_READ);
161 error = vn_rdwr(UIO_READ, vp, epp->ep_hdr, epp->ep_hdrlen, 0,
162 UIO_SYSSPACE, 0, p->p_ucred, &resid, p);
163 if (error)
164 goto bad2;
165 epp->ep_hdrvalid = epp->ep_hdrlen - resid;
166
167 /*
168 * set up the vmcmds for creation of the process
169 * address space
170 */
171 error = ENOEXEC;
172 for (i = 0; i < nexecs && error != 0; i++) {
173 int newerror;
174
175 if (execsw[i].es_check == NULL)
176 continue;
177
178 epp->ep_esch = &execsw[i];
179 newerror = (*execsw[i].es_check)(p, epp);
180 /* make sure the first "interesting" error code is saved. */
181 if (!newerror || error == ENOEXEC)
182 error = newerror;
183
184 /* if es_check call was successful, update epp->ep_es */
185 if (!newerror && (epp->ep_flags & EXEC_HASES) == 0)
186 epp->ep_es = &execsw[i];
187
188 if (epp->ep_flags & EXEC_DESTR && error != 0)
189 return error;
190 }
191 if (!error) {
192 /* check that entry point is sane */
193 if (epp->ep_entry > VM_MAXUSER_ADDRESS)
194 error = ENOEXEC;
195
196 /* check limits */
197 if ((epp->ep_tsize > MAXTSIZ) ||
198 (epp->ep_dsize > p->p_rlimit[RLIMIT_DATA].rlim_cur))
199 error = ENOMEM;
200
201 if (!error)
202 return (0);
203 }
204
205 /*
206 * free any vmspace-creation commands,
207 * and release their references
208 */
209 kill_vmcmds(&epp->ep_vmcmds);
210
211 bad2:
212 /*
213 * close and release the vnode, restore the old one, free the
214 * pathname buf, and punt.
215 */
216 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
217 VOP_CLOSE(vp, FREAD, p->p_ucred, p);
218 vput(vp);
219 PNBUF_PUT(ndp->ni_cnd.cn_pnbuf);
220 return error;
221
222 bad1:
223 /*
224 * free the namei pathname buffer, and put the vnode
225 * (which we don't yet have open).
226 */
227 vput(vp); /* was still locked */
228 PNBUF_PUT(ndp->ni_cnd.cn_pnbuf);
229 return error;
230 }
231
232 /*
233 * exec system call
234 */
235 /* ARGSUSED */
236 int
237 sys_execve(struct proc *p, void *v, register_t *retval)
238 {
239 struct sys_execve_args /* {
240 syscallarg(const char *) path;
241 syscallarg(char * const *) argp;
242 syscallarg(char * const *) envp;
243 } */ *uap = v;
244 int error, i;
245 struct exec_package pack;
246 struct nameidata nid;
247 struct vattr attr;
248 struct ucred *cred = p->p_ucred;
249 char *argp;
250 char * const *cpp;
251 char *dp, *sp;
252 long argc, envc;
253 size_t len;
254 char *stack;
255 struct ps_strings arginfo;
256 struct vmspace *vm;
257 char **tmpfap;
258 int szsigcode;
259 struct exec_vmcmd *base_vcp = NULL;
260
261 /*
262 * figure out the maximum size of an exec header, if necessary.
263 * XXX should be able to keep LKM code from modifying exec switch
264 * when we're still using it, but...
265 */
266 if (exec_maxhdrsz == 0) {
267 for (i = 0; i < nexecs; i++)
268 if (execsw[i].es_check != NULL
269 && execsw[i].es_hdrsz > exec_maxhdrsz)
270 exec_maxhdrsz = execsw[i].es_hdrsz;
271 }
272
273 /* init the namei data to point the file user's program name */
274 /* XXX cgd 960926: why do this here? most will be clobbered. */
275 NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
276
277 /*
278 * initialize the fields of the exec package.
279 */
280 pack.ep_name = SCARG(uap, path);
281 pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
282 pack.ep_hdrlen = exec_maxhdrsz;
283 pack.ep_hdrvalid = 0;
284 pack.ep_ndp = &nid;
285 pack.ep_emul_arg = NULL;
286 pack.ep_vmcmds.evs_cnt = 0;
287 pack.ep_vmcmds.evs_used = 0;
288 pack.ep_vap = &attr;
289 pack.ep_flags = 0;
290
291 /* see if we can run it. */
292 if ((error = check_exec(p, &pack)) != 0)
293 goto freehdr;
294
295 /* XXX -- THE FOLLOWING SECTION NEEDS MAJOR CLEANUP */
296
297 /* allocate an argument buffer */
298 argp = (char *) uvm_km_valloc_wait(exec_map, NCARGS);
299 #ifdef DIAGNOSTIC
300 if (argp == (vaddr_t) 0)
301 panic("execve: argp == NULL");
302 #endif
303 dp = argp;
304 argc = 0;
305
306 /* copy the fake args list, if there's one, freeing it as we go */
307 if (pack.ep_flags & EXEC_HASARGL) {
308 tmpfap = pack.ep_fa;
309 while (*tmpfap != NULL) {
310 char *cp;
311
312 cp = *tmpfap;
313 while (*cp)
314 *dp++ = *cp++;
315 dp++;
316
317 FREE(*tmpfap, M_EXEC);
318 tmpfap++; argc++;
319 }
320 FREE(pack.ep_fa, M_EXEC);
321 pack.ep_flags &= ~EXEC_HASARGL;
322 }
323
324 /* Now get argv & environment */
325 if (!(cpp = SCARG(uap, argp))) {
326 error = EINVAL;
327 goto bad;
328 }
329
330 if (pack.ep_flags & EXEC_SKIPARG)
331 cpp++;
332
333 while (1) {
334 len = argp + ARG_MAX - dp;
335 if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
336 goto bad;
337 if (!sp)
338 break;
339 if ((error = copyinstr(sp, dp, len, &len)) != 0) {
340 if (error == ENAMETOOLONG)
341 error = E2BIG;
342 goto bad;
343 }
344 dp += len;
345 cpp++;
346 argc++;
347 }
348
349 envc = 0;
350 /* environment need not be there */
351 if ((cpp = SCARG(uap, envp)) != NULL ) {
352 while (1) {
353 len = argp + ARG_MAX - dp;
354 if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
355 goto bad;
356 if (!sp)
357 break;
358 if ((error = copyinstr(sp, dp, len, &len)) != 0) {
359 if (error == ENAMETOOLONG)
360 error = E2BIG;
361 goto bad;
362 }
363 dp += len;
364 cpp++;
365 envc++;
366 }
367 }
368
369 dp = (char *) ALIGN(dp);
370
371 szsigcode = pack.ep_es->es_emul->e_esigcode -
372 pack.ep_es->es_emul->e_sigcode;
373
374 /* Now check if args & environ fit into new stack */
375 if (pack.ep_flags & EXEC_32)
376 len = ((argc + envc + 2 + pack.ep_es->es_arglen) *
377 sizeof(int) + sizeof(int) + dp + STACKGAPLEN +
378 szsigcode + sizeof(struct ps_strings)) - argp;
379 else
380 len = ((argc + envc + 2 + pack.ep_es->es_arglen) *
381 sizeof(char *) + sizeof(int) + dp + STACKGAPLEN +
382 szsigcode + sizeof(struct ps_strings)) - argp;
383
384 len = ALIGN(len); /* make the stack "safely" aligned */
385
386 if (len > pack.ep_ssize) { /* in effect, compare to initial limit */
387 error = ENOMEM;
388 goto bad;
389 }
390
391 /* adjust "active stack depth" for process VSZ */
392 pack.ep_ssize = len; /* maybe should go elsewhere, but... */
393
394 /*
395 * Do whatever is necessary to prepare the address space
396 * for remapping. Note that this might replace the current
397 * vmspace with another!
398 */
399 uvmspace_exec(p);
400
401 /* Now map address space */
402 vm = p->p_vmspace;
403 vm->vm_taddr = (char *) pack.ep_taddr;
404 vm->vm_tsize = btoc(pack.ep_tsize);
405 vm->vm_daddr = (char *) pack.ep_daddr;
406 vm->vm_dsize = btoc(pack.ep_dsize);
407 vm->vm_ssize = btoc(pack.ep_ssize);
408 vm->vm_maxsaddr = (char *) pack.ep_maxsaddr;
409 vm->vm_minsaddr = (char *) pack.ep_minsaddr;
410
411 /* create the new process's VM space by running the vmcmds */
412 #ifdef DIAGNOSTIC
413 if (pack.ep_vmcmds.evs_used == 0)
414 panic("execve: no vmcmds");
415 #endif
416 for (i = 0; i < pack.ep_vmcmds.evs_used && !error; i++) {
417 struct exec_vmcmd *vcp;
418
419 vcp = &pack.ep_vmcmds.evs_cmds[i];
420 if (vcp->ev_flags & VMCMD_RELATIVE) {
421 #ifdef DIAGNOSTIC
422 if (base_vcp == NULL)
423 panic("execve: relative vmcmd with no base");
424 if (vcp->ev_flags & VMCMD_BASE)
425 panic("execve: illegal base & relative vmcmd");
426 #endif
427 vcp->ev_addr += base_vcp->ev_addr;
428 }
429 error = (*vcp->ev_proc)(p, vcp);
430 #ifdef DEBUG
431 if (error) {
432 if (i > 0)
433 printf("vmcmd[%d] = %#lx/%#lx @ %#lx\n", i-1,
434 vcp[-1].ev_addr, vcp[-1].ev_len,
435 vcp[-1].ev_offset);
436 printf("vmcmd[%d] = %#lx/%#lx @ %#lx\n", i,
437 vcp->ev_addr, vcp->ev_len, vcp->ev_offset);
438 }
439 #endif
440 if (vcp->ev_flags & VMCMD_BASE)
441 base_vcp = vcp;
442 }
443
444 /* free the vmspace-creation commands, and release their references */
445 kill_vmcmds(&pack.ep_vmcmds);
446
447 /* if an error happened, deallocate and punt */
448 if (error) {
449 #ifdef DEBUG
450 printf("execve: vmcmd %i failed: %d\n", i-1, error);
451 #endif
452 goto exec_abort;
453 }
454
455 /* remember information about the process */
456 arginfo.ps_nargvstr = argc;
457 arginfo.ps_nenvstr = envc;
458
459 stack = (char *) (vm->vm_minsaddr - len);
460 /* Now copy argc, args & environ to new stack */
461 if (!(*pack.ep_es->es_copyargs)(&pack, &arginfo, stack, argp)) {
462 #ifdef DEBUG
463 printf("execve: copyargs failed\n");
464 #endif
465 goto exec_abort;
466 }
467
468 /* fill process ps_strings info */
469 p->p_psstr = (struct ps_strings *)(vm->vm_minsaddr
470 - sizeof(struct ps_strings));
471 p->p_psargv = offsetof(struct ps_strings, ps_argvstr);
472 p->p_psnargv = offsetof(struct ps_strings, ps_nargvstr);
473 p->p_psenv = offsetof(struct ps_strings, ps_envstr);
474 p->p_psnenv = offsetof(struct ps_strings, ps_nenvstr);
475
476 /* copy out the process's ps_strings structure */
477 if (copyout(&arginfo, (char *)p->p_psstr, sizeof(arginfo))) {
478 #ifdef DEBUG
479 printf("execve: ps_strings copyout failed\n");
480 #endif
481 goto exec_abort;
482 }
483
484 /* copy out the process's signal trapoline code */
485 if (szsigcode) {
486 if (copyout((char *)pack.ep_es->es_emul->e_sigcode,
487 p->p_sigacts->ps_sigcode = (char *)p->p_psstr - szsigcode,
488 szsigcode)) {
489 #ifdef DEBUG
490 printf("execve: sig trampoline copyout failed\n");
491 #endif
492 goto exec_abort;
493 }
494 #ifdef PMAP_NEED_PROCWR
495 /* This is code. Let the pmap do what is needed. */
496 pmap_procwr(p, (vaddr_t)p->p_sigacts->ps_sigcode, szsigcode);
497 #endif
498 }
499
500 stopprofclock(p); /* stop profiling */
501 fdcloseexec(p); /* handle close on exec */
502 execsigs(p); /* reset catched signals */
503 p->p_ctxlink = NULL; /* reset ucontext link */
504
505 /* set command name & other accounting info */
506 len = min(nid.ni_cnd.cn_namelen, MAXCOMLEN);
507 memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, len);
508 p->p_comm[len] = 0;
509 p->p_acflag &= ~AFORK;
510
511 /* record proc's vnode, for use by procfs and others */
512 if (p->p_textvp)
513 vrele(p->p_textvp);
514 VREF(pack.ep_vp);
515 p->p_textvp = pack.ep_vp;
516
517 p->p_flag |= P_EXEC;
518 if (p->p_flag & P_PPWAIT) {
519 p->p_flag &= ~P_PPWAIT;
520 wakeup((caddr_t) p->p_pptr);
521 }
522
523 /*
524 * deal with set[ug]id.
525 * MNT_NOSUID and P_TRACED have already been used to disable s[ug]id.
526 */
527 if (((attr.va_mode & S_ISUID) != 0 && p->p_ucred->cr_uid != attr.va_uid)
528 || ((attr.va_mode & S_ISGID) != 0 && p->p_ucred->cr_gid != attr.va_gid)){
529 p->p_ucred = crcopy(cred);
530 #ifdef KTRACE
531 /*
532 * If process is being ktraced, turn off - unless
533 * root set it.
534 */
535 if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT))
536 ktrderef(p);
537 #endif
538 if (attr.va_mode & S_ISUID)
539 p->p_ucred->cr_uid = attr.va_uid;
540 if (attr.va_mode & S_ISGID)
541 p->p_ucred->cr_gid = attr.va_gid;
542 p_sugid(p);
543 } else
544 p->p_flag &= ~P_SUGID;
545 p->p_cred->p_svuid = p->p_ucred->cr_uid;
546 p->p_cred->p_svgid = p->p_ucred->cr_gid;
547
548 doexechooks(p);
549
550 uvm_km_free_wakeup(exec_map, (vaddr_t) argp, NCARGS);
551
552 PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
553 vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
554 VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
555 vput(pack.ep_vp);
556
557 /* setup new registers and do misc. setup. */
558 (*pack.ep_es->es_setregs)(p, &pack, (u_long) stack);
559
560 if (p->p_flag & P_TRACED)
561 psignal(p, SIGTRAP);
562
563 free(pack.ep_hdr, M_EXEC);
564
565 /*
566 * Call emulation specific exec hook. This can setup setup per-process
567 * p->p_emuldata or do any other per-process stuff an emulation needs.
568 *
569 * If we are executing process of different emulation than the
570 * original forked process, call e_proc_exit() of the old emulation
571 * first, then e_proc_exec() of new emulation. If the emulation is
572 * same, the exec hook code should deallocate any old emulation
573 * resources held previously by this process.
574 */
575 if (p->p_emul && p->p_emul->e_proc_exit
576 && p->p_emul != pack.ep_es->es_emul)
577 (*p->p_emul->e_proc_exit)(p);
578
579 /*
580 * Call exec hook. Emulation code may NOT store reference to anything
581 * from &pack.
582 */
583 if (pack.ep_es->es_emul->e_proc_exec)
584 (*pack.ep_es->es_emul->e_proc_exec)(p, &pack);
585
586 /* update p_emul, the old value is no longer needed */
587 p->p_emul = pack.ep_es->es_emul;
588
589 #ifdef KTRACE
590 if (KTRPOINT(p, KTR_EMUL))
591 ktremul(p);
592 #endif
593
594 return (EJUSTRETURN);
595
596 bad:
597 /* free the vmspace-creation commands, and release their references */
598 kill_vmcmds(&pack.ep_vmcmds);
599 /* kill any opened file descriptor, if necessary */
600 if (pack.ep_flags & EXEC_HASFD) {
601 pack.ep_flags &= ~EXEC_HASFD;
602 (void) fdrelease(p, pack.ep_fd);
603 }
604 /* close and put the exec'd file */
605 vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
606 VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
607 vput(pack.ep_vp);
608 PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
609 uvm_km_free_wakeup(exec_map, (vaddr_t) argp, NCARGS);
610
611 freehdr:
612 free(pack.ep_hdr, M_EXEC);
613 return error;
614
615 exec_abort:
616 /*
617 * the old process doesn't exist anymore. exit gracefully.
618 * get rid of the (new) address space we have created, if any, get rid
619 * of our namei data and vnode, and exit noting failure
620 */
621 uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS,
622 VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS);
623 if (pack.ep_emul_arg)
624 FREE(pack.ep_emul_arg, M_TEMP);
625 PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
626 vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
627 VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
628 vput(pack.ep_vp);
629 uvm_km_free_wakeup(exec_map, (vaddr_t) argp, NCARGS);
630 free(pack.ep_hdr, M_EXEC);
631 exit1(p, W_EXITCODE(0, SIGABRT));
632 exit1(p, -1);
633
634 /* NOTREACHED */
635 return 0;
636 }
637
638
639 void *
640 copyargs(struct exec_package *pack, struct ps_strings *arginfo,
641 void *stack, void *argp)
642 {
643 char **cpp = stack;
644 char *dp, *sp;
645 size_t len;
646 void *nullp = NULL;
647 long argc = arginfo->ps_nargvstr;
648 long envc = arginfo->ps_nenvstr;
649
650 #ifdef __sparc_v9__
651 /* XXX Temporary hack for argc format conversion. */
652 argc <<= 32;
653 #endif
654 if (copyout(&argc, cpp++, sizeof(argc)))
655 return NULL;
656 #ifdef __sparc_v9__
657 /* XXX Temporary hack for argc format conversion. */
658 argc >>= 32;
659 #endif
660
661 dp = (char *) (cpp + argc + envc + 2 + pack->ep_es->es_arglen);
662 sp = argp;
663
664 /* XXX don't copy them out, remap them! */
665 arginfo->ps_argvstr = cpp; /* remember location of argv for later */
666
667 for (; --argc >= 0; sp += len, dp += len)
668 if (copyout(&dp, cpp++, sizeof(dp)) ||
669 copyoutstr(sp, dp, ARG_MAX, &len))
670 return NULL;
671
672 if (copyout(&nullp, cpp++, sizeof(nullp)))
673 return NULL;
674
675 arginfo->ps_envstr = cpp; /* remember location of envp for later */
676
677 for (; --envc >= 0; sp += len, dp += len)
678 if (copyout(&dp, cpp++, sizeof(dp)) ||
679 copyoutstr(sp, dp, ARG_MAX, &len))
680 return NULL;
681
682 if (copyout(&nullp, cpp++, sizeof(nullp)))
683 return NULL;
684
685 return cpp;
686 }
687