home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume21
/
libiexec
/
part01
/
iexec.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-25
|
8KB
|
389 lines
/* 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, if
dupi is in /usr/local/bin, /usr/local/bin is in the PATH,
and /usr/local/bin/dupi starts with "#!/bin/sh -x", then
iexecvp ("dupi", ["dupi", "/usr/lib", NULL]);
is equivalent to
execve ("/bin/sh", ["/bin/sh", "-x", "/usr/local/bin/dupi", "/usr/lib", NULL], environ);
Written by David MacKenzie <djm@eng.umd.edu>
Version 1.6
This file is in the public domain. */
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
extern int errno;
#include <string.h>
#ifndef UNISTD_MISSING
#include <unistd.h>
#endif
#ifndef X_OK
#define X_OK 1
#endif
#ifndef LIMITS_MISSING
#include <limits.h>
#else
#include <sys/param.h>
#endif
#ifndef STDLIB_MISSING
#include <stdlib.h>
#else
char *getenv ();
char *malloc ();
#endif
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
extern char **environ;
/* Longest pathname allowed by the system. */
#ifndef PATH_MAX
#ifdef _PC_PATH_MAX
#define PATH_MAX pathconf ("/", _PC_PATH_MAX)
#else
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN
#else
#define PATH_MAX 1024
#endif
#endif
#endif
#ifndef ARG_MAX
#ifdef _SC_ARG_MAX
#define ARG_MAX sysconf (_SC_ARG_MAX)
#else
#ifdef NCARGS
#define ARG_MAX NCARGS
#else
#define ARG_MAX 5120
#endif
#endif
#endif
/* Maximum number of chars to read from the first line of a script. */
#define MAXLINELEN 256
/* Search path to use if PATH is not set in environment. */
#define DEFAULT_PATH ":/bin:/usr/bin"
/* Make sure we get the real execve from the C library. */
#ifdef execve
#undef execve
#endif
/* 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 = 0;
if (trycommand == 0)
{
trycommand = (char *) malloc (PATH_MAX);
if (trycommand == 0)
return 0;
}
/* 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)
path = DEFAULT_PATH;
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.
If SH_DEFAULT is nonzero, try to run files that do not start with "#!"
as /bin/sh scripts.
Return 1 if successful, 0 if not. */
static char *command, *cmdarg;
static int
read_interpreter (file, sh_default)
char *file;
int sh_default;
{
static char line[MAXLINELEN + 1];
register char *cp;
int fd, st;
fd = open (file, O_RDONLY, 0);
if (fd == -1)
return 0;
st = read (fd, line, MAXLINELEN);
if (close (fd) == -1)
return 0;
if (st == -1)
return 0;
if (st < 5 || line[0] != '#' || line[1] != '!')
{
if (sh_default)
{
strcpy (line, "/bin/sh");
command = line;
cmdarg = 0;
return 1;
}
else
return 0;
}
line[MAXLINELEN] = '\0';
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. */ ;
/* Find start of argument. */
cmdarg = 0;
if (*cp != '\0')
{
*cp++ = '\0';
for (; *cp == ' ' || *cp == '\t'; ++cp)
/* Do nothing. */ ;
if (*cp != '\0')
{
cmdarg = cp;
/* Find end of argument. In BSD the argument goes to the end of
the line, but stopping at the first whitespace is more useful. */
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 = 0;
new_argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 4)));
if (new_argv == 0)
return -1;
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;
register char **argv;
register int argc = 0;
argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 1)));
if (argv == 0)
{
errno = ENOMEM;
return -1;
}
#ifdef __STDC__
va_start (args, path);
#else
va_start (args);
#endif
while (argv[argc++] = va_arg (args, char *))
/* Do nothing. */ ;
va_end (args);
iexecve (path, argv, environ);
free (argv);
return -1;
}
/* VARARGS */
int
#ifdef __STDC__
iexecle (char *path, ...)
#else
iexecle (path, va_alist)
char *path;
va_dcl
#endif
{
va_list args;
register char **argv;
register int argc = 0;
char **envp;
argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 1)));
if (argv == 0)
{
errno = ENOMEM;
return -1;
}
#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);
iexecve (path, argv, envp);
free (argv);
return -1;
}
/* VARARGS */
int
#ifdef __STDC__
iexeclp (char *path, ...)
#else
iexeclp (path, va_alist)
char *path;
va_dcl
#endif
{
va_list args;
register char **argv;
register int argc = 0;
argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 1)));
if (argv == 0)
{
errno = ENOMEM;
return -1;
}
#ifdef __STDC__
va_start (args, path);
#else
va_start (args);
#endif
while (argv[argc++] = va_arg (args, char *))
/* Do nothing. */ ;
va_end (args);
iexecvp (path, argv);
free (argv);
return -1;
}
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, 0))
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. */
path = full_pathname (path);
if (path == 0)
{
errno = ENOENT;
return -1;
}
if (execve (path, argv, environ) == -1 && errno == ENOEXEC)
{
if (read_interpreter (path, 1))
script_execve (path, argv, environ);
errno = ENOEXEC;
}
return -1;
}