imgact_shell.c revision 140992
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 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/kern/imgact_shell.c 140992 2005-01-29 23:12:00Z sobomax $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/sysproto.h> 33#include <sys/exec.h> 34#include <sys/imgact.h> 35#include <sys/kernel.h> 36 37#if BYTE_ORDER == LITTLE_ENDIAN 38#define SHELLMAGIC 0x2123 /* #! */ 39#else 40#define SHELLMAGIC 0x2321 41#endif 42 43/* 44 * Shell interpreter image activator. An interpreter name beginning 45 * at imgp->args->begin_argv is the minimal successful exit requirement. 46 */ 47int 48exec_shell_imgact(imgp) 49 struct image_params *imgp; 50{ 51 const char *image_header = imgp->image_header; 52 const char *ihp; 53 int error, length, offset; 54 55 /* a shell script? */ 56 if (((const short *) image_header)[0] != SHELLMAGIC) 57 return(-1); 58 59 /* 60 * Don't allow a shell script to be the shell for a shell 61 * script. :-) 62 */ 63 if (imgp->interpreted) 64 return(ENOEXEC); 65 66 imgp->interpreted = 1; 67 68 /* 69 * Figure out the number of bytes that need to be reserved in the 70 * argument string to copy the contents of the interpreter's command 71 * line into the argument string. 72 */ 73 ihp = &image_header[2]; 74 offset = 0; 75 while (ihp < &image_header[MAXSHELLCMDLEN]) { 76 /* Skip any whitespace */ 77 while ((*ihp == ' ') || (*ihp == '\t')) { 78 ihp++; 79 continue; 80 } 81 82 /* End of line? */ 83 if ((*ihp == '\n') || (*ihp == '#')) 84 break; 85 86 /* Found a token */ 87 while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') && 88 (*ihp != '#')) { 89 offset++; 90 ihp++; 91 } 92 /* Include terminating nulls in the offset */ 93 offset++; 94 } 95 96 /* If the script gives a null line as the interpreter, we bail */ 97 if (offset == 0) 98 return (ENOEXEC); 99 100 /* Check that we aren't too big */ 101 if (offset > MAXSHELLCMDLEN) 102 return (ENAMETOOLONG); 103 104 /* 105 * The full path name of the original script file must be tagged 106 * onto the end, adjust the offset to deal with it. 107 * 108 * The original argv[0] is being replaced, set 'length' to the number 109 * of bytes being removed. So 'offset' is the number of bytes being 110 * added and 'length' is the number of bytes being removed. 111 */ 112 offset += strlen(imgp->args->fname) + 1; /* add fname */ 113 length = (imgp->args->argc == 0) ? 0 : 114 strlen(imgp->args->begin_argv) + 1; /* bytes to delete */ 115 116 if (offset - length > imgp->args->stringspace) 117 return (E2BIG); 118 119 bcopy(imgp->args->begin_argv + length, imgp->args->begin_argv + offset, 120 imgp->args->endp - (imgp->args->begin_argv + length)); 121 122 offset -= length; /* calculate actual adjustment */ 123 imgp->args->begin_envv += offset; 124 imgp->args->endp += offset; 125 imgp->args->stringspace -= offset; 126 127 /* 128 * If there were no arguments then we've added one, otherwise 129 * decr argc remove old argv[0], incr argc for fname add, net 0 130 */ 131 if (imgp->args->argc == 0) 132 imgp->args->argc = 1; 133 134 /* 135 * Loop through the interpreter name yet again, copying as 136 * we go. 137 */ 138 ihp = &image_header[2]; 139 offset = 0; 140 while (ihp < &image_header[MAXSHELLCMDLEN]) { 141 /* Skip whitespace */ 142 while ((*ihp == ' ' || *ihp == '\t')) { 143 ihp++; 144 continue; 145 } 146 147 /* End of line? */ 148 if ((*ihp == '\n') || (*ihp == '#')) 149 break; 150 151 /* Found a token, copy it */ 152 while ((*ihp != ' ') && (*ihp != '\t') && 153 (*ihp != '\n') && (*ihp != '#')) { 154 imgp->args->begin_argv[offset++] = *ihp++; 155 } 156 imgp->args->begin_argv[offset++] = '\0'; 157 imgp->args->argc++; 158 } 159 160 /* 161 * Finally, add the filename onto the end for the interpreter to 162 * use and copy the interpreter's name to imgp->interpreter_name 163 * for exec to use. 164 */ 165 error = copystr(imgp->args->fname, imgp->args->buf + offset, 166 imgp->args->stringspace, &length); 167 168 if (error == 0) 169 error = copystr(imgp->args->begin_argv, imgp->interpreter_name, 170 MAXSHELLCMDLEN, &length); 171 172 return (error); 173} 174 175/* 176 * Tell kern_execve.c about it, with a little help from the linker. 177 */ 178static struct execsw shell_execsw = { exec_shell_imgact, "#!" }; 179EXEC_SET(shell, shell_execsw); 180