summaryrefslogtreecommitdiff
path: root/src/subprocs.c
blob: 757daf8e4fb1629b7f40bc9e9b748087a7ffa385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 *
 * subprocs.c --- choosing, spawning, and killing screenhacks.
 *
 * xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski <jwz@jwz.org>
 * Modified:     Copyright (c) 2004 William Jon McCann <mccann@jhu.edu>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 */

#include "config.h"

#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#ifndef ESRCH
# include <errno.h>
#endif

#include <sys/time.h>		/* sys/resource.h needs this for timeval */
# include <sys/wait.h>		/* for waitpid() and associated macros */

#ifdef VMS
# include <processes.h>
# include <unixio.h>		/* for close */
# include <unixlib.h>		/* for getpid */
# define pid_t int
# define fork  vfork
#endif /* VMS */

#include <signal.h>		/* for the signal names */

#include <glib.h>
#include "subprocs.h"

#if !defined(SIGCHLD) && defined(SIGCLD)
# define SIGCHLD SIGCLD
#endif

/* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
   Don't alter this directly -- use block_sigchld() / unblock_sigchld().
*/
static int block_sigchld_handler = 0;


#ifdef HAVE_SIGACTION
sigset_t
#else  /* !HAVE_SIGACTION */
int
#endif /* !HAVE_SIGACTION */
block_sigchld (void)
{
#ifdef HAVE_SIGACTION
	sigset_t child_set;
	sigemptyset (&child_set);
	sigaddset (&child_set, SIGCHLD);
	sigaddset (&child_set, SIGPIPE);
	sigprocmask (SIG_BLOCK, &child_set, 0);
#endif /* HAVE_SIGACTION */

	block_sigchld_handler++;

#ifdef HAVE_SIGACTION
	return child_set;
#else  /* !HAVE_SIGACTION */
	return 0;
#endif /* !HAVE_SIGACTION */
}

void
unblock_sigchld (void)
{
#ifdef HAVE_SIGACTION
	sigset_t child_set;
	sigemptyset (&child_set);
	sigaddset (&child_set, SIGCHLD);
	sigaddset (&child_set, SIGPIPE);
	sigprocmask (SIG_UNBLOCK, &child_set, 0);
#endif /* HAVE_SIGACTION */

	block_sigchld_handler--;
}

int
signal_pid (int    pid,
            int    signal)
{
	int status = -1;
	gboolean verbose = TRUE;

	if (block_sigchld_handler)
		/* This function should not be called from the signal handler. */
		abort();

	block_sigchld ();                      /* we control the horizontal... */

	status = kill (pid, signal);

	if (verbose && status < 0)
	{
		if (errno == ESRCH)
			g_message ("Child process %lu was already dead.",
			           (unsigned long) pid);
		else
		{
			char buf [1024];
			snprintf (buf, sizeof (buf), "Couldn't kill child process %lu",
			          (unsigned long) pid);
			perror (buf);
		}
	}

	unblock_sigchld ();

	if (block_sigchld_handler < 0)
		abort ();

	return status;
}

#ifndef VMS

void
await_dying_children (int      pid,
                      gboolean debug)
{
	while (1)
	{
		int wait_status = 0;
		pid_t kid;

		errno = 0;
		kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED);

		if (debug)
		{
			if (kid < 0 && errno)
				g_message ("waitpid(%d) ==> %ld (%d)", pid, (long) kid, errno);
			else if (kid != 0)
				g_message ("waitpid(%d) ==> %ld", pid, (long) kid);
		}

		/* 0 means no more children to reap.
		   -1 means error -- except "interrupted system call" isn't a "real"
		   error, so if we get that, we should just try again. */
		if (kid < 0 && errno != EINTR)
			break;
	}
}


#else  /* VMS */
static void await_dying_children (saver_info *si)
{
	return;
}
#endif /* VMS */