martin      98/12/22 16:20:59

  Modified:    src/ap   ap_execve.c
  Log:
  The hashbang emulation code was "forgetting" to use the default shell
  for scripts without a "#!/interpreter" staring line. Now it behaves
  like a regular shell or a regular OS's execve() implementation.
  
  Revision  Changes    Path
  1.10      +59 -17    apache-1.3/src/ap/ap_execve.c
  
  Index: ap_execve.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/ap/ap_execve.c,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ap_execve.c       1998/03/31 12:52:10     1.9
  +++ ap_execve.c       1998/12/23 00:20:58     1.10
  @@ -126,7 +126,8 @@
       }
       va_end(adummy);
   
  -    argv = (char **) malloc((argc + 2) * sizeof(*argv));
  +    if ((argv = (char **) malloc((argc + 2) * sizeof(*argv))) == NULL)
  +     return -1;
   
       /* Pass two --- copy the argument strings into the result space */
       va_start(adummy, argv0);
  @@ -143,10 +144,27 @@
       return ret;
   }
   
  +/* Count number of entries in vector "args", including the trailing NULL 
entry
  + */
  +static int
  +count_args(const char **args)
  +{
  +    int i;
  +    for (i = 0; args[i] != NULL; ++i) {
  +     continue;
  +    }
  +    return i+1;
  +}
  +
  +/* Emulate the execve call, respecting a #!/interpreter line if present.
  + * On "real" unixes, the kernel does this.
  + * We have to fiddle with the argv array to make it work on platforms
  + * which don't support the "hashbang" interpreter line by default.
  + */
   int ap_execve(const char *filename, const char *argv[],
              const char *envp[])
   {
  -    const char *argv0 = argv[0];
  +    const char **script_argv;
       extern char **environ;
   
       if (envp == NULL) {
  @@ -174,26 +192,50 @@
        * 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) {
  +    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.
  +      */
  +     if ((script_argv = hashbang(filename, argv)) != NULL) {
  +
  +         /* new filename is the interpreter to call */
  +         filename = script_argv[0];
  +
  +         /* Restore argv[0] as on entry */
  +         if (argv[0] != NULL) {
  +             script_argv[0] = argv[0];
  +         }
   
  -     /* new filename is the interpreter to call */
  -     filename = argv[0];
  +         execve(filename, script_argv, envp);
   
  -     /* Restore argv[0] as on entry */
  -     if (argv0 != NULL) {
  -         argv[0] = argv0;
  +         free(script_argv);
        }
  +     /*
  +      * Script doesn't start with a hashbang line!
  +      * So, try to have the default shell execute it.
  +      * For this, the size of argv must be increased by one
  +      * entry: the shell's name. The remaining args are appended.
  +      */
  +     else {
  +         int i = count_args(argv) + 1;   /* +1 for leading SHELL_PATH */
  +
  +         if ((script_argv = malloc(sizeof(*script_argv) * i)) == NULL)
  +             return -1;
  +
  +         script_argv[0] = SHELL_PATH;
  +
  +         while (i > 0) {
  +             script_argv[i] = argv[i-1];
  +             --i;
  +         }
   
  -     execve(filename, argv, envp);
  +         execve(SHELL_PATH, script_argv, envp);
   
  -     free(argv);
  +         free(script_argv);
  +     }
       }
       return -1;
   }
  
  
  

Reply via email to