1 /*
2 **
3 ** process.c
4 **
5 ** Copyright (C) 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with GNU gv; see the file COPYING. If not, write to
20 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ** Boston, MA 02111-1307, USA.
22 **
23 ** Author: Johannes Plass (plass@thep.physik.uni-mainz.de)
24 ** Department of Physics
25 ** Johannes Gutenberg-University
26 ** Mainz, Germany
27 **
28 ** Jose E. Marchesi (jemarch@gnu.org)
29 ** GNU Project
30 **
31 */
32 #include "ac_config.h"
33
34 /*
35 #define MESSAGES
36 */
37 #include "message.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42
43
44 # include <sys/types.h>
45 # include <sys/wait.h>
46 # include <unistd.h>
47 # include <signal.h>
48 # include <gv_signal.h>
49
50 #include "paths.h"
51 #include INC_X11(Intrinsic.h)
52 #include INC_X11(StringDefs.h)
53 #include INC_XAW(MenuButton.h)
54 #include INC_XAW(SimpleMenu.h)
55 #include INC_XAW(SmeBSB.h)
56 #include INC_X11(IntrinsicP.h)
57 #include INC_X11(ShellP.h)
58
59 #include "types.h"
60 #include "config.h"
61 #include "callbacks.h"
62 #include "process.h"
63 #include "main_resources.h"
64 #include "main_globals.h"
65 #include "misc_private.h"
66
67 #include "resource.h"
68
69 #define CHECK_PERIOD 500
70 #define ADD_TIMEOUT(widget,interval,data) \
71 XtAppAddTimeOut ( \
72 app_con, \
73 ((unsigned long)(interval)), \
74 process_notify, \
75 ((XtPointer)(data)) \
76 )
77
78 #define DISABLED ((XtIntervalId) 0)
79 #define DESTROY_TIMER(aaa) \
80 if ((aaa)) { \
81 XtRemoveTimeOut((aaa)); \
82 aaa = DISABLED; \
83 }
84
85 static ProcessData gpd = NULL;
86
87 /*------------------------------------------------------------*/
88 /* process_get_pd */
89 /*------------------------------------------------------------*/
90
process_get_pd(void)91 static ProcessData process_get_pd(void)
92 {
93 ProcessData pd;
94 Cardinal size = sizeof(ProcessDataStruct);
95 BEGINMESSAGE(process_get_pd)
96 # ifdef MESSAGES
97 if (!gpd) { INFMESSAGE(no processes registered yet) }
98 # endif
99 pd = (ProcessData) XtMalloc(size);
100 memset((void*) pd ,0,(size_t)size);
101 if (!gpd) gpd = pd;
102 else {
103 ProcessData tmppd;
104 tmppd = gpd; while (tmppd->next) tmppd = tmppd->next;
105 tmppd->next=pd;
106 }
107 ENDMESSAGE(process_get_pd)
108 return(pd);
109 }
110
111 /*------------------------------------------------------------*/
112 /* process_remove_pd */
113 /*------------------------------------------------------------*/
114
process_remove_pd(ProcessData pd)115 static void process_remove_pd(ProcessData pd)
116 {
117 BEGINMESSAGE(process_remove_pd)
118 if (gpd == pd) gpd = pd->next;
119 else {
120 ProcessData tmppd = gpd;
121 while (tmppd->next != pd) tmppd=tmppd->next;
122 tmppd->next = pd->next;
123 }
124 process_menu(pd,PROCESS_MENU_DEL_ENTRY);
125 DESTROY_TIMER(pd->timer)
126 XtFree(pd->name);
127 XtFree((XtPointer)pd);
128 # ifdef MESSAGES
129 if (!gpd) { INFMESSAGE(no more processes registered) }
130 # endif
131 ENDMESSAGE(process_remove_pd)
132 }
133
134 /*------------------------------------------------------------*/
135 /* process_child_status */
136 /*------------------------------------------------------------*/
137
138 #define CHILD_UNKNOWN_STATUS -2
139 #define CHILD_ERROR -1
140 #define CHILD_OKAY 0
141 #define CHILD_EXITED 1
142
process_child_status(ProcessData pd)143 static int process_child_status(ProcessData pd)
144 {
145 int status;
146 pid_t child_pid;
147
148 BEGINMESSAGE(process_child_status)
149
150 child_pid = waitpid(pd->pid,NULL,WNOHANG);
151 if (child_pid==pd->pid) { status=CHILD_EXITED; INFMESSAGE(CHILD_EXITED) }
152 else if (child_pid==0) { status=CHILD_OKAY; INFMESSAGE(CHILD_OKAY) }
153 else if (child_pid==-1) { status=CHILD_ERROR; INFMESSAGE(CHILD_ERROR) }
154 else { status=CHILD_UNKNOWN_STATUS; INFMESSAGE(CHILD_UNKNOWN_STATUS) }
155 ENDMESSAGE(process_child_status)
156 return(status);
157 }
158
159
160 /*##############################################################*/
161 /* cb_processKillProcess */
162 /*##############################################################*/
163
164 void
cb_processKillProcess(Widget w _GL_UNUSED,XtPointer client_data,XtPointer call_data _GL_UNUSED)165 cb_processKillProcess(Widget w _GL_UNUSED, XtPointer client_data, XtPointer call_data _GL_UNUSED)
166 {
167 ProcessData pd;
168 BEGINMESSAGE(cb_processKillProcess)
169 pd = (ProcessData)client_data;
170 process_kill_process(pd);
171 ENDMESSAGE(cb_processKillProcess)
172 }
173
174 /*##############################################################*/
175 /* process_kill_process */
176 /*##############################################################*/
177
process_kill_process(ProcessData pd)178 void process_kill_process(ProcessData pd)
179 {
180 int status;
181 BEGINMESSAGE(process_kill_process)
182 kill(pd->pid, SIGTERM);
183 status=process_child_status(pd);
184 if (status==CHILD_OKAY) {
185 INFMESSAGE(waiting for child to exit);
186 wait(NULL);
187 }
188 (*(pd->notify_proc))(pd->data,PROCESS_KILL);
189 process_remove_pd(pd);
190 ENDMESSAGE(process_kill_process)
191 }
192
193 /*##############################################################*/
194 /* process_kill_all_processes */
195 /*##############################################################*/
196
process_kill_all_processes(void)197 void process_kill_all_processes(void)
198 {
199 BEGINMESSAGE(process_kill_all_processes)
200 while (gpd) process_kill_process(gpd);
201 ENDMESSAGE(process_kill_all_processes)
202 }
203
204 /*------------------------------------------------------------*/
205 /* process_notify */
206 /*------------------------------------------------------------*/
207
process_notify(XtPointer client_data,XtIntervalId * idp _GL_UNUSED)208 static void process_notify(XtPointer client_data, XtIntervalId *idp _GL_UNUSED)
209 {
210 pid_t child_pid;
211 ProcessData pd = (ProcessData) client_data;
212
213 BEGINMESSAGE(process_notify)
214 child_pid = process_child_status(pd);
215 if (child_pid==0) {
216 INFMESSAGE(child did not exit yet)
217 pd->timer = ADD_TIMEOUT(toplevel,CHECK_PERIOD,client_data);
218 process_menu(pd,PROCESS_MENU_PROGRESS);
219 } else {
220 INFMESSAGE(calling notify procedure)
221 (*(pd->notify_proc))(pd->data,PROCESS_NOTIFY);
222 process_remove_pd(pd);
223 }
224 ENDMESSAGE(process_notify)
225 }
226
227 /*##############################################################*/
228 /* process_fork */
229 /*##############################################################*/
230
process_fork(String name,String command,ProcessNotifyProc notify_proc,XtPointer data)231 ProcessData process_fork(String name, String command, ProcessNotifyProc notify_proc, XtPointer data)
232 {
233 ProcessData pd;
234 pid_t pid;
235
236 BEGINMESSAGE(process_fork)
237
238 pd = process_get_pd();
239
240 pid = fork();
241
242 if (pid == 0) { /* child */
243 char *argv[4];
244 char *c;
245
246 INFMESSAGE(child process)
247 c = command;
248 SMESSAGE(c)
249
250
251 argv[0] = "sh";
252 argv[1] = "-c";
253 argv[2] = c;
254 argv[3] = NULL;
255
256 INFMESSAGE(spawning conversion process)
257 /*
258 if (!freopen("/dev/null", "w", stdout)) perror("/dev/null");
259 */
260 if (!freopen("/dev/null", "r", stdin)) perror("/dev/null");
261
262 if (gv_gs_safeDir) {
263 if (chdir(gv_safe_gs_workdir) != 0) {
264 char buf[512];
265 sprintf(buf, "Chdir to %s failed", gv_safe_gs_workdir);
266 perror(buf);
267 _exit(EXIT_STATUS_ERROR);
268 }
269 }
270 execvp(argv[0], argv);
271
272 {
273 char tmp[512];
274 sprintf(tmp, execOfFailedLabel, argv[0]);
275 perror(tmp);
276 _exit(EXIT_STATUS_ERROR);
277 }
278 }
279 INFMESSAGE(parent process)
280 pd->name = XtNewString(name);
281 pd->notify_proc = notify_proc;
282 pd->data = data;
283 pd->pid = pid;
284 pd->timer = ADD_TIMEOUT(toplevel,CHECK_PERIOD,pd);
285
286 process_menu(pd,PROCESS_MENU_ADD_ENTRY);
287
288 ENDMESSAGE(process_fork)
289 return(pd);
290 }
291
292 /*------------------------------------------------------------*/
293 /* process_set_shell_resize */
294 /*------------------------------------------------------------*/
295
process_set_shell_resize(Boolean allow_resize)296 static Boolean process_set_shell_resize(Boolean allow_resize)
297 {
298 Boolean old_allow_resize;
299 ShellWidget sw = (ShellWidget)toplevel;
300 old_allow_resize = sw->shell.allow_shell_resize;
301 sw->shell.allow_shell_resize=allow_resize;
302 return(old_allow_resize);
303 }
304
305 /*##############################################################*/
306 /* process_menu */
307 /*##############################################################*/
308
process_menu(ProcessData pd,int action)309 void process_menu(ProcessData pd, int action)
310 {
311
312 Arg args[5];
313 Cardinal n;
314 static int visible=1;
315 static int progress=0;
316
317 if (action==PROCESS_MENU_HIDE) {
318 INFMESSAGE(PROCESS_MENU_HIDE)
319 if (visible) {
320 Boolean allow_resize;
321
322 allow_resize=process_set_shell_resize(False);
323 n=0;
324 XtSetArg(args[n], XtNwidth, 0); n++;
325 XtSetArg(args[n], XtNheight, 0); n++;
326 XtSetValues(processButton,args,n);
327
328 process_set_shell_resize(allow_resize);
329
330 visible=0;
331 progress=0;
332 }
333 }
334 else if (action==PROCESS_MENU_SHOW) {
335 INFMESSAGE(PROCESS_MENU_SHOW)
336 if (!visible) {
337 String label;
338 Boolean allow_resize;
339
340 allow_resize=process_set_shell_resize(False);
341
342 n=0;
343 XtSetArg(args[n], XtNlabel, &label); n++;
344 XtGetValues(processButton,args,n);
345 label=XtNewString(label);
346 SMESSAGE(label)
347
348 n=0;
349 XtSetArg(args[n], XtNresize, True); n++;
350 XtSetArg(args[n], XtNlabel, ""); n++;
351 XtSetValues(processButton,args,n);
352
353 n=0;
354 XtSetArg(args[n], XtNlabel, label); n++;
355 XtSetValues(processButton,args,n);
356 n=0;
357 XtSetArg(args[n], XtNresize, False); n++;
358 XtSetValues(processButton,args,n);
359 XtFree(label);
360
361 process_set_shell_resize(allow_resize);
362 visible=1;
363 progress=0;
364 }
365 }
366 else if (action==PROCESS_MENU_ADD_ENTRY) {
367 Widget entry;
368 char label[512];
369 INFMESSAGE(PROCESS_MENU_ADD_ENTRY)
370 if (!processMenu) {
371 n=0;
372 processMenu = XtCreatePopupShell("menu",
373 simpleMenuWidgetClass,processButton,args,n);
374 }
375 sprintf(label,"Stop %s",pd->name);
376
377 n=0;
378 XtSetArg(args[n], XtNlabel, label); n++;
379 entry = XtCreateManagedWidget("aaa", smeBSBObjectClass,processMenu,args,n);
380 XtAddCallback(entry, XtNcallback, cb_processKillProcess, (XtPointer)pd);
381 pd->menuentry = entry;
382 process_menu(NULL,PROCESS_MENU_SHOW);
383 process_menu(pd,PROCESS_MENU_PROGRESS);
384 }
385 else if (action==PROCESS_MENU_DEL_ENTRY) {
386 INFMESSAGE(PROCESS_MENU_DEL_ENTRY)
387 if (!gv_exiting) {
388 if (!gpd) {
389 INFMESSAGE(destroying processMenu)
390 XtDestroyWidget(processMenu);
391 processMenu=NULL;
392 process_menu(NULL,PROCESS_MENU_HIDE);
393 }
394 else {
395 INFMESSAGE(destroying menu entry)
396 XtDestroyWidget(pd->menuentry);
397 }
398 }
399 }
400 else if (action==PROCESS_MENU_PROGRESS) {
401 INFMESSAGE(PROCESS_MENU_PROGRESS)
402 if (visible) {
403 char *label;
404 char *tmp;
405 size_t len;
406 n=0;
407 XtSetArg(args[n], XtNlabel, &label); n++;
408 XtGetValues(processButton,args,n);
409 len = strlen(label);
410 tmp = (char*) XtMalloc(len*sizeof(char)+1);
411 strcpy(tmp,&(label[progress]));
412 if (progress) {
413 if (progress>(int)len) progress=(int)len;
414 strncpy(&(tmp[(int)len-progress]),label,(size_t)progress);
415 }
416 tmp[len]='\0';
417 progress++;
418 if (progress==(int)len+1) progress=0;
419 update_label(processButton,tmp);
420 XtFree(tmp);
421 }
422 }
423 }
424
425 /*##############################################################*/
426 /* process_disallow_quit */
427 /*##############################################################*/
428
process_disallow_quit(void)429 char *process_disallow_quit(void)
430 {
431 # define MAX_DISALLOW_QUIT_MESSAGE 512
432 static char message[MAX_DISALLOW_QUIT_MESSAGE];
433 ProcessData pd;
434 int l;
435
436 BEGINMESSAGE(process_disallow_quit)
437 if (!gpd) {
438 ENDMESSAGE(process_disallow_quit)
439 return NULL;
440 }
441 strcpy(message,stillInProgressLabel);
442 l = strlen(message);
443 for (pd = gpd; pd ; pd = pd->next) {
444 l = l + strlen(pd->name) + 1;
445 if (l + 10 < MAX_DISALLOW_QUIT_MESSAGE) {
446 strcat(message,"\n");
447 strcat(message,pd->name);
448 } else break;
449 };
450 if (pd) strcat(message,"\n...");
451 ENDMESSAGE(process_disallow_quit)
452 return message;
453 }
454
455