-
-
-#ifndef VMS
-
-static void
-exec_simple_command (const char *command)
-{
- char *av[1024];
- int ac = 0;
- char *token = strtok (strdup(command), " \t");
- while (token)
- {
- av[ac++] = token;
- token = strtok(0, " \t");
- }
- av[ac] = 0;
-
- execvp (av[0], av); /* shouldn't return. */
-
- {
- char buf [512];
- sprintf (buf, "%s: could not execute \"%s\"", blurb(), av[0]);
- perror (buf);
-
- if (errno == ENOENT &&
- (token = getenv("PATH")))
- {
-# ifndef PATH_MAX
-# ifdef MAXPATHLEN
-# define PATH_MAX MAXPATHLEN
-# else
-# define PATH_MAX 2048
-# endif
-# endif
- char path[PATH_MAX];
- fprintf (stderr, "\n");
- *path = 0;
-# if defined(HAVE_GETCWD)
- getcwd (path, sizeof(path));
-# elif defined(HAVE_GETWD)
- getwd (path);
-# endif
- if (*path)
- fprintf (stderr, " Current directory is: %s\n", path);
- fprintf (stderr, " PATH is:\n");
- token = strtok (strdup(token), ":");
- while (token)
- {
- fprintf (stderr, " %s\n", token);
- token = strtok(0, ":");
- }
- fprintf (stderr, "\n");
- }
- }
- fflush(stderr);
- fflush(stdout);
- exit (1); /* Note that this only exits a child fork. */
-}
-
-
-static void
-exec_complex_command (const char *shell, const char *command)
-{
- char *av[5];
- int ac = 0;
- char *command2 = (char *) malloc (strlen (command) + 10);
- const char *s;
- int got_eq = 0;
- const char *after_vars;
-
- /* Skip leading whitespace.
- */
- while (*command == ' ' || *command == '\t')
- command++;
-
- /* If the string has a series of tokens with "=" in them at them, set
- `after_vars' to point into the string after those tokens and any
- trailing whitespace. Otherwise, after_vars == command.
- */
- after_vars = command;
- for (s = command; *s; s++)
- {
- if (*s == '=') got_eq = 1;
- else if (*s == ' ')
- {
- if (got_eq)
- {
- while (*s == ' ' || *s == '\t')
- s++;
- after_vars = s;
- got_eq = 0;
- }
- else
- break;
- }
- }
-
- *command2 = 0;
- strncat (command2, command, after_vars - command);
- strcat (command2, "exec ");
- strcat (command2, after_vars);
-
- /* We have now done these transformations:
- "foo -x -y" ==> "exec foo -x -y"
- "BLAT=foop foo -x" ==> "BLAT=foop exec foo -x"
- "BLAT=foop A=b foo -x" ==> "BLAT=foop A=b exec foo -x"
- */
-
-
- /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
- av [ac++] = (char *) shell;
- av [ac++] = "-c";
- av [ac++] = command2;
- av [ac] = 0;
-
- execvp (av[0], av); /* shouldn't return. */
-
- {
- char buf [512];
- sprintf (buf, "%s: execvp(\"%s\") failed", blurb(), av[0]);
- perror (buf);
- fflush(stderr);
- fflush(stdout);
- exit (1); /* Note that this only exits a child fork. */
- }
-}
-
-#else /* VMS */
-
-static void
-exec_vms_command (const char *command)
-{
- system (command);
- fflush (stderr);
- fflush (stdout);
- exit (1); /* Note that this only exits a child fork. */
-}
-
-#endif /* !VMS */
-
-
-static void
-exec_screenhack (saver_info *si, const char *command)
-{
- /* I don't believe what a sorry excuse for an operating system UNIX is!
-
- - I want to spawn a process.
- - I want to know it's pid so that I can kill it.
- - I would like to receive a message when it dies of natural causes.
- - I want the spawned process to have user-specified arguments.
-
- If shell metacharacters are present (wildcards, backquotes, etc), the
- only way to parse those arguments is to run a shell to do the parsing
- for you.
-
- And the only way to know the pid of the process is to fork() and exec()
- it in the spawned side of the fork.
-
- But if you're running a shell to parse your arguments, this gives you
- the pid of the *shell*, not the pid of the *process* that you're
- actually interested in, which is an *inferior* of the shell. This also
- means that the SIGCHLD you get applies to the shell, not its inferior.
- (Why isn't that sufficient? I don't remember any more, but it turns
- out that it isn't.)
-
- So, the only solution, when metacharacters are present, is to force the
- shell to exec() its inferior. What a fucking hack! We prepend "exec "
- to the command string, and hope it doesn't contain unquoted semicolons
- or ampersands (we don't search for them, because we don't want to
- prohibit their use in quoted strings (messages, for example) and parsing
- out the various quote characters is too much of a pain.)
-
- (Actually, Clint Wong <clint@jts.com> points out that process groups
- might be used to take care of this problem; this may be worth considering
- some day, except that, 1: this code works now, so why fix it, and 2: from
- what I've seen in Emacs, dealing with process groups isn't especially
- portable.)
- */
- saver_preferences *p = &si->prefs;
-
-#ifndef VMS
- Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
- /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
-
- if (getuid() == (uid_t) 0 || geteuid() == (uid_t) 0)
- {
- /* If you're thinking of commenting this out, think again.
- If you do so, you will open a security hole. Mail jwz
- so that he may enlighten you as to the error of your ways.
- */
- fprintf (stderr, "%s: we're still running as root! Disaster!\n",
- blurb());
- saver_exit (si, 1, 0);
- }
-
- if (p->verbose_p)
- fprintf (stderr, "%s: spawning \"%s\" in pid %lu%s.\n",
- blurb(), command, (unsigned long) getpid (),
- (hairy_p ? " (via shell)" : ""));
-
- if (hairy_p)
- /* If it contains any shell metacharacters, do it the hard way,
- and fork a shell to parse the arguments for us. */
- exec_complex_command (p->shell, command);
- else
- /* Otherwise, we can just exec the program directly. */
- exec_simple_command (command);
-
-#else /* VMS */
- if (p->verbose_p)
- fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
- blurb(), command, getpid());
- exec_vms_command (command);
-#endif /* VMS */
-
- abort(); /* that shouldn't have returned. */
-}
-
-