~ubuntu-branches/ubuntu/dapper/xscreensaver/dapper

« back to all changes in this revision

Viewing changes to driver/subprocs.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-11 21:00:42 UTC
  • mfrom: (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051011210042-u7q6zslgevdxspr3
Tags: 4.21-4ubuntu17
updated pt_BR again, fixed to UTF-8 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* subprocs.c --- choosing, spawning, and killing screenhacks.
2
 
 * xscreensaver, Copyright (c) 1991-2001 Jamie Zawinski <jwz@jwz.org>
 
2
 * xscreensaver, Copyright (c) 1991-2005 Jamie Zawinski <jwz@jwz.org>
3
3
 *
4
4
 * Permission to use, copy, modify, distribute, and sell this software and its
5
5
 * documentation for any purpose is hereby granted without fee, provided that
30
30
# include <sys/wait.h>          /* for waitpid() and associated macros */
31
31
#endif
32
32
 
33
 
#if (defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)) || \
34
 
     defined(HAVE_SETRLIMIT)
35
 
# include <sys/resource.h>      /* for setpriority() and PRIO_PROCESS */
36
 
                                /* and also setrlimit() and RLIMIT_AS */
 
33
#ifdef HAVE_SETRLIMIT
 
34
# include <sys/resource.h>      /* for setrlimit() and RLIMIT_AS */
37
35
#endif
38
36
 
39
37
#ifdef VMS
72
70
 
73
71
extern saver_info *global_si_kludge;    /* I hate C so much... */
74
72
 
75
 
static void
76
 
nice_subproc (int nice_level)
77
 
{
78
 
  if (nice_level == 0)
79
 
    return;
80
 
 
81
 
#if defined(HAVE_NICE)
82
 
  {
83
 
    int old_nice = nice (0);
84
 
    int n = nice_level - old_nice;
85
 
    errno = 0;
86
 
    if (nice (n) == -1 && errno != 0)
87
 
      {
88
 
        char buf [512];
89
 
        sprintf (buf, "%s: nice(%d) failed", blurb(), n);
90
 
        perror (buf);
91
 
    }
92
 
  }
93
 
#elif defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
94
 
  if (setpriority (PRIO_PROCESS, getpid(), nice_level) != 0)
95
 
    {
96
 
      char buf [512];
97
 
      sprintf (buf, "%s: setpriority(PRIO_PROCESS, %lu, %d) failed",
98
 
               blurb(), (unsigned long) getpid(), nice_level);
99
 
      perror (buf);
100
 
    }
101
 
#else
102
 
  fprintf (stderr,
103
 
           "%s: don't know how to change process priority on this system.\n",
104
 
           blurb());
105
 
 
106
 
#endif
107
 
}
108
 
 
109
73
 
110
74
/* RLIMIT_AS (called RLIMIT_VMEM on some systems) controls the maximum size
111
75
   of a process's address space, i.e., the maximal brk(2) and mmap(2) values.
112
76
   Setting this lets you put a cap on how much memory a process can allocate.
 
77
 
 
78
   Except the "and mmap()" part kinda makes this useless, since many GL
 
79
   implementations end up using mmap() to pull the whole frame buffer into
 
80
   memory (or something along those lines) making it appear processes are
 
81
   using hundreds of megabytes when in fact they're using very little, and
 
82
   we end up capping their mallocs prematurely.  YAY!
113
83
 */
114
84
#if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS)
115
85
# define RLIMIT_AS RLIMIT_VMEM
118
88
static void
119
89
limit_subproc_memory (int address_space_limit, Bool verbose_p)
120
90
{
 
91
 
 
92
/* This has caused way more problems than it has solved...
 
93
   Let's just completely ignore the "memoryLimit" option now.
 
94
 */
 
95
#undef HAVE_SETRLIMIT
 
96
 
121
97
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS)
122
98
  struct rlimit r;
123
99
 
163
139
#endif /* HAVE_SETRLIMIT && RLIMIT_AS */
164
140
}
165
141
 
166
 
 
167
 
 
168
 
#ifndef VMS
169
 
 
170
 
static void
171
 
exec_simple_command (const char *command)
172
 
{
173
 
  char *av[1024];
174
 
  int ac = 0;
175
 
  char *token = strtok (strdup(command), " \t");
176
 
  while (token)
177
 
    {
178
 
      av[ac++] = token;
179
 
      token = strtok(0, " \t");
180
 
    }
181
 
  av[ac] = 0;
182
 
 
183
 
  execvp (av[0], av);                   /* shouldn't return. */
184
 
 
185
 
  {
186
 
    char buf [512];
187
 
    sprintf (buf, "%s: could not execute \"%s\"", blurb(), av[0]);
188
 
    perror (buf);
189
 
 
190
 
    if (errno == ENOENT &&
191
 
        (token = getenv("PATH")))
192
 
      {
193
 
# ifndef PATH_MAX
194
 
#  ifdef MAXPATHLEN
195
 
#   define PATH_MAX MAXPATHLEN
196
 
#  else
197
 
#   define PATH_MAX 2048
198
 
#  endif
199
 
# endif
200
 
        char path[PATH_MAX];
201
 
        fprintf (stderr, "\n");
202
 
        *path = 0;
203
 
# if defined(HAVE_GETCWD)
204
 
        getcwd (path, sizeof(path));
205
 
# elif defined(HAVE_GETWD)
206
 
        getwd (path);
207
 
# endif
208
 
        if (*path)
209
 
          fprintf (stderr, "    Current directory is: %s\n", path);
210
 
        fprintf (stderr, "    PATH is:\n");
211
 
        token = strtok (strdup(token), ":");
212
 
        while (token)
213
 
          {
214
 
            fprintf (stderr, "        %s\n", token);
215
 
            token = strtok(0, ":");
216
 
          }
217
 
        fprintf (stderr, "\n");
218
 
      }
219
 
  }
220
 
  fflush(stderr);
221
 
  fflush(stdout);
222
 
  exit (1);     /* Note that this only exits a child fork.  */
223
 
}
224
 
 
225
 
 
226
 
static void
227
 
exec_complex_command (const char *shell, const char *command)
228
 
{
229
 
  char *av[5];
230
 
  int ac = 0;
231
 
  char *command2 = (char *) malloc (strlen (command) + 10);
232
 
  const char *s;
233
 
  int got_eq = 0;
234
 
  const char *after_vars;
235
 
 
236
 
  /* Skip leading whitespace.
237
 
   */
238
 
  while (*command == ' ' || *command == '\t')
239
 
    command++;
240
 
 
241
 
  /* If the string has a series of tokens with "=" in them at them, set
242
 
     `after_vars' to point into the string after those tokens and any
243
 
     trailing whitespace.  Otherwise, after_vars == command.
244
 
   */
245
 
  after_vars = command;
246
 
  for (s = command; *s; s++)
247
 
    {
248
 
      if (*s == '=') got_eq = 1;
249
 
      else if (*s == ' ')
250
 
        {
251
 
          if (got_eq)
252
 
            {
253
 
              while (*s == ' ' || *s == '\t')
254
 
                s++;
255
 
              after_vars = s;
256
 
              got_eq = 0;
257
 
            }
258
 
          else
259
 
            break;
260
 
        }
261
 
    }
262
 
 
263
 
  *command2 = 0;
264
 
  strncat (command2, command, after_vars - command);
265
 
  strcat (command2, "exec ");
266
 
  strcat (command2, after_vars);
267
 
 
268
 
  /* We have now done these transformations:
269
 
     "foo -x -y"               ==>  "exec foo -x -y"
270
 
     "BLAT=foop      foo -x"   ==>  "BLAT=foop      exec foo -x"
271
 
     "BLAT=foop A=b  foo -x"   ==>  "BLAT=foop A=b  exec foo -x"
272
 
   */
273
 
 
274
 
 
275
 
  /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
276
 
  av [ac++] = (char *) shell;
277
 
  av [ac++] = "-c";
278
 
  av [ac++] = command2;
279
 
  av [ac]   = 0;
280
 
 
281
 
  execvp (av[0], av);                   /* shouldn't return. */
282
 
 
283
 
  {
284
 
    char buf [512];
285
 
    sprintf (buf, "%s: execvp(\"%s\") failed", blurb(), av[0]);
286
 
    perror (buf);
287
 
    fflush(stderr);
288
 
    fflush(stdout);
289
 
    exit (1);   /* Note that this only exits a child fork.  */
290
 
  }
291
 
}
292
 
 
293
 
#else  /* VMS */
294
 
 
295
 
static void
296
 
exec_vms_command (const char *command)
297
 
{
298
 
  system (command);
299
 
  fflush (stderr);
300
 
  fflush (stdout);
301
 
  exit (1);     /* Note that this only exits a child fork.  */
302
 
}
303
 
 
304
 
#endif /* !VMS */
305
 
 
306
 
 
307
 
static void
308
 
exec_screenhack (saver_info *si, const char *command)
309
 
{
310
 
  /* I don't believe what a sorry excuse for an operating system UNIX is!
311
 
 
312
 
     - I want to spawn a process.
313
 
     - I want to know it's pid so that I can kill it.
314
 
     - I would like to receive a message when it dies of natural causes.
315
 
     - I want the spawned process to have user-specified arguments.
316
 
 
317
 
     If shell metacharacters are present (wildcards, backquotes, etc), the
318
 
     only way to parse those arguments is to run a shell to do the parsing
319
 
     for you.
320
 
 
321
 
     And the only way to know the pid of the process is to fork() and exec()
322
 
     it in the spawned side of the fork.
323
 
 
324
 
     But if you're running a shell to parse your arguments, this gives you
325
 
     the pid of the *shell*, not the pid of the *process* that you're
326
 
     actually interested in, which is an *inferior* of the shell.  This also
327
 
     means that the SIGCHLD you get applies to the shell, not its inferior.
328
 
     (Why isn't that sufficient?  I don't remember any more, but it turns
329
 
     out that it isn't.)
330
 
 
331
 
     So, the only solution, when metacharacters are present, is to force the
332
 
     shell to exec() its inferior.  What a fucking hack!  We prepend "exec "
333
 
     to the command string, and hope it doesn't contain unquoted semicolons
334
 
     or ampersands (we don't search for them, because we don't want to
335
 
     prohibit their use in quoted strings (messages, for example) and parsing
336
 
     out the various quote characters is too much of a pain.)
337
 
 
338
 
     (Actually, Clint Wong <clint@jts.com> points out that process groups
339
 
     might be used to take care of this problem; this may be worth considering
340
 
     some day, except that, 1: this code works now, so why fix it, and 2: from
341
 
     what I've seen in Emacs, dealing with process groups isn't especially
342
 
     portable.)
343
 
   */
344
 
  saver_preferences *p = &si->prefs;
345
 
 
346
 
#ifndef VMS
347
 
  Bool hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
348
 
  /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
349
 
 
350
 
  if (getuid() == (uid_t) 0 || geteuid() == (uid_t) 0)
351
 
    {
352
 
      /* If you're thinking of commenting this out, think again.
353
 
         If you do so, you will open a security hole.  Mail jwz
354
 
         so that he may enlighten you as to the error of your ways.
355
 
       */
356
 
      fprintf (stderr, "%s: we're still running as root!  Disaster!\n",
357
 
               blurb());
358
 
      saver_exit (si, 1, 0);
359
 
    }
360
 
 
361
 
  if (p->verbose_p)
362
 
    fprintf (stderr, "%s: spawning \"%s\" in pid %lu%s.\n",
363
 
             blurb(), command, (unsigned long) getpid (),
364
 
             (hairy_p ? " (via shell)" : ""));
365
 
 
366
 
  if (hairy_p)
367
 
    /* If it contains any shell metacharacters, do it the hard way,
368
 
       and fork a shell to parse the arguments for us. */
369
 
    exec_complex_command (p->shell, command);
370
 
  else
371
 
    /* Otherwise, we can just exec the program directly. */
372
 
    exec_simple_command (command);
373
 
 
374
 
#else /* VMS */
375
 
  if (p->verbose_p)
376
 
    fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
377
 
             blurb(), command, getpid());
378
 
  exec_vms_command (command);
379
 
#endif /* VMS */
380
 
 
381
 
  abort();      /* that shouldn't have returned. */
382
 
}
383
 
 
384
 
 
385
142
 
386
143
/* Management of child processes, and de-zombification.
387
144
 */
399
156
struct screenhack_job {
400
157
  char *name;
401
158
  pid_t pid;
 
159
  int screen;
402
160
  enum job_status status;
403
161
  struct screenhack_job *next;
404
162
};
412
170
  struct screenhack_job *job;
413
171
  fprintf(stderr, "%s: job list:\n", blurb());
414
172
  for (job = jobs; job; job = job->next)
415
 
    fprintf (stderr, "  %5ld: (%s) %s\n",
 
173
    fprintf (stderr, "  %5ld: %2d: (%s) %s\n",
416
174
             (long) job->pid,
 
175
             job->screen,
417
176
             (job->status == job_running ? "running" :
418
177
              job->status == job_stopped ? "stopped" :
419
178
              job->status == job_killed  ? " killed" :
426
185
static void clean_job_list (void);
427
186
 
428
187
static struct screenhack_job *
429
 
make_job (pid_t pid, const char *cmd)
 
188
make_job (pid_t pid, int screen, const char *cmd)
430
189
{
431
190
  struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
432
191
 
458
217
 
459
218
  job->name = strdup(name);
460
219
  job->pid = pid;
 
220
  job->screen = screen;
461
221
  job->status = job_running;
462
222
  job->next = jobs;
463
223
  jobs = job;
534
294
static int block_sigchld_handler = 0;
535
295
 
536
296
 
537
 
void
 
297
#ifdef HAVE_SIGACTION
 
298
 sigset_t
 
299
#else  /* !HAVE_SIGACTION */
 
300
 int
 
301
#endif /* !HAVE_SIGACTION */
538
302
block_sigchld (void)
539
303
{
540
304
#ifdef HAVE_SIGACTION
541
305
  sigset_t child_set;
542
306
  sigemptyset (&child_set);
543
307
  sigaddset (&child_set, SIGCHLD);
 
308
  sigaddset (&child_set, SIGPIPE);
544
309
  sigprocmask (SIG_BLOCK, &child_set, 0);
545
310
#endif /* HAVE_SIGACTION */
546
311
 
547
312
  block_sigchld_handler++;
 
313
 
 
314
#ifdef HAVE_SIGACTION
 
315
  return child_set;
 
316
#else  /* !HAVE_SIGACTION */
 
317
  return 0;
 
318
#endif /* !HAVE_SIGACTION */
548
319
}
549
320
 
550
321
void
554
325
  sigset_t child_set;
555
326
  sigemptyset(&child_set);
556
327
  sigaddset(&child_set, SIGCHLD);
 
328
  sigaddset(&child_set, SIGPIPE);
557
329
  sigprocmask(SIG_UNBLOCK, &child_set, 0);
558
330
#endif /* HAVE_SIGACTION */
559
331
 
596
368
  default: abort();
597
369
  }
598
370
 
599
 
#ifdef SIGSTOP
600
 
  if (p->verbose_p)
601
 
    fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
602
 
             (signal == SIGTERM ? "killing" :
603
 
              signal == SIGSTOP ? "suspending" :
604
 
              signal == SIGCONT ? "resuming" : "signalling"),
605
 
             (unsigned long) job->pid);
606
 
#else  /* !SIGSTOP */
607
 
  if (p->verbose_p)
608
 
    fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
609
 
             (unsigned long) job->pid);
610
 
#endif /* !SIGSTOP */
 
371
  if (p->verbose_p)
 
372
    fprintf (stderr, "%s: %d: %s pid %lu (%s)\n",
 
373
             blurb(), job->screen,
 
374
             (job->status == job_killed  ? "killing" :
 
375
              job->status == job_stopped ? "suspending" : "resuming"),
 
376
             (unsigned long) job->pid,
 
377
             job->name);
611
378
 
612
379
  status = kill (job->pid, signal);
613
380
 
614
381
  if (p->verbose_p && status < 0)
615
382
    {
616
383
      if (errno == ESRCH)
617
 
        fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
618
 
                 blurb(), job->pid, job->name);
 
384
        fprintf (stderr,
 
385
                 "%s: %d: child process %lu (%s) was already dead.\n",
 
386
                 blurb(), job->screen, (unsigned long) job->pid, job->name);
619
387
      else
620
388
        {
621
389
          char buf [1024];
622
 
          sprintf (buf, "%s: couldn't kill child process %lu (%s)",
623
 
                   blurb(), job->pid, job->name);
 
390
          sprintf (buf, "%s: %d: couldn't kill child process %lu (%s)",
 
391
                   blurb(), job->screen, (unsigned long) job->pid, job->name);
624
392
          perror (buf);
625
393
        }
626
394
    }
702
470
  saver_preferences *p = &si->prefs;
703
471
  struct screenhack_job *job = find_job (kid);
704
472
  const char *name = job ? job->name : "<unknown>";
 
473
  int screen_no = job ? job->screen : 0;
705
474
 
706
475
  if (WIFEXITED (wait_status))
707
476
    {
720
489
          (exit_status != 0 &&
721
490
           (p->verbose_p || job->status != job_killed)))
722
491
        fprintf (stderr,
723
 
                 "%s: child pid %lu (%s) exited abnormally (code %d).\n",
724
 
                 blurb(), (unsigned long) kid, name, exit_status);
 
492
                 "%s: %d: child pid %lu (%s) exited abnormally (code %d).\n",
 
493
                 blurb(), screen_no, (unsigned long) kid, name, exit_status);
725
494
      else if (p->verbose_p)
726
 
        fprintf (stderr, "%s: child pid %lu (%s) exited normally.\n",
727
 
                 blurb(), (unsigned long) kid, name);
 
495
        fprintf (stderr, "%s: %d: child pid %lu (%s) exited normally.\n",
 
496
                 blurb(), screen_no, (unsigned long) kid, name);
728
497
 
729
498
      if (job)
730
499
        job->status = job_dead;
735
504
          !job ||
736
505
          job->status != job_killed ||
737
506
          WTERMSIG (wait_status) != SIGTERM)
738
 
        fprintf (stderr, "%s: child pid %lu (%s) terminated with %s.\n",
739
 
                 blurb(), (unsigned long) kid, name,
 
507
        fprintf (stderr, "%s: %d: child pid %lu (%s) terminated with %s.\n",
 
508
                 blurb(), screen_no, (unsigned long) kid, name,
740
509
                 signal_name (WTERMSIG(wait_status)));
741
510
 
742
511
      if (job)
843
612
 
844
613
 
845
614
static void
 
615
print_path_error (const char *program)
 
616
{
 
617
  char buf [512];
 
618
  char *cmd = strdup (program);
 
619
  char *token = strchr (cmd, ' ');
 
620
 
 
621
  if (token) *token = 0;
 
622
  sprintf (buf, "%s: could not execute \"%.100s\"", blurb(), cmd);
 
623
  free (cmd);
 
624
  perror (buf);
 
625
 
 
626
  if (errno == ENOENT &&
 
627
      (token = getenv("PATH")))
 
628
    {
 
629
# ifndef PATH_MAX
 
630
#  ifdef MAXPATHLEN
 
631
#   define PATH_MAX MAXPATHLEN
 
632
#  else
 
633
#   define PATH_MAX 2048
 
634
#  endif
 
635
# endif
 
636
      char path[PATH_MAX];
 
637
      fprintf (stderr, "\n");
 
638
      *path = 0;
 
639
# if defined(HAVE_GETCWD)
 
640
      getcwd (path, sizeof(path));
 
641
# elif defined(HAVE_GETWD)
 
642
      getwd (path);
 
643
# endif
 
644
      if (*path)
 
645
        fprintf (stderr, "    Current directory is: %s\n", path);
 
646
      fprintf (stderr, "    PATH is:\n");
 
647
      token = strtok (strdup(token), ":");
 
648
      while (token)
 
649
        {
 
650
          fprintf (stderr, "        %s\n", token);
 
651
          token = strtok(0, ":");
 
652
        }
 
653
      fprintf (stderr, "\n");
 
654
    }
 
655
}
 
656
 
 
657
 
 
658
/* Executes the command in another process.
 
659
   Command may be any single command acceptable to /bin/sh.
 
660
   It may include wildcards, but no semicolons.
 
661
   If successful, the pid of the other process is returned.
 
662
   Otherwise, -1 is returned and an error may have been
 
663
   printed to stderr.
 
664
 */
 
665
pid_t
 
666
fork_and_exec (saver_screen_info *ssi, const char *command)
 
667
{
 
668
  saver_info *si = ssi->global;
 
669
  saver_preferences *p = &si->prefs;
 
670
  pid_t forked;
 
671
 
 
672
  switch ((int) (forked = fork ()))
 
673
    {
 
674
    case -1:
 
675
      {
 
676
        char buf [255];
 
677
        sprintf (buf, "%s: couldn't fork", blurb());
 
678
        perror (buf);
 
679
        break;
 
680
      }
 
681
 
 
682
    case 0:
 
683
      close (ConnectionNumber (si->dpy));       /* close display fd */
 
684
      limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
 
685
      hack_subproc_environment (ssi);           /* set $DISPLAY */
 
686
 
 
687
      if (p->verbose_p)
 
688
        fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
 
689
                 blurb(), ssi->number, command,
 
690
                 (unsigned long) getpid ());
 
691
 
 
692
      exec_command (p->shell, command, p->nice_inferior);
 
693
 
 
694
      /* If that returned, we were unable to exec the subprocess.
 
695
         Print an error message, if desired.
 
696
       */
 
697
      if (! p->ignore_uninstalled_p)
 
698
        print_path_error (command);
 
699
 
 
700
      exit (1);  /* exits child fork */
 
701
      break;
 
702
 
 
703
    default:    /* parent */
 
704
      (void) make_job (forked, ssi->number, command);
 
705
      break;
 
706
    }
 
707
 
 
708
  return forked;
 
709
}
 
710
 
 
711
 
 
712
static void
846
713
spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
847
714
{
848
715
  saver_info *si = ssi->global;
855
722
      screenhack *hack;
856
723
      pid_t forked;
857
724
      char buf [255];
858
 
      int new_hack;
 
725
      int new_hack = -1;
859
726
      int retry_count = 0;
860
727
      Bool force = False;
861
728
 
862
729
    AGAIN:
863
730
 
864
 
      if (p->screenhacks_count == 1)
865
 
        /* If there is only one hack in the list, there is no choice. */
866
 
        new_hack = 0;
867
 
 
 
731
      if (p->screenhacks_count < 1)
 
732
        {
 
733
          /* No hacks at all */
 
734
          new_hack = -1;
 
735
        }
 
736
      else if (p->screenhacks_count == 1)
 
737
        {
 
738
          /* Exactly one hack in the list */
 
739
          new_hack = 0;
 
740
        }
868
741
      else if (si->selection_mode == -1)
869
 
        /* Select the next hack, wrapping. */
870
 
        new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
871
 
 
 
742
        {
 
743
          /* Select the next hack, wrapping. */
 
744
          new_hack = (ssi->current_hack + 1) % p->screenhacks_count;
 
745
        }
872
746
      else if (si->selection_mode == -2)
873
 
        /* Select the previous hack, wrapping. */
874
 
        new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
875
 
                    % p->screenhacks_count);
876
 
 
 
747
        {
 
748
          /* Select the previous hack, wrapping. */
 
749
          if (ssi->current_hack < 0)
 
750
            new_hack = p->screenhacks_count - 1;
 
751
          else
 
752
            new_hack = ((ssi->current_hack + p->screenhacks_count - 1)
 
753
                        % p->screenhacks_count);
 
754
        }
877
755
      else if (si->selection_mode > 0)
878
 
        /* Select a specific hack, by number.  No negotiation. */
879
756
        {
 
757
          /* Select a specific hack, by number (via the ACTIVATE command.) */
880
758
          new_hack = ((si->selection_mode - 1) % p->screenhacks_count);
881
759
          force = True;
882
760
        }
883
 
      else
 
761
      else if (p->mode == ONE_HACK &&
 
762
               p->selected_hack >= 0)
 
763
        {
 
764
          /* Select a specific hack, by number (via "One Saver" mode.) */
 
765
          new_hack = p->selected_hack;
 
766
          force = True;
 
767
        }
 
768
      else if (p->mode == BLANK_ONLY || p->mode == DONT_BLANK)
 
769
        {
 
770
          new_hack = -1;
 
771
        }
 
772
      else if (p->mode == RANDOM_HACKS_SAME &&
 
773
               ssi->number != 0)
 
774
        {
 
775
          /* Use the same hack that's running on screen 0.
 
776
             (Assumes this function was called on screen 0 first.)
 
777
           */
 
778
          ssi->current_hack = si->screens[0].current_hack;
 
779
        }
 
780
      else  /* (p->mode == RANDOM_HACKS) */
884
781
        {
885
782
          /* Select a random hack (but not the one we just ran.) */
886
783
          while ((new_hack = random () % p->screenhacks_count)
888
785
            ;
889
786
        }
890
787
 
 
788
      if (new_hack < 0)   /* don't run a hack */
 
789
        {
 
790
          ssi->current_hack = -1;
 
791
          if (si->selection_mode < 0)
 
792
            si->selection_mode = 0;
 
793
          return;
 
794
        }
 
795
 
891
796
      ssi->current_hack = new_hack;
892
797
      hack = p->screenhacks[ssi->current_hack];
893
798
 
912
817
              */
913
818
              if (p->verbose_p)
914
819
                fprintf(stderr,
915
 
                        "%s: no suitable visuals for these programs.\n",
916
 
                        blurb());
 
820
                      "%s: %d: no programs enabled, or no suitable visuals.\n",
 
821
                        blurb(), ssi->number);
917
822
              return;
918
823
            }
919
824
          else
926
831
      if (si->selection_mode < 0)
927
832
        si->selection_mode = 0;
928
833
 
929
 
      switch ((int) (forked = fork ()))
 
834
      forked = fork_and_exec (ssi, hack->command);
 
835
      switch ((int) forked)
930
836
        {
931
 
        case -1:
 
837
        case -1: /* fork failed */
 
838
        case 0:  /* child fork (can't happen) */
932
839
          sprintf (buf, "%s: couldn't fork", blurb());
933
840
          perror (buf);
934
841
          restore_real_vroot (si);
935
 
          saver_exit (si, 1, 0);
936
 
 
937
 
        case 0:
938
 
          close (ConnectionNumber (si->dpy));   /* close display fd */
939
 
          nice_subproc (p->nice_inferior);      /* change process priority */
940
 
          limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
941
 
          hack_subproc_environment (ssi);       /* set $DISPLAY */
942
 
          exec_screenhack (si, hack->command);  /* this does not return */
943
 
          abort();
 
842
          saver_exit (si, 1, "couldn't fork");
944
843
          break;
945
844
 
946
845
        default:
947
846
          ssi->pid = forked;
948
 
          (void) make_job (forked, hack->command);
949
847
          break;
950
848
        }
951
849
    }
1058
956
 
1059
957
      if (putenv (npath))
1060
958
        abort ();
 
959
 
 
960
      /* don't free (npath) -- some implementations of putenv (BSD 4.4,
 
961
         glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
 
962
         do not.  So we must leak it (and/or the previous setting). Yay.
 
963
       */
1061
964
    }
1062
965
#endif /* HAVE_PUTENV && DEFAULT_PATH_PREFIX */
1063
966
}
1074
977
     be the screen on which this particular hack is running -- not the display
1075
978
     specification which the driver itself is using, since the driver ignores
1076
979
     its screen number and manages all existing screens.
 
980
 
 
981
     Likewise, store a window ID in $XSCREENSAVER_WINDOW -- this will allow
 
982
     us to (eventually) run multiple hacks in Xinerama mode, where each hack
 
983
     has the same $DISPLAY but a different piece of glass.
1077
984
   */
1078
985
  saver_info *si = ssi->global;
1079
986
  const char *odpy = DisplayString (si->dpy);
1080
 
  char *ndpy = (char *) malloc(strlen(odpy) + 20);
1081
 
  int screen_number;
 
987
  char *ndpy = (char *) malloc (strlen(odpy) + 20);
 
988
  char *nssw = (char *) malloc (40);
1082
989
  char *s;
1083
990
 
1084
 
  for (screen_number = 0; screen_number < si->nscreens; screen_number++)
1085
 
    if (ssi == &si->screens[screen_number])
1086
 
      break;
1087
 
 
1088
991
  strcpy (ndpy, "DISPLAY=");
1089
992
  s = ndpy + strlen(ndpy);
1090
993
  strcpy (s, odpy);
1094
997
  while (isdigit(*s)) s++;                      /* skip over dpy number */
1095
998
  while (*s == '.') s++;                        /* skip over dot */
1096
999
  if (s[-1] != '.') *s++ = '.';                 /* put on a dot */
1097
 
  sprintf(s, "%d", screen_number);              /* put on screen number */
 
1000
  sprintf(s, "%d", ssi->real_screen_number);    /* put on screen number */
 
1001
 
 
1002
  sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
 
1003
           (unsigned long) ssi->screensaver_window);
1098
1004
 
1099
1005
  /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
1100
1006
     any more, right?  It's not Posix, but everyone seems to have it. */
1101
1007
#ifdef HAVE_PUTENV
1102
1008
  if (putenv (ndpy))
1103
1009
    abort ();
 
1010
  if (putenv (nssw))
 
1011
    abort ();
 
1012
 
 
1013
  /* don't free ndpy/nssw -- some implementations of putenv (BSD 4.4,
 
1014
     glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
 
1015
     do not.  So we must leak it (and/or the previous setting). Yay.
 
1016
   */
1104
1017
#endif /* HAVE_PUTENV */
1105
1018
}
1106
1019
 
1183
1096
        /* Wait for the child to die. */
1184
1097
        waitpid (-1, &wait_status, 0);
1185
1098
 
1186
 
        if (1 == sscanf (buf, "0x%x %c", &v, &c))
 
1099
        if (1 == sscanf (buf, "0x%lx %c", &v, &c))
1187
1100
          result = (int) v;
1188
1101
 
1189
1102
        if (result == 0)
1190
1103
          {
1191
1104
            if (si->prefs.verbose_p)
1192
 
              fprintf (stderr, "%s: %s did not report a GL visual!\n",
1193
 
                       blurb(), av[0]);
 
1105
              {
 
1106
                int L = strlen(buf);
 
1107
                fprintf (stderr, "%s: %s did not report a GL visual!\n",
 
1108
                         blurb(), av[0]);
 
1109
 
 
1110
                if (L && buf[L-1] == '\n')
 
1111
                  buf[--L] = 0;
 
1112
                if (*buf)
 
1113
                  fprintf (stderr, "%s: %s said: \"%s\"\n",
 
1114
                           blurb(), av[0], buf);
 
1115
              }
1194
1116
            return 0;
1195
1117
          }
1196
1118
        else
1197
1119
          {
1198
1120
            Visual *v = id_to_visual (ssi->screen, result);
1199
1121
            if (si->prefs.verbose_p)
1200
 
              fprintf (stderr, "%s: %s says the GL visual is 0x%X%s.\n",
1201
 
                       blurb(), av[0], result,
1202
 
                       (v == ssi->default_visual ? " (the default)" : ""));
 
1122
              fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
 
1123
                       blurb(), ssi->number,
 
1124
                       av[0], result,
 
1125
                       (v == ssi->default_visual ? " (default)" : ""));
1203
1126
            return v;
1204
1127
          }
1205
1128
      }
1228
1151
}
1229
1152
 
1230
1153
 
1231
 
/* Re-execs the process with the arguments in saved_argv.
1232
 
   Does not return unless there was an error.
 
1154
/* Re-execs the process with the arguments in saved_argv.  Does not return.
1233
1155
 */
1234
1156
void
1235
1157
restart_process (saver_info *si)
1236
1158
{
 
1159
  fflush (stdout);
 
1160
  fflush (stderr);
 
1161
  shutdown_stderr (si);
1237
1162
  if (si->prefs.verbose_p)
1238
1163
    {
1239
1164
      int i;
1240
 
      fprintf (real_stderr, "%s: re-executing", blurb());
 
1165
      fprintf (stderr, "%s: re-executing", blurb());
1241
1166
      for (i = 0; saved_argv[i]; i++)
1242
 
        fprintf (real_stderr, " %s", saved_argv[i]);
1243
 
      fprintf (real_stderr, "\n");
 
1167
        fprintf (stderr, " %s", saved_argv[i]);
 
1168
      fprintf (stderr, "\n");
1244
1169
    }
1245
 
  describe_uids (si, real_stderr);
1246
 
  fprintf (real_stderr, "\n");
 
1170
  describe_uids (si, stderr);
 
1171
  fprintf (stderr, "\n");
1247
1172
 
1248
 
  fflush (real_stdout);
1249
 
  fflush (real_stderr);
 
1173
  fflush (stdout);
 
1174
  fflush (stderr);
1250
1175
  execvp (saved_argv [0], saved_argv);  /* shouldn't return */
1251
1176
  {
1252
1177
    char buf [512];
1253
1178
    sprintf (buf, "%s: could not restart process", blurb());
1254
1179
    perror(buf);
1255
1180
    fflush(stderr);
 
1181
    abort();
1256
1182
  }
1257
 
  XBell(si->dpy, 0);
1258
1183
}