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