martin      98/01/24 17:40:57

  Modified:    .        STATUS
               src      CHANGES
               src/ap   Makefile.tmpl
               src/main conf.h
  Added:       src/ap   ap_execve.c
  Log:
  Add function to emulate the execution of #! scripts
  for OS's which don't support starting them automatically
  (enable with #define NEED_HASHBANG_EMUL)
  
  Obtained from: tcsh-6.07.05, written by [EMAIL PROTECTED] (Peter Wemm)
  
  Revision  Changes    Path
  1.126     +3 -0      apachen/STATUS
  
  Index: STATUS
  ===================================================================
  RCS file: /home/cvs/apachen/STATUS,v
  retrieving revision 1.125
  retrieving revision 1.126
  diff -u -u -r1.125 -r1.126
  --- STATUS    1998/01/24 19:30:09     1.125
  +++ STATUS    1998/01/25 01:40:38     1.126
  @@ -129,6 +129,9 @@
       * Jim's [PATCH] force Unixware to use mmap() scoreboard (before
         was dependent on ordering of the #defines in http_main.c)
       * table api cleanup
  +    * [PORT] Add function to emulate the execution of #! scripts
  +      for OS's which don't support starting them automatically
  +      (enable with #define NEED_HASHBANG_EMUL)
   
   Available Patches:
   
  
  
  
  1.598     +7 -0      apachen/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apachen/src/CHANGES,v
  retrieving revision 1.597
  retrieving revision 1.598
  diff -u -u -r1.597 -r1.598
  --- CHANGES   1998/01/24 19:39:46     1.597
  +++ CHANGES   1998/01/25 01:40:53     1.598
  @@ -1,5 +1,12 @@
   Changes with Apache 1.3b4
   
  +  *) PORT: Some older *nix dialects cannot automatically start scripts
  +     which begin with a #! interpreter line (the shell starts the scripts
  +     appropriately on these platforms). Apache now supports starting of
  +     "hashbang-scripts" when the NEED_HASHBANG_EMUL define is set.
  +     [Martin Kraemer, with code from [EMAIL PROTECTED] (Peter Wemm)
  +     taken from tcsh]
  +
     *) "typedef array_header table" removed from alloc.h, folks should have
        been writing to use table as if it were an opaque type, but even
        some standard modules got this wrong.  By changing the definition
  
  
  
  1.7       +2 -1      apachen/src/ap/Makefile.tmpl
  
  Index: Makefile.tmpl
  ===================================================================
  RCS file: /home/cvs/apachen/src/ap/Makefile.tmpl,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -u -r1.6 -r1.7
  --- Makefile.tmpl     1997/12/30 15:10:42     1.6
  +++ Makefile.tmpl     1998/01/25 01:40:55     1.7
  @@ -6,7 +6,7 @@
   
   LIB=libap.a
   
  -OBJS=ap_signal.o ap_slack.o ap_snprintf.o ap_strings.o ap_cpystrn.o
  +OBJS=ap_signal.o ap_slack.o ap_snprintf.o ap_strings.o ap_cpystrn.o 
ap_execve.o
   
   .c.o:
        $(CC) -c $(INCLUDES) $(CFLAGS) $(SPACER) $<
  @@ -29,3 +29,4 @@
   ap_snprintf.o: $(INCDIR)/conf.h
   ap_strings.o: $(INCDIR)/httpd.h
   ap_cpystrn.o: $(INCDIR)/httpd.h
  +ap_execve.o: $(INCDIR)/httpd.h
  
  
  
  1.1                  apachen/src/ap/ap_execve.c
  
  Index: ap_execve.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    [EMAIL PROTECTED]
   *
   * 5. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  #include "httpd.h"
  #include "http_log.h"
  
  /*---------------------------------------------------------------*/
  
  #ifdef NEED_HASHBANG_EMUL
  
  #undef execle
  #undef execve
  
  static const char **hashbang(const char *filename, char **argv);
  
  
  /* Historically, a list of arguments on the stack was often treated as
   * being equivalent to an array (since they already were "contiguous"
   * on the stack, and the arguments were pushed in the correct order).
   * On today's processors, this is not necessarily equivalent, because
   * often arguments are padded or passed partially in registers,
   * or the stack direction is backwards.
   * To be on the safe side, we copy the argument list to our own
   * local argv[] array. The va_arg logic makes sure we do the right thing.
   * XXX: malloc() is used because we expect to be overlaid soon.
   */
  int ap_execle(const char *filename, const char *arg,...)
  {
      va_list adummy;
      char **envp;
      char **argv;
      int argc, ret;
  
      /* First pass: Count arguments on stack */
      va_start(adummy, arg);
      for (argc = 0; va_arg(adummy, char *) != NULL; ++argc)
        continue;
      va_end(adummy);
  
      argv = (char **) malloc((argc + 2) * sizeof(*argv));
  
      /* Pass two --- copy the argument strings into the result space */
      va_start(adummy, arg);
      for (argc = 0; (argv[argc] = va_arg(adummy, char *)) != NULL; ++argc)
        continue;
      envp = va_arg(adummy, char **);
      va_end(adummy);
  
      ret = ap_execve(filename, argv, envp);
      free(argv);
  
      return ret;
  }
  
  int ap_execve(const char *filename, const char *argv[],
                    const char *envp[])
  {
      const char *argv0 = argv[0];
      extern char **environ;
  
      if (envp == NULL)
        envp = (const char **) environ;
  
      /* Try to execute the file directly first: */
      execve(filename, argv, envp);
  
      /* Still with us? Then something went seriously wrong.
       * From the (linux) man page:
       * EACCES The file is not a regular file.
       * EACCES Execute permission is denied for the file.
       * EACCES Search  permission  is denied on a component of the path prefix.
       * EPERM  The file system is mounted noexec.
       * EPERM  The file system is mounted nosuid and the file  has an SUID or 
SGID bit set.
       * E2BIG  The argument list is too big.
       * ENOEXEC The magic number in the file is incorrect.
       * EFAULT filename  points  outside  your  accessible address space.
       * ENAMETOOLONG filename is too long.
       * ENOENT The file does not exist.
       * ENOMEM Insufficient kernel memory was available.
       * ENOTDIR A component of the path prefix is not a  directory.
       * ELOOP  filename contains a circular reference (i.e., via a symbolic 
link)
       */
  
      if (errno == ENOEXEC
      /* Probably a script.
       * Have a look; if there's a "#!" header then try to emulate
       * the feature found in all modern OS's:
       * Interpret the line following the #! as a command line
       * in shell style.
       */
        && (argv = hashbang(filename, argv)) != NULL) {
  
          aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, NULL,
                          "Script %s needs interpreter %s to exec", filename, 
argv[0]);
  
        /* new filename is the interpreter to call */
        filename = argv[0];
  
        /* Restore argv[0] as on entry */
        if (argv0 != NULL)
            argv[0] = argv0;
  
        execve(filename, argv, envp);
  
        free(argv);
      }
      return -1;
  }
  
  /*---------------------------------------------------------------*/
  
  /*
   * From: [EMAIL PROTECTED] (Peter Wemm)
   * (taken from tcsh)
   * If exec() fails look first for a #! [word] [word] ....
   * If it is, splice the header into the argument list and retry.
   * Return value: the original argv array (sans argv[0]), with the
   * script's argument list prepended.
   * XXX: malloc() is used so that everything can be free()ed after a failure.
   */
  #define HACKBUFSZ 1024                /* Max chars in #! vector */
  #define HACKVECSZ 128         /* Max words in #! vector */
  static const char **hashbang(const char *filename, char **argv)
  {
      char lbuf[HACKBUFSZ];
      char *sargv[HACKVECSZ];
      const char **newargv;
      char *p, *ws;
      int fd;
      int sargc = 0;
      int i, j;
  #ifdef WIN32
      int fw = 0;                       /* found at least one word */
      int first_word = 0;
  #endif /* WIN32 */
  
      if ((fd = open(filename, O_RDONLY)) == -1)
        return NULL;
  
      if (read(fd, (char *) lbuf, 2) != 2
        || lbuf[0] != '#' || lbuf[1] != '!'
        || read(fd, (char *) lbuf, HACKBUFSZ) <= 0) {
        close(fd);
        return NULL;
      }
  
      close(fd);
  
      ws = NULL;                        /* word started = 0 */
  
      for (p = lbuf; p < &lbuf[HACKBUFSZ];)
        switch (*p) {
        case ' ':
        case '\t':
  #ifdef NEW_CRLF
        case '\r':
  #endif /*NEW_CRLF */
            if (ws) {           /* a blank after a word.. save it */
                *p = '\0';
  #ifndef WIN32
                if (sargc < HACKVECSZ - 1)
                    sargv[sargc++] = ws;
                ws = NULL;
  #else /* WIN32 */
                if (sargc < HACKVECSZ - 1) {
                    sargv[sargc] = first_word ? NULL : hb_subst(ws);
                    if (sargv[sargc] == NULL)
                        sargv[sargc] = ws;
                    sargc++;
                }
                ws = NULL;
                fw = 1;
                first_word = 1;
  #endif /* WIN32 */
            }
            p++;
            continue;
  
        case '\0':              /* Whoa!! what the hell happened */
            return NULL;
  
        case '\n':              /* The end of the line. */
            if (
  #ifdef WIN32
                   fw ||
  #endif /* WIN32 */
                   ws) {        /* terminate the last word */
                *p = '\0';
  #ifndef WIN32
                if (sargc < HACKVECSZ - 1)
                    sargv[sargc++] = ws;
  #else /* WIN32 */
                if (sargc < HACKVECSZ - 1) {    /* deal with the 1-word case */
                    sargv[sargc] = first_word ? NULL : hb_subst(ws);
                    if (sargv[sargc] == NULL)
                        sargv[sargc] = ws;
                    sargc++;
                }
  #endif /* !WIN32 */
                sargv[sargc] = NULL;
            }
            /* Count number of entries in the old argv vector */
            for (i = 0; argv[i] != NULL; ++i)
                continue;
            ++i;
  
            newargv = (char **) malloc((p - lbuf + 1) + (i + sargc + 1) * 
sizeof(*newargv));
            ws = &((char *) newargv)[(i + sargc + 1) * sizeof(*newargv)];
  
            /* Copy entries to allocated memory */
            for (j = 0; j < sargc; ++j) {
                newargv[j] = strcpy(ws, sargv[j]);
                ws += strlen(ws) + 1;   /* skip trailing '\0' */
            }
            newargv[sargc] = filename;
  
            /* Append the old array. The old argv[0] is skipped. */
            if (i > 1)
                memcpy(&newargv[sargc + 1], &argv[1], (i - 1) * 
sizeof(*newargv));
            newargv[sargc + i] = NULL;
  
            ws = NULL;
  
            return newargv;
  
        default:
            if (!ws)            /* Start a new word? */
                ws = p;
            p++;
            break;
        }
      return NULL;
  }
  #endif /* NEED_HASHBANG_EMUL */
  
  
  
  1.177     +13 -0     apachen/src/main/conf.h
  
  Index: conf.h
  ===================================================================
  RCS file: /home/cvs/apachen/src/main/conf.h,v
  retrieving revision 1.176
  retrieving revision 1.177
  diff -u -u -r1.176 -r1.177
  --- conf.h    1998/01/23 16:19:19     1.176
  +++ conf.h    1998/01/25 01:40:56     1.177
  @@ -467,6 +467,7 @@
   #define USE_SHMGET_SCOREBOARD
   #ifdef _OSD_POSIX /* BS2000-POSIX mainframe does not have syslog and needs 
initgroups */
   #define NEED_INITGROUPS
  +#define NEED_HASHBANG_EMUL /* execve() doesn't start shell scripts by 
default */
   #undef HAVE_SYSLOG
   #undef HAVE_SHMGET
   #undef USE_SHMGET_SCOREBOARD
  @@ -970,6 +971,18 @@
   
   #ifdef NO_OTHER_CHILD
   #define NO_RELIABLE_PIPED_LOGS
  +#endif
  +
  +/* When the underlying OS doesn't support exec() of scripts which start
  + * with a HASHBANG (#!) followed by interpreter name and args, define this.
  + */
  +#ifdef NEED_HASHBANG_EMUL
  +extern int ap_execle(const char *filename, const char *arg,...);
  +extern int ap_execve(const char *filename, const char *argv[],
  +                     const char *envp[]);
  +/* ap_execle() is a wrapper function around ap_execve(). */
  +#define execle  ap_execle
  +#define execve(path,argv,envp)  ap_execve(path,argv,envp)
   #endif
   
   /* Finding offsets of elements within structures.
  
  
  

Reply via email to