imgact_shell.c revision 140992
1139804Simp/*-
2885Swollman * Copyright (c) 1993, David Greenman
3885Swollman * All rights reserved.
4885Swollman *
5885Swollman * Redistribution and use in source and binary forms, with or without
6885Swollman * modification, are permitted provided that the following conditions
7885Swollman * are met:
8885Swollman * 1. Redistributions of source code must retain the above copyright
9885Swollman *    notice, this list of conditions and the following disclaimer.
10885Swollman * 2. Redistributions in binary form must reproduce the above copyright
11885Swollman *    notice, this list of conditions and the following disclaimer in the
12885Swollman *    documentation and/or other materials provided with the distribution.
13885Swollman *
14885Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15885Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16885Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1710625Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18885Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19885Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20885Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21885Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22885Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23885Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24885Swollman * SUCH DAMAGE.
25885Swollman */
26885Swollman
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/imgact_shell.c 140992 2005-01-29 23:12:00Z sobomax $");
29116182Sobrien
302056Swollman#include <sys/param.h>
3140435Speter#include <sys/systm.h>
3211332Sswallace#include <sys/sysproto.h>
331549Srgrimes#include <sys/exec.h>
342056Swollman#include <sys/imgact.h>
352056Swollman#include <sys/kernel.h>
36885Swollman
37886Swollman#if BYTE_ORDER == LITTLE_ENDIAN
38885Swollman#define SHELLMAGIC	0x2123 /* #! */
39886Swollman#else
40886Swollman#define SHELLMAGIC	0x2321
41886Swollman#endif
42886Swollman
43885Swollman/*
44108533Sschweikh * Shell interpreter image activator. An interpreter name beginning
45140992Ssobomax *	at imgp->args->begin_argv is the minimal successful exit requirement.
46885Swollman */
4759663Sdillonint
4812130Sdgexec_shell_imgact(imgp)
4912130Sdg	struct image_params *imgp;
50885Swollman{
5112130Sdg	const char *image_header = imgp->image_header;
52140992Ssobomax	const char *ihp;
53140992Ssobomax	int error, length, offset;
54885Swollman
55885Swollman	/* a shell script? */
5617974Sbde	if (((const short *) image_header)[0] != SHELLMAGIC)
57885Swollman		return(-1);
58885Swollman
59885Swollman	/*
60885Swollman	 * Don't allow a shell script to be the shell for a shell
61885Swollman	 *	script. :-)
62885Swollman	 */
6312130Sdg	if (imgp->interpreted)
64885Swollman		return(ENOEXEC);
65885Swollman
6612130Sdg	imgp->interpreted = 1;
67885Swollman
68885Swollman	/*
69140992Ssobomax	 * Figure out the number of bytes that need to be reserved in the
70140992Ssobomax	 * argument string to copy the contents of the interpreter's command
71140992Ssobomax	 * line into the argument string.
72885Swollman	 */
73140992Ssobomax	ihp = &image_header[2];
74140992Ssobomax	offset = 0;
75140992Ssobomax	while (ihp < &image_header[MAXSHELLCMDLEN]) {
76140992Ssobomax		/* Skip any whitespace */
77140992Ssobomax		while ((*ihp == ' ') || (*ihp == '\t')) {
78140992Ssobomax			ihp++;
79140992Ssobomax			continue;
80140992Ssobomax		}
81885Swollman
82140992Ssobomax		/* End of line? */
83140992Ssobomax		if ((*ihp == '\n') || (*ihp == '#'))
84140992Ssobomax			break;
85140992Ssobomax
86140992Ssobomax		/* Found a token */
87140992Ssobomax		while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') &&
88140992Ssobomax		    (*ihp != '#')) {
89140992Ssobomax			offset++;
90140992Ssobomax			ihp++;
91140992Ssobomax		}
92140992Ssobomax		/* Include terminating nulls in the offset */
93140992Ssobomax		offset++;
94140992Ssobomax	}
95140992Ssobomax
96140992Ssobomax	/* If the script gives a null line as the interpreter, we bail */
97140992Ssobomax	if (offset == 0)
98140992Ssobomax		return (ENOEXEC);
99140992Ssobomax
100140992Ssobomax	/* Check that we aren't too big */
101140992Ssobomax	if (offset > MAXSHELLCMDLEN)
102140992Ssobomax		return (ENAMETOOLONG);
103140992Ssobomax
104885Swollman	/*
105140992Ssobomax	 * The full path name of the original script file must be tagged
106140992Ssobomax	 * onto the end, adjust the offset to deal with it.
107140992Ssobomax	 *
108140992Ssobomax	 * The original argv[0] is being replaced, set 'length' to the number
109140992Ssobomax	 * of bytes being removed.  So 'offset' is the number of bytes being
110140992Ssobomax	 * added and 'length' is the number of bytes being removed.
111885Swollman	 */
112140992Ssobomax	offset += strlen(imgp->args->fname) + 1;	/* add fname */
113140992Ssobomax	length = (imgp->args->argc == 0) ? 0 :
114140992Ssobomax	    strlen(imgp->args->begin_argv) + 1;		/* bytes to delete */
115885Swollman
116140992Ssobomax	if (offset - length > imgp->args->stringspace)
117140992Ssobomax		return (E2BIG);
118885Swollman
119140992Ssobomax	bcopy(imgp->args->begin_argv + length, imgp->args->begin_argv + offset,
120140992Ssobomax	    imgp->args->endp - (imgp->args->begin_argv + length));
121885Swollman
122140992Ssobomax	offset -= length;		/* calculate actual adjustment */
123140992Ssobomax	imgp->args->begin_envv += offset;
124140992Ssobomax	imgp->args->endp += offset;
125140992Ssobomax	imgp->args->stringspace -= offset;
126885Swollman
127140992Ssobomax	/*
128140992Ssobomax	 * If there were no arguments then we've added one, otherwise
129140992Ssobomax	 * decr argc remove old argv[0], incr argc for fname add, net 0
130140992Ssobomax	 */
131140992Ssobomax	if (imgp->args->argc == 0)
132140992Ssobomax		imgp->args->argc = 1;
133885Swollman
134140992Ssobomax	/*
135140992Ssobomax	 * Loop through the interpreter name yet again, copying as
136140992Ssobomax	 * we go.
137140992Ssobomax	 */
138885Swollman	ihp = &image_header[2];
139140992Ssobomax	offset = 0;
140140992Ssobomax	while (ihp < &image_header[MAXSHELLCMDLEN]) {
141140992Ssobomax		/* Skip whitespace */
142140992Ssobomax		while ((*ihp == ' ' || *ihp == '\t')) {
143140992Ssobomax			ihp++;
144140992Ssobomax			continue;
145140992Ssobomax		}
146885Swollman
147140992Ssobomax		/* End of line? */
148140992Ssobomax		if ((*ihp == '\n') || (*ihp == '#'))
149140992Ssobomax			break;
150885Swollman
151140992Ssobomax		/* Found a token, copy it */
152140992Ssobomax		while ((*ihp != ' ') && (*ihp != '\t') &&
153140992Ssobomax		    (*ihp != '\n') && (*ihp != '#')) {
154140992Ssobomax			imgp->args->begin_argv[offset++] = *ihp++;
155885Swollman		}
156140992Ssobomax		imgp->args->begin_argv[offset++] = '\0';
157140992Ssobomax		imgp->args->argc++;
158885Swollman	}
159885Swollman
160140992Ssobomax	/*
161140992Ssobomax	 * Finally, add the filename onto the end for the interpreter to
162140992Ssobomax	 * use and copy the interpreter's name to imgp->interpreter_name
163140992Ssobomax	 * for exec to use.
164140992Ssobomax	 */
165140992Ssobomax	error = copystr(imgp->args->fname, imgp->args->buf + offset,
166140992Ssobomax	    imgp->args->stringspace, &length);
167885Swollman
168140992Ssobomax	if (error == 0)
169140992Ssobomax		error = copystr(imgp->args->begin_argv, imgp->interpreter_name,
170140992Ssobomax		    MAXSHELLCMDLEN, &length);
171140992Ssobomax
172140992Ssobomax	return (error);
173885Swollman}
174886Swollman
175886Swollman/*
176886Swollman * Tell kern_execve.c about it, with a little help from the linker.
177886Swollman */
17843402Sdillonstatic struct execsw shell_execsw = { exec_shell_imgact, "#!" };
17940435SpeterEXEC_SET(shell, shell_execsw);
180