home *** CD-ROM | disk | FTP | other *** search
- /* iexec.c -- script interpreter wrappers for exec functions
-
- These exec-family functions try to run a command interpreter
- on scripts, like BSD-based kernels do. Thus
- iexecvp ("dupi", ["dupi", "/usr/lib", NULL]);
- is equivalent to
- execve ("/bin/sh", ["/bin/sh", "-x", "/usr/local/bin/dupi", "/usr/lib", NULL], environ);
- assuming that dupi is in /usr/local/bin and /usr/local/bin/dupi starts
- with "#!/bin/sh -x".
-
- David MacKenzie <djm@eng.umd.edu>.
- Version 1.0.
- This file is in the public domain. */
-
- #include <sys/types.h>
- #include <fcntl.h>
- #include <errno.h>
- extern int errno;
- #include <string.h>
- #include <limits.h>
- #ifdef __STDC__
- #include <stdarg.h>
- #include <stdlib.h>
- #include <unistd.h>
- #else
- #include <varargs.h>
- char *getenv ();
- char *malloc ();
- #define X_OK 01
- #endif
- extern char **environ;
-
- /* Longest pathname allowed by the system. */
- #ifndef PATH_MAX
- #define PATH_MAX 1024
- #endif
-
- /* Maximum number of chars to read from the first line of a script. */
- #define MAXLINELEN 256
-
- /* Return a static string containing the full pathname of PROGRAM,
- the first place it is found in the PATH environment variable.
- Return 0 if it is not found. */
-
- static char *
- full_pathname (program)
- char *program;
- {
- char *path;
- char *start, *end;
- static char trycommand[PATH_MAX];
-
- /* If an absolute pathname, no need to search the PATH. */
- if (*program == '/'
- || !strncmp (program, "./", 2) || !strncmp (program, "../", 3))
- {
- strcpy (trycommand, program);
- return trycommand;
- }
-
- path = getenv ("PATH");
- if (path == 0)
- return 0;
- for (start = end = path; *end; start = end + 1)
- {
- register char *s, *d;
-
- end = strchr (start, ':');
- if (end == 0)
- end = strchr (start, '\0');
- d = trycommand;
- if (end == start)
- *d++ = '.';
- else
- {
- s = start;
- while ((*d++ = *s++) != *end)
- /* Do nothing. */ ;
- --d;
- }
- *d++ = '/';
- strcpy (d, program);
- if (access (trycommand, X_OK) == 0)
- return trycommand;
- }
- return 0;
- }
-
- /* If FILE is a script, set `command' to the name of the program
- that should run it. If FILE specifies an argument for the program,
- put it as a static value in `cmdarg'; otherwise set `cmdarg' to 0.
- Return 1 if successful, 0 if not. */
-
- static char *command, *cmdarg;
-
- static int
- read_interpreter (file)
- char *file;
- {
- static char line[MAXLINELEN];
- register char *cp;
- int fd, st;
-
- fd = open (file, O_RDONLY, 0);
- if (fd == -1)
- return 0;
- st = read (fd, line, sizeof line);
- if (close (fd) == -1)
- return 0;
- if (st == -1)
- return 0;
- if (st < 5 || line[0] != '#' || line[1] != '!')
- {
- strcpy (line, "/bin/sh");
- command = line;
- cmdarg = 0;
- return 1;
- }
-
- cp = strchr (line, '\n');
- if (cp == 0)
- return 0;
- *cp = '\0';
-
- /* Find start of program name. */
- for (cp = line + 2; *cp == ' ' || *cp == '\t'; ++cp)
- /* Do nothing. */ ;
- command = cp;
- /* Find end of program name. */
- for (; *cp != '\0' && *cp != ' ' && *cp != '\t'; ++cp)
- /* Do nothing. */ ;
- *cp = '\0';
-
- /* Find start of argument. */
- for (; *cp == ' ' || *cp == '\t'; ++cp)
- /* Do nothing. */ ;
- if (*cp != '\0')
- cmdarg = cp;
- else
- cmdarg = 0;
- /* Find end of argument. */
- for (; *cp != '\0' && *cp != ' ' && *cp != '\t'; ++cp)
- /* Do nothing. */ ;
- *cp = '\0';
-
- return 1;
- }
-
- /* From null-terminated argument list ARGV, create a new argument list
- containing `command' and, if non-0, `cmdarg', and SCRIPT_PATH.
- Then try to run `command' with the new argument list and ENVP.
- If it fails, return -1. */
-
- static int
- script_execve (script_path, argv, envp)
- char *script_path;
- char **argv;
- char **envp;
- {
- register char **new_argv;
- register char **ap;
- register int argc;
-
- /* Count the non-null elements in ARGV. */
- for (argc = 0; argv[argc]; ++argc)
- /* Do nothing. */ ;
- argc += 3; /* For command, cmdarg, null. */
- new_argv = (char **) malloc (sizeof (char *) * argc);
- if (new_argv == 0)
- return -1;
- argc = 0;
- new_argv[argc++] = command;
- if (cmdarg)
- new_argv[argc++] = cmdarg;
- new_argv[argc++] = script_path;
- /* Copy the rest of the arguments. */
- for (ap = argv + 1; *ap; ++ap)
- new_argv[argc++] = *ap;
- new_argv[argc++] = 0;
-
- execve (command, new_argv, envp);
- free (new_argv);
- return -1;
- }
-
- /* VARARGS */
- int
- #ifdef __STDC__
- iexecl (char *path, ...)
- #else
- iexecl (path, va_alist)
- char *path;
- va_dcl
- #endif
- {
- va_list args;
- char *argv[ARG_MAX + 1];
- register int argc = 0;
-
- #ifdef __STDC__
- va_start (args, path);
- #else
- va_start (args);
- #endif
- while (argv[argc++] = va_arg (args, char *))
- /* Do nothing. */ ;
- va_end (args);
- return iexecve (path, argv, environ);
- }
-
- /* VARARGS */
- int
- #ifdef __STDC__
- iexecle (char *path, ...)
- #else
- iexecle (path, va_alist)
- char *path;
- va_dcl
- #endif
- {
- va_list args;
- char *argv[ARG_MAX + 1];
- register int argc = 0;
- char **envp;
-
- #ifdef __STDC__
- va_start (args, path);
- #else
- va_start (args);
- #endif
- while (argv[argc++] = va_arg (args, char *))
- /* Do nothing. */ ;
- envp = va_arg (args, char **);
- va_end (args);
- return iexecve (path, argv, envp);
- }
-
- /* VARARGS */
- int
- #ifdef __STDC__
- iexeclp (char *path, ...)
- #else
- iexeclp (path, va_alist)
- char *path;
- va_dcl
- #endif
- {
- va_list args;
- char *argv[ARG_MAX + 1];
- register int argc = 0;
-
- #ifdef __STDC__
- va_start (args, path);
- #else
- va_start (args);
- #endif
- while (argv[argc++] = va_arg (args, char *))
- /* Do nothing. */ ;
- va_end (args);
- return iexecvp (path, argv);
- }
-
- int
- iexecv (path, argv)
- char *path;
- char **argv;
- {
- return iexecve (path, argv, environ);
- }
-
- int
- iexecve (path, argv, envp)
- char *path;
- char **argv;
- char **envp;
- {
- if (execve (path, argv, envp) == -1 && errno == ENOEXEC)
- {
- if (read_interpreter (path))
- script_execve (path, argv, envp);
- errno = ENOEXEC;
- }
- return -1;
- }
-
- int
- iexecvp (path, argv)
- char *path;
- char **argv;
- {
- /* Don't use execvp; it tries to run scripts in its own way on
- some systems. */
- path = full_pathname (path);
- if (path == 0)
- {
- errno = ENOENT;
- return -1;
- }
- if (execv (path, argv) == -1 && errno == ENOEXEC)
- {
- if (read_interpreter (path))
- script_execve (path, argv, environ);
- errno = ENOEXEC;
- }
- return -1;
- }
-