예제 #1
0
파일: signal.c 프로젝트: yugui/ruby
/*
 * call-seq:
 *   Signal.trap( signal, command ) -> obj
 *   Signal.trap( signal ) {| | block } -> obj
 *
 * Specifies the handling of signals. The first parameter is a signal
 * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
 * signal number. The characters ``SIG'' may be omitted from the
 * signal name. The command or block specifies code to be run when the
 * signal is raised.
 * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
 * will be ignored.
 * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
 * will be invoked.
 * If the command is ``EXIT'', the script will be terminated by the signal.
 * If the command is ``SYSTEM_DEFAULT'', the operating system's default
 * handler will be invoked.
 * Otherwise, the given command or block will be run.
 * The special signal name ``EXIT'' or signal number zero will be
 * invoked just prior to program termination.
 * trap returns the previous handler for the given signal.
 *
 *     Signal.trap(0, proc { puts "Terminating: #{$$}" })
 *     Signal.trap("CLD")  { puts "Child died" }
 *     fork && Process.wait
 *
 * produces:
 *     Terminating: 27461
 *     Child died
 *     Terminating: 27460
 */
static VALUE
sig_trap(int argc, VALUE *argv)
{
    int sig;
    sighandler_t func;
    VALUE cmd;

    rb_secure(2);
    rb_check_arity(argc, 1, 2);

    sig = trap_signm(argv[0]);
    if (reserved_signal_p(sig)) {
        const char *name = signo2signm(sig);
        if (name)
            rb_raise(rb_eArgError, "can't trap reserved signal: SIG%s", name);
        else
            rb_raise(rb_eArgError, "can't trap reserved signal: %d", sig);
    }

    if (argc == 1) {
	cmd = rb_block_proc();
	func = sighandler;
    }
    else {
	cmd = argv[1];
	func = trap_handler(&cmd, sig);
    }

    if (OBJ_TAINTED(cmd)) {
	rb_raise(rb_eSecurityError, "Insecure: tainted signal trap");
    }

    return trap(sig, func, cmd);
}
예제 #2
0
파일: signal.c 프로젝트: yugui/ruby
static VALUE
rb_signo2signm(int signo)
{
    const char *const signm = signo2signm(signo);
    if (signm) {
	return rb_sprintf("SIG%s", signm);
    }
    else {
	return rb_sprintf("SIG%u", signo);
    }
}
예제 #3
0
/*
 * call-seq:
 *     Signal.signame(signo)  ->  string or nil
 *
 *  Convert signal number to signal name.
 *  Returns +nil+ if the signo is an invalid signal number.
 *
 *     Signal.trap("INT") { |signo| puts Signal.signame(signo) }
 *     Process.kill("INT", 0)
 *
 *  <em>produces:</em>
 *
 *     INT
 */
static mrb_value
signal_signame(mrb_state *mrb, mrb_value mod)
{
  mrb_int signo;
  const char *signame;

  mrb_get_args(mrb, "i", &signo);
  signame = signo2signm(signo);
  if (signame)
    return mrb_str_new_cstr(mrb, signame);
  else
    return mrb_nil_value();
}
예제 #4
0
static VALUE
esignal_init(int argc, VALUE *argv, VALUE self)
{
    int argnum = 1;
    VALUE sig = Qnil;
    int signo;
    const char *signm;

    if (argc > 0) {
	sig = rb_check_to_integer(argv[0], "to_int");
	if (!NIL_P(sig)) argnum = 2;
    }
    if (argc < 1 || argnum < argc) {
	rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
		 argc, argnum);
    }
    if (argnum == 2) {
	signo = NUM2INT(sig);
	if (signo < 0 || signo > NSIG) {
	    rb_raise(rb_eArgError, "invalid signal number (%d)", signo);
	}
	if (argc > 1) {
	    sig = argv[1];
	}
	else {
	    signm = signo2signm(signo);
	    if (signm) {
		sig = rb_sprintf("SIG%s", signm);
	    }
	    else {
		sig = rb_sprintf("SIG%u", signo);
	    }
	}
    }
    else {
	signm = SYMBOL_P(sig) ? rb_id2name(SYM2ID(sig)) : StringValuePtr(sig);
	if (strncmp(signm, "SIG", 3) == 0) signm += 3;
	signo = signm2signo(signm);
	if (!signo) {
	    rb_raise(rb_eArgError, "unsupported name `SIG%s'", signm);
	}
	if (SYMBOL_P(sig)) {
	    sig = rb_str_new2(signm);
	}
    }
    rb_call_super(1, &sig);
    rb_iv_set(self, "signo", INT2NUM(signo));

    return self;
}
예제 #5
0
static mrb_value
trap(mrb_state *mrb, mrb_value mod, int sig, sighandler_t func, mrb_value command)
{
  sighandler_t oldfunc;
  mrb_value oldcmd;
  mrb_value trap_list;
  mrb_sym id_trap_list;

  if (sig == 0) { /* EXIT */
    oldfunc = SIG_ERR;
  }
  else {
    oldfunc = mrb_signal(mrb, sig, func);
    if (oldfunc == SIG_ERR)
      mrb_sys_fail(mrb, signo2signm(sig));
  }
  id_trap_list = mrb_intern_lit(mrb, "trap_list");
  trap_list = mrb_iv_get(mrb, mod, id_trap_list);
  oldcmd = mrb_ary_ref(mrb, trap_list, (mrb_int)sig);

  if (mrb_nil_p(oldcmd)) {
    if (oldfunc == sighandler)
      oldcmd = mrb_str_new_cstr(mrb, "DEFAULT");
    else
      oldcmd = mrb_nil_value();
  }
  else if (mrb_type(oldcmd) == MRB_TT_TRUE) {
    if (oldfunc == SIG_IGN)
      oldcmd = mrb_str_new_cstr(mrb, "IGNORE");
    else if (oldfunc == SIG_DFL)
      oldcmd = mrb_str_new_cstr(mrb, "SYSTEM_DEFAULT");
    else if (oldfunc == sighandler)
      oldcmd = mrb_str_new_cstr(mrb, "DEFAULT");
    else
      oldcmd = mrb_nil_value();
  }
  else if (mrb_undef_p(oldcmd)) {
    oldcmd = mrb_str_new_cstr(mrb, "EXIT");
  }

  mrb_ary_set(mrb, trap_list, (mrb_int)sig, command);

  return oldcmd;
}
예제 #6
0
/*
 * call-seq:
 *   Signal.trap( signal, command ) -> obj
 *   Signal.trap( signal ) {| | block } -> obj
 *
 * Specifies the handling of signals. The first parameter is a signal
 * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
 * signal number. The characters ``SIG'' may be omitted from the
 * signal name. The command or block specifies code to be run when the
 * signal is raised.
 * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
 * will be ignored.
 * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
 * will be invoked.
 * If the command is ``EXIT'', the script will be terminated by the signal.
 * If the command is ``SYSTEM_DEFAULT'', the operating system's default
 * handler will be invoked.
 * Otherwise, the given command or block will be run.
 * The special signal name ``EXIT'' or signal number zero will be
 * invoked just prior to program termination.
 * trap returns the previous handler for the given signal.
 *
 *     Signal.trap(0, proc { puts "Terminating: #{$$}" })
 *     Signal.trap("CLD")  { puts "Child died" }
 *     fork && Process.wait
 *
 * produces:
 *     Terminating: 27461
 *     Child died
 *     Terminating: 27460
 */
static VALUE
sig_trap(int argc, VALUE *argv)
{
    struct trap_arg arg;

    rb_secure(2);
    rb_check_arity(argc, 1, 2);

    arg.sig = trap_signm(argv[0]);
    if (reserved_signal_p(arg.sig)) {
        const char *name = signo2signm(arg.sig);
        if (name)
            rb_raise(rb_eArgError, "can't trap reserved signal: SIG%s", name);
        else
            rb_raise(rb_eArgError, "can't trap reserved signal: %d", (int)arg.sig);
    }

    if (argc == 1) {
	arg.cmd = rb_block_proc();
	arg.func = sighandler;
    }
    else {
	arg.cmd = argv[1];
	arg.func = trap_handler(&arg.cmd, arg.sig);
    }

    if (OBJ_TAINTED(arg.cmd)) {
	rb_raise(rb_eSecurityError, "Insecure: tainted signal trap");
    }
#if USE_TRAP_MASK
    {
      sigset_t fullmask;

      /* disable interrupt */
      sigfillset(&fullmask);
      pthread_sigmask(SIG_BLOCK, &fullmask, &arg.mask);

      return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg);
    }
#else
    return trap(&arg);
#endif
}
예제 #7
0
void
rb_signal_exec(rb_thread_t *th, int sig)
{
    VALUE cmd = rb_get_trap_cmd(sig);

    if (cmd == 0) {
	switch (sig) {
	  case SIGINT:
	    rb_interrupt();
	    break;
#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
	    rb_thread_signal_raise(th, signo2signm(sig));
	    break;
	}
    }
    else if (cmd == Qundef) {
	rb_thread_signal_exit(th);
    }
    else {
	rb_proc_t *proc;
	VALUE signum = INT2FIX(sig);
	GetProcPtr(cmd, proc);
	th_invoke_proc(th, proc, proc->block.self, 1, &signum);
    }
}
예제 #8
0
파일: signal.c 프로젝트: yugui/ruby
const char *
ruby_signal_name(int no)
{
    return signo2signm(no);
}
예제 #9
0
파일: signal.c 프로젝트: yugui/ruby
/*
 * call-seq:
 *     Signal.signame(signo)  ->  string
 *
 *  convert signal number to signal name
 *
 *     Signal.trap("INT") { |signo| puts Signal.signame(signo) }
 *     Process.kill("INT", 0)
 *
 *  <em>produces:</em>
 *
 *     INT
 */
static VALUE
sig_signame(VALUE recv, VALUE signo)
{
    const char *signame = signo2signm(NUM2INT(signo));
    return rb_str_new_cstr(signame);
}