19454b2d8SWarner Losh /*- 2cfefd687SGarrett Wollman * Copyright (c) 1993, David Greenman 3cfefd687SGarrett Wollman * All rights reserved. 4cfefd687SGarrett Wollman * 5cfefd687SGarrett Wollman * Redistribution and use in source and binary forms, with or without 6cfefd687SGarrett Wollman * modification, are permitted provided that the following conditions 7cfefd687SGarrett Wollman * are met: 8cfefd687SGarrett Wollman * 1. Redistributions of source code must retain the above copyright 9cfefd687SGarrett Wollman * notice, this list of conditions and the following disclaimer. 10cfefd687SGarrett Wollman * 2. Redistributions in binary form must reproduce the above copyright 11cfefd687SGarrett Wollman * notice, this list of conditions and the following disclaimer in the 12cfefd687SGarrett Wollman * documentation and/or other materials provided with the distribution. 13cfefd687SGarrett Wollman * 14cfefd687SGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15cfefd687SGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16cfefd687SGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171984b014SDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18cfefd687SGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19cfefd687SGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20cfefd687SGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21cfefd687SGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22cfefd687SGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23cfefd687SGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24cfefd687SGarrett Wollman * SUCH DAMAGE. 25cfefd687SGarrett Wollman */ 26cfefd687SGarrett Wollman 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 30f540b106SGarrett Wollman #include <sys/param.h> 316916a1daSMaxim Sobolev #include <sys/vnode.h> 326916a1daSMaxim Sobolev #include <sys/proc.h> 33aa855a59SPeter Wemm #include <sys/systm.h> 34ad7507e2SSteven Wallace #include <sys/sysproto.h> 3526f9a767SRodney W. Grimes #include <sys/exec.h> 36f540b106SGarrett Wollman #include <sys/imgact.h> 37f540b106SGarrett Wollman #include <sys/kernel.h> 38cfefd687SGarrett Wollman 395f49915eSGarance A Drosehn #define KEEP_OLDCODE 1 405f49915eSGarance A Drosehn #if BYTE_ORDER == LITTLE_ENDIAN /* temp for OLD_CODE kludge */ 415f49915eSGarance A Drosehn #define DBG_MAGIC 0x2B23 /* #+ in "little-endian" */ 425f49915eSGarance A Drosehn #define OLD_MAGIC 0x3C23 /* #< */ 435f49915eSGarance A Drosehn #else 445f49915eSGarance A Drosehn #define DBG_MAGIC 0x232B /* #+ in big-endian */ 455f49915eSGarance A Drosehn #define OLD_MAGIC 0x233C /* #< */ 465f49915eSGarance A Drosehn #endif 475f49915eSGarance A Drosehn 4892d91f76SGarrett Wollman #if BYTE_ORDER == LITTLE_ENDIAN 49cfefd687SGarrett Wollman #define SHELLMAGIC 0x2123 /* #! */ 5092d91f76SGarrett Wollman #else 5192d91f76SGarrett Wollman #define SHELLMAGIC 0x2321 5292d91f76SGarrett Wollman #endif 5392d91f76SGarrett Wollman 54cfefd687SGarrett Wollman /* 555f49915eSGarance A Drosehn * At the time of this writing, MAXSHELLCMDLEN == PAGE_SIZE. This is 565f49915eSGarance A Drosehn * significant because the caller has only mapped in one page of the 575f49915eSGarance A Drosehn * file we're reading. This code should be changed to know how to 585f49915eSGarance A Drosehn * read in the second page, but I'm not doing that just yet... 595f49915eSGarance A Drosehn */ 605f49915eSGarance A Drosehn #if MAXSHELLCMDLEN > PAGE_SIZE 615f49915eSGarance A Drosehn #error "MAXSHELLCMDLEN is larger than a single page!" 625f49915eSGarance A Drosehn #endif 635f49915eSGarance A Drosehn 645f49915eSGarance A Drosehn /** 655f49915eSGarance A Drosehn * Shell interpreter image activator. An interpreter name beginning at 665f49915eSGarance A Drosehn * imgp->args->begin_argv is the minimal successful exit requirement. 675f49915eSGarance A Drosehn * 685f49915eSGarance A Drosehn * If the given file is a shell-script, then the first line will start 695f49915eSGarance A Drosehn * with the two characters `#!' (aka SHELLMAGIC), followed by the name 705f49915eSGarance A Drosehn * of the shell-interpreter to run, followed by zero or more tokens. 715f49915eSGarance A Drosehn * 725f49915eSGarance A Drosehn * The interpreter is then started up such that it will see: 735f49915eSGarance A Drosehn * arg[0] -> The name of interpreter as specified after `#!' in the 745f49915eSGarance A Drosehn * first line of the script. The interpreter name must 755f49915eSGarance A Drosehn * not be longer than MAXSHELLCMDLEN bytes. 765f49915eSGarance A Drosehn * arg[1] -> *If* there are any additional tokens on the first line, 775f49915eSGarance A Drosehn * then we add a new arg[1], which is a copy of the rest of 785f49915eSGarance A Drosehn * that line. The copy starts at the first token after the 795f49915eSGarance A Drosehn * interpreter name. We leave it to the interpreter to 805f49915eSGarance A Drosehn * parse the tokens in that value. 815f49915eSGarance A Drosehn * arg[x] -> the full pathname of the script. This will either be 825f49915eSGarance A Drosehn * arg[2] or arg[1], depending on whether or not tokens 835f49915eSGarance A Drosehn * were found after the interpreter name. 845f49915eSGarance A Drosehn * arg[x+1] -> all the arguments that were specified on the original 855f49915eSGarance A Drosehn * command line. 865f49915eSGarance A Drosehn * 875f49915eSGarance A Drosehn * This processing is described in the execve(2) man page. 885f49915eSGarance A Drosehn */ 895f49915eSGarance A Drosehn 905f49915eSGarance A Drosehn /* 915f49915eSGarance A Drosehn * HISTORICAL NOTE: From 1993 to mid-2005, FreeBSD parsed out the tokens as 925f49915eSGarance A Drosehn * found on the first line of the script, and setup each token as a separate 935f49915eSGarance A Drosehn * value in arg[]. This extra processing did not match the behavior of other 945f49915eSGarance A Drosehn * OS's, and caused a few subtle problems. For one, it meant the kernel was 955f49915eSGarance A Drosehn * deciding how those values should be parsed (wrt characters for quoting or 965f49915eSGarance A Drosehn * comments, etc), while the interpreter might have other rules for parsing. 975f49915eSGarance A Drosehn * It also meant the interpreter had no way of knowing which arguments came 985f49915eSGarance A Drosehn * from the first line of the shell script, and which arguments were specified 995f49915eSGarance A Drosehn * by the user on the command line. 1005f49915eSGarance A Drosehn * 1015f49915eSGarance A Drosehn * Only few things in the base system might depend on that non-standard 1025f49915eSGarance A Drosehn * processing (mainly /bin/sh and /usr/bin/env). And for programs which are 1035f49915eSGarance A Drosehn * not in the base system, the "newer" behavior matches how NetBSD, OpenBSD, 1045f49915eSGarance A Drosehn * Linux, Solaris, AIX, IRIX, and many other Unixes have set up the arg-list 1055f49915eSGarance A Drosehn * for the interpreter. So if a program can handle this behavior on those 1065f49915eSGarance A Drosehn * other OS's, it should be able to handle it for FreeBSD too. 107cfefd687SGarrett Wollman */ 108d323ddf3SMatthew Dillon int 109c52007c2SDavid Greenman exec_shell_imgact(imgp) 110c52007c2SDavid Greenman struct image_params *imgp; 111cfefd687SGarrett Wollman { 112c52007c2SDavid Greenman const char *image_header = imgp->image_header; 1135f49915eSGarance A Drosehn const char *ihp, *interpb, *interpe, *maxp, *optb, *opte; 114ec217396SMaxim Sobolev int error, offset; 1156916a1daSMaxim Sobolev size_t length, clength; 1166916a1daSMaxim Sobolev struct vattr vattr; 117cfefd687SGarrett Wollman 118cfefd687SGarrett Wollman /* a shell script? */ 119e0c95ed9SBruce Evans if (((const short *) image_header)[0] != SHELLMAGIC) 120cfefd687SGarrett Wollman return(-1); 121cfefd687SGarrett Wollman 122cfefd687SGarrett Wollman /* 123cfefd687SGarrett Wollman * Don't allow a shell script to be the shell for a shell 124cfefd687SGarrett Wollman * script. :-) 125cfefd687SGarrett Wollman */ 126c52007c2SDavid Greenman if (imgp->interpreted) 127cfefd687SGarrett Wollman return(ENOEXEC); 128cfefd687SGarrett Wollman 129c52007c2SDavid Greenman imgp->interpreted = 1; 130cfefd687SGarrett Wollman 131cfefd687SGarrett Wollman /* 1326916a1daSMaxim Sobolev * At this point we have the first page of the file mapped. 1336916a1daSMaxim Sobolev * However, we don't know how far into the page the contents are 1346916a1daSMaxim Sobolev * valid -- the actual file might be much shorter than the page. 1356916a1daSMaxim Sobolev * So find out the file size. 1366916a1daSMaxim Sobolev */ 1376916a1daSMaxim Sobolev error = VOP_GETATTR(imgp->vp, &vattr, imgp->proc->p_ucred, curthread); 1386916a1daSMaxim Sobolev if (error) 1396916a1daSMaxim Sobolev return (error); 1406916a1daSMaxim Sobolev 1415f49915eSGarance A Drosehn /* 1425f49915eSGarance A Drosehn * Copy shell name and arguments from image_header into a string 1435f49915eSGarance A Drosehn * buffer. Remember that the caller has mapped only the 1445f49915eSGarance A Drosehn * first page of the file into memory. 1455f49915eSGarance A Drosehn */ 1465f49915eSGarance A Drosehn clength = (vattr.va_size > PAGE_SIZE) ? PAGE_SIZE : vattr.va_size; 1475f49915eSGarance A Drosehn 1485f49915eSGarance A Drosehn maxp = &image_header[clength]; 1495f49915eSGarance A Drosehn ihp = &image_header[2]; 1505f49915eSGarance A Drosehn #if KEEP_OLDCODE 1515f49915eSGarance A Drosehn /* 1525f49915eSGarance A Drosehn * XXX - Temporarily provide a quick-and-dirty way to get the 1535f49915eSGarance A Drosehn * older, non-standard option-parsing behavior, just in case 1545f49915eSGarance A Drosehn * someone finds themselves in an emergency where they need it. 1555f49915eSGarance A Drosehn * This will not be documented. It is only for initial testing. 1565f49915eSGarance A Drosehn */ 1575f49915eSGarance A Drosehn if (*(const short *)ihp == OLD_MAGIC) 1585f49915eSGarance A Drosehn ihp += 2; 1595f49915eSGarance A Drosehn else 1605f49915eSGarance A Drosehn goto new_code; 1615f49915eSGarance A Drosehn interpb = ihp; 1625f49915eSGarance A Drosehn 1636916a1daSMaxim Sobolev /* 164610ecfe0SMaxim Sobolev * Figure out the number of bytes that need to be reserved in the 165610ecfe0SMaxim Sobolev * argument string to copy the contents of the interpreter's command 166610ecfe0SMaxim Sobolev * line into the argument string. 167cfefd687SGarrett Wollman */ 1685f49915eSGarance A Drosehn ihp = interpb; 169610ecfe0SMaxim Sobolev offset = 0; 1706916a1daSMaxim Sobolev while (ihp < &image_header[clength]) { 171610ecfe0SMaxim Sobolev /* Skip any whitespace */ 172b4305f8dSMaxim Sobolev if ((*ihp == ' ') || (*ihp == '\t')) { 173610ecfe0SMaxim Sobolev ihp++; 174610ecfe0SMaxim Sobolev continue; 175610ecfe0SMaxim Sobolev } 176cfefd687SGarrett Wollman 177610ecfe0SMaxim Sobolev /* End of line? */ 178b4305f8dSMaxim Sobolev if ((*ihp == '\n') || (*ihp == '#') || (*ihp == '\0')) 179610ecfe0SMaxim Sobolev break; 180cfefd687SGarrett Wollman 181610ecfe0SMaxim Sobolev /* Found a token */ 1826916a1daSMaxim Sobolev do { 183610ecfe0SMaxim Sobolev offset++; 184610ecfe0SMaxim Sobolev ihp++; 1856916a1daSMaxim Sobolev } while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') && 1866916a1daSMaxim Sobolev (*ihp != '#') && (*ihp != '\0') && 1876916a1daSMaxim Sobolev (ihp < &image_header[clength])); 188610ecfe0SMaxim Sobolev /* Include terminating nulls in the offset */ 189610ecfe0SMaxim Sobolev offset++; 190610ecfe0SMaxim Sobolev } 191cfefd687SGarrett Wollman 192610ecfe0SMaxim Sobolev /* If the script gives a null line as the interpreter, we bail */ 193610ecfe0SMaxim Sobolev if (offset == 0) 194cfefd687SGarrett Wollman return (ENOEXEC); 195cfefd687SGarrett Wollman 196610ecfe0SMaxim Sobolev /* Check that we aren't too big */ 1976916a1daSMaxim Sobolev if (ihp == &image_header[MAXSHELLCMDLEN]) 198610ecfe0SMaxim Sobolev return (ENAMETOOLONG); 199cfefd687SGarrett Wollman 200cfefd687SGarrett Wollman /* 201610ecfe0SMaxim Sobolev * The full path name of the original script file must be tagged 202610ecfe0SMaxim Sobolev * onto the end, adjust the offset to deal with it. 203610ecfe0SMaxim Sobolev * 204610ecfe0SMaxim Sobolev * The original argv[0] is being replaced, set 'length' to the number 205610ecfe0SMaxim Sobolev * of bytes being removed. So 'offset' is the number of bytes being 206610ecfe0SMaxim Sobolev * added and 'length' is the number of bytes being removed. 207cfefd687SGarrett Wollman */ 208610ecfe0SMaxim Sobolev offset += strlen(imgp->args->fname) + 1; /* add fname */ 209610ecfe0SMaxim Sobolev length = (imgp->args->argc == 0) ? 0 : 210610ecfe0SMaxim Sobolev strlen(imgp->args->begin_argv) + 1; /* bytes to delete */ 211610ecfe0SMaxim Sobolev 212610ecfe0SMaxim Sobolev if (offset - length > imgp->args->stringspace) 213610ecfe0SMaxim Sobolev return (E2BIG); 214610ecfe0SMaxim Sobolev 215610ecfe0SMaxim Sobolev bcopy(imgp->args->begin_argv + length, imgp->args->begin_argv + offset, 216610ecfe0SMaxim Sobolev imgp->args->endp - (imgp->args->begin_argv + length)); 217610ecfe0SMaxim Sobolev 218610ecfe0SMaxim Sobolev offset -= length; /* calculate actual adjustment */ 219610ecfe0SMaxim Sobolev imgp->args->begin_envv += offset; 220610ecfe0SMaxim Sobolev imgp->args->endp += offset; 221610ecfe0SMaxim Sobolev imgp->args->stringspace -= offset; 222610ecfe0SMaxim Sobolev 223610ecfe0SMaxim Sobolev /* 224610ecfe0SMaxim Sobolev * If there were no arguments then we've added one, otherwise 225610ecfe0SMaxim Sobolev * decr argc remove old argv[0], incr argc for fname add, net 0 226610ecfe0SMaxim Sobolev */ 227610ecfe0SMaxim Sobolev if (imgp->args->argc == 0) 228610ecfe0SMaxim Sobolev imgp->args->argc = 1; 229610ecfe0SMaxim Sobolev 230610ecfe0SMaxim Sobolev /* 231610ecfe0SMaxim Sobolev * Loop through the interpreter name yet again, copying as 232610ecfe0SMaxim Sobolev * we go. 233610ecfe0SMaxim Sobolev */ 2345f49915eSGarance A Drosehn ihp = interpb; 235610ecfe0SMaxim Sobolev offset = 0; 2366916a1daSMaxim Sobolev while (ihp < &image_header[clength]) { 237610ecfe0SMaxim Sobolev /* Skip whitespace */ 238b4305f8dSMaxim Sobolev if ((*ihp == ' ') || (*ihp == '\t')) { 239610ecfe0SMaxim Sobolev ihp++; 240610ecfe0SMaxim Sobolev continue; 241cfefd687SGarrett Wollman } 242cfefd687SGarrett Wollman 243610ecfe0SMaxim Sobolev /* End of line? */ 244b4305f8dSMaxim Sobolev if ((*ihp == '\n') || (*ihp == '#') || (*ihp == '\0')) 245610ecfe0SMaxim Sobolev break; 246cfefd687SGarrett Wollman 247610ecfe0SMaxim Sobolev /* Found a token, copy it */ 2486916a1daSMaxim Sobolev do { 249610ecfe0SMaxim Sobolev imgp->args->begin_argv[offset++] = *ihp++; 2506916a1daSMaxim Sobolev } while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') && 2516916a1daSMaxim Sobolev (*ihp != '#') && (*ihp != '\0') && 2526916a1daSMaxim Sobolev (ihp < &image_header[MAXSHELLCMDLEN])); 253610ecfe0SMaxim Sobolev imgp->args->begin_argv[offset++] = '\0'; 254610ecfe0SMaxim Sobolev imgp->args->argc++; 255cfefd687SGarrett Wollman } 2565f49915eSGarance A Drosehn goto common_end; 2575f49915eSGarance A Drosehn new_code: 2585f49915eSGarance A Drosehn #endif 2595f49915eSGarance A Drosehn /* 2605f49915eSGarance A Drosehn * Find the beginning and end of the interpreter_name. If the 2615f49915eSGarance A Drosehn * line does not include any interpreter, or if the name which 2625f49915eSGarance A Drosehn * was found is too long, we bail out. 2635f49915eSGarance A Drosehn */ 2645f49915eSGarance A Drosehn while (ihp < maxp && ((*ihp == ' ') || (*ihp == '\t'))) 2655f49915eSGarance A Drosehn ihp++; 2665f49915eSGarance A Drosehn interpb = ihp; 2675f49915eSGarance A Drosehn while (ihp < maxp && ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') 2685f49915eSGarance A Drosehn && (*ihp != '\0'))) 2695f49915eSGarance A Drosehn ihp++; 2705f49915eSGarance A Drosehn interpe = ihp; 2715f49915eSGarance A Drosehn if (interpb == interpe) 2725f49915eSGarance A Drosehn return (ENOEXEC); 2735f49915eSGarance A Drosehn if ((interpe - interpb) >= MAXSHELLCMDLEN) 2745f49915eSGarance A Drosehn return (ENAMETOOLONG); 275cfefd687SGarrett Wollman 276610ecfe0SMaxim Sobolev /* 2775f49915eSGarance A Drosehn * Find the beginning of the options (if any), and the end-of-line. 2785f49915eSGarance A Drosehn * Then trim the trailing blanks off the value. Note that some 2795f49915eSGarance A Drosehn * other operating systems do *not* trim the trailing whitespace... 2805f49915eSGarance A Drosehn */ 2815f49915eSGarance A Drosehn while (ihp < maxp && ((*ihp == ' ') || (*ihp == '\t'))) 2825f49915eSGarance A Drosehn ihp++; 2835f49915eSGarance A Drosehn optb = ihp; 2845f49915eSGarance A Drosehn while (ihp < maxp && ((*ihp != '\n') && (*ihp != '\0'))) 2855f49915eSGarance A Drosehn ihp++; 2865f49915eSGarance A Drosehn opte = ihp; 2875f49915eSGarance A Drosehn while (--ihp > interpe && ((*ihp == ' ') || (*ihp == '\t'))) 2885f49915eSGarance A Drosehn opte = ihp; 2895f49915eSGarance A Drosehn 2905f49915eSGarance A Drosehn /* 2915f49915eSGarance A Drosehn * We need to "pop" (remove) the present value of arg[0], and "push" 2925f49915eSGarance A Drosehn * either two or three new values in the arg[] list. To do this, 2935f49915eSGarance A Drosehn * we first shift all the other values in the `begin_argv' area to 2945f49915eSGarance A Drosehn * provide the exact amount of room for the values added. Set up 2955f49915eSGarance A Drosehn * `offset' as the number of bytes to be added to the `begin_argv' 2965f49915eSGarance A Drosehn * area, and 'length' as the number of bytes being removed. 2975f49915eSGarance A Drosehn */ 2985f49915eSGarance A Drosehn offset = interpe - interpb + 1; /* interpreter */ 2995f49915eSGarance A Drosehn if (opte != optb) /* options (if any) */ 3005f49915eSGarance A Drosehn offset += opte - optb + 1; 3015f49915eSGarance A Drosehn offset += strlen(imgp->args->fname) + 1; /* fname of script */ 3025f49915eSGarance A Drosehn length = (imgp->args->argc == 0) ? 0 : 3035f49915eSGarance A Drosehn strlen(imgp->args->begin_argv) + 1; /* bytes to delete */ 3045f49915eSGarance A Drosehn 3055f49915eSGarance A Drosehn if (offset - length > imgp->args->stringspace) 3065f49915eSGarance A Drosehn return (E2BIG); 3075f49915eSGarance A Drosehn 3085f49915eSGarance A Drosehn bcopy(imgp->args->begin_argv + length, imgp->args->begin_argv + offset, 3095f49915eSGarance A Drosehn imgp->args->endp - (imgp->args->begin_argv + length)); 3105f49915eSGarance A Drosehn 3115f49915eSGarance A Drosehn offset -= length; /* calculate actual adjustment */ 3125f49915eSGarance A Drosehn imgp->args->begin_envv += offset; 3135f49915eSGarance A Drosehn imgp->args->endp += offset; 3145f49915eSGarance A Drosehn imgp->args->stringspace -= offset; 3155f49915eSGarance A Drosehn 3165f49915eSGarance A Drosehn /* 3175f49915eSGarance A Drosehn * If there was no arg[0] when we started, then the interpreter_name 3185f49915eSGarance A Drosehn * is adding an argument (instead of replacing the arg[0] we started 3195f49915eSGarance A Drosehn * with). And we're always adding an argument when we include the 3205f49915eSGarance A Drosehn * full pathname of the original script. 3215f49915eSGarance A Drosehn */ 3225f49915eSGarance A Drosehn if (imgp->args->argc == 0) 3235f49915eSGarance A Drosehn imgp->args->argc = 1; 3245f49915eSGarance A Drosehn imgp->args->argc++; 3255f49915eSGarance A Drosehn 3265f49915eSGarance A Drosehn /* 3275f49915eSGarance A Drosehn * The original arg[] list has been shifted appropriately. Copy in 3285f49915eSGarance A Drosehn * the interpreter name and options-string. 3295f49915eSGarance A Drosehn */ 3305f49915eSGarance A Drosehn length = interpe - interpb; 3315f49915eSGarance A Drosehn bcopy(interpb, imgp->args->buf, length); 3325f49915eSGarance A Drosehn *(imgp->args->buf + length) = '\0'; 3335f49915eSGarance A Drosehn offset = length + 1; 3345f49915eSGarance A Drosehn if (opte != optb) { 3355f49915eSGarance A Drosehn length = opte - optb; 3365f49915eSGarance A Drosehn bcopy(optb, imgp->args->buf + offset, length); 3375f49915eSGarance A Drosehn *(imgp->args->buf + offset + length) = '\0'; 3385f49915eSGarance A Drosehn offset += length + 1; 3395f49915eSGarance A Drosehn imgp->args->argc++; 3405f49915eSGarance A Drosehn } 3415f49915eSGarance A Drosehn 3425f49915eSGarance A Drosehn #if KEEP_OLDCODE 3435f49915eSGarance A Drosehn common_end: 3445f49915eSGarance A Drosehn #endif 3455f49915eSGarance A Drosehn /* 346610ecfe0SMaxim Sobolev * Finally, add the filename onto the end for the interpreter to 347610ecfe0SMaxim Sobolev * use and copy the interpreter's name to imgp->interpreter_name 348610ecfe0SMaxim Sobolev * for exec to use. 349610ecfe0SMaxim Sobolev */ 350610ecfe0SMaxim Sobolev error = copystr(imgp->args->fname, imgp->args->buf + offset, 351610ecfe0SMaxim Sobolev imgp->args->stringspace, &length); 352cfefd687SGarrett Wollman 353610ecfe0SMaxim Sobolev if (error == 0) 354610ecfe0SMaxim Sobolev error = copystr(imgp->args->begin_argv, imgp->interpreter_name, 355610ecfe0SMaxim Sobolev MAXSHELLCMDLEN, &length); 356610ecfe0SMaxim Sobolev 357610ecfe0SMaxim Sobolev return (error); 358cfefd687SGarrett Wollman } 35992d91f76SGarrett Wollman 36092d91f76SGarrett Wollman /* 36192d91f76SGarrett Wollman * Tell kern_execve.c about it, with a little help from the linker. 36292d91f76SGarrett Wollman */ 363820ca326SMatthew Dillon static struct execsw shell_execsw = { exec_shell_imgact, "#!" }; 364aa855a59SPeter Wemm EXEC_SET(shell, shell_execsw); 365