/********************************************************************** signal.c - $Author$ $Date$ created at: Tue Dec 20 10:13:44 JST 1994 Copyright (C) 1993-2002 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include #include #ifdef __BEOS__ #undef SIGBUS #endif #ifndef NSIG # ifdef DJGPP # define NSIG SIGMAX # else # define NSIG (_SIGMAX + 1) /* For QNX */ # endif #endif static struct signals { char *signm; int signo; } siglist [] = { #ifdef SIGHUP {"HUP", SIGHUP}, #endif #ifdef SIGINT {"INT", SIGINT}, #endif #ifdef SIGQUIT {"QUIT", SIGQUIT}, #endif #ifdef SIGILL {"ILL", SIGILL}, #endif #ifdef SIGTRAP {"TRAP", SIGTRAP}, #endif #ifdef SIGIOT {"IOT", SIGIOT}, #endif #ifdef SIGABRT {"ABRT", SIGABRT}, #endif #ifdef SIGEMT {"EMT", SIGEMT}, #endif #ifdef SIGFPE {"FPE", SIGFPE}, #endif #ifdef SIGKILL {"KILL", SIGKILL}, #endif #ifdef SIGBUS {"BUS", SIGBUS}, #endif #ifdef SIGSEGV {"SEGV", SIGSEGV}, #endif #ifdef SIGSYS {"SYS", SIGSYS}, #endif #ifdef SIGPIPE {"PIPE", SIGPIPE}, #endif #ifdef SIGALRM {"ALRM", SIGALRM}, #endif #ifdef SIGTERM {"TERM", SIGTERM}, #endif #ifdef SIGURG {"URG", SIGURG}, #endif #ifdef SIGSTOP {"STOP", SIGSTOP}, #endif #ifdef SIGTSTP {"TSTP", SIGTSTP}, #endif #ifdef SIGCONT {"CONT", SIGCONT}, #endif #ifdef SIGCHLD {"CHLD", SIGCHLD}, #endif #ifdef SIGCLD {"CLD", SIGCLD}, #else # ifdef SIGCHLD {"CLD", SIGCHLD}, # endif #endif #ifdef SIGTTIN {"TTIN", SIGTTIN}, #endif #ifdef SIGTTOU {"TTOU", SIGTTOU}, #endif #ifdef SIGIO {"IO", SIGIO}, #endif #ifdef SIGXCPU {"XCPU", SIGXCPU}, #endif #ifdef SIGXFSZ {"XFSZ", SIGXFSZ}, #endif #ifdef SIGVTALRM {"VTALRM", SIGVTALRM}, #endif #ifdef SIGPROF {"PROF", SIGPROF}, #endif #ifdef SIGWINCH {"WINCH", SIGWINCH}, #endif #ifdef SIGUSR1 {"USR1", SIGUSR1}, #endif #ifdef SIGUSR2 {"USR2", SIGUSR2}, #endif #ifdef SIGLOST {"LOST", SIGLOST}, #endif #ifdef SIGMSG {"MSG", SIGMSG}, #endif #ifdef SIGPWR {"PWR", SIGPWR}, #endif #ifdef SIGPOLL {"POLL", SIGPOLL}, #endif #ifdef SIGDANGER {"DANGER", SIGDANGER}, #endif #ifdef SIGMIGRATE {"MIGRATE", SIGMIGRATE}, #endif #ifdef SIGPRE {"PRE", SIGPRE}, #endif #ifdef SIGGRANT {"GRANT", SIGGRANT}, #endif #ifdef SIGRETRACT {"RETRACT", SIGRETRACT}, #endif #ifdef SIGSOUND {"SOUND", SIGSOUND}, #endif #ifdef SIGINFO {"INFO", SIGINFO}, #endif {NULL, 0} }; static int signm2signo(nm) char *nm; { struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) if (strcmp(sigs->signm, nm) == 0) return sigs->signo; return 0; } static char* signo2signm(no) int no; { struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) if (sigs->signo == no) return sigs->signm; return 0; } VALUE rb_f_kill(argc, argv) int argc; VALUE *argv; { int negative = 0; int sig; int i; char *s; rb_secure(2); if (argc < 2) rb_raise(rb_eArgError, "wrong number of arguments -- kill(sig, pid...)"); switch (TYPE(argv[0])) { case T_FIXNUM: sig = FIX2INT(argv[0]); break; case T_SYMBOL: s = rb_id2name(SYM2ID(argv[0])); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; case T_STRING: s = RSTRING(argv[0])->ptr; if (s[0] == '-') { negative++; s++; } str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; if((sig = signm2signo(s)) == 0) rb_raise(rb_eArgError, "unsupported name `SIG%s'", s); if (negative) sig = -sig; break; default: { VALUE str; str = rb_check_convert_type(argv[0], T_STRING, "String", "to_str"); if (!NIL_P(str)) { s = RSTRING(str)->ptr; goto str_signal; } rb_raise(rb_eArgError, "bad signal type %s", rb_class2name(CLASS_OF(argv[0]))); } break; } if (sig < 0) { sig = -sig; for (i=1; i= NSIG) { rb_bug("trap_handler: Bad signal %d", sig); } #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL) ruby_signal(sig, sighandler); #endif if (ATOMIC_TEST(rb_trap_immediate)) { IN_MAIN_CONTEXT(signal_exec, sig); ATOMIC_SET(rb_trap_immediate, 1); } else { ATOMIC_INC(rb_trap_pending); ATOMIC_INC(trap_pending_list[sig]); } } #ifdef SIGBUS static RETSIGTYPE sigbus _((int)); static RETSIGTYPE sigbus(sig) int sig; { rb_bug("Bus Error"); } #endif #ifdef SIGSEGV static RETSIGTYPE sigsegv _((int)); static RETSIGTYPE sigsegv(sig) int sig; { rb_bug("Segmentation fault"); } #endif #ifdef SIGPIPE static RETSIGTYPE sigpipe _((int)); static RETSIGTYPE sigpipe(sig) int sig; { /* do nothing */ } #endif void rb_trap_exit() { #ifndef MACOS_UNUSE_SIGNAL if (trap_list[0]) { VALUE trap_exit = trap_list[0]; trap_list[0] = 0; rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0)), 0); } #endif } void rb_trap_exec() { #ifndef MACOS_UNUSE_SIGNAL int i; for (i=0; icmd; if (NIL_P(command)) { func = SIG_IGN; } else if (TYPE(command) == T_STRING) { SafeStringValue(command); /* taint check */ if (RSTRING(command)->len == 0) { func = SIG_IGN; } else if (RSTRING(command)->len == 7) { if (strncmp(RSTRING(command)->ptr, "SIG_IGN", 7) == 0) { func = SIG_IGN; } else if (strncmp(RSTRING(command)->ptr, "SIG_DFL", 7) == 0) { func = SIG_DFL; } else if (strncmp(RSTRING(command)->ptr, "DEFAULT", 7) == 0) { func = SIG_DFL; } } else if (RSTRING(command)->len == 6) { if (strncmp(RSTRING(command)->ptr, "IGNORE", 6) == 0) { func = SIG_IGN; } } else if (RSTRING(command)->len == 4) { if (strncmp(RSTRING(command)->ptr, "EXIT", 4) == 0) { func = sigexit; } } } if (func == SIG_IGN || func == SIG_DFL) { command = 0; } switch (TYPE(arg->sig)) { case T_FIXNUM: sig = NUM2INT(arg->sig); break; case T_SYMBOL: s = rb_id2name(SYM2ID(arg->sig)); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; case T_STRING: s = RSTRING(arg->sig)->ptr; str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; sig = signm2signo(s); if (sig == 0 && strcmp(s, "EXIT") != 0) rb_raise(rb_eArgError, "unsupported signal SIG%s", s); } if (sig < 0 || sig > NSIG) { rb_raise(rb_eArgError, "invalid signal number (%d)", sig); } #if defined(HAVE_SETITIMER) && !defined(__BOW__) if (sig == SIGVTALRM) { rb_raise(rb_eArgError, "SIGVTALRM reserved for Thread; cannot set handler"); } #endif if (func == SIG_DFL) { switch (sig) { case SIGINT: #ifdef SIGHUP case SIGHUP: #endif #ifdef SIGQUIT case SIGQUIT: #endif #ifdef SIGALRM case SIGALRM: #endif #ifdef SIGUSR1 case SIGUSR1: #endif #ifdef SIGUSR2 case SIGUSR2: #endif func = sighandler; break; #ifdef SIGBUS case SIGBUS: func = sigbus; break; #endif #ifdef SIGSEGV case SIGSEGV: func = sigsegv; break; #endif #ifdef SIGPIPE case SIGPIPE: func = sigpipe; break; #endif } } ruby_signal(sig, func); old = trap_list[sig]; if (!old) old = Qnil; trap_list[sig] = command; /* enable at least specified signal. */ #if !defined(NT) #ifdef HAVE_SIGPROCMASK sigdelset(&arg->mask, sig); #else arg->mask &= ~sigmask(sig); #endif #endif return old; } #if !defined(NT) static VALUE trap_ensure(arg) struct trap_arg *arg; { /* enable interrupt */ #ifdef HAVE_SIGPROCMASK sigprocmask(SIG_SETMASK, &arg->mask, NULL); #else sigsetmask(arg->mask); #endif trap_last_mask = arg->mask; return 0; } #endif void rb_trap_restore_mask() { #if !defined(NT) # ifdef HAVE_SIGPROCMASK sigprocmask(SIG_SETMASK, &trap_last_mask, NULL); # else sigsetmask(trap_last_mask); # endif #endif } static VALUE sig_trap(argc, argv) int argc; VALUE *argv; { struct trap_arg arg; rb_secure(2); if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "wrong number of arguments -- trap(sig, cmd)/trap(sig){...}"); } arg.sig = argv[0]; if (argc == 1) { arg.cmd = rb_f_lambda(); } else if (argc == 2) { arg.cmd = argv[1]; } if (OBJ_TAINTED(arg.cmd)) { rb_raise(rb_eSecurityError, "Insecure: tainted signal trap"); } #if !defined(NT) /* disable interrupt */ # ifdef HAVE_SIGPROCMASK sigfillset(&arg.mask); sigprocmask(SIG_BLOCK, &arg.mask, &arg.mask); # else arg.mask = sigblock(~0); # endif return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg); #else return trap(&arg); #endif } static VALUE sig_list() { VALUE h = rb_hash_new(); struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) { rb_hash_aset(h, rb_str_new2(sigs->signm), INT2FIX(sigs->signo)); } return h; } static void install_sighandler(signum, handler) int signum; sighandler_t handler; { sighandler_t old; old = ruby_signal(signum, handler); if (old != SIG_DFL) { ruby_signal(signum, old); } } void Init_signal() { #ifndef MACOS_UNUSE_SIGNAL VALUE mSignal = rb_define_module("Signal"); rb_define_global_function("trap", sig_trap, -1); rb_define_module_function(mSignal, "trap", sig_trap, -1); rb_define_module_function(mSignal, "list", sig_list, 0); install_sighandler(SIGINT, sighandler); #ifdef SIGHUP install_sighandler(SIGHUP, sighandler); #endif #ifdef SIGQUIT install_sighandler(SIGQUIT, sighandler); #endif #ifdef SIGALRM install_sighandler(SIGALRM, sighandler); #endif #ifdef SIGUSR1 install_sighandler(SIGUSR1, sighandler); #endif #ifdef SIGUSR2 install_sighandler(SIGUSR2, sighandler); #endif #ifdef SIGBUS install_sighandler(SIGBUS, sigbus); #endif #ifdef SIGSEGV install_sighandler(SIGSEGV, sigsegv); #endif #ifdef SIGPIPE install_sighandler(SIGPIPE, sigpipe); #endif #endif /* MACOS_UNUSE_SIGNAL */ }