home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3588 / iexec.c next >
Encoding:
C/C++ Source or Header  |  1991-07-04  |  6.3 KB  |  307 lines

  1. /* iexec.c -- script interpreter wrappers for exec functions
  2.  
  3.    These exec-family functions try to run a command interpreter
  4.    on scripts, like BSD-based kernels do.  Thus
  5. iexecvp ("dupi", ["dupi", "/usr/lib", NULL]);
  6.    is equivalent to
  7. execve ("/bin/sh", ["/bin/sh", "-x", "/usr/local/bin/dupi", "/usr/lib", NULL], environ);
  8.   assuming that dupi is in /usr/local/bin and /usr/local/bin/dupi starts
  9.   with "#!/bin/sh -x".
  10.  
  11.   David MacKenzie <djm@eng.umd.edu>.
  12.   Version 1.0.
  13.   This file is in the public domain. */
  14.  
  15. #include <sys/types.h>
  16. #include <fcntl.h>
  17. #include <errno.h>
  18. extern int errno;
  19. #include <string.h>
  20. #include <limits.h>
  21. #ifdef __STDC__
  22. #include <stdarg.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #else
  26. #include <varargs.h>
  27. char *getenv ();
  28. char *malloc ();
  29. #define X_OK 01
  30. #endif
  31. extern char **environ;
  32.  
  33. /* Longest pathname allowed by the system. */
  34. #ifndef PATH_MAX
  35. #define PATH_MAX 1024
  36. #endif
  37.  
  38. /* Maximum number of chars to read from the first line of a script. */
  39. #define MAXLINELEN 256
  40.  
  41. /* Return a static string containing the full pathname of PROGRAM,
  42.    the first place it is found in the PATH environment variable.
  43.    Return 0 if it is not found. */
  44.  
  45. static char *
  46. full_pathname (program)
  47.      char *program;
  48. {
  49.   char *path;
  50.   char *start, *end;
  51.   static char trycommand[PATH_MAX];
  52.  
  53.   /* If an absolute pathname, no need to search the PATH. */
  54.   if (*program == '/'
  55.       || !strncmp (program, "./", 2) || !strncmp (program, "../", 3))
  56.     {
  57.       strcpy (trycommand, program);
  58.       return trycommand;
  59.     }
  60.  
  61.   path = getenv ("PATH");
  62.   if (path == 0)
  63.     return 0;
  64.   for (start = end = path; *end; start = end + 1)
  65.     {
  66.       register char *s, *d;
  67.  
  68.       end = strchr (start, ':');
  69.       if (end == 0)
  70.     end = strchr (start, '\0');
  71.       d = trycommand;
  72.       if (end == start)
  73.     *d++ = '.';
  74.       else
  75.     {
  76.       s = start;
  77.       while ((*d++ = *s++) != *end)
  78.         /* Do nothing. */ ;
  79.       --d;
  80.     }
  81.       *d++ = '/';
  82.       strcpy (d, program);
  83.       if (access (trycommand, X_OK) == 0)
  84.     return trycommand;
  85.     }
  86.   return 0;
  87. }
  88.  
  89. /* If FILE is a script, set `command' to the name of the program
  90.    that should run it.  If FILE specifies an argument for the program,
  91.    put it as a static value in `cmdarg'; otherwise set `cmdarg' to 0.
  92.    Return 1 if successful, 0 if not. */
  93.  
  94. static char *command, *cmdarg;
  95.  
  96. static int
  97. read_interpreter (file)
  98.      char *file;
  99. {
  100.   static char line[MAXLINELEN];
  101.   register char *cp;
  102.   int fd, st;
  103.  
  104.   fd = open (file, O_RDONLY, 0);
  105.   if (fd == -1)
  106.     return 0;
  107.   st = read (fd, line, sizeof line);
  108.   if (close (fd) == -1)
  109.     return 0;
  110.   if (st == -1)
  111.     return 0;
  112.   if (st < 5 || line[0] != '#' || line[1] != '!')
  113.     {
  114.       strcpy (line, "/bin/sh");
  115.       command = line;
  116.       cmdarg = 0;
  117.       return 1;
  118.     }
  119.  
  120.   cp = strchr (line, '\n');
  121.   if (cp == 0)
  122.     return 0;
  123.   *cp = '\0';
  124.  
  125.   /* Find start of program name. */
  126.   for (cp = line + 2; *cp == ' ' || *cp == '\t'; ++cp)
  127.     /* Do nothing. */ ;
  128.   command = cp;
  129.   /* Find end of program name. */
  130.   for (; *cp != '\0' && *cp != ' ' && *cp != '\t'; ++cp)
  131.     /* Do nothing. */ ;
  132.   *cp = '\0';
  133.  
  134.   /* Find start of argument. */
  135.   for (; *cp == ' ' || *cp == '\t'; ++cp)
  136.     /* Do nothing. */ ;
  137.   if (*cp != '\0')
  138.     cmdarg = cp;
  139.   else
  140.     cmdarg = 0;
  141.   /* Find end of argument. */
  142.   for (; *cp != '\0' && *cp != ' ' && *cp != '\t'; ++cp)
  143.     /* Do nothing. */ ;
  144.   *cp = '\0';
  145.  
  146.   return 1;
  147. }
  148.  
  149. /* From null-terminated argument list ARGV, create a new argument list
  150.    containing `command' and, if non-0, `cmdarg', and SCRIPT_PATH.
  151.    Then try to run `command' with the new argument list and ENVP.
  152.    If it fails, return -1. */
  153.  
  154. static int
  155. script_execve (script_path, argv, envp)
  156.      char *script_path;
  157.      char **argv;
  158.      char **envp;
  159. {
  160.   register char **new_argv;
  161.   register char **ap;
  162.   register int argc;
  163.  
  164.   /* Count the non-null elements in ARGV. */
  165.   for (argc = 0; argv[argc]; ++argc)
  166.     /* Do nothing. */ ;
  167.   argc += 3;            /* For command, cmdarg, null. */
  168.   new_argv = (char **) malloc (sizeof (char *) * argc);
  169.   if (new_argv == 0)
  170.     return -1;
  171.   argc = 0;
  172.   new_argv[argc++] = command;
  173.   if (cmdarg)
  174.     new_argv[argc++] = cmdarg;
  175.   new_argv[argc++] = script_path;
  176.   /* Copy the rest of the arguments. */
  177.   for (ap = argv + 1; *ap; ++ap)
  178.     new_argv[argc++] = *ap;
  179.   new_argv[argc++] = 0;
  180.  
  181.   execve (command, new_argv, envp);
  182.   free (new_argv);
  183.   return -1;
  184. }
  185.  
  186. /* VARARGS */
  187. int
  188. #ifdef __STDC__
  189. iexecl (char *path, ...)
  190. #else
  191. iexecl (path, va_alist)
  192.      char *path;
  193.      va_dcl
  194. #endif
  195. {
  196.   va_list args;
  197.   char *argv[ARG_MAX + 1];
  198.   register int argc = 0;
  199.  
  200. #ifdef __STDC__
  201.   va_start (args, path);
  202. #else
  203.   va_start (args);
  204. #endif
  205.   while (argv[argc++] = va_arg (args, char *))
  206.     /* Do nothing. */ ;
  207.   va_end (args);
  208.   return iexecve (path, argv, environ);
  209. }
  210.  
  211. /* VARARGS */
  212. int
  213. #ifdef __STDC__
  214. iexecle (char *path, ...)
  215. #else
  216. iexecle (path, va_alist)
  217.      char *path;
  218.      va_dcl
  219. #endif
  220. {
  221.   va_list args;
  222.   char *argv[ARG_MAX + 1];
  223.   register int argc = 0;
  224.   char **envp;
  225.  
  226. #ifdef __STDC__
  227.   va_start (args, path);
  228. #else
  229.   va_start (args);
  230. #endif
  231.   while (argv[argc++] = va_arg (args, char *))
  232.     /* Do nothing. */ ;
  233.   envp = va_arg (args, char **);
  234.   va_end (args);
  235.   return iexecve (path, argv, envp);
  236. }
  237.  
  238. /* VARARGS */
  239. int
  240. #ifdef __STDC__
  241. iexeclp (char *path, ...)
  242. #else
  243. iexeclp (path, va_alist)
  244.      char *path;
  245.      va_dcl
  246. #endif
  247. {
  248.   va_list args;
  249.   char *argv[ARG_MAX + 1];
  250.   register int argc = 0;
  251.  
  252. #ifdef __STDC__
  253.   va_start (args, path);
  254. #else
  255.   va_start (args);
  256. #endif
  257.   while (argv[argc++] = va_arg (args, char *))
  258.     /* Do nothing. */ ;
  259.   va_end (args);
  260.   return iexecvp (path, argv);
  261. }
  262.  
  263. int
  264. iexecv (path, argv)
  265.      char *path;
  266.      char **argv;
  267. {
  268.   return iexecve (path, argv, environ);
  269. }
  270.  
  271. int
  272. iexecve (path, argv, envp)
  273.      char *path;
  274.      char **argv;
  275.      char **envp;
  276. {
  277.   if (execve (path, argv, envp) == -1 && errno == ENOEXEC)
  278.     {
  279.       if (read_interpreter (path))
  280.     script_execve (path, argv, envp);
  281.       errno = ENOEXEC;
  282.     }
  283.   return -1;
  284. }
  285.  
  286. int
  287. iexecvp (path, argv)
  288.      char *path;
  289.      char **argv;
  290. {
  291.   /* Don't use execvp; it tries to run scripts in its own way on
  292.      some systems. */
  293.   path = full_pathname (path);
  294.   if (path == 0)
  295.     {
  296.       errno = ENOENT;
  297.       return -1;
  298.     }
  299.   if (execv (path, argv) == -1 && errno == ENOEXEC)
  300.     {
  301.       if (read_interpreter (path))
  302.     script_execve (path, argv, environ);
  303.       errno = ENOEXEC;
  304.     }
  305.   return -1;
  306. }
  307.