Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/exec.c
1069 views
1
/*
2
* exec.c: handles exec'd process for IRCII
3
*
4
* Copyright 1990 Michael Sandrof
5
* Copyright 1997 EPIC Software Labs
6
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
7
*/
8
9
#define _GNU_SOURCE /* Needed for strsignal from string.h on GLIBC systems */
10
11
#include "irc.h"
12
static char cvsrevision[] = "$Id: exec.c 156 2012-02-17 12:30:55Z keaston $";
13
CVS_REVISION(exec_c)
14
#include "struct.h"
15
16
#include "dcc.h"
17
#include "exec.h"
18
#include "vars.h"
19
#include "ircaux.h"
20
#include "commands.h"
21
#include "window.h"
22
#include "screen.h"
23
#include "hook.h"
24
#include "input.h"
25
#include "list.h"
26
#include "server.h"
27
#include "output.h"
28
#include "parse.h"
29
#include "newio.h"
30
#include "gui.h"
31
#define MAIN_SOURCE
32
#include "modval.h"
33
34
#include <unistd.h>
35
#include <sys/wait.h>
36
#include <sys/ioctl.h>
37
#ifdef HAVE_SYS_FILIO_H
38
#include <sys/filio.h>
39
#endif
40
#ifdef __EMX__
41
#include <process.h>
42
#endif
43
44
pid_t getpid(void);
45
46
/* Process: the structure that has all the info needed for each process */
47
typedef struct
48
{
49
int index; /* Where in the proc array it is */
50
char *name; /* full process name */
51
char *logical;
52
pid_t pid; /* process-id of process */
53
int p_stdin; /* stdin description for process */
54
int p_stdout; /* stdout descriptor for process */
55
int p_stderr; /* stderr descriptor for process */
56
int counter; /* output line counter for process */
57
char *redirect; /* redirection command (MSG, NOTICE) */
58
unsigned refnum; /* a window for output to go to */
59
int server; /* the server to use for output */
60
char *who; /* nickname used for redirection */
61
int exited; /* true if process has exited */
62
int termsig; /* The signal that terminated
63
* the process */
64
int retcode; /* return code of process */
65
List *waitcmds; /* commands queued by WAIT -CMD */
66
int dumb; /* 0 if input still going, 1 if not */
67
int disowned; /* 1 if we let it loose */
68
char *stdoutc;
69
char *stdoutpc;
70
char *stderrc;
71
char *stderrpc;
72
} Process;
73
74
static Process **process_list = NULL;
75
static int process_list_size = 0;
76
77
static void handle_filedesc (Process *, int *, int, int);
78
static void cleanup_dead_processes (void);
79
static void ignore_process (int index);
80
void kill_process (int, int);
81
static void kill_all_processes (int signo);
82
static int valid_process_index (int proccess);
83
static int is_logical_unique (char *logical);
84
int logical_to_index (const char *logical);
85
extern int dead_children_processes;
86
extern int in_cparse;
87
extern char *next_expr (char **, char);
88
89
/*
90
* A nice array of the possible signals. Used by the coredump trapping
91
* routines and in the exec.c package.
92
*/
93
#if !HAVE_DECL_SYS_SIGLIST && !HAVE_DECL__SYS_SIGLIST && !defined(__QNX__)
94
#if defined(WINNT) || defined(__EMX__)
95
char *sys_siglist[] = { "ZERO", "SIGINT", "SIGKILL", "SIGPIPE", "SIGFPE",
96
"SIGHUP", "SIGTERM", "SIGSEGV", "SIGTSTP",
97
"SIGQUIT", "SIGTRAP", "SIGILL", "SIGEMT", "SIGALRM",
98
"SIGBUS", "SIGLOST", "SIGSTOP", "SIGABRT", "SIGUSR1",
99
"SIGUSR2", "SIGCHLD", "SIGTTOU", "SIGTTIN", "SIGCONT" };
100
#elif HAVE_DECL_STRSIGNAL
101
#define USING_STRSIGNAL
102
/* use strsignal() from <string.h> */
103
#include <string.h>
104
#else
105
#include "sig.inc"
106
#endif
107
#endif
108
109
/*
110
* exec: the /EXEC command. Does the whole shebang for ircII sub procceses
111
* I melded in about half a dozen external functions, since they were only
112
* ever used here. Perhaps at some point theyll be broken out again, but
113
* not until i regain control of this module.
114
*/
115
BUILT_IN_COMMAND(execcmd)
116
{
117
#if !defined(PUBLIC_ACCESS)
118
#if defined(EXEC_COMMAND)
119
char *who = NULL,
120
*logical = NULL,
121
*redirect = NULL,
122
*flag;
123
unsigned refnum = 0;
124
int sig,
125
len,
126
i,
127
refnum_flag = 0,
128
logical_flag = 0;
129
int direct = 0;
130
Process *proc;
131
char *stdoutc = NULL,
132
*stderrc = NULL,
133
*stderrpc = NULL,
134
*stdoutpc = NULL,
135
*endc = NULL;
136
137
/*
138
* Protect the user against themselves.
139
* XXX This is stupid.
140
*/
141
if (get_int_var(EXEC_PROTECTION_VAR) && (current_on_hook != -1))
142
{
143
say("Attempt to use EXEC from within an ON function!");
144
say("Command \"%s\" not executed!", args);
145
say("Please read /HELP SET EXEC_PROTECTION");
146
say("for important details about this!");
147
return;
148
}
149
if (in_cparse)
150
{
151
yell("Something very bad just happened. an $exec() was issued");
152
yell("from within a format. Please notify panasync about this immediately");
153
yell("with what version of BitchX as well the scripts loaded when this happened");
154
return;
155
}
156
/*
157
* If no args are given, list all the processes.
158
*/
159
if (!*args)
160
{
161
int i;
162
163
if (!process_list)
164
{
165
say("No processes are running");
166
return;
167
}
168
169
say("Process List:");
170
for (i = 0; i < process_list_size; i++)
171
{
172
Process *proc = process_list[i];
173
174
if (!proc)
175
continue;
176
177
if (proc->logical)
178
say("\t%d (%s) (pid %d): %s",
179
i, proc->logical, proc->pid, proc->name);
180
else
181
say("\t%d (pid %d): %s", i, proc->pid, proc->name);
182
}
183
return;
184
}
185
186
/*
187
* Walk through and parse out all the args
188
*/
189
while ((*args == '-') && (flag = next_arg(args, &args)))
190
{
191
flag++;
192
if (!*flag)
193
break;
194
len = strlen(flag);
195
196
/*
197
* /EXEC -OUT redirects all output from the /exec to the
198
* current channel for the current window.
199
*/
200
if (my_strnicmp(flag, "OUT", len) == 0)
201
{
202
if (doing_privmsg)
203
redirect = "NOTICE";
204
else
205
redirect = "PRIVMSG";
206
207
/* Now we can `/exec -o' to queries too. - djw */
208
if (!(who = get_target_by_refnum(0)))
209
{
210
say("No target for this window for -OUT");
211
return;
212
}
213
}
214
215
/*
216
* /EXEC -NAME gives the /exec a logical name that can be
217
* refered to as %name
218
*/
219
else if (my_strnicmp(flag, "NAME", len) == 0)
220
{
221
logical_flag = 1;
222
if (!(logical = next_arg(args, &args)))
223
{
224
say("You must specify a logical name");
225
return;
226
}
227
}
228
229
/*
230
* /EXEC -WINDOW forces all output for an /exec to go to
231
* the window that is current at this time
232
*/
233
else if (my_strnicmp(flag, "WINDOW", len) == 0)
234
{
235
refnum_flag = 1;
236
refnum = current_refnum();
237
}
238
239
/*
240
* /EXEC -MSG <target> redirects the output of an /exec
241
* to the given target.
242
*/
243
else if (my_strnicmp(flag, "MSG", len) == 0)
244
{
245
if (doing_privmsg)
246
redirect = "NOTICE";
247
else
248
redirect = "PRIVMSG";
249
250
if (!(who = next_arg(args, &args)))
251
{
252
say("No nicknames specified");
253
return;
254
}
255
}
256
257
/*
258
* /EXEC -LINE specifies the stdout callback
259
*/
260
else if (my_strnicmp(flag, "LINE", len) == 0)
261
{
262
if ((stdoutc = next_expr(&args, '{')) == NULL)
263
say("Need {...} argument for -LINE flag");
264
}
265
266
/*
267
* /EXEC -LINEPART specifies the stdout partial line callback
268
*/
269
else if (my_strnicmp(flag, "LINEPART", len) == 0)
270
{
271
if ((stdoutpc = next_expr(&args, '{')) == NULL)
272
say("Need {...} argument for -LINEPART flag");
273
}
274
275
/*
276
* /EXEC -ERROR specifies the stderr callback
277
*/
278
else if (my_strnicmp(flag, "ERROR", len) == 0)
279
{
280
if ((stderrc = next_expr(&args, '{')) == NULL)
281
say("Need {...} argument for -ERROR flag");
282
}
283
284
/*
285
* /EXEC -ERRORPART specifies the stderr part line callback
286
*/
287
else if (my_strnicmp(flag, "ERRORPART", len) == 0)
288
{
289
if ((stderrpc = next_expr(&args, '{')) == NULL)
290
say("Need {...} argument for -ERRORPART flag");
291
}
292
293
/*
294
* /EXEC -END specifies the final collection callback
295
*/
296
else if (my_strnicmp(flag, "END", len) == 0)
297
{
298
if ((endc = next_expr(&args, '{')) == NULL)
299
say("Need {...} argument for -END flag");
300
}
301
302
/*
303
* /EXEC -CLOSE forcibly closes all the fd's to a process,
304
* in the hope that it will take the hint.
305
*/
306
else if (my_strnicmp(flag, "CLOSE", len) == 0)
307
{
308
if ((i = get_process_index(&args)) == -1)
309
return;
310
311
ignore_process(i);
312
return;
313
}
314
315
/*
316
* /EXEC -NOTICE <target> redirects the output of an /exec
317
* to a specified target
318
*/
319
else if (my_strnicmp(flag, "NOTICE", len) == 0)
320
{
321
redirect = "NOTICE";
322
if (!(who = next_arg(args, &args)))
323
{
324
say("No nicknames specified");
325
return;
326
}
327
}
328
329
/*
330
* /EXEC -start <command> starts a command with no association
331
* to the main BitchX process.
332
*/
333
else if (my_strnicmp(flag, "START", len) == 0)
334
{
335
#ifndef __EMX__
336
if(fork() == 0)
337
{
338
int i;
339
#endif
340
char *name = args;
341
char **args, *arg;
342
int max, cnt;
343
344
cnt = 0;
345
max = 5;
346
args = new_malloc(sizeof(char *) * max);
347
while ((arg = new_next_arg(name, &name)))
348
{
349
if (!arg || !*arg)
350
break;
351
if (cnt == max)
352
{
353
max += 5;
354
RESIZE(args, char *, max);
355
}
356
357
args[cnt++] = arg;
358
}
359
args[cnt] = NULL;
360
#ifndef __EMX__
361
for (i = 3; i < 256; i++)
362
close(i);
363
setsid();
364
execvp(args[0], args);
365
_exit(-1);
366
}
367
#else
368
spawnvp(P_SESSION, args[0], args);
369
#endif
370
return;
371
}
372
373
/*
374
* /EXEC -IN sends a line of text to a process
375
*/
376
else if (my_strnicmp(flag, "IN", len) == 0)
377
{
378
if ((i = get_process_index(&args)) == -1)
379
return;
380
381
text_to_process(i, args, 1);
382
return;
383
}
384
385
/*
386
* /EXEC -INQUIET quietly sends a line of text to a process
387
*/
388
else if (my_strnicmp(flag, "INQUIET", len) == 0)
389
{
390
if ((i = get_process_index(&args)) == -1)
391
return;
392
393
text_to_process(i, args, 0);
394
return;
395
}
396
397
/*
398
* /EXEC -DIRECT suppresses the use of a shell
399
*/
400
else if (my_strnicmp(flag, "DIRECT", len) == 0)
401
direct = 1;
402
403
/*
404
* All other - arguments are implied KILLs
405
*/
406
else
407
{
408
if (*args != '%')
409
{
410
say("%s is not a valid process", args);
411
return;
412
}
413
414
/*
415
* Check for a process to kill
416
*/
417
if ((i = get_process_index(&args)) == -1)
418
return;
419
420
/*
421
* Handle /exec -<num> %<process>
422
*/
423
if ((sig = my_atol(flag)) > 0)
424
{
425
if ((sig > 0) && (sig < NSIG-1))
426
kill_process(i, sig);
427
else
428
say("Signal number can be from 1 to %d", NSIG-1);
429
return;
430
}
431
432
/*
433
* Handle /exec -<SIGNAME> %<process>
434
*/
435
for (sig = 1; sig < NSIG-1; sig++)
436
{
437
#if defined(USING_STRSIGNAL)
438
if (strsignal(sig) && !my_strnicmp(strsignal(sig), flag, len))
439
#else
440
if (sys_siglist[sig] && !my_strnicmp(sys_siglist[sig], flag, len))
441
#endif
442
{
443
kill_process(i, sig);
444
return;
445
}
446
}
447
448
/*
449
* Give up! =)
450
*/
451
say("No such signal: %s", flag);
452
return;
453
}
454
}
455
456
/*
457
* This handles the form:
458
*
459
* /EXEC <flags> %process
460
*
461
* Where the user wants to redefine some options for %process.
462
*/
463
if (*args == '%')
464
{
465
int i;
466
467
/*
468
* Make sure the process is actually running
469
*/
470
if ((i = get_process_index(&args)) == -1)
471
return;
472
473
proc = process_list[i];
474
message_to(refnum);
475
476
/*
477
* Check to see if the user wants to change windows
478
*/
479
if (refnum_flag)
480
{
481
proc->refnum = refnum;
482
if (refnum)
483
say("Output from process %d (%s) now going to this window", i, proc->name);
484
else
485
say("Output from process %d (%s) not going to any window", i, proc->name);
486
}
487
488
/*
489
* Check to see if the user is changing the default target
490
*/
491
malloc_strcpy(&(proc->redirect), redirect);
492
malloc_strcpy(&(proc->who), who);
493
494
if (redirect)
495
say("Output from process %d (%s) now going to %s", i, proc->name, who);
496
else
497
say("Output from process %d (%s) now going to you", i, proc->name);
498
499
/*
500
* Check to see if the user changed the NAME of %proc.
501
*/
502
if (logical_flag)
503
{
504
if (is_logical_unique(logical))
505
{
506
malloc_strcpy(&proc->logical, logical);
507
say("Process %d (%s) is now called %s",
508
i, proc->name, proc->logical);
509
}
510
else
511
say("The name %s is not unique!", logical);
512
}
513
message_to(0);
514
}
515
516
/*
517
* The user is trying to fire up a new /exec, so pass the buck.
518
*/
519
else
520
{
521
int p0[2], p1[2], p2[2],
522
pid, cnt;
523
char *shell,
524
*flag,
525
*arg;
526
char *name = args;
527
528
if (!is_logical_unique(logical))
529
{
530
say("The name %s is not unique!", logical);
531
return;
532
}
533
534
p0[0] = p1[0] = p2[0] = -1;
535
p0[1] = p1[1] = p2[1] = -1;
536
537
/*
538
* Open up the communication pipes
539
*/
540
if (pipe(p0) || pipe(p1) || pipe(p2))
541
{
542
say("Unable to start new process: %s", strerror(errno));
543
new_close(p0[0]);
544
new_close(p0[1]);
545
new_close(p1[0]);
546
new_close(p1[1]);
547
new_close(p2[0]);
548
new_close(p2[1]);
549
return;
550
}
551
552
#ifndef __EMXPM__
553
switch ((pid = fork()))
554
{
555
case -1:
556
say("Couldn't start new process!");
557
break;
558
559
/*
560
* CHILD: set up and exec the process
561
*/
562
case 0:
563
{
564
int i;
565
566
/*
567
* Fire up a new job control session,
568
* Sever all ties we had with the parent ircII process
569
*/
570
#if !defined(WINNT) && !defined(__EMX__)
571
setsid();
572
#endif
573
setuid(getuid());
574
setgid(getgid());
575
my_signal(SIGINT, SIG_IGN, 0);
576
my_signal(SIGQUIT, SIG_DFL, 0);
577
my_signal(SIGSEGV, SIG_DFL, 0);
578
my_signal(SIGBUS, SIG_DFL, 0);
579
#endif
580
581
dup2(p0[0], 0);
582
dup2(p1[1], 1);
583
dup2(p2[1], 2);
584
#ifdef __EMXPM__
585
/* prevent inheritance */
586
fcntl(p0[1], F_SETFD, FD_CLOEXEC);
587
fcntl(p1[0], F_SETFD, FD_CLOEXEC);
588
fcntl(p2[0], F_SETFD, FD_CLOEXEC);
589
#else
590
close(p0[1]);
591
close(p1[0]);
592
close(p2[0]);
593
p0[1] = p1[0] = p2[0] = -1;
594
for (i = 3; i < 256; i++)
595
close(i);
596
#endif
597
598
/*
599
* Pretend to be just a dumb terminal
600
*/
601
/*
602
bsd_setenv("TERM", "tty", 1);
603
*/
604
/*
605
* Figure out what shell (if any) we're using
606
*/
607
shell = get_string_var(SHELL_VAR);
608
609
/*
610
* If we're not using a shell, doovie up the exec args
611
* array and pass it off to execvp
612
*/
613
if (direct || !shell)
614
{
615
char **args;
616
int max;
617
618
cnt = 0;
619
max = 5;
620
args = new_malloc(sizeof(char *) * max);
621
while ((arg = new_next_arg(name, &name)))
622
{
623
if (!arg || !*arg)
624
break;
625
if (cnt == max)
626
{
627
max += 5;
628
RESIZE(args, char *, max);
629
}
630
631
args[cnt++] = arg;
632
}
633
args[cnt] = NULL;
634
#ifndef __EMXPM__
635
execvp(args[0], args);
636
#else
637
pid = spawnvp(P_NOWAIT, args[0], args);
638
#endif
639
}
640
641
/*
642
* If we're using a shell, let them have all the fun
643
*/
644
else
645
{
646
if (!(flag = get_string_var(SHELL_FLAGS_VAR)))
647
flag = empty_string;
648
649
#ifndef __EMXPM__
650
execl(shell, shell, flag, name, NULL);
651
#else
652
pid = spawnl(P_NOWAIT, shell, shell, flag, name, NULL);
653
#endif
654
}
655
656
#ifndef __EMXPM__
657
/*
658
* Something really died if we got here
659
*/
660
printf("*** Error starting shell \"%s\": %s\n",
661
shell, strerror(errno));
662
_exit(-1);
663
break;
664
}
665
666
/*
667
* PARENT: add the new process to the process table list
668
*/
669
default:
670
#else
671
if(pid == -1)
672
say("Couldn't start new process!");
673
else
674
#endif
675
{
676
int i;
677
Process *proc = new_malloc(sizeof(Process));
678
679
new_close(p0[0]);
680
new_close(p1[1]);
681
new_close(p2[1]);
682
683
/*
684
* Init the proc list if neccesary
685
*/
686
if (!process_list)
687
{
688
process_list = new_malloc(sizeof(Process *));
689
process_list_size = 1;
690
process_list[0] = NULL;
691
}
692
693
/*
694
* Find the first empty proc entry
695
*/
696
for (i = 0; i < process_list_size; i++)
697
{
698
if (!process_list[i])
699
{
700
process_list[i] = proc;
701
break;
702
}
703
}
704
705
/*
706
* If there are no empty proc entries, make a new one.
707
*/
708
if (i == process_list_size)
709
{
710
process_list_size++;
711
RESIZE(process_list, Process *, process_list_size);
712
process_list[i] = proc;
713
}
714
715
/*
716
* Fill in the new proc entry
717
*/
718
proc->name = m_strdup(name);
719
proc->logical = logical ? m_strdup(logical) : NULL;
720
proc->index = i;
721
proc->pid = pid;
722
proc->p_stdin = p0[1];
723
proc->p_stdout = p1[0];
724
proc->p_stderr = p2[0];
725
proc->refnum = refnum;
726
proc->redirect = NULL;
727
if (redirect)
728
proc->redirect = m_strdup(redirect);
729
proc->server = current_window->server;
730
proc->counter = 0;
731
proc->exited = 0;
732
proc->termsig = 0;
733
proc->retcode = 0;
734
proc->waitcmds = NULL;
735
proc->who = NULL;
736
proc->disowned = 0;
737
if (who)
738
proc->who = m_strdup(who);
739
proc->dumb = 0;
740
741
if (stdoutc)
742
proc->stdoutc = m_strdup(stdoutc);
743
else
744
proc->stdoutc = NULL;
745
746
if (stdoutpc)
747
proc->stdoutpc = m_strdup(stdoutpc);
748
else
749
proc->stdoutpc = NULL;
750
751
if (stderrc)
752
proc->stderrc = m_strdup(stderrc);
753
else
754
proc->stderrc = NULL;
755
756
if (stderrpc)
757
proc->stderrpc = m_strdup(stderrpc);
758
else
759
proc->stderrpc = NULL;
760
761
if (endc)
762
add_process_wait(proc->index, endc);
763
764
new_open(proc->p_stdout);
765
new_open(proc->p_stderr);
766
#ifndef __EMXPM__
767
break;
768
}
769
#endif
770
}
771
}
772
773
cleanup_dead_processes();
774
#endif
775
#endif
776
}
777
778
/*
779
* do_processes: This is called from the main io() loop to handle any
780
* pending /exec'd events. All this does is call handle_filedesc() on
781
* the two reading descriptors. If an EOF is asserted on either, then they
782
* are closed. If EOF has been asserted on both, then we mark the process
783
* as being "dumb". Once it is reaped (exited), it is expunged.
784
*/
785
void do_processes (fd_set *rd)
786
{
787
int i;
788
int limit;
789
790
if (!process_list)
791
return;
792
793
limit = get_int_var(SHELL_LIMIT_VAR);
794
for (i = 0; i < process_list_size; i++)
795
{
796
Process *proc = process_list[i];
797
798
if (!proc)
799
continue;
800
801
if (proc->p_stdout != -1 && FD_ISSET(proc->p_stdout, rd))
802
handle_filedesc(proc, &proc->p_stdout,
803
EXEC_PROMPT_LIST, EXEC_LIST);
804
805
if (proc->p_stderr != -1 && FD_ISSET(proc->p_stderr, rd))
806
handle_filedesc(proc, &proc->p_stderr,
807
EXEC_PROMPT_LIST, EXEC_ERRORS_LIST);
808
809
if (limit && proc->counter >= limit)
810
ignore_process(proc->index);
811
}
812
813
/* Clean up any (now) dead processes */
814
cleanup_dead_processes();
815
}
816
817
/*
818
* This is the back end to do_processes, saves some repeated code
819
*/
820
static void handle_filedesc (Process *proc, int *fd, int hook_nonl, int hook_nl)
821
{
822
char exec_buffer[IO_BUFFER_SIZE + 1];
823
int len;
824
825
switch ((len = dgets(exec_buffer, *fd, 0, IO_BUFFER_SIZE, NULL))) /* No buffering! */
826
{
827
case -1: /* Something died */
828
{
829
*fd = new_close(*fd);
830
if (proc->p_stdout == -1 && proc->p_stderr == -1)
831
proc->dumb = 1;
832
break;
833
}
834
case 0: /* We didnt get a full line */
835
{
836
if (hook_nl == EXEC_LIST && proc->stdoutpc)
837
parse_line("EXEC", proc->stdoutpc, exec_buffer, 0, 0, 1);
838
else if (hook_nl == EXEC_ERRORS_LIST && proc->stderrpc)
839
parse_line("EXEC", proc->stderrpc, exec_buffer, 0, 0, 1);
840
else if (proc->logical)
841
do_hook(hook_nonl, "%s %s",
842
proc->logical, exec_buffer);
843
else
844
do_hook(hook_nonl, "%d %s",
845
proc->index, exec_buffer);
846
847
set_prompt_by_refnum(proc->refnum, exec_buffer);
848
update_input(UPDATE_ALL);
849
break;
850
}
851
default: /* We got a full line */
852
{
853
message_to(proc->refnum);
854
proc->counter++;
855
856
while (len > 0 && (exec_buffer[len] == '\n' ||
857
exec_buffer[len] == '\r'))
858
{
859
exec_buffer[len--] = 0;
860
}
861
862
if (proc->redirect)
863
redirect_text(proc->server, proc->who,
864
exec_buffer, proc->redirect, 1, 0);
865
866
if (hook_nl == EXEC_LIST && proc->stdoutc)
867
parse_line("EXEC", proc->stdoutc, exec_buffer, 0, 0, 1);
868
else if (hook_nl == EXEC_ERRORS_LIST && proc->stderrc)
869
parse_line("EXEC", proc->stderrc, exec_buffer, 0, 0,1);
870
else if (proc->logical)
871
{
872
if ((do_hook(hook_nl, "%s %s",
873
proc->logical, exec_buffer)))
874
if (!proc->redirect)
875
put_it("%s", exec_buffer);
876
}
877
else
878
{
879
if ((do_hook(hook_nl, "%d %s",
880
proc->index, exec_buffer)))
881
if (!proc->redirect)
882
put_it("%s", exec_buffer);
883
}
884
885
message_to(0);
886
}
887
}
888
}
889
890
/*
891
* get_child_exit: This looks for dead child processes of the client.
892
* There are two main sources of dead children: Either an /exec'd process
893
* has exited, or the client has attempted to fork() off a helper process
894
* (such as wserv or gzip) and that process has choked on itself.
895
*
896
* When SIGCHLD is recieved, the global variable 'dead_children_processes'
897
* is incremented. When this function is called, we go through and call
898
* waitpid() on all of the outstanding zombies, conditionally stopping when
899
* we reach a specific wanted sub-process.
900
*
901
* If you want to stop reaping children when a specific subprocess is
902
* reached, specify the process in 'wanted'. If all youre doing is cleaning
903
* up after zombies and /exec's, then 'wanted' should be -1.
904
*/
905
906
extern SIGNAL_HANDLER(child_reap);
907
908
int get_child_exit (pid_t wanted)
909
{
910
Process *proc;
911
pid_t pid;
912
int status, i;
913
914
/*
915
* Iterate until we've reaped all of the dead processes
916
* or we've found the one asked for.
917
*/
918
if (dead_children_processes)
919
while ((pid = waitpid(wanted, &status, WNOHANG)) > 0)
920
{
921
/*
922
* Ideally, this should never be < 0.
923
*/
924
dead_children_processes--;
925
926
#ifdef __EMX__
927
my_signal(SIGCHLD, child_reap, 0);
928
#endif
929
/*
930
* First thing we do is look to see if the process we're
931
* working on is the one that was asked for. If it is,
932
* then we get its exit status information and return it.
933
*/
934
if (wanted != -1 && pid == wanted)
935
{
936
if (WIFEXITED(status))
937
return WEXITSTATUS(status);
938
if (WIFSTOPPED(status))
939
return -(WSTOPSIG(status));
940
if (WIFSIGNALED(status))
941
return -(WTERMSIG(status));
942
}
943
944
/*
945
* If it wasnt the process asked for, then we've probably
946
* stumbled across a dead /exec'd process. Look for the
947
* corresponding child process, and mark it as being dead.
948
*/
949
else
950
{
951
for (i = 0; i < process_list_size; i++)
952
{
953
proc = process_list[i];
954
if (proc && proc->pid == pid)
955
{
956
proc->exited = 1;
957
#ifdef __EMX__
958
proc->disowned = 1;
959
#endif
960
proc->termsig = WTERMSIG(status);
961
proc->retcode = WEXITSTATUS(status);
962
#ifdef __EMXPM__
963
pm_seticon(last_input_screen);
964
#endif
965
break;
966
}
967
}
968
}
969
}
970
971
/*
972
* Now we may have reaped some /exec'd processes that were previously
973
* dumb and have now exited. So we call cleanup_dead_processes() to
974
* find and delete any such processes.
975
*/
976
cleanup_dead_processes();
977
978
/*
979
* If 'wanted' is not -1, then we didnt find that process, and
980
* if 'wanted' is -1, then you should ignore the retval anyhow. ;-)
981
*/
982
return -1;
983
}
984
985
986
/*
987
* clean_up_processes: In effect, we want to tell all of our sub processes
988
* that we're going away. We cant be 100% sure that theyre all dead by
989
* the time this function returns, but we can be 100% sure that they will
990
* be killed off next time they come up to run. This is the only thing that
991
* can be guaranteed, and is in fact all we really need to know.
992
*/
993
void clean_up_processes (void)
994
{
995
if (process_list_size)
996
{
997
say("Closing all left over exec's");
998
kill_all_processes(SIGTERM);
999
sleep(2);
1000
kill_all_processes(SIGKILL);
1001
}
1002
}
1003
1004
1005
/*
1006
* text_to_process: sends the given text to the given process. If the given
1007
* process index is not valid, an error is reported and 1 is returned.
1008
* Otherwise 0 is returned.
1009
* Added show, to remove some bad recursion, phone, april 1993
1010
*/
1011
int text_to_process (int proc_index, const char *text, int show)
1012
{
1013
Process * proc;
1014
char * my_buffer;
1015
1016
if (valid_process_index(proc_index) == 0)
1017
return 1;
1018
1019
proc = process_list[proc_index];
1020
1021
message_to(proc->refnum);
1022
if (show)
1023
put_it("%s%s", get_prompt_by_refnum(proc->refnum), text);
1024
message_to(0);
1025
1026
my_buffer = alloca(strlen(text) + 2);
1027
strcpy(my_buffer, text);
1028
strcat(my_buffer, "\n");
1029
write(proc->p_stdin, my_buffer, strlen(my_buffer));
1030
set_prompt_by_refnum(proc->refnum, empty_string);
1031
1032
return (0);
1033
}
1034
1035
/*
1036
* When a server goes away, re-assign all of the /exec's that are
1037
* current bound to that server.
1038
*/
1039
void exec_server_delete (int i)
1040
{
1041
int j;
1042
1043
for (j = 0; j < process_list_size; j++)
1044
if (process_list[j] && process_list[j]->server >= i)
1045
process_list[j]->server--;
1046
}
1047
1048
/*
1049
* This adds a new /wait %proc -cmd entry to a running process.
1050
*/
1051
void add_process_wait (int proc_index, const char *cmd)
1052
{
1053
Process *proc = process_list[proc_index];
1054
List *new, *posn;
1055
1056
new = new_malloc(sizeof(List));
1057
new->next = NULL;
1058
new->name = m_strdup(cmd);
1059
1060
if ((posn = proc->waitcmds))
1061
{
1062
while (posn->next)
1063
posn = posn->next;
1064
posn->next = new;
1065
}
1066
else
1067
proc->waitcmds = new;
1068
1069
}
1070
1071
1072
1073
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
1074
1075
/*
1076
* A process must go through two stages to be completely obliterated from
1077
* the client. Either stage may happen first, but until both are completed
1078
* we keep the process around.
1079
*
1080
* 1) We must recieve an EOF on both stdin and stderr, or we must
1081
* have closed stdin and stderr already (handled by do_processes)
1082
* 2) The process must have died (handled by get_child_exit)
1083
*
1084
* The reason why both must happen is becuase the process can die (and
1085
* we would get an async signal) before we read all of its output on the
1086
* pipe, and if we simply deleted the process when it dies, we could lose
1087
* some of its output. The reason why we cant delete a process that has
1088
* asserted EOF on its output is because it could still be running (duh! ;-)
1089
* So we wait for both to happen.
1090
*/
1091
1092
/*
1093
* This function is called by the three places that can effect a change
1094
* on the state of a running process:
1095
* 1) get_child_exit, which can mark a process as exited
1096
* 2) do_processes, which can mark a child as being done with I/O
1097
* 3) execcmd, which cacn mark a child as being done with I/O
1098
*
1099
* Any processes that are found to have both exited and having completed
1100
* their I/O will be summarily destroyed.
1101
*/
1102
static void cleanup_dead_processes (void)
1103
{
1104
int i, flag;
1105
List *cmd,
1106
*next;
1107
Process *dead, *proc;
1108
1109
if (!process_list)
1110
return; /* Nothing to do */
1111
1112
for (i = 0; i < process_list_size; i++)
1113
{
1114
if (!(proc = process_list[i]))
1115
continue;
1116
1117
/*
1118
* We do not parse the process if it has not
1119
* both exited and finished its io, UNLESS
1120
* it has been disowned.
1121
*/
1122
if ((!proc->exited || !proc->dumb) && !proc->disowned)
1123
continue; /* Not really dead yet */
1124
1125
dead = process_list[i];
1126
process_list[i] = NULL;
1127
1128
/*
1129
* First thing we do is run any /wait %proc -cmd commands
1130
*/
1131
next = dead->waitcmds;
1132
dead->waitcmds = NULL;
1133
while ((cmd = next))
1134
{
1135
next = cmd->next;
1136
parse_line(NULL, cmd->name, empty_string, 0, 0, 1);
1137
new_free(&cmd->name);
1138
new_free((char **)&cmd);
1139
}
1140
if (dead->p_stdin != -1)
1141
close(dead->p_stdin);
1142
dead->p_stdout = new_close(dead->p_stdout);
1143
dead->p_stderr = new_close(dead->p_stderr);
1144
1145
1146
/*
1147
* Flag /on exec_exit
1148
*/
1149
if (dead->logical && *dead->logical)
1150
flag = do_hook(EXEC_EXIT_LIST, "%s %d %d",
1151
dead->logical, dead->termsig,
1152
dead->retcode);
1153
else
1154
flag = do_hook(EXEC_EXIT_LIST, "%d %d %d",
1155
dead->index, dead->termsig, dead->retcode);
1156
1157
/*
1158
* Tell the user, if they care
1159
*/
1160
if (flag)
1161
{
1162
if (get_int_var(NOTIFY_ON_TERMINATION_VAR))
1163
{
1164
if (dead->termsig > 0 && dead->termsig < NSIG)
1165
say("Process %d (%s) terminated with signal %s (%d)",
1166
dead->index, dead->name,
1167
#if defined(USING_STRSIGNAL)
1168
strsignal(dead->termsig),
1169
#else
1170
sys_siglist[dead->termsig],
1171
#endif
1172
dead->termsig);
1173
else if (dead->disowned)
1174
say("Process %d (%s) disowned", dead->index, dead->name);
1175
else
1176
say("Process %d (%s) terminated with return code %d",
1177
dead->index, dead->name, dead->retcode);
1178
}
1179
}
1180
1181
/*
1182
* Clean up after the process
1183
*/
1184
new_free(&dead->name);
1185
new_free(&dead->logical);
1186
new_free(&dead->who);
1187
new_free(&dead->redirect);
1188
new_free(&dead->stdoutc);
1189
new_free(&dead->stdoutpc);
1190
new_free(&dead->stderrc);
1191
new_free(&dead->stderrpc);
1192
new_free((char **)&dead);
1193
}
1194
1195
/*
1196
* Resize away any dead processes at the end
1197
*/
1198
for (i = process_list_size - 1; i >= 0; i--)
1199
{
1200
if (process_list[i])
1201
break;
1202
}
1203
1204
if (process_list_size != i + 1)
1205
{
1206
process_list_size = i + 1;
1207
RESIZE(process_list, Process, process_list_size);
1208
}
1209
}
1210
1211
1212
1213
1214
1215
/*
1216
* ignore_process: When we no longer want to communicate with the process
1217
* any longer, we call here. It continues execution until it is done, but
1218
* we are oblivious to any output it sends. Now, it will get an EOF
1219
* condition on its output fd, so it will probably either take the hint, or
1220
* its output will go the bit bucket (which we want to happen)
1221
*/
1222
static void ignore_process (int index)
1223
{
1224
Process *proc;
1225
1226
if (valid_process_index(index) == 0)
1227
return;
1228
1229
proc = process_list[index];
1230
if (proc->p_stdin != -1)
1231
proc->p_stdin = new_close(proc->p_stdin);
1232
if (proc->p_stdout != -1)
1233
proc->p_stdout = new_close(proc->p_stdout);
1234
if (proc->p_stderr != -1)
1235
proc->p_stderr = new_close(proc->p_stderr);
1236
1237
proc->dumb = 1;
1238
}
1239
1240
1241
1242
1243
1244
1245
1246
/*
1247
* kill_process: sends the given signal to the specified process. It does
1248
* not delete the process from the process table or anything like that, it
1249
* only is for sending a signal to a sub process (most likely in an attempt
1250
* to kill it.) The actual reaping of the children will take place async
1251
* on the next parsing run.
1252
*/
1253
void kill_process (int kill_index, int sig)
1254
{
1255
pid_t pgid;
1256
1257
if (!process_list || kill_index > process_list_size ||
1258
!process_list[kill_index])
1259
{
1260
say("There is no such process %d", kill_index);
1261
return;
1262
}
1263
1264
say("Sending signal %s (%d) to process %d: %s",
1265
#if defined(USING_STRSIGNAL)
1266
strsignal(sig),
1267
#else
1268
sys_siglist[sig],
1269
#endif
1270
sig, kill_index, process_list[kill_index]->name);
1271
1272
#ifdef HAVE_GETPGID
1273
pgid = getpgid(process_list[kill_index]->pid);
1274
#else
1275
# ifndef GETPGRP_VOID
1276
pgid = getpgrp(process_list[kill_index]->pid);
1277
# else
1278
pgid = process_list[kill_index]->pid;
1279
# endif
1280
#endif
1281
1282
#ifndef HAVE_KILLPG
1283
# define killpg(pg, sig) kill(-(pg), (sig))
1284
#endif
1285
1286
/* The exec'd process shouldn't be in our process group */
1287
if (pgid == getpid())
1288
{
1289
yell("--- exec'd process is in my job control session! Something is hosed ---");
1290
return;
1291
}
1292
1293
killpg(pgid, sig);
1294
kill(process_list[kill_index]->pid, sig);
1295
}
1296
1297
1298
/*
1299
* This kills (sends a signal, *NOT* ``make it stop running'') all of the
1300
* currently running subprocesses with the given signal. Presumably this
1301
* is because you want them to die.
1302
*
1303
* Remember that UNIX signals are asynchornous. At best, you should assume
1304
* that they have an advisory effect. You can tell a process that it should
1305
* die, but you cannot tell it *when* it will die -- that is up to the system.
1306
* That means that it is pointless to assume the condition of any of the
1307
* kill()ed processes after the kill(). They may indeed be dead, or they may
1308
* be ``sleeping but runnable'', or they might even be waiting for a hardware
1309
* condition (such as a swap in). You do not know when the process will
1310
* actually die. It could be 15 ns, it could be 15 minutes, it could be
1311
* 15 years. Its also useful to note that we, as the parent process, will not
1312
* recieve the SIGCHLD signal until after the child dies. That means it is
1313
* pointless to try to reap any children processes here. The main io()
1314
* loop handles reaping children (by calling get_child_exit()).
1315
*/
1316
static void kill_all_processes (int signo)
1317
{
1318
int i;
1319
int tmp;
1320
1321
tmp = window_display;
1322
window_display = 0;
1323
for (i = 0; i < process_list_size; i++)
1324
{
1325
if (process_list[i])
1326
{
1327
ignore_process(i);
1328
kill_process(i, signo);
1329
}
1330
}
1331
window_display = tmp;
1332
}
1333
1334
1335
1336
1337
/* * * * * * logical stuff * * * * * * */
1338
/*
1339
* valid_process_index: checks to see if index refers to a valid running
1340
* process and returns true if this is the case. Returns false otherwise
1341
*/
1342
static int valid_process_index (int process)
1343
{
1344
if ((process < 0) || (process >= process_list_size) || !process_list[process])
1345
{
1346
say("No such process number %d", process);
1347
return (0);
1348
}
1349
1350
return (1);
1351
}
1352
1353
static int is_logical_unique (char *logical)
1354
{
1355
Process *proc;
1356
int i;
1357
1358
if (!logical)
1359
return 1;
1360
1361
for (i = 0; i < process_list_size; i++)
1362
{
1363
if (!(proc = process_list[i]) || !proc->logical)
1364
continue;
1365
1366
if (!my_stricmp(proc->logical, logical))
1367
return 0;
1368
}
1369
1370
return 1;
1371
}
1372
1373
1374
/*
1375
* logical_to_index: converts a logical process name to it's approriate index
1376
* in the process list, or -1 if not found
1377
*/
1378
int logical_to_index (const char *logical)
1379
{
1380
Process *proc;
1381
int i;
1382
1383
for (i = 0; i < process_list_size; i++)
1384
{
1385
if (!(proc = process_list[i]) || !proc->logical)
1386
continue;
1387
1388
if (!my_stricmp(proc->logical, logical))
1389
return i;
1390
}
1391
1392
return -1;
1393
}
1394
1395
/*
1396
* get_process_index: parses out a process index or logical name from the
1397
* given string
1398
*/
1399
int get_process_index (char **args)
1400
{
1401
char *s = next_arg(*args, args);
1402
return is_valid_process(s);
1403
}
1404
1405
/*
1406
* is_valid_process: tells me if the spec is a process that is either
1407
* running or still has not closed its pipes, or both.
1408
*/
1409
int is_valid_process (const char *arg)
1410
{
1411
if (!arg || *arg != '%')
1412
return -1;
1413
1414
arg++;
1415
if (is_number((char *)arg) && valid_process_index(my_atol((char *)arg)))
1416
return my_atol((char *)arg);
1417
else
1418
return logical_to_index(arg);
1419
1420
return -1;
1421
}
1422
1423
int process_is_running (char *arg)
1424
{
1425
int idx = is_valid_process(arg);
1426
1427
if (idx == -1)
1428
return 0;
1429
else
1430
return 1;
1431
}
1432
1433
/*
1434
* set_process_bits: This will set the bits in a fd_set map for each of the
1435
* process descriptors.
1436
*/
1437
void set_process_bits(fd_set *rd)
1438
{
1439
int i;
1440
Process *proc;
1441
1442
if (process_list)
1443
{
1444
for (i = 0; i < process_list_size; i++)
1445
{
1446
if ((proc = process_list[i]) != NULL)
1447
{
1448
if (proc->p_stdout != -1)
1449
FD_SET(proc->p_stdout, rd);
1450
if (proc->p_stderr != -1)
1451
FD_SET(proc->p_stderr, rd);
1452
}
1453
}
1454
}
1455
}
1456
1457