# include <sys/wait.h> /* for waitpid() and associated macros */
#endif
-#if (defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)) || \
- defined(HAVE_SETRLIMIT)
-# include <sys/resource.h> /* for setpriority() and PRIO_PROCESS */
- /* and also setrlimit() and RLIMIT_AS */
+#ifdef HAVE_SETRLIMIT
+# include <sys/resource.h> /* for setrlimit() and RLIMIT_AS */
#endif
#ifdef VMS
extern saver_info *global_si_kludge; /* I hate C so much... */
-static void
-nice_subproc (int nice_level)
-{
- if (nice_level == 0)
- return;
-
-#if defined(HAVE_NICE)
- {
- int old_nice = nice (0);
- int n = nice_level - old_nice;
- errno = 0;
- if (nice (n) == -1 && errno != 0)
- {
- char buf [512];
- sprintf (buf, "%s: nice(%d) failed", blurb(), n);
- perror (buf);
- }
- }
-#elif defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
- if (setpriority (PRIO_PROCESS, getpid(), nice_level) != 0)
- {
- char buf [512];
- sprintf (buf, "%s: setpriority(PRIO_PROCESS, %lu, %d) failed",
- blurb(), (unsigned long) getpid(), nice_level);
- perror (buf);
- }
-#else
- fprintf (stderr,
- "%s: don't know how to change process priority on this system.\n",
- blurb());
-
-#endif
-}
-
/* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
Setting this lets you put a cap on how much memory a process can allocate.
+
+ Except the "and mmap()" part kinda makes this useless, since many GL
+ implementations end up using mmap() to pull the whole frame buffer into
+ memory (or something along those lines) making it appear processes are
+ using hundreds of megabytes when in fact they're using very little, and
+ we end up capping their mallocs prematurely. YAY!
*/
#if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
# define RLIMIT_AS RLIMIT_VMEM
#endif /* HAVE_SETRLIMIT && RLIMIT_AS */
}
-
-
-#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_screen_info *ssi, 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_info *si = ssi->global;
- 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: %d: spawning \"%s\" in pid %lu%s.\n",
- blurb(), ssi->number, 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: %d: spawning \"%s\" in pid %lu.\n",
- blurb(), ssi->number, command, getpid());
- exec_vms_command (command);
-#endif /* VMS */
-
- abort(); /* that shouldn't have returned. */
-}
-
-
\f
/* Management of child processes, and de-zombification.
*/
}
+static void
+print_path_error (const char *program)
+{
+ char buf [512];
+ char *cmd = strdup (program);
+ char *token = strchr (cmd, ' ');
+
+ if (token) *token = 0;
+ sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
+ free (cmd);
+ 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");
+ }
+}
+
+
static void
spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
{
*/
if (p->verbose_p)
fprintf(stderr,
- "%s: no suitable visuals for these programs.\n",
- blurb());
+ "%s: %d: no programs enabled, or no suitable visuals.\n",
+ blurb(), ssi->number);
return;
}
else
case 0:
close (ConnectionNumber (si->dpy)); /* close display fd */
- nice_subproc (p->nice_inferior); /* change process priority */
limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
hack_subproc_environment (ssi); /* set $DISPLAY */
- exec_screenhack (ssi, hack->command); /* this does not return */
- abort();
+
+ if (p->verbose_p)
+ fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
+ blurb(), ssi->number, hack->command,
+ (unsigned long) getpid ());
+
+ exec_command (p->shell, hack->command, p->nice_inferior);
+ /* If that returned, we were unable to exec the subprocess. */
+ print_path_error (hack->command);
+ exit (1); /* exits child fork */
break;
default:
if (putenv (npath))
abort ();
+
+ /* don't free (npath) -- some implementations of putenv (BSD 4.4,
+ glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
+ do not. So we must leak it (and/or the previous setting). Yay.
+ */
}
#endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
}
#ifdef HAVE_PUTENV
if (putenv (ndpy))
abort ();
+ /* do not free(ndpy) -- see above. */
#endif /* HAVE_PUTENV */
}
}
-/* Re-execs the process with the arguments in saved_argv.
- Does not return unless there was an error.
+/* Re-execs the process with the arguments in saved_argv. Does not return.
*/
void
restart_process (saver_info *si)
{
+ fflush (stdout);
+ fflush (stderr);
+ shutdown_stderr (si);
if (si->prefs.verbose_p)
{
int i;
- fprintf (real_stderr, "%s: re-executing", blurb());
+ fprintf (stderr, "%s: re-executing", blurb());
for (i = 0; saved_argv[i]; i++)
- fprintf (real_stderr, " %s", saved_argv[i]);
- fprintf (real_stderr, "\n");
+ fprintf (stderr, " %s", saved_argv[i]);
+ fprintf (stderr, "\n");
}
- describe_uids (si, real_stderr);
- fprintf (real_stderr, "\n");
+ describe_uids (si, stderr);
+ fprintf (stderr, "\n");
- fflush (real_stdout);
- fflush (real_stderr);
+ fflush (stdout);
+ fflush (stderr);
execvp (saved_argv [0], saved_argv); /* shouldn't return */
{
char buf [512];
sprintf (buf, "%s: could not restart process", blurb());
perror(buf);
fflush(stderr);
+ abort();
}
- XBell(si->dpy, 0);
}