1 /*
2 * exec.c: handles exec'd process for IRCII
3 *
4 * Written By Michael Sandrof
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2003 Matthew R. Green.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $Id: exec.c,v 1.14 2006-04-30 14:15:43 f Exp $
35 */
36
37 #include "irc.h"
38
39 #ifdef M_UNIX
40 # define __SCO_WAIT3__
41 # include <sys/wait.h>
42 # include <sys/resource.h>
43 #else /* M_UNIX */
44 # ifdef HAVE_SYS_WAIT_H
45 # include <sys/wait.h>
46 # endif
47 #endif /* M_UNIX */
48
49 #ifdef ISC
50 #include <sys/bsdtypes.h>
51 #include <wait.h>
52 #endif /* ISC */
53
54 #ifdef XD88
55 # define ISC
56 #endif /* XD88 */
57
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61
62 #include "exec.h"
63 #include "vars.h"
64 #include "ircaux.h"
65 #include "edit.h"
66 #include "window.h"
67 #include "screen.h"
68 #include "hook.h"
69 #include "input.h"
70 #include "list.h"
71 #include "server.h"
72 #include "output.h"
73 #include "parse.h"
74 #include "dcc.h"
75 #include "newio.h"
76 #include "alias.h"
77
78 #if defined(SVR3) && defined(HAVE_SOCKETPAIR)
79 /* SVR3's pipe's are *unidirectional*! We could spend all day pushing
80 STREAMS modules onto two pipes to get bidirectionality, or we can just
81 take the easy way out...like so:
82 */
83 #define pipe(p) socketpair(AF_UNIX, SOCK_STREAM, 0, (p))
84 #endif
85
86 #if !defined(NSIG) && defined(_SIGMAX)
87 /* mmm, posix */
88 # define NSIG _SIGMAX
89 #endif
90
91 static int wait_index = -1;
92
93 /* Process: the structure that has all the info needed for each process */
94 typedef struct
95 {
96 char *name; /* full process name */
97 char *logical;
98 pid_t pid; /* process-id of process */
99 int p_stdin; /* stdin description for process */
100 int p_stdout; /* stdout descriptor for process */
101 int p_stderr; /* stderr descriptor for process */
102 int counter; /* output line counter for process */
103 char *redirect; /* redirection command (MSG, NOTICE) */
104 unsigned int refnum; /* a window for output to go to */
105 int server; /* the server to use for output */
106 char *who; /* nickname used for redirection */
107 int exited; /* true if process has exited */
108 int termsig; /* The signal that terminated
109 * the process */
110 int retcode; /* return code of process */
111 List *waitcmds; /* commands queued by WAIT -CMD */
112 } Process;
113
114 static Process **process_list = NULL;
115 static int process_list_size = 0;
116
117 static int exec_close _((int));
118 static void start_process _((char *, char *, char *, char *, unsigned int));
119 static void kill_process _((int, int));
120 static int delete_process _((int));
121 static void list_processes _((void));
122 static int valid_process_index _((int));
123 static void add_process _((char *, char *, int, int, int, int, char *, char *, unsigned int));
124 static int is_logical_unique _((char *));
125 static void send_exec_result _((Process *, char *));
126
127 /*
128 * A nice array of the possible signals. Used by the coredump trapping
129 * routines and in the exec.c package .
130 *
131 * We really rely on the signals being all upper case.
132 */
133
134 #include "sig.inc"
135
136 /*
137 * exec_close: silly, eh? Well, it makes the code look nicer. Or does it
138 * really? No. But what the hell
139 */
140 static int
exec_close(des)141 exec_close(des)
142 int des;
143 {
144 if (des != -1)
145 new_close(des);
146 return (-1);
147 }
148
149 /*
150 * set_wait_process: Sets the given index number so that it will be checked
151 * for upon process exit. This is used by waitcmd() in edit.c. An index of
152 * -1 disables this.
153 */
154 void
set_wait_process(proccess)155 set_wait_process(proccess)
156 int proccess;
157 {
158 wait_index = proccess;
159 }
160
161 /*
162 * valid_process_index: checks to see if index refers to a valid running
163 * process and returns true if this is the case. Returns false otherwise
164 */
165 static int
valid_process_index(proccess)166 valid_process_index(proccess)
167 int proccess;
168 {
169 if ((proccess < 0) || (proccess >= process_list_size))
170 return (0);
171 if (process_list[proccess])
172 return (1);
173 return (0);
174 }
175
176 #if !defined(BSDWAIT) && defined(NEED_WAITPID)
177
178 #ifndef WNOHANG
179 # define WNOHANG 1
180 #endif
181
182 #ifndef SIGCLD
183 # define SIGCLD SIGCHLD
184 #endif
185
186 volatile static int _child_died = 0;
187
188 static void
_child_death()189 _child_death()
190 {
191 _child_died = 1;
192 }
193
194 int
waitpid(pid,status,options)195 waitpid(pid, status, options)
196 int pid; /* Only works if pid == -1! */
197 int *status;
198 int options;
199 {
200 int rval;
201 void (*prev_sigcld)();
202
203 if (options & WNOHANG)
204 {
205 _child_died = 0;
206 prev_sigcld = signal(SIGCLD, _child_death);
207 if (_child_died == 0)
208 {
209 signal(SIGCLD, prev_sigcld);
210 return (0);
211 }
212 }
213 rval = wait(status);
214 if (options & WNOHANG)
215 {
216 signal(SIGCLD, prev_sigcld);
217 }
218 return rval;
219 }
220 #endif /* not BSDWAIT && NEED_WAITPID */
221
222 int
get_child_exit(pid)223 get_child_exit(pid)
224 int pid;
225 {
226 return (check_wait_status(pid));
227 }
228
229 /*
230 * check_wait_status: This waits on child processes, reporting terminations
231 * as needed, etc
232 */
233 int
check_wait_status(wanted)234 check_wait_status(wanted)
235 int wanted;
236 {
237 Process *proc;
238 #ifdef BSDWAIT
239 union wait status;
240 #else
241 int status;
242 #endif /* BSDWAIT */
243 int pid,
244 i;
245
246 #if defined(use_wait2) || defined(MUNIX)
247 if ((pid = wait2(&status, WNOHANG, 0)) > 0)
248 #else
249 # ifdef BSDWAIT
250 if ((pid = wait3(&status, WNOHANG, NULL)) > 0)
251 # else
252 if ((pid = waitpid(wanted, &status, WNOHANG)) > 0)
253 # endif /* BSDWAIT */
254 #endif /* defined(use_wait2) || defined(MUNIX) */
255 {
256 if (wanted != -1 && pid == wanted)
257 {
258 if (WIFEXITED(status))
259 return WEXITSTATUS(status);
260 if (WIFSTOPPED(status))
261 return - (WSTOPSIG(status));
262 if (WIFSIGNALED(status))
263 return - (WTERMSIG(status));
264 }
265 errno = 0; /* reset errno, cause wait3 changes it */
266 for (i = 0; i < process_list_size; i++)
267 {
268 if ((proc = process_list[i]) && proc->pid == pid)
269 {
270 proc->exited = 1;
271 proc->termsig = WTERMSIG(status);
272 proc->retcode = WEXITSTATUS(status);
273 if ((proc->p_stderr == -1) &&
274 (proc->p_stdout == -1))
275 delete_process(i);
276 return 0;
277 }
278 }
279 }
280 return -1;
281 }
282
283 /*
284 * check_process_limits: checks each running process to see if it's reached
285 * the user selected maximum number of output lines. If so, the processes is
286 * effectively killed
287 */
288 void
check_process_limits()289 check_process_limits()
290 {
291 int limit;
292 int i;
293 Process *proc;
294
295 if ((limit = get_int_var(SHELL_LIMIT_VAR)) && process_list)
296 {
297 for (i = 0; i < process_list_size; i++)
298 {
299 if ((proc = process_list[i]) != NULL)
300 {
301 if (proc->counter >= limit)
302 {
303 proc->p_stdin = exec_close(proc->p_stdin);
304 proc->p_stdout = exec_close(proc->p_stdout);
305 proc->p_stderr = exec_close(proc->p_stderr);
306 if (proc->exited)
307 delete_process(i);
308 }
309 }
310 }
311 }
312 }
313
314 static void
send_exec_result(proc,exec_buffer)315 send_exec_result(proc, exec_buffer)
316 Process *proc;
317 char *exec_buffer;
318 {
319 if (proc->redirect)
320 {
321 if (!strcmp(proc->redirect, "FILTER"))
322 {
323 char *rest, *filter;
324 int arg_flag = 0;
325
326 rest = exec_buffer;
327 while (*rest && *rest != ' ')
328 ++rest;
329
330 while (*rest == ' ')
331 ++rest;
332
333 filter = call_function(proc->who,
334 exec_buffer /* f_args */,
335 empty_string /* args */,
336 &arg_flag);
337 if (filter)
338 {
339 char *sub_buffer = NULL;
340
341 malloc_strcpy(&sub_buffer, filter);
342 malloc_strcat(&sub_buffer, " ");
343 malloc_strcat(&sub_buffer, rest);
344
345 parse_command(sub_buffer, 0, empty_string);
346 new_free(&sub_buffer);
347 new_free(&filter);
348 }
349 }
350 else
351 {
352 send_text(proc->who, exec_buffer, proc->redirect);
353 }
354 }
355 else
356 put_it("%s", exec_buffer);
357 }
358
359 /*
360 * do_processes: given a set of read-descriptors (as returned by a call to
361 * select()), this will determine which of the process has produced output
362 * and will hadle it appropriately
363 */
364 void
do_processes(rd)365 do_processes(rd)
366 fd_set *rd;
367 {
368 int i,
369 flag;
370 char exec_buffer[INPUT_BUFFER_SIZE + 1];
371 char *ptr;
372 Process *proc;
373 int old_timeout;
374 int server;
375
376 if (process_list == (Process **) 0)
377 return;
378 old_timeout = dgets_timeout(1);
379 for (i = 0; i < process_list_size && !break_io_processing; i++)
380 {
381 if ((proc = process_list[i]) && proc->p_stdout != -1)
382 {
383 if (FD_ISSET(proc->p_stdout, rd))
384 {
385 switch (dgets(exec_buffer, INPUT_BUFFER_SIZE, proc->p_stdout, (u_char *) 0))
386 {
387 case 0:
388 if (proc->p_stderr == -1)
389 {
390 proc->p_stdin = exec_close(proc->p_stdin);
391 proc->p_stdout = exec_close(proc->p_stdout);
392 if (proc->exited)
393 delete_process(i);
394 }
395 else
396 proc->p_stdout = exec_close(proc->p_stdout);
397 break;
398 case -1:
399 server = from_server;
400 from_server = proc->server;
401 if (proc->logical)
402 flag = do_hook(EXEC_PROMPT_LIST, "%s %s", proc->logical, exec_buffer);
403 else
404 flag = do_hook(EXEC_PROMPT_LIST, "%d %s", i, exec_buffer);
405 from_server = server;
406 set_prompt_by_refnum(proc->refnum, exec_buffer);
407 update_input(UPDATE_ALL);
408 /* if (flag == 0) */
409 break;
410 default:
411 server = from_server;
412 from_server = proc->server;
413 message_to(proc->refnum);
414 proc->counter++;
415 exec_buffer[sizeof(exec_buffer) - 1] = '\0'; /* blah... */
416 ptr = exec_buffer + strlen(exec_buffer) - 1;
417 if ((*ptr == '\n') || (*ptr == '\r'))
418 {
419 *ptr = (u_char) 0;
420 ptr = exec_buffer + strlen(exec_buffer) - 1;
421 if ((*ptr == '\n') || (*ptr == '\r'))
422 *ptr = (u_char) 0;
423 }
424 if (proc->logical)
425 flag = do_hook(EXEC_LIST, "%s %s", proc->logical, exec_buffer);
426 else
427 flag = do_hook(EXEC_LIST, "%d %s", i, exec_buffer);
428
429 if (flag)
430 send_exec_result(proc, exec_buffer);
431 message_to(0);
432 from_server = server;
433 break;
434 }
435 }
436 }
437 if (process_list && i < process_list_size &&
438 (proc = process_list[i]) && proc->p_stderr != -1)
439 {
440 if (FD_ISSET(proc->p_stderr, rd))
441 {
442 switch (dgets(exec_buffer, INPUT_BUFFER_SIZE, proc->p_stderr, (u_char *) 0))
443 {
444 case 0:
445 if (proc->p_stdout == -1)
446 {
447 proc->p_stderr = exec_close(proc->p_stderr);
448 proc->p_stdin = exec_close(proc->p_stdin);
449 if (proc->exited)
450 delete_process(i);
451 }
452 else
453 proc->p_stderr = exec_close(proc->p_stderr);
454 break;
455
456 case -1:
457 server = from_server;
458 from_server = proc->server;
459 if (proc->logical)
460 flag = do_hook(EXEC_PROMPT_LIST, "%s %s", proc->logical, exec_buffer);
461 else
462 flag = do_hook(EXEC_PROMPT_LIST, "%d %s", i, exec_buffer);
463 set_prompt_by_refnum(proc->refnum, exec_buffer);
464 update_input(UPDATE_ALL);
465 from_server = server;
466 if (flag == 0)
467 break;
468
469 default:
470 server = from_server;
471 from_server = proc->server;
472 message_to(proc->refnum);
473 (proc->counter)++;
474 ptr = exec_buffer + strlen(exec_buffer) - 1;
475 if ((*ptr == '\n') || (*ptr == '\r'))
476 {
477 *ptr = (u_char) 0;
478 ptr = exec_buffer + strlen(exec_buffer) - 1;
479 if ((*ptr == '\n') || (*ptr == '\r'))
480 *ptr = (u_char) 0;
481 }
482 if (proc->logical)
483 flag = do_hook(EXEC_ERRORS_LIST, "%s %s", proc->logical, exec_buffer);
484 else
485 flag = do_hook(EXEC_ERRORS_LIST, "%d %s", i, exec_buffer);
486 if (flag)
487 send_exec_result(proc, exec_buffer);
488 message_to(0);
489 from_server = server;
490 break;
491 }
492 }
493 }
494 }
495 (void) dgets_timeout(old_timeout);
496 }
497
498 /*
499 * set_process_bits: This will set the bits in a fd_set map for each of the
500 * process descriptors.
501 */
502 void
set_process_bits(rd)503 set_process_bits(rd)
504 fd_set *rd;
505 {
506 int i;
507 Process *proc;
508
509 if (process_list)
510 {
511 for (i = 0; i < process_list_size; i++)
512 {
513 if ((proc = process_list[i]) != NULL)
514 {
515 if (proc->p_stdout != -1)
516 FD_SET(proc->p_stdout, rd);
517 if (proc->p_stderr != -1)
518 FD_SET(proc->p_stderr, rd);
519 }
520 }
521 }
522 }
523
524 /*
525 * list_processes: displays a list of all currently running processes,
526 * including index number, pid, and process name
527 */
528 static void
list_processes()529 list_processes()
530 {
531 Process *proc;
532 int i;
533 int lastlog_level;
534
535 lastlog_level = set_lastlog_msg_level(LOG_CRAP);
536 if (process_list)
537 {
538 say("Process List:");
539 for (i = 0; i < process_list_size; i++)
540 {
541 if ((proc = process_list[i]) != NULL)
542 {
543 if (proc->logical)
544 say("\t%d (%s): %s", i,
545 proc->logical,
546 proc->name);
547 else
548 say("\t%d: %s", i,
549 proc->name);
550 }
551 }
552 }
553 else
554 say("No processes are running");
555 set_lastlog_msg_level(lastlog_level);
556 }
557
558 void
add_process_wait(proc_index,cmd)559 add_process_wait(proc_index, cmd)
560 int proc_index;
561 char *cmd;
562 {
563 List *new,
564 **posn;
565
566 for (posn = &process_list[proc_index]->waitcmds; *posn != (List *) 0; posn = &(*posn)->next)
567 ;
568 new = (List *) new_malloc(sizeof(List));
569 *posn = new;
570 new->next = (List *) 0;
571 new->name = (char *) 0;
572 malloc_strcpy(&new->name, cmd);
573 }
574
575 /*
576 * delete_process: Removes the process specifed by index from the process
577 * list. The does not kill the process, close the descriptors, or any such
578 * thing. It only deletes it from the list. If appropriate, this will also
579 * shrink the list as needed
580 */
581 static int
delete_process(process)582 delete_process(process)
583 int process;
584 {
585 int flag;
586 List *cmd,
587 *next;
588
589 if (process_list)
590 {
591 if (process >= process_list_size)
592 return (-1);
593 if (process_list[process])
594 {
595 Process *dead;
596
597 if (process == wait_index)
598 {
599 wait_index = -1;
600 irc_io_loop = 0;
601 }
602 dead = process_list[process];
603 process_list[process] = (Process *) 0;
604 if (process == (process_list_size - 1))
605 {
606 int i;
607
608 for (i = process_list_size - 1;
609 process_list_size;
610 process_list_size--, i--)
611 {
612 if (process_list[i])
613 break;
614 }
615 if (process_list_size)
616 process_list = (Process **)
617 new_realloc((char *) process_list, sizeof(Process *) * process_list_size);
618 else
619 {
620 new_free(&process_list);
621 process_list = (Process **) 0;
622 }
623 }
624 for (next = dead->waitcmds; next;)
625 {
626 cmd = next;
627 next = next->next;
628 parse_command(cmd->name, 0, empty_string);
629 new_free(&cmd->name);
630 new_free(&cmd);
631 }
632 dead->waitcmds = (List *) 0;
633 if (dead->logical)
634 flag = do_hook(EXEC_EXIT_LIST, "%s %d %d",
635 dead->logical, dead->termsig,
636 dead->retcode);
637 else
638 flag = do_hook(EXEC_EXIT_LIST, "%d %d %d",
639 process, dead->termsig, dead->retcode);
640 if (flag)
641 {
642 if (get_int_var(NOTIFY_ON_TERMINATION_VAR))
643 {
644 if (dead->termsig)
645 say("Process %d (%s) terminated with signal %s (%d)", process, dead->name, signals[dead->termsig],
646 dead->termsig);
647 else
648 say("Process %d (%s) terminated with return code %d", process, dead->name, dead->retcode);
649 }
650 }
651 new_free(&dead->name);
652 new_free(&dead->logical);
653 new_free(&dead->who);
654 new_free(&dead->redirect);
655 new_free(&dead);
656 return (0);
657 }
658 }
659 return (-1);
660 }
661
662 /*
663 * add_process: adds a new process to the process list, expanding the list as
664 * needed. It will first try to add the process to a currently unused spot
665 * in the process table before it increases it's size.
666 */
667 static void
add_process(name,logical,pid,p_stdin,p_stdout,p_stderr,redirect,who,refnum)668 add_process(name, logical, pid, p_stdin, p_stdout, p_stderr, redirect, who, refnum)
669 char *name,
670 *logical;
671 int pid,
672 p_stdin,
673 p_stdout,
674 p_stderr;
675 char *redirect;
676 char *who;
677 unsigned int refnum;
678 {
679 int i;
680 Process *proc;
681
682 if (process_list == (Process **) 0)
683 {
684 process_list = (Process **) new_malloc(sizeof(Process *));
685 process_list_size = 1;
686 process_list[0] = (Process *) 0;
687 }
688 for (i = 0; i < process_list_size; i++)
689 {
690 if (!process_list[i])
691 {
692 proc = process_list[i] = (Process *)
693 new_malloc(sizeof(Process));
694 proc->name = (char *) 0;
695 malloc_strcpy(&(proc->name), name);
696 proc->logical = (char *) 0;
697 malloc_strcpy(&(proc->logical), logical);
698 proc->pid = pid;
699 proc->p_stdin = p_stdin;
700 proc->p_stdout = p_stdout;
701 proc->p_stderr = p_stderr;
702 proc->refnum = refnum;
703 proc->redirect = (char *) 0;
704 if (redirect)
705 malloc_strcpy(&(proc->redirect),
706 redirect);
707 if (parsing_server_index != -1)
708 proc->server = parsing_server_index;
709 else
710 proc->server = curr_scr_win->server;
711 proc->counter = 0;
712 proc->exited = 0;
713 proc->termsig = 0;
714 proc->retcode = 0;
715 proc->who = (char *) 0;
716 proc->waitcmds = (List *) 0;
717 if (who)
718 malloc_strcpy(&(process_list[i]->who), who);
719 return;
720 }
721 }
722 process_list_size++;
723 process_list = (Process **) new_realloc((char *) process_list, sizeof(Process *) * process_list_size);
724 process_list[process_list_size - 1] = (Process *) 0;
725 proc = process_list[i] = (Process *) new_malloc(sizeof(Process));
726 proc->name = (char *) 0;
727 malloc_strcpy(&(proc->name), name);
728 proc->logical = (char *) 0;
729 malloc_strcpy(&(proc->logical), logical);
730 proc->pid = pid;
731 proc->p_stdin = p_stdin;
732 proc->p_stdout = p_stdout;
733 proc->p_stderr = p_stderr;
734 proc->refnum = refnum;
735 proc->redirect = (char *) 0;
736 if (redirect)
737 malloc_strcpy(&(proc->redirect), redirect);
738 proc->server = curr_scr_win->server;
739 proc->counter = 0;
740 proc->exited = 0;
741 proc->termsig = 0;
742 proc->retcode = 0;
743 proc->who = (char *) 0;
744 proc->waitcmds = (List *) 0;
745 if (who)
746 malloc_strcpy(&(proc->who), who);
747 }
748
749 /*
750 * kill_process: sends the given signal to the process specified by the given
751 * index into the process table. After the signal is sent, the process is
752 * deleted from the process table
753 */
754 static void
kill_process(kill_index,sig)755 kill_process(kill_index, sig)
756 int kill_index,
757 sig;
758 {
759 if (process_list && (kill_index < process_list_size) && process_list[kill_index])
760 {
761 pid_t pgid;
762
763 say("Sending signal %s (%d) to process %d: %s", signals[sig], sig, kill_index, process_list[kill_index]->name);
764 #ifdef HAVE_GETPGID
765 pgid = getpgid(process_list[kill_index]->pid);
766 #else
767 # ifdef __sgi
768 pgid = BSDgetpgrp(process_list[kill_index]->pid);
769 # else
770 # ifdef HPUX
771 pgid = getpgrp2(process_list[kill_index]->pid);
772 # else
773 # ifdef mips /* XXX */
774 pgid = getpgrp(process_list[kill_index]->pid);
775 # else
776 # ifdef HAVE_GETSID
777 pgid = getsid(process_list[kill_index]->pid);
778 # else
779 # if defined(ISC) || defined(MUNIX) || defined(BROKEN_GETPGRP)
780 pgid = process_list[kill_index]->pid;
781 # else
782 pgid = getpgrp(process_list[kill_index]->pid);
783 # endif /* ISC || MUNIX || BROKEN_GETPGRP */
784 # endif /* HAVE_GETSID */
785 # endif /* mips */
786 # endif /* HPUX */
787 # endif /* __sgi */
788 #endif /* HAVE_GETPGID */
789
790 #ifndef HAVE_KILLPG
791 # define killpg(pg, sig) kill(-(pg), (sig))
792 #endif /* HAVE_KILLPG */
793
794 if (pgid == getpid())
795 {
796 yell("--- kill_process got pgid of pid!!! something is very wrong");
797 return;
798 }
799 killpg(pgid, sig);
800 kill(process_list[kill_index]->pid, sig);
801 }
802 else
803 say("There is no process %d", kill_index);
804 }
805
806 static int
is_logical_unique(logical)807 is_logical_unique(logical)
808 char *logical;
809 {
810 Process *proc;
811 int i;
812
813 if (logical)
814 for (i = 0; i < process_list_size; i++)
815 if ((proc = process_list[i]) && proc->logical &&
816 (my_stricmp(proc->logical, logical) == 0))
817 return 0;
818 return 1;
819 }
820
821 /*
822 * start_process: Attempts to start the given process using the SHELL as set
823 * by the user.
824 */
825 static void
start_process(name,logical,redirect,who,refnum)826 start_process(name, logical, redirect, who, refnum)
827 char *name,
828 *logical,
829 *who,
830 *redirect;
831 unsigned int refnum;
832 {
833 int p0[2],
834 p1[2],
835 p2[2],
836 pid,
837 cnt;
838 char *shell,
839 *flag,
840 *arg;
841 char buffer[BIG_BUFFER_SIZE+1];
842
843 #ifdef DAEMON_UID
844 if (getuid() == DAEMON_UID)
845 {
846 say("Sorry, you are not allowed to use EXEC");
847 return;
848 }
849 #endif /* DAEMON_UID */
850 p0[0] = p0[1] = -1;
851 p1[0] = p1[1] = -1;
852 p2[0] = p2[1] = -1;
853 if (pipe(p0) || pipe(p1) || pipe(p2))
854 {
855 say("Unable to start new process: %s", strerror(errno));
856 if (p0[0] != -1)
857 {
858 new_close(p0[0]);
859 new_close(p0[1]);
860 }
861 if (p1[0] != -1)
862 {
863 new_close(p1[0]);
864 new_close(p1[1]);
865 }
866 if (p2[0] != -1)
867 {
868 new_close(p2[0]);
869 new_close(p2[1]);
870 }
871 return;
872 }
873 switch (pid = fork())
874 {
875 case -1:
876 say("Couldn't start new process!");
877 break;
878 case 0:
879 #ifdef HAVE_SETSID
880 setsid();
881 #else
882 setpgrp(0, getpid());
883 #endif /* HAVE_SETSID */
884 MY_SIGNAL(SIGINT, (sigfunc *) SIG_IGN, 0);
885 dup2(p0[0], 0);
886 dup2(p1[1], 1);
887 dup2(p2[1], 2);
888 new_close(p0[0]);
889 new_close(p0[1]);
890 new_close(p1[0]);
891 new_close(p1[1]);
892 new_close(p2[0]);
893 new_close(p2[1]);
894 close_all_server();
895 close_all_dcc();
896 close_all_exec();
897 close_all_screen();
898
899 /* fix environment */
900 for (cnt = 0, arg = environ[0]; arg; arg = environ[++cnt])
901 {
902 if (strncmp(arg, "TERM=", 5) == 0)
903 {
904 environ[cnt] = "TERM=tty";
905 break;
906 }
907 }
908 if ((shell = get_string_var(SHELL_VAR)) == (char *) 0)
909 {
910 char **args; /* = (char **) 0 */
911 int max;
912
913 cnt = 0;
914 max = 5;
915 args = (char **) new_malloc(sizeof(char *) * max);
916 while ((arg = next_arg(name, &name)) != NULL)
917 {
918 if (cnt == max)
919 {
920 max += 5;
921 args = (char **) new_realloc((char *) args, sizeof(char *) * max);
922 }
923 args[cnt++] = arg;
924 }
925 args[cnt] = (char *) 0;
926 setuid(getuid()); /* If we are setuid, set it back! */
927 setgid(getgid());
928 execvp(args[0], args);
929 }
930 else
931 {
932 if ((flag = get_string_var(SHELL_FLAGS_VAR)) ==
933 (char *) 0)
934 flag = empty_string;
935 setuid(getuid());
936 setgid(getgid());
937 execl(shell, shell, flag, name, (char *) 0);
938 }
939 snprintf(buffer, sizeof buffer, "*** Error starting shell \"%s\": %s\n", shell,
940 strerror(errno));
941 write(1, buffer, strlen(buffer));
942 _exit(-1);
943 break;
944 default:
945 new_close(p0[0]);
946 new_close(p1[1]);
947 new_close(p2[1]);
948 add_process(name, logical, pid, p0[1], p1[0], p2[0], redirect,
949 who, refnum);
950 break;
951 }
952 }
953
954 /*
955 * text_to_process: sends the given text to the given process. If the given
956 * process index is not valid, an error is reported and 1 is returned.
957 * Otherwise 0 is returned.
958 * Added show, to remove some bad recursion, phone, april 1993
959 */
960 int
text_to_process(proc_index,text,show)961 text_to_process(proc_index, text, show)
962 int proc_index;
963 char *text;
964 int show;
965 {
966 u_int ref;
967 Process *proc;
968
969 if (valid_process_index(proc_index) == 0)
970 {
971 say("No such process number %d", proc_index);
972 return (1);
973 }
974 ref = process_list[proc_index]->refnum;
975 proc = process_list[proc_index];
976 message_to(ref);
977 if (show)
978 put_it("%s%s", get_prompt_by_refnum(ref), text); /* lynx */
979 write(proc->p_stdin, text, strlen(text));
980 write(proc->p_stdin, "\n", 1);
981 set_prompt_by_refnum(ref, empty_string);
982 /* update_input(UPDATE_ALL); */
983 message_to(0);
984 return (0);
985 }
986
987 /*
988 * is_process_running: Given an index, this returns true if the index referes
989 * to a currently running process, 0 otherwise
990 */
991 int
is_process_running(proc_index)992 is_process_running(proc_index)
993 int proc_index;
994 {
995 if (proc_index < 0 || proc_index >= process_list_size)
996 return (0);
997 if (process_list && process_list[proc_index])
998 return (!process_list[proc_index]->exited);
999 return (0);
1000 }
1001
1002 /*
1003 * logical_to_index: converts a logical process name to it's approriate index
1004 * in the process list, or -1 if not found
1005 */
1006 int
logical_to_index(logical)1007 logical_to_index(logical)
1008 char *logical;
1009 {
1010 Process *proc;
1011 int i;
1012
1013 for (i = 0; i < process_list_size; i++)
1014 {
1015 if ((proc = process_list[i]) && proc->logical &&
1016 (my_stricmp(proc->logical, logical) == 0))
1017 return i;
1018 }
1019 return -1;
1020 }
1021
1022 /*
1023 * get_process_index: parses out a process index or logical name from the
1024 * given string
1025 */
1026 int
get_process_index(args)1027 get_process_index(args)
1028 char **args;
1029 {
1030 char *s;
1031
1032 if ((s = next_arg(*args, args)) != NULL)
1033 {
1034 if (*s == '%')
1035 s++;
1036 else
1037 return (-1);
1038 if (is_number(s))
1039 return (atoi(s));
1040 else
1041 return (logical_to_index(s));
1042 }
1043 else
1044 return (-1);
1045 }
1046
1047 /* is_process: checks to see if arg is a valid process specification */
1048 int
is_process(arg)1049 is_process(arg)
1050 char *arg;
1051 {
1052 if (arg && *arg == '%')
1053 {
1054 arg++;
1055 if (is_number(arg) || (logical_to_index(arg) != -1))
1056 return (1);
1057 }
1058 return (0);
1059 }
1060
1061 /*
1062 * exec: the /EXEC command. Handles the whole IRCII process crap.
1063 */
1064 /*ARGSUSED*/
1065 void
execcmd(command,args,subargs)1066 execcmd(command, args, subargs)
1067 char *command,
1068 *args,
1069 *subargs;
1070 {
1071 char *who = (char *) 0,
1072 *logical = (char *) 0,
1073 *redirect, /* = (char *) 0, */
1074 *flag,
1075 *cmd = (char *) 0;
1076 unsigned int refnum = 0;
1077 int sig,
1078 i,
1079 refnum_flag = 0,
1080 logical_flag = 0;
1081 size_t len;
1082 Process *proc;
1083
1084 if (get_int_var(EXEC_PROTECTION_VAR) && (send_text_flag != -1))
1085 {
1086 say("Attempt to use EXEC from within an ON function!");
1087 say("Command \"%s\" not executed!", args);
1088 say("Please read /HELP SET EXEC_PROTECTION");
1089 say("or important details about this!");
1090 return;
1091 }
1092 #ifdef DAEMON_UID
1093 if (getuid() == DAEMON_UID)
1094 {
1095 say("You are not permitted to use EXEC.");
1096 return;
1097 }
1098 #endif /* DAEMON_UID */
1099 if (*args == '\0')
1100 {
1101 list_processes();
1102 return;
1103 }
1104 redirect = NULL;
1105 while ((*args == '-') && (flag = next_arg(args, &args)))
1106 {
1107 if (*flag == '-')
1108 {
1109 len = strlen(++flag);
1110 malloc_strcpy(&cmd, flag);
1111 upper(cmd);
1112 if (strncmp(cmd, "OUT", len) == 0)
1113 {
1114 redirect = "PRIVMSG";
1115 if (!(who = get_channel_by_refnum(0)))
1116 {
1117 say("No current channel in this window for -OUT");
1118 new_free(&cmd);
1119 return;
1120 }
1121 }
1122 else if (strncmp(cmd, "TARGET", len) == 0)
1123 {
1124 redirect = "PRIVMSG";
1125 if (!(who = get_target_by_refnum(0)))
1126 {
1127 say("No current target in this window for -TARGET");
1128 new_free(&cmd);
1129 return;
1130 }
1131 }
1132 else if (strncmp(cmd, "NAME", len) == 0)
1133 {
1134 logical_flag = 1;
1135 if ((logical = next_arg(args, &args)) ==
1136 (char *) 0)
1137 {
1138 say("You must specify a logical name");
1139 new_free(&cmd);
1140 return;
1141 }
1142 }
1143 else if (strncmp(cmd, "WINDOW", len) == 0)
1144 {
1145 refnum_flag = 1;
1146 refnum = current_refnum();
1147 }
1148 else if (strncmp(cmd, "MSG", len) == 0)
1149 {
1150 if (doing_privmsg)
1151 redirect = "NOTICE";
1152 else
1153 redirect = "PRIVMSG";
1154 if ((who = next_arg(args, &args)) ==
1155 (char *) 0)
1156 {
1157 say("No nicknames specified");
1158 new_free(&cmd);
1159 return;
1160 }
1161 }
1162 else if (strncmp(cmd, "FILTER", len) == 0)
1163 {
1164 redirect = "FILTER";
1165 if ((who = next_arg(args, &args)) ==
1166 (char *) 0)
1167 {
1168 say("No filter function specified");
1169 new_free(&cmd);
1170 return;
1171 }
1172 }
1173 else if (strncmp(cmd, "CLOSE", len) == 0)
1174 {
1175 if ((i = get_process_index(&args)) == -1)
1176 {
1177 say("Missing process number or logical name.");
1178 new_free(&cmd);
1179 return;
1180 }
1181 if (is_process_running(i))
1182 {
1183 proc = process_list[i];
1184 proc->p_stdin = exec_close(proc->p_stdin);
1185 proc->p_stdout = exec_close(proc->p_stdout);
1186 proc->p_stderr = exec_close(proc->p_stderr);
1187 }
1188 else
1189 say("No such process running!");
1190 new_free(&cmd);
1191 return;
1192 }
1193 else if (strncmp(cmd, "NOTICE", len) == 0)
1194 {
1195 redirect = "NOTICE";
1196 if ((who = next_arg(args, &args)) ==
1197 (char *) 0)
1198 {
1199 say("No nicknames specified");
1200 new_free(&cmd);
1201 return;
1202 }
1203 }
1204 else if (strncmp(cmd, "IN", len) == 0)
1205 {
1206 if ((i = get_process_index(&args)) == -1)
1207 {
1208 say("Missing process number or logical name.");
1209 new_free(&cmd);
1210 return;
1211 }
1212 text_to_process(i, args, 1);
1213 new_free(&cmd);
1214 return;
1215 }
1216 else
1217 {
1218 char *cmd2 = (char *) 0;
1219
1220 if ((i = get_process_index(&args)) == -1)
1221 {
1222 say("Invalid process specification");
1223 goto out;
1224 }
1225 if ((sig = atoi(flag)) > 0)
1226 {
1227 if ((sig > 0) && (sig < NSIG))
1228 kill_process(i, sig);
1229 else
1230 say("Signal number can be from 1 to %d", NSIG);
1231 goto out;
1232 }
1233 malloc_strcpy(&cmd2, flag);
1234 upper(cmd2);
1235 for (sig = 1; sig < NSIG && signals[sig]; sig++)
1236 {
1237 if (!strncmp(signals[sig], flag, len))
1238 {
1239 kill_process(i, sig);
1240 goto out2;
1241 }
1242 }
1243 say("No such signal: %s", flag);
1244 out2:
1245 new_free(&cmd2);
1246 out:
1247 new_free(&cmd);
1248 return;
1249 }
1250 new_free(&cmd);
1251 }
1252 else
1253 break;
1254 }
1255 if (is_process(args))
1256 {
1257 if ((i = get_process_index(&args)) == -1)
1258 {
1259 say("Invalid process specification");
1260 return;
1261 }
1262 if (valid_process_index(i))
1263 {
1264 proc = process_list[i];
1265 message_to(refnum);
1266 if (refnum_flag)
1267 {
1268 proc->refnum = refnum;
1269 if (refnum)
1270 say("Output from process %d (%s) now going to this window", i, proc->name);
1271 else
1272 say("Output from process %d (%s) not going to any window", i, proc->name);
1273 }
1274 malloc_strcpy(&(proc->redirect), redirect);
1275 malloc_strcpy(&(proc->who), who);
1276 if (redirect)
1277 {
1278 say("Output from process %d (%s) now going to %s", i, proc->name, who);
1279 }
1280 else
1281 say("Output from process %d (%s) now going to you", i, proc->name);
1282 if (logical_flag)
1283 {
1284 if (logical)
1285 {
1286 if (is_logical_unique(logical))
1287 {
1288 malloc_strcpy(&(
1289 proc->logical),
1290 logical);
1291 say("Process %d (%s) is now called %s",
1292 i, proc->name, proc->logical);
1293 }
1294 else
1295 say("The name %s is not unique!"
1296 , logical);
1297 }
1298 else
1299 say("The name for process %d (%s) has been removed", i, proc->name);
1300 }
1301 message_to(0);
1302 }
1303 else
1304 say("Invalid process specification");
1305 }
1306 else
1307 {
1308 if (is_logical_unique(logical))
1309 start_process(args, logical, redirect, who, refnum);
1310 else
1311 say("The name %s is not unique!", logical);
1312 }
1313 }
1314
1315 /*
1316 * clean_up_processes: kills all processes in the procss list by first
1317 * sending a SIGTERM, then a SIGKILL to clean things up
1318 */
1319 void
clean_up_processes()1320 clean_up_processes()
1321 {
1322 int i;
1323
1324 if (process_list_size)
1325 {
1326 say("Cleaning up left over processes....");
1327 for (i = 0; i < process_list_size; i++)
1328 {
1329 if (process_list[i])
1330 kill_process(i, SIGTERM);
1331 }
1332 sleep(2); /* Give them a chance for a graceful exit */
1333 for (i = 0; i < process_list_size; i++)
1334 {
1335 if (process_list[i])
1336 kill_process(i, SIGKILL);
1337 }
1338 }
1339 }
1340
1341 /*
1342 * close_all_exec: called when we fork of a wserv process for interaction
1343 * with screen/X, to close all unnessicary fd's that might cause problems
1344 * later.
1345 */
1346 void
close_all_exec()1347 close_all_exec()
1348 {
1349 int i;
1350 int tmp;
1351
1352 tmp = window_display;
1353 window_display = 0;
1354 for (i = 0; i < process_list_size; i++)
1355 if (process_list[i])
1356 {
1357 if (process_list[i]->p_stdin)
1358 new_close(process_list[i]->p_stdin);
1359 if (process_list[i]->p_stdout)
1360 new_close(process_list[i]->p_stdout);
1361 if (process_list[i]->p_stderr)
1362 new_close(process_list[i]->p_stderr);
1363 delete_process(i);
1364 kill_process(i, SIGKILL);
1365 }
1366 window_display = tmp;
1367 }
1368
1369 void
exec_server_delete(i)1370 exec_server_delete(i)
1371 int i;
1372 {
1373 int j;
1374
1375 for (j = 0; j < process_list_size; j++)
1376 if (process_list[j] && process_list[j]->server >= i)
1377 process_list[j]->server--;
1378 }
1379