home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume21 / libiexec / part01 / iexec.c < prev    next >
C/C++ Source or Header  |  1991-07-25  |  8KB  |  389 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, if
  5.    dupi is in /usr/local/bin, /usr/local/bin is in the PATH,
  6.    and /usr/local/bin/dupi starts with "#!/bin/sh -x", then
  7. iexecvp ("dupi", ["dupi", "/usr/lib", NULL]);
  8.    is equivalent to
  9. execve ("/bin/sh", ["/bin/sh", "-x", "/usr/local/bin/dupi", "/usr/lib", NULL], environ);
  10.  
  11.   Written by David MacKenzie <djm@eng.umd.edu>
  12.   Version 1.6
  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. #ifndef UNISTD_MISSING
  21. #include <unistd.h>
  22. #endif
  23. #ifndef X_OK
  24. #define X_OK 1
  25. #endif
  26.  
  27. #ifndef LIMITS_MISSING
  28. #include <limits.h>
  29. #else
  30. #include <sys/param.h>
  31. #endif
  32.  
  33. #ifndef STDLIB_MISSING
  34. #include <stdlib.h>
  35. #else
  36. char *getenv ();
  37. char *malloc ();
  38. #endif
  39.  
  40. #ifdef __STDC__
  41. #include <stdarg.h>
  42. #else
  43. #include <varargs.h>
  44. #endif
  45.  
  46. extern char **environ;
  47.  
  48. /* Longest pathname allowed by the system. */
  49. #ifndef PATH_MAX
  50. #ifdef _PC_PATH_MAX
  51. #define PATH_MAX pathconf ("/", _PC_PATH_MAX)
  52. #else
  53. #ifdef MAXPATHLEN
  54. #define PATH_MAX MAXPATHLEN
  55. #else
  56. #define PATH_MAX 1024
  57. #endif
  58. #endif
  59. #endif
  60.  
  61. #ifndef ARG_MAX
  62. #ifdef _SC_ARG_MAX
  63. #define ARG_MAX sysconf (_SC_ARG_MAX)
  64. #else
  65. #ifdef NCARGS
  66. #define ARG_MAX NCARGS
  67. #else
  68. #define ARG_MAX 5120
  69. #endif
  70. #endif
  71. #endif
  72.  
  73. /* Maximum number of chars to read from the first line of a script. */
  74. #define MAXLINELEN 256
  75.  
  76. /* Search path to use if PATH is not set in environment. */
  77. #define DEFAULT_PATH ":/bin:/usr/bin"
  78.  
  79. /* Make sure we get the real execve from the C library. */
  80. #ifdef execve
  81. #undef execve
  82. #endif
  83.  
  84. /* Return a static string containing the full pathname of PROGRAM,
  85.    the first place it is found in the PATH environment variable.
  86.    Return 0 if it is not found. */
  87.  
  88. static char *
  89. full_pathname (program)
  90.      char *program;
  91. {
  92.   char *path;
  93.   char *start, *end;
  94.   static char *trycommand = 0;
  95.  
  96.   if (trycommand == 0)
  97.     {
  98.       trycommand = (char *) malloc (PATH_MAX);
  99.       if (trycommand == 0)
  100.     return 0;
  101.     }
  102.   /* If an absolute pathname, no need to search the PATH. */
  103.   if (*program == '/'
  104.       || !strncmp (program, "./", 2) || !strncmp (program, "../", 3))
  105.     {
  106.       strcpy (trycommand, program);
  107.       return trycommand;
  108.     }
  109.  
  110.   path = getenv ("PATH");
  111.   if (path == 0)
  112.     path = DEFAULT_PATH;
  113.   for (start = end = path; *end; start = end + 1)
  114.     {
  115.       register char *s, *d;
  116.  
  117.       end = strchr (start, ':');
  118.       if (end == 0)
  119.     end = strchr (start, '\0');
  120.       d = trycommand;
  121.       if (end == start)
  122.     *d++ = '.';
  123.       else
  124.     {
  125.       s = start;
  126.       while ((*d++ = *s++) != *end)
  127.         /* Do nothing. */ ;
  128.       --d;
  129.     }
  130.       *d++ = '/';
  131.       strcpy (d, program);
  132.       if (access (trycommand, X_OK) == 0)
  133.     return trycommand;
  134.     }
  135.   return 0;
  136. }
  137.  
  138. /* If FILE is a script, set `command' to the name of the program
  139.    that should run it.  If FILE specifies an argument for the program,
  140.    put it as a static value in `cmdarg'; otherwise set `cmdarg' to 0.
  141.    If SH_DEFAULT is nonzero, try to run files that do not start with "#!"
  142.    as /bin/sh scripts.
  143.    Return 1 if successful, 0 if not. */
  144.  
  145. static char *command, *cmdarg;
  146.  
  147. static int
  148. read_interpreter (file, sh_default)
  149.      char *file;
  150.      int sh_default;
  151. {
  152.   static char line[MAXLINELEN + 1];
  153.   register char *cp;
  154.   int fd, st;
  155.  
  156.   fd = open (file, O_RDONLY, 0);
  157.   if (fd == -1)
  158.     return 0;
  159.   st = read (fd, line, MAXLINELEN);
  160.   if (close (fd) == -1)
  161.     return 0;
  162.   if (st == -1)
  163.     return 0;
  164.   if (st < 5 || line[0] != '#' || line[1] != '!')
  165.     {
  166.       if (sh_default)
  167.     {
  168.       strcpy (line, "/bin/sh");
  169.       command = line;
  170.       cmdarg = 0;
  171.       return 1;
  172.     }
  173.       else
  174.     return 0;
  175.     }
  176.  
  177.   line[MAXLINELEN] = '\0';
  178.   cp = strchr (line, '\n');
  179.   if (cp == 0)
  180.     return 0;
  181.   *cp = '\0';
  182.  
  183.   /* Find start of program name. */
  184.   for (cp = line + 2; *cp == ' ' || *cp == '\t'; ++cp)
  185.     /* Do nothing. */ ;
  186.   command = cp;
  187.   /* Find end of program name. */
  188.   for (; *cp != '\0' && *cp != ' ' && *cp != '\t'; ++cp)
  189.     /* Do nothing. */ ;
  190.  
  191.   /* Find start of argument. */
  192.   cmdarg = 0;
  193.   if (*cp != '\0')
  194.     {
  195.       *cp++ = '\0';
  196.       for (; *cp == ' ' || *cp == '\t'; ++cp)
  197.     /* Do nothing. */ ;
  198.       if (*cp != '\0')
  199.     {
  200.       cmdarg = cp;
  201.       /* Find end of argument.  In BSD the argument goes to the end of
  202.          the line, but stopping at the first whitespace is more useful. */
  203.       for (; *cp != '\0' && *cp != ' ' && *cp != '\t'; ++cp)
  204.         /* Do nothing. */ ;
  205.       *cp = '\0';
  206.     }
  207.     }
  208.  
  209.   return 1;
  210. }
  211.  
  212. /* From null-terminated argument list ARGV, create a new argument list
  213.    containing `command' and, if non-0, `cmdarg', and SCRIPT_PATH.
  214.    Then try to run `command' with the new argument list and ENVP.
  215.    If it fails, return -1. */
  216.  
  217. static int
  218. script_execve (script_path, argv, envp)
  219.      char *script_path;
  220.      char **argv;
  221.      char **envp;
  222. {
  223.   register char **new_argv;
  224.   register char **ap;
  225.   register int argc = 0;
  226.  
  227.   new_argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 4)));
  228.   if (new_argv == 0)
  229.     return -1;
  230.  
  231.   new_argv[argc++] = command;
  232.   if (cmdarg)
  233.     new_argv[argc++] = cmdarg;
  234.   new_argv[argc++] = script_path;
  235.   /* Copy the rest of the arguments. */
  236.   for (ap = argv + 1; *ap; ++ap)
  237.     new_argv[argc++] = *ap;
  238.   new_argv[argc++] = 0;
  239.  
  240.   execve (command, new_argv, envp);
  241.   free (new_argv);
  242.   return -1;
  243. }
  244.  
  245. /* VARARGS */
  246. int
  247. #ifdef __STDC__
  248. iexecl (char *path, ...)
  249. #else
  250. iexecl (path, va_alist)
  251.      char *path;
  252.      va_dcl
  253. #endif
  254. {
  255.   va_list args;
  256.   register char **argv;
  257.   register int argc = 0;
  258.  
  259.   argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 1)));
  260.   if (argv == 0)
  261.     {
  262.       errno = ENOMEM;
  263.       return -1;
  264.     }
  265. #ifdef __STDC__
  266.   va_start (args, path);
  267. #else
  268.   va_start (args);
  269. #endif
  270.   while (argv[argc++] = va_arg (args, char *))
  271.     /* Do nothing. */ ;
  272.   va_end (args);
  273.   iexecve (path, argv, environ);
  274.   free (argv);
  275.   return -1;
  276. }
  277.  
  278. /* VARARGS */
  279. int
  280. #ifdef __STDC__
  281. iexecle (char *path, ...)
  282. #else
  283. iexecle (path, va_alist)
  284.      char *path;
  285.      va_dcl
  286. #endif
  287. {
  288.   va_list args;
  289.   register char **argv;
  290.   register int argc = 0;
  291.   char **envp;
  292.  
  293.   argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 1)));
  294.   if (argv == 0)
  295.     {
  296.       errno = ENOMEM;
  297.       return -1;
  298.     }
  299. #ifdef __STDC__
  300.   va_start (args, path);
  301. #else
  302.   va_start (args);
  303. #endif
  304.   while (argv[argc++] = va_arg (args, char *))
  305.     /* Do nothing. */ ;
  306.   envp = va_arg (args, char **);
  307.   va_end (args);
  308.   iexecve (path, argv, envp);
  309.   free (argv);
  310.   return -1;
  311. }
  312.  
  313. /* VARARGS */
  314. int
  315. #ifdef __STDC__
  316. iexeclp (char *path, ...)
  317. #else
  318. iexeclp (path, va_alist)
  319.      char *path;
  320.      va_dcl
  321. #endif
  322. {
  323.   va_list args;
  324.   register char **argv;
  325.   register int argc = 0;
  326.  
  327.   argv = (char **) malloc ((sizeof (char *) * (ARG_MAX + 1)));
  328.   if (argv == 0)
  329.     {
  330.       errno = ENOMEM;
  331.       return -1;
  332.     }
  333. #ifdef __STDC__
  334.   va_start (args, path);
  335. #else
  336.   va_start (args);
  337. #endif
  338.   while (argv[argc++] = va_arg (args, char *))
  339.     /* Do nothing. */ ;
  340.   va_end (args);
  341.   iexecvp (path, argv);
  342.   free (argv);
  343.   return -1;
  344. }
  345.  
  346. int
  347. iexecv (path, argv)
  348.      char *path;
  349.      char **argv;
  350. {
  351.   return iexecve (path, argv, environ);
  352. }
  353.  
  354. int
  355. iexecve (path, argv, envp)
  356.      char *path;
  357.      char **argv;
  358.      char **envp;
  359. {
  360.   if (execve (path, argv, envp) == -1 && errno == ENOEXEC)
  361.     {
  362.       if (read_interpreter (path, 0))
  363.     script_execve (path, argv, envp);
  364.       errno = ENOEXEC;
  365.     }
  366.   return -1;
  367. }
  368.  
  369. int
  370. iexecvp (path, argv)
  371.      char *path;
  372.      char **argv;
  373. {
  374.   /* Don't use execvp; it tries to run scripts in its own way. */
  375.   path = full_pathname (path);
  376.   if (path == 0)
  377.     {
  378.       errno = ENOENT;
  379.       return -1;
  380.     }
  381.   if (execve (path, argv, environ) == -1 && errno == ENOEXEC)
  382.     {
  383.       if (read_interpreter (path, 1))
  384.     script_execve (path, argv, environ);
  385.       errno = ENOEXEC;
  386.     }
  387.   return -1;
  388. }
  389.