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