kern_sharedpage.c revision 54655
1/*
2 * Copyright (c) 1993, David Greenman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/kern/kern_exec.c 54655 1999-12-15 23:02:35Z eivind $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/sysproto.h>
32#include <sys/signalvar.h>
33#include <sys/kernel.h>
34#include <sys/mount.h>
35#include <sys/filedesc.h>
36#include <sys/fcntl.h>
37#include <sys/acct.h>
38#include <sys/exec.h>
39#include <sys/imgact.h>
40#include <sys/imgact_elf.h>
41#include <sys/wait.h>
42#include <sys/proc.h>
43#include <sys/pioctl.h>
44#include <sys/malloc.h>
45#include <sys/namei.h>
46#include <sys/sysent.h>
47#include <sys/shm.h>
48#include <sys/sysctl.h>
49#include <sys/vnode.h>
50#include <sys/buf.h>
51
52#include <vm/vm.h>
53#include <vm/vm_param.h>
54#include <sys/lock.h>
55#include <vm/pmap.h>
56#include <vm/vm_page.h>
57#include <vm/vm_map.h>
58#include <vm/vm_kern.h>
59#include <vm/vm_extern.h>
60#include <vm/vm_object.h>
61#include <vm/vm_zone.h>
62#include <vm/vm_pager.h>
63
64#include <machine/reg.h>
65
66MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments");
67
68static long *exec_copyout_strings __P((struct image_params *));
69
70static long ps_strings = PS_STRINGS;
71SYSCTL_LONG(_kern, KERN_PS_STRINGS, ps_strings, CTLFLAG_RD, &ps_strings, "");
72
73static long usrstack = USRSTACK;
74SYSCTL_LONG(_kern, KERN_USRSTACK, usrstack, CTLFLAG_RD, &usrstack, "");
75
76u_long ps_arg_cache_limit = PAGE_SIZE / 16;
77SYSCTL_LONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW,
78    &ps_arg_cache_limit, "");
79
80int ps_argsopen = 1;
81SYSCTL_INT(_kern, OID_AUTO, ps_argsopen, CTLFLAG_RW, &ps_argsopen, 0, "");
82
83/*
84 * Each of the items is a pointer to a `const struct execsw', hence the
85 * double pointer here.
86 */
87static const struct execsw **execsw;
88
89#ifndef _SYS_SYSPROTO_H_
90struct execve_args {
91        char    *fname;
92        char    **argv;
93        char    **envv;
94};
95#endif
96
97/*
98 * execve() system call.
99 */
100int
101execve(p, uap)
102	struct proc *p;
103	register struct execve_args *uap;
104{
105	struct nameidata nd, *ndp;
106	long *stack_base;
107	int error, len, i;
108	struct image_params image_params, *imgp;
109	struct vattr attr;
110
111	imgp = &image_params;
112
113	/*
114	 * Initialize part of the common data
115	 */
116	imgp->proc = p;
117	imgp->uap = uap;
118	imgp->attr = &attr;
119	imgp->argc = imgp->envc = 0;
120	imgp->argv0 = NULL;
121	imgp->entry_addr = 0;
122	imgp->vmspace_destroyed = 0;
123	imgp->interpreted = 0;
124	imgp->interpreter_name[0] = '\0';
125	imgp->auxargs = NULL;
126	imgp->vp = NULL;
127	imgp->firstpage = NULL;
128	imgp->ps_strings = 0;
129
130	/*
131	 * Allocate temporary demand zeroed space for argument and
132	 *	environment strings
133	 */
134	imgp->stringbase = (char *)kmem_alloc_wait(exec_map, ARG_MAX + PAGE_SIZE);
135	if (imgp->stringbase == NULL) {
136		error = ENOMEM;
137		goto exec_fail;
138	}
139	imgp->stringp = imgp->stringbase;
140	imgp->stringspace = ARG_MAX;
141	imgp->image_header = imgp->stringbase + ARG_MAX;
142
143	/*
144	 * Translate the file name. namei() returns a vnode pointer
145	 *	in ni_vp amoung other things.
146	 */
147	ndp = &nd;
148	NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
149	    UIO_USERSPACE, uap->fname, p);
150
151interpret:
152
153	error = namei(ndp);
154	if (error) {
155		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase,
156			ARG_MAX + PAGE_SIZE);
157		goto exec_fail;
158	}
159
160	imgp->vp = ndp->ni_vp;
161	imgp->fname = uap->fname;
162
163	/*
164	 * Check file permissions (also 'opens' file)
165	 */
166	error = exec_check_permissions(imgp);
167	if (error) {
168		VOP_UNLOCK(imgp->vp, 0, p);
169		goto exec_fail_dealloc;
170	}
171
172	error = exec_map_first_page(imgp);
173	VOP_UNLOCK(imgp->vp, 0, p);
174	if (error)
175		goto exec_fail_dealloc;
176
177	/*
178	 * Loop through list of image activators, calling each one.
179	 *	If there is no match, the activator returns -1. If there
180	 *	is a match, but there was an error during the activation,
181	 *	the error is returned. Otherwise 0 means success. If the
182	 *	image is interpreted, loop back up and try activating
183	 *	the interpreter.
184	 */
185	for (i = 0; execsw[i]; ++i) {
186		if (execsw[i]->ex_imgact)
187			error = (*execsw[i]->ex_imgact)(imgp);
188		else
189			continue;
190		if (error == -1)
191			continue;
192		if (error)
193			goto exec_fail_dealloc;
194		if (imgp->interpreted) {
195			exec_unmap_first_page(imgp);
196			/* free name buffer and old vnode */
197			NDFREE(ndp, NDF_ONLY_PNBUF);
198			vrele(ndp->ni_vp);
199			/* set new name to that of the interpreter */
200			NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
201			    UIO_SYSSPACE, imgp->interpreter_name, p);
202			goto interpret;
203		}
204		break;
205	}
206	/* If we made it through all the activators and none matched, exit. */
207	if (error == -1) {
208		error = ENOEXEC;
209		goto exec_fail_dealloc;
210	}
211
212	/*
213	 * Copy out strings (args and env) and initialize stack base
214	 */
215	stack_base = exec_copyout_strings(imgp);
216	p->p_vmspace->vm_minsaddr = (char *)stack_base;
217
218	/*
219	 * If custom stack fixup routine present for this process
220	 * let it do the stack setup.
221	 * Else stuff argument count as first item on stack
222	 */
223	if (p->p_sysent->sv_fixup)
224		(*p->p_sysent->sv_fixup)(&stack_base, imgp);
225	else
226		suword(--stack_base, imgp->argc);
227
228	/*
229	 * For security and other reasons, the file descriptor table cannot
230	 * be shared after an exec.
231	 */
232	if (p->p_fd->fd_refcnt > 1) {
233		struct filedesc *tmp;
234
235		tmp = fdcopy(p);
236		fdfree(p);
237		p->p_fd = tmp;
238	}
239
240	/* Stop profiling */
241	stopprofclock(p);
242
243	/* close files on exec */
244	fdcloseexec(p);
245
246	/* reset caught signals */
247	execsigs(p);
248
249	/* name this process - nameiexec(p, ndp) */
250	len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN);
251	bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len);
252	p->p_comm[len] = 0;
253
254	/*
255	 * mark as execed, wakeup the process that vforked (if any) and tell
256	 * it that it now has its own resources back
257	 */
258	p->p_flag |= P_EXEC;
259	if (p->p_pptr && (p->p_flag & P_PPWAIT)) {
260		p->p_flag &= ~P_PPWAIT;
261		wakeup((caddr_t)p->p_pptr);
262	}
263
264	/*
265	 * Implement image setuid/setgid.
266	 *
267	 * Don't honor setuid/setgid if the filesystem prohibits it or if
268	 * the process is being traced.
269	 */
270	if ((((attr.va_mode & VSUID) && p->p_ucred->cr_uid != attr.va_uid) ||
271	     ((attr.va_mode & VSGID) && p->p_ucred->cr_gid != attr.va_gid)) &&
272	    (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 &&
273	    (p->p_flag & P_TRACED) == 0) {
274		/*
275		 * Turn off syscall tracing for set-id programs, except for
276		 * root.
277		 */
278		if (p->p_tracep && suser(p)) {
279			p->p_traceflag = 0;
280			vrele(p->p_tracep);
281			p->p_tracep = NULL;
282		}
283		/*
284		 * Set the new credentials.
285		 */
286		p->p_ucred = crcopy(p->p_ucred);
287		if (attr.va_mode & VSUID)
288			p->p_ucred->cr_uid = attr.va_uid;
289		if (attr.va_mode & VSGID)
290			p->p_ucred->cr_gid = attr.va_gid;
291		setsugid(p);
292	} else {
293		if (p->p_ucred->cr_uid == p->p_cred->p_ruid &&
294		    p->p_ucred->cr_gid == p->p_cred->p_rgid)
295			p->p_flag &= ~P_SUGID;
296	}
297
298	/*
299	 * Implement correct POSIX saved-id behavior.
300	 */
301	p->p_cred->p_svuid = p->p_ucred->cr_uid;
302	p->p_cred->p_svgid = p->p_ucred->cr_gid;
303
304	/*
305	 * Store the vp for use in procfs
306	 */
307	if (p->p_textvp)		/* release old reference */
308		vrele(p->p_textvp);
309	VREF(ndp->ni_vp);
310	p->p_textvp = ndp->ni_vp;
311
312	/*
313	 * If tracing the process, trap to debugger so breakpoints
314	 * 	can be set before the program executes.
315	 */
316	STOPEVENT(p, S_EXEC, 0);
317
318	if (p->p_flag & P_TRACED)
319		psignal(p, SIGTRAP);
320
321	/* clear "fork but no exec" flag, as we _are_ execing */
322	p->p_acflag &= ~AFORK;
323
324	/* Set values passed into the program in registers. */
325	setregs(p, imgp->entry_addr, (u_long)(uintptr_t)stack_base,
326	    imgp->ps_strings);
327
328	/* Free any previous argument cache */
329	if (p->p_args && --p->p_args->ar_ref == 0)
330		FREE(p->p_args, M_PARGS);
331	p->p_args = NULL;
332
333	/* Cache arguments if they fit inside our allowance */
334	i = imgp->endargs - imgp->stringbase;
335	if (ps_arg_cache_limit >= i + sizeof(struct pargs)) {
336		MALLOC(p->p_args, struct pargs *, sizeof(struct pargs) + i,
337		    M_PARGS, M_WAITOK);
338		p->p_args->ar_ref = 1;
339		p->p_args->ar_length = i;
340		bcopy(imgp->stringbase, p->p_args->ar_args, i);
341	}
342
343exec_fail_dealloc:
344
345	/*
346	 * free various allocated resources
347	 */
348	if (imgp->firstpage)
349		exec_unmap_first_page(imgp);
350
351	if (imgp->stringbase != NULL)
352		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase,
353			ARG_MAX + PAGE_SIZE);
354
355	if (imgp->vp) {
356		NDFREE(ndp, NDF_ONLY_PNBUF);
357		vrele(imgp->vp);
358	}
359
360	if (error == 0)
361		return (0);
362
363exec_fail:
364	if (imgp->vmspace_destroyed) {
365		/* sorry, no more process anymore. exit gracefully */
366		exit1(p, W_EXITCODE(0, SIGABRT));
367		/* NOT REACHED */
368		return(0);
369	} else {
370		return(error);
371	}
372}
373
374int
375exec_map_first_page(imgp)
376	struct image_params *imgp;
377{
378	int s, rv, i;
379	int initial_pagein;
380	vm_page_t ma[VM_INITIAL_PAGEIN];
381	vm_object_t object;
382
383
384	if (imgp->firstpage) {
385		exec_unmap_first_page(imgp);
386	}
387
388	object = imgp->vp->v_object;
389	s = splvm();
390
391	ma[0] = vm_page_grab(object, 0, VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
392
393	if ((ma[0]->valid & VM_PAGE_BITS_ALL) != VM_PAGE_BITS_ALL) {
394		initial_pagein = VM_INITIAL_PAGEIN;
395		if (initial_pagein > object->size)
396			initial_pagein = object->size;
397		for (i = 1; i < initial_pagein; i++) {
398			if ((ma[i] = vm_page_lookup(object, i)) != NULL) {
399				if ((ma[i]->flags & PG_BUSY) || ma[i]->busy)
400					break;
401				if (ma[i]->valid)
402					break;
403				vm_page_busy(ma[i]);
404			} else {
405				ma[i] = vm_page_alloc(object, i, VM_ALLOC_NORMAL);
406				if (ma[i] == NULL)
407					break;
408			}
409		}
410		initial_pagein = i;
411
412		rv = vm_pager_get_pages(object, ma, initial_pagein, 0);
413		ma[0] = vm_page_lookup(object, 0);
414
415		if ((rv != VM_PAGER_OK) || (ma[0] == NULL) || (ma[0]->valid == 0)) {
416			if (ma[0]) {
417				vm_page_protect(ma[0], VM_PROT_NONE);
418				vm_page_free(ma[0]);
419			}
420			splx(s);
421			return EIO;
422		}
423	}
424
425	vm_page_wire(ma[0]);
426	vm_page_wakeup(ma[0]);
427	splx(s);
428
429	pmap_kenter((vm_offset_t) imgp->image_header, VM_PAGE_TO_PHYS(ma[0]));
430	imgp->firstpage = ma[0];
431
432	return 0;
433}
434
435void
436exec_unmap_first_page(imgp)
437	struct image_params *imgp;
438{
439	if (imgp->firstpage) {
440		pmap_kremove((vm_offset_t) imgp->image_header);
441		vm_page_unwire(imgp->firstpage, 1);
442		imgp->firstpage = NULL;
443	}
444}
445
446/*
447 * Destroy old address space, and allocate a new stack
448 *	The new stack is only SGROWSIZ large because it is grown
449 *	automatically in trap.c.
450 */
451int
452exec_new_vmspace(imgp)
453	struct image_params *imgp;
454{
455	int error;
456	struct vmspace *vmspace = imgp->proc->p_vmspace;
457	caddr_t	stack_addr = (caddr_t) (USRSTACK - MAXSSIZ);
458	vm_map_t map = &vmspace->vm_map;
459
460	imgp->vmspace_destroyed = 1;
461
462	/*
463	 * Blow away entire process VM, if address space not shared,
464	 * otherwise, create a new VM space so that other threads are
465	 * not disrupted
466	 */
467	if (vmspace->vm_refcnt == 1) {
468		if (vmspace->vm_shm)
469			shmexit(imgp->proc);
470		pmap_remove_pages(vmspace_pmap(vmspace), 0, VM_MAXUSER_ADDRESS);
471		vm_map_remove(map, 0, VM_MAXUSER_ADDRESS);
472	} else {
473		vmspace_exec(imgp->proc);
474		vmspace = imgp->proc->p_vmspace;
475		map = &vmspace->vm_map;
476	}
477
478	/* Allocate a new stack */
479	error = vm_map_stack (&vmspace->vm_map, (vm_offset_t)stack_addr,
480			      (vm_size_t)MAXSSIZ, VM_PROT_ALL, VM_PROT_ALL, 0);
481	if (error)
482		return (error);
483
484	/* vm_ssize and vm_maxsaddr are somewhat antiquated concepts in the
485	 * VM_STACK case, but they are still used to monitor the size of the
486	 * process stack so we can check the stack rlimit.
487	 */
488	vmspace->vm_ssize = SGROWSIZ >> PAGE_SHIFT;
489	vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ;
490
491	return(0);
492}
493
494/*
495 * Copy out argument and environment strings from the old process
496 *	address space into the temporary string buffer.
497 */
498int
499exec_extract_strings(imgp)
500	struct image_params *imgp;
501{
502	char	**argv, **envv;
503	char	*argp, *envp;
504	int	error;
505	size_t	length;
506
507	/*
508	 * extract arguments first
509	 */
510
511	argv = imgp->uap->argv;
512
513	if (argv) {
514		argp = (caddr_t) (intptr_t) fuword(argv);
515		if (argp == (caddr_t) -1)
516			return (EFAULT);
517		if (argp)
518			argv++;
519		if (imgp->argv0)
520			argp = imgp->argv0;
521		if (argp) {
522			do {
523				if (argp == (caddr_t) -1)
524					return (EFAULT);
525				if ((error = copyinstr(argp, imgp->stringp,
526				    imgp->stringspace, &length))) {
527					if (error == ENAMETOOLONG)
528						return(E2BIG);
529					return (error);
530				}
531				imgp->stringspace -= length;
532				imgp->stringp += length;
533				imgp->argc++;
534			} while ((argp = (caddr_t) (intptr_t) fuword(argv++)));
535		}
536	}
537
538	imgp->endargs = imgp->stringp;
539
540	/*
541	 * extract environment strings
542	 */
543
544	envv = imgp->uap->envv;
545
546	if (envv) {
547		while ((envp = (caddr_t) (intptr_t) fuword(envv++))) {
548			if (envp == (caddr_t) -1)
549				return (EFAULT);
550			if ((error = copyinstr(envp, imgp->stringp,
551			    imgp->stringspace, &length))) {
552				if (error == ENAMETOOLONG)
553					return(E2BIG);
554				return (error);
555			}
556			imgp->stringspace -= length;
557			imgp->stringp += length;
558			imgp->envc++;
559		}
560	}
561
562	return (0);
563}
564
565/*
566 * Copy strings out to the new process address space, constructing
567 *	new arg and env vector tables. Return a pointer to the base
568 *	so that it can be used as the initial stack pointer.
569 */
570long *
571exec_copyout_strings(imgp)
572	struct image_params *imgp;
573{
574	int argc, envc;
575	char **vectp;
576	char *stringp, *destp;
577	long *stack_base;
578	struct ps_strings *arginfo;
579	int szsigcode;
580
581	/*
582	 * Calculate string base and vector table pointers.
583	 * Also deal with signal trampoline code for this exec type.
584	 */
585	arginfo = (struct ps_strings *)PS_STRINGS;
586	szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
587	destp =	(caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
588		roundup((ARG_MAX - imgp->stringspace), sizeof(char *));
589
590	/*
591	 * install sigcode
592	 */
593	if (szsigcode)
594		copyout(imgp->proc->p_sysent->sv_sigcode,
595			((caddr_t)arginfo - szsigcode), szsigcode);
596
597	/*
598	 * If we have a valid auxargs ptr, prepare some room
599	 * on the stack.
600	 */
601	if (imgp->auxargs)
602	/*
603	 * The '+ 2' is for the null pointers at the end of each of the
604	 * arg and env vector sets, and 'AT_COUNT*2' is room for the
605	 * ELF Auxargs data.
606	 */
607		vectp = (char **)(destp - (imgp->argc + imgp->envc + 2 +
608				  AT_COUNT*2) * sizeof(char*));
609	else
610	/*
611	 * The '+ 2' is for the null pointers at the end of each of the
612	 * arg and env vector sets
613	 */
614		vectp = (char **)
615			(destp - (imgp->argc + imgp->envc + 2) * sizeof(char*));
616
617	/*
618	 * vectp also becomes our initial stack base
619	 */
620	stack_base = (long *)vectp;
621
622	stringp = imgp->stringbase;
623	argc = imgp->argc;
624	envc = imgp->envc;
625
626	/*
627	 * Copy out strings - arguments and environment.
628	 */
629	copyout(stringp, destp, ARG_MAX - imgp->stringspace);
630
631	/*
632	 * Fill in "ps_strings" struct for ps, w, etc.
633	 */
634	suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
635	suword(&arginfo->ps_nargvstr, argc);
636
637	/*
638	 * Fill in argument portion of vector table.
639	 */
640	for (; argc > 0; --argc) {
641		suword(vectp++, (long)(intptr_t)destp);
642		while (*stringp++ != 0)
643			destp++;
644		destp++;
645	}
646
647	/* a null vector table pointer seperates the argp's from the envp's */
648	suword(vectp++, 0);
649
650	suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
651	suword(&arginfo->ps_nenvstr, envc);
652
653	/*
654	 * Fill in environment portion of vector table.
655	 */
656	for (; envc > 0; --envc) {
657		suword(vectp++, (long)(intptr_t)destp);
658		while (*stringp++ != 0)
659			destp++;
660		destp++;
661	}
662
663	/* end of vector table is a null pointer */
664	suword(vectp, 0);
665
666	return (stack_base);
667}
668
669/*
670 * Check permissions of file to execute.
671 *	Return 0 for success or error code on failure.
672 */
673int
674exec_check_permissions(imgp)
675	struct image_params *imgp;
676{
677	struct proc *p = imgp->proc;
678	struct vnode *vp = imgp->vp;
679	struct vattr *attr = imgp->attr;
680	int error;
681
682	/* Get file attributes */
683	error = VOP_GETATTR(vp, attr, p->p_ucred, p);
684	if (error)
685		return (error);
686
687	/*
688	 * 1) Check if file execution is disabled for the filesystem that this
689	 *	file resides on.
690	 * 2) Insure that at least one execute bit is on - otherwise root
691	 *	will always succeed, and we don't want to happen unless the
692	 *	file really is executable.
693	 * 3) Insure that the file is a regular file.
694	 */
695	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
696	    ((attr->va_mode & 0111) == 0) ||
697	    (attr->va_type != VREG)) {
698		return (EACCES);
699	}
700
701	/*
702	 * Zero length files can't be exec'd
703	 */
704	if (attr->va_size == 0)
705		return (ENOEXEC);
706
707	/*
708	 *  Check for execute permission to file based on current credentials.
709	 */
710	error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
711	if (error)
712		return (error);
713
714	/*
715	 * Check number of open-for-writes on the file and deny execution
716	 * if there are any.
717	 */
718	if (vp->v_writecount)
719		return (ETXTBSY);
720
721	/*
722	 * Call filesystem specific open routine (which does nothing in the
723	 * general case).
724	 */
725	error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
726	if (error)
727		return (error);
728
729	return (0);
730}
731
732/*
733 * Exec handler registration
734 */
735int
736exec_register(execsw_arg)
737	const struct execsw *execsw_arg;
738{
739	const struct execsw **es, **xs, **newexecsw;
740	int count = 2;	/* New slot and trailing NULL */
741
742	if (execsw)
743		for (es = execsw; *es; es++)
744			count++;
745	newexecsw = malloc(count * sizeof(*es), M_TEMP, M_WAITOK);
746	if (newexecsw == NULL)
747		return ENOMEM;
748	xs = newexecsw;
749	if (execsw)
750		for (es = execsw; *es; es++)
751			*xs++ = *es;
752	*xs++ = execsw_arg;
753	*xs = NULL;
754	if (execsw)
755		free(execsw, M_TEMP);
756	execsw = newexecsw;
757	return 0;
758}
759
760int
761exec_unregister(execsw_arg)
762	const struct execsw *execsw_arg;
763{
764	const struct execsw **es, **xs, **newexecsw;
765	int count = 1;
766
767	if (execsw == NULL)
768		panic("unregister with no handlers left?\n");
769
770	for (es = execsw; *es; es++) {
771		if (*es == execsw_arg)
772			break;
773	}
774	if (*es == NULL)
775		return ENOENT;
776	for (es = execsw; *es; es++)
777		if (*es != execsw_arg)
778			count++;
779	newexecsw = malloc(count * sizeof(*es), M_TEMP, M_WAITOK);
780	if (newexecsw == NULL)
781		return ENOMEM;
782	xs = newexecsw;
783	for (es = execsw; *es; es++)
784		if (*es != execsw_arg)
785			*xs++ = *es;
786	*xs = NULL;
787	if (execsw)
788		free(execsw, M_TEMP);
789	execsw = newexecsw;
790	return 0;
791}
792