1 /*
2 ** 1998-09-25 -	This module deals with child processes. Cut out from the old commands module,
3 **		which really was kind of bloated.
4 ** 1998-12-15 -	Rewritten. Now uses the POSIX sigaction() API, which perhaps is more portable.
5 **		I've been noticing some odd problems on Solaris, with "infinite signals" etc.
6 **		I found my (virtual) copy of the Linux Programmer's Guide, and it makes me
7 **		believe that POSIX signals are reliable by default (i.e. the handler need not
8 **		be reinstalled). New problem: possible interruption of system calls. :(
9 ** 1999-03-31 -	Made this module a lot more self-contained.
10 ** 1999-04-08 -	Now waitpid()s for the child after chd_kill_child(), which really is better.
11 */
12 
13 #include "gentoo.h"
14 
15 #if !defined _POSIX_SOURCE
16  #define _POSIX_SOURCE
17 #endif
18 
19 #include <stdlib.h>
20 #include <signal.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 
24 #include "dialog.h"
25 #include "strutil.h"
26 #include "queue.h"
27 #include "children.h"
28 
29 /* ----------------------------------------------------------------------------------------- */
30 
31 typedef struct {			/* Information about a single child process. */
32 	GPid	pid;
33 	guint	watch;				/* Glib source associated with this child. */
34 	gchar	prog[MAXNAMLEN];		/* Name of program running as this child (argv[0]). */
35 	guint32	gflags;				/* The general flags for the command. */
36 	guint32	aflags;				/* After-flags to associate with this child. */
37 } Child;
38 
39 typedef struct {			/* Holds data about child processes we have spawned. */
40 	MainInfo	*min;			/* Very handy to have around. Keep first! */
41 	GSList		*child_list;		/* List of running processes. */
42 	GPid		lock_pid;		/* Pid of a command that we want to wait for. */
43 	CmdSeq		*running;		/* If non-null, we're currently running this sequence. */
44 	guint		index;			/* When 'running' is set, this is the next position to run. */
45 } ChildInfo;
46 
47 static ChildInfo	the_chi = { NULL };
48 
49 /* ----------------------------------------------------------------------------------------- */
50 
51 static gboolean	chd_unregister(const gchar *name);
52 
53 /* ----------------------------------------------------------------------------------------- */
54 
55 /* 1999-04-08 -	Rewritten, now simply initializes our private ChildInfo. */
chd_initialize(MainInfo * min)56 gboolean chd_initialize(MainInfo *min)
57 {
58 	if(the_chi.min == NULL)
59 	{
60 		the_chi.min	   = min;
61 		the_chi.child_list = NULL;
62 		the_chi.lock_pid   = -1;
63 		the_chi.running    = NULL;
64 		the_chi.index	   = 0;
65 
66 		return TRUE;
67 	}
68 	return FALSE;
69 }
70 
71 /* ----------------------------------------------------------------------------------------- */
72 
73 /* 2010-03-08 -	A child process has tragically died, and needs to be reaped. */
cb_watch_child(GPid pid,gint status,gpointer user)74 static void cb_watch_child(GPid pid, gint status, gpointer user)
75 {
76 	ChildInfo	*chi = &the_chi;
77 	Child		*ch = user;
78 
79 	/* Unlink from rest of GTK+, as soon as possible, to be safe. */
80 	chi->child_list = g_slist_remove(chi->child_list, ch);
81 	g_source_remove(ch->watch);
82 
83 	/* Now handle exit status. */
84 	if(WIFEXITED(status) && WEXITSTATUS(status) == CHD_EXIT_FAILURE)
85 	{
86 		gchar	buf[1024];
87 
88 		g_snprintf(buf, sizeof buf, _("Execution of \"%s\" Failed"), ch->prog);
89 		dlg_dialog_sync_new_simple_wait(buf, _("Error"), _("_OK"));
90 	}
91 	if(chi->lock_pid == ch->pid)		/* Running in foreground? */
92 		que_enqueue(chi->min, QEVT_CONTINUE_CMD);
93 	que_enqueue(chi->min, QEVT_END_CMD, ch->aflags);
94 
95 	g_free(ch);
96 }
97 
98 /* ----------------------------------------------------------------------------------------- */
99 
100 /* 1998-09-09 -	Register a child process started by a user command. Keeps not only
101 **		the <pid>. This information is used to kill previous instance(s).
102 ** 1998-09-10 -	Now takes an additional parameter, <lock>. If set, the GUI is locked.
103 ** 1998-09-18 -	This routine is now exported for use by other code (the new "file" module).
104 */
chd_register(const gchar * prog,GPid pid,guint32 gflags,guint32 aflags)105 void chd_register(const gchar *prog, GPid pid, guint32 gflags, guint32 aflags)
106 {
107 	ChildInfo	*chi = &the_chi;
108 	Child		*ch;
109 
110 	ch = g_malloc(sizeof *ch);
111 	g_strlcpy(ch->prog, prog, sizeof ch->prog);
112 	ch->pid	   = pid;
113 	ch->gflags = gflags;
114 	ch->aflags = aflags;
115 	chi->child_list = g_slist_append(chi->child_list, ch);
116 	if(!(gflags & CGF_RUNINBG))
117 	{
118 		chi->lock_pid = pid;
119 		gtk_widget_set_sensitive(the_chi.min->gui->window, FALSE);
120 	}
121 	ch->watch = g_child_watch_add(ch->pid, cb_watch_child, ch);
122 }
123 
124 /* 1999-04-08 -	Unregister the child named <name>. This is not meant for public consumption,
125 **		hence it's static. Returns TRUE if a child was found, else FALSE.
126 ** NOTE NOTE	This function doesn't kill any processes or otherwise affect the system's
127 **		process table: it just removes the internal data.
128 */
chd_unregister(const gchar * name)129 static gboolean chd_unregister(const gchar *name)
130 {
131 	GSList		*iter;
132 	Child		*ch;
133 	ChildInfo	*chi = &the_chi;
134 
135 	for(iter = chi->child_list; iter != NULL; iter = g_slist_next(iter))
136 	{
137 		ch = iter->data;
138 		if(strcmp(ch->prog, name) == 0)
139 		{
140 			chi->child_list = g_slist_remove_link(chi->child_list, iter);
141 			g_slist_free_1(iter);
142 			g_source_remove(ch->watch);
143 			g_free(ch);
144 			return TRUE;
145 		}
146 	}
147 	return FALSE;
148 }
149 
150 /* 1999-03-31 -	Set the continuation information. */
chd_set_running(CmdSeq * cs,guint index)151 void chd_set_running(CmdSeq *cs, guint index)
152 {
153 	the_chi.running	= cs;
154 	the_chi.index	= index;
155 }
156 
157 /* 1999-03-31 -	Get the currently running command sequence. If non-NULL, <index> will
158 **		receive the index of the next row to run.
159 */
chd_get_running(guint * index)160 CmdSeq * chd_get_running(guint *index)
161 {
162 	if(index != NULL)
163 		*index = the_chi.index;
164 	return the_chi.running;
165 }
166 
167 /* 1999-03-31 -	Clear continuation info (since the sequence has finished). */
chd_clear_running(void)168 void chd_clear_running(void)
169 {
170 	the_chi.running	= NULL;
171 	the_chi.index	= 0;
172 }
173 
174 /* 1999-03-31 -	Just clear the locking child PID (since it just died, typically). */
chd_clear_lock(void)175 void chd_clear_lock(void)
176 {
177 	the_chi.lock_pid = -1;
178 }
179 
180 /* 1998-09-28 -	Kill (all) running instances of command named <name>. */
chd_kill_child(const gchar * name)181 void chd_kill_child(const gchar *name)
182 {
183 	GSList	*iter, *next;
184 	Child	*ch;
185 	guint	rcount = 0U;
186 	pid_t	pid;
187 
188 	for(iter = the_chi.child_list; iter != NULL; iter = next)
189 	{
190 		next = g_slist_next(iter);
191 		ch = iter->data;
192 		if(strcmp(ch->prog, name) == 0)
193 		{
194 			pid = ch->pid;		/* Buffer in case sighandler g_free()s it. */
195 			if(kill(pid, SIGTERM) == 0)
196 			{
197 				int	ret;
198 
199 				if((ret = waitpid(pid, NULL, 0)) == pid)
200 					rcount++;
201 			}
202 			else
203 				perror("CHILDREN: kill() failed");
204 		}
205 	}
206 	while(rcount && chd_unregister(name))
207 		rcount--;
208 }
209 
210 /* 1998-05-26 -	Kill any child processes (left over from running asynchronous commands).
211 ** 1998-09-09 -	Rewritten due a more advanced child data format.
212 ** 1998-10-11 -	Moved into the children module, where it belongs.
213 */
chd_kill_children(void)214 void chd_kill_children(void)
215 {
216 	GSList	*iter, *next;
217 	Child	*ch;
218 
219 	for(iter = the_chi.child_list; iter != NULL; iter = next)
220 	{
221 		next = g_slist_next(iter);
222 		ch   = iter->data;
223 		if(ch->gflags & CGF_SURVIVE)
224 			continue;
225 		g_source_remove(ch->watch);
226 		if(kill(ch->pid, SIGTERM) != 0)
227 			g_warning(_("Couldn't terminate child \"%s\" (pid=%d)--zombie alert"), ch->prog, (gint) ch->pid);
228 		else
229 		{
230 			waitpid(ch->pid, NULL, 0);
231 			the_chi.child_list = g_slist_remove(the_chi.child_list, ch);
232 			g_free(ch);
233 		}
234 	}
235 }
236