From dad69b4643c296c84f9941b630c9f8b3be5ec73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Sat, 1 Mar 2003 17:33:35 +0100 Subject: [PATCH] Moved tracing of processes to a separate class: Process.TraceProcess(). Rev: lib/modules/Process.pmod:1.39 Rev: src/signal_handler.c:1.243 Rev: src/testsuite.in:1.612 --- lib/modules/Process.pmod | 4 + src/signal_handler.c | 182 ++++++++++++++++++++++++++++++--------- src/testsuite.in | 29 +++---- 3 files changed, 161 insertions(+), 54 deletions(-) diff --git a/lib/modules/Process.pmod b/lib/modules/Process.pmod index a7a59a603a..b46fdf7e02 100644 --- a/lib/modules/Process.pmod +++ b/lib/modules/Process.pmod @@ -2,6 +2,10 @@ constant create_process = __builtin.create_process; +#if constant(__builtin.TraceProcess) +constant TraceProcess = __builtin.TraceProcess; +#endif + //! Slightly polished version of @[create_process]. //! @seealso //! @[create_process] diff --git a/src/signal_handler.c b/src/signal_handler.c index 41222677ff..e78deb09bf 100644 --- a/src/signal_handler.c +++ b/src/signal_handler.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: signal_handler.c,v 1.242 2003/03/01 13:51:43 grubba Exp $ +|| $Id: signal_handler.c,v 1.243 2003/03/01 16:33:34 grubba Exp $ */ #include "global.h" @@ -26,7 +26,7 @@ #include "main.h" #include <signal.h> -RCSID("$Id: signal_handler.c,v 1.242 2003/03/01 13:51:43 grubba Exp $"); +RCSID("$Id: signal_handler.c,v 1.243 2003/03/01 16:33:34 grubba Exp $"); #ifdef HAVE_PASSWD_H # include <passwd.h> @@ -145,7 +145,17 @@ RCSID("$Id: signal_handler.c,v 1.242 2003/03/01 13:51:43 grubba Exp $"); #ifdef HAVE_PTRACE /* BSDs have different names for these constants... + * + * And Solaris 2.x doesn't name them at all... */ +#ifndef PTRACE_TRACEME +#ifdef PT_TRACE_ME +#define PTRACE_TRACEME PT_TRACE_ME +#else +#define PTRACE_TRACEME 0 +#endif +#endif + #ifndef PTRACE_CONT #ifdef PT_CONTINUE #define PTRACE_CONT PT_CONTINUE @@ -154,11 +164,11 @@ RCSID("$Id: signal_handler.c,v 1.242 2003/03/01 13:51:43 grubba Exp $"); #endif #endif -#ifndef PTRACE_TRACEME -#ifdef PT_TRACE_ME -#define PTRACE_TRACEME PT_TRACE_ME +#ifndef PTRACE_KILL +#ifdef PT_KILL +#define PTRACE_KILL PT_KILL #else -#define PTRACE_TRACEME 0 +#define PTRACE_KILL 8 #endif #endif @@ -1246,21 +1256,19 @@ static TH_RETURN_TYPE wait_thread(void *data) *! system process, with methods for various process housekeeping. */ -/*! @decl int wait(int(0..1)|void wait_for_stopped) +/*! @decl int wait() *! Waits for the process to end. *! - *! @param wait_for_stopped - *! If non-zero, wait for the process to stop running. - *! *! @returns *! @int *! @value 0.. *! The exit code of the process. *! @value -1 *! The process was killed by a signal. - *! @value -2 - *! The process was stopped by a non-lethal signal. *! @endint + *! + *! @seelalso + *! @[TraceProcess()->wait()] */ static void f_pid_status_wait(INT32 args) { @@ -1268,7 +1276,8 @@ static void f_pid_status_wait(INT32 args) if(THIS->pid == -1) Pike_error("This process object has no process associated with it.\n"); - wait_for_stopped = args && !UNSAFE_IS_ZERO(Pike_sp-args); + /* NB: This function also implements TraceProcess()->wait(). */ + wait_for_stopped = THIS->flags & PROCESS_FLAG_TRACED; pop_n_elems(args); @@ -1532,20 +1541,70 @@ static void f_pid_status_set_priority(INT32 args) } +/*! @endclass + */ + #ifdef HAVE_PTRACE -/*! @decl void continue(int|void signal) + +/*! @class TraceProcess + *! + *! Class that enables tracing of processes. + *! + *! The new process will be started in stopped state. + *! Use @[cont()] to let it start executing. + *! + *! @note + *! This class currently only exists on systems that + *! implement @tt{ptrace()@}. + */ + +/*! @decl inherit create_process + */ + +/* NB: The code below can use THIS only because + * pid_status_program is inherited first. + */ + +static void init_trace_process(struct object *o) +{ + THIS->flags |= PROCESS_FLAG_TRACED; +} + +static void exit_trace_process(struct object *o) +{ + /* FIXME: Detach the process? */ +} + +/*! @decl int wait() + *! Waits for the process to stop. + *! + *! @returns + *! @int + *! @value 0.. + *! The exit code of the process. + *! @value -1 + *! The process was killed by a signal. + *! @value -2 + *! The process has stopped. + *! @endint + *! + *! @seealso + *! @[create_process::wait()] + */ + +/*! @decl void cont(int|void signal) *! Allow a traced process to continue. *! *! @param signal *! Deliver this signal to the process. *! *! @note - *! This function is only useful for traced processes. + *! This function may only be called for stopped processes. *! - *! This function currently only exists on systems that - *! implement @tt{ptrace()@}. + *! @seealso + *! @[wait()] */ -static void f_pid_status_continue(INT32 args) +static void f_trace_process_cont(INT32 args) { int cont_signal = 0; #ifdef PIKE_SECURITY @@ -1555,10 +1614,6 @@ static void f_pid_status_continue(INT32 args) if(THIS->pid == -1) Pike_error("This process object has no process associated with it.\n"); - if (!(THIS->flags & PROCESS_FLAG_TRACED)) { - Pike_error("This process is not being traced.\n"); - } - if (THIS->state != PROCESS_STOPPED) { if (THIS->state == PROCESS_RUNNING) { Pike_error("Process already running.\n"); @@ -1581,11 +1636,46 @@ static void f_pid_status_continue(INT32 args) pop_n_elems(args); push_int(0); } -#endif /* HAVE_PTRACE */ + +/*! @decl void exit() + *! Cause the traced process to exit. + *! + *! @note + *! This function may only be called for stopped processes. + *! + *! @seealso + *! @[cont()], @[wait()] + */ +static void f_trace_process_exit(INT32 args) +{ +#ifdef PIKE_SECURITY + if(!CHECK_SECURITY(SECURITY_BIT_SECURITY)) + Pike_error("pid_status_wait: permission denied.\n"); +#endif + if(THIS->pid == -1) + Pike_error("This process object has no process associated with it.\n"); + + if (THIS->state != PROCESS_STOPPED) { + if (THIS->state == PROCESS_EXITED) { + Pike_error("Process already exited.\n"); + } + Pike_error("Process not stopped\n"); + } + + if (ptrace(PTRACE_KILL, THIS->pid, NULL, 0) == -1) { + int err = errno; + /* FIXME: Better diagnostics. */ + Pike_error("Failed to exit process. errno:%d\n", err); + } + pop_n_elems(args); + push_int(0); +} /*! @endclass */ +#endif /* HAVE_PTRACE */ + /*! @endmodule */ @@ -2165,10 +2255,6 @@ static void internal_add_limit( struct perishables *storage, *! will be inherited from the current process rather than changed to *! the approperiate values for that uid. *! - *! @member int(0..1) "trace" - *! This parameter starts the child process in trace mode. - *! See @[trace()]. - *! *! @member string "priority" *! This sets the priority of the new process, see *! @[set_priority] for more info. @@ -2912,14 +2998,17 @@ void f_create_process(INT32 args) if(!SAFE_IS_ZERO(tmp)) do_initgroups=0; - if((tmp=simple_mapping_string_lookup(optional, "trace"))) - if(!SAFE_IS_ZERO(tmp)) - do_trace=1; - if((tmp=simple_mapping_string_lookup(optional, "keep_signals"))) keep_signals = !SAFE_IS_ZERO(tmp); } + if (THIS->flags & PROCESS_FLAG_TRACED) { + /* We're inherited from TraceProcess. + * Start the process in trace mode. + */ + do_trace = 1; + } + #ifdef HAVE_SETGROUPS #ifdef HAVE_GETGRENT @@ -3147,7 +3236,6 @@ void f_create_process(INT32 args) THIS->pid = pid; THIS->state = PROCESS_RUNNING; - THIS->flags = do_trace?PROCESS_FLAG_TRACED:0; ref_push_object(Pike_fp->current_object); push_int(pid); mapping_insert(pid_mapping, Pike_sp-1, Pike_sp-2); @@ -3270,7 +3358,7 @@ void f_create_process(INT32 args) Pike_error("Process.create_process(): failed to set controlling TTY. errno:%d\n", buf[1]); break; case PROCE_PTRACE: - Pike_error("Process.create_process(): failed to enter trace mode. errno:%d\n", buf[1]); + Pike_error("Process.TraceProcess(): failed to enter trace mode. errno:%d\n", buf[1]); break; case PROCE_EXEC: switch(buf[1]) { @@ -4294,14 +4382,9 @@ void init_signals(void) /* function(string:int) */ ADD_FUNCTION("set_priority",f_pid_status_set_priority,tFunc(tStr,tInt),0); /* function(int(0..1)|void:int) */ - ADD_FUNCTION("wait",f_pid_status_wait,tFunc(tOr(tInt01,tVoid),tInt),0); + ADD_FUNCTION("wait",f_pid_status_wait,tFunc(tNone,tInt),0); /* function(:int) */ ADD_FUNCTION("status",f_pid_status_status,tFunc(tNone,tInt),0); -#ifdef HAVE_PTRACE - /* function(int|void:void) */ - ADD_FUNCTION("continue",f_pid_status_continue, - tFunc(tOr(tVoid,tInt),tVoid),0); -#endif /* HAVE_PTRACE */ /* function(:int) */ ADD_FUNCTION("last_signal", f_pid_status_last_signal,tFunc(tNone,tInt),0); /* function(:int) */ @@ -4312,9 +4395,30 @@ void init_signals(void) #endif /* HAVE_KILL */ /* function(array(string),void|mapping(string:mixed):object) */ ADD_FUNCTION("create",f_create_process,tFunc(tArr(tStr) tOr(tVoid,tMap(tStr,tMix)),tObj),0); + pid_status_program=end_program(); add_program_constant("create_process",pid_status_program,0); +#ifdef HAVE_PTRACE + start_new_program(); + /* NOTE: This inherit MUST be first! */ + low_inherit(pid_status_program, NULL, -1, 0, 0, NULL); + set_init_callback(init_trace_process); + set_exit_callback(exit_trace_process); + + /* NOTE: Several of the functions inherited from pid_status_program + * change behaviour if PROCESS_FLAG_TRACED is set. + */ + + /* function(int|void:void) */ + ADD_FUNCTION("cont",f_trace_process_cont, + tFunc(tOr(tVoid,tInt),tVoid), 0); + /* function(:void) */ + ADD_FUNCTION("exit", f_trace_process_exit, + tFunc(tNone, tVoid), 0); + + end_class("TraceProcess", 0); +#endif /* HAVE_PTRACE */ /* function(string,int|void:int) */ ADD_EFUN("set_priority",f_set_priority,tFunc(tStr tOr(tInt,tVoid),tInt), diff --git a/src/testsuite.in b/src/testsuite.in index 5414ee285c..641f1f3bf2 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -1,4 +1,4 @@ -test_true([["$Id: testsuite.in,v 1.611 2003/03/01 14:24:25 nilsson Exp $"]]); +test_true([["$Id: testsuite.in,v 1.612 2003/03/01 16:33:34 grubba Exp $"]]); // This triggered a bug only if run sufficiently early. test_compile_any([[#pike 7.2]]) @@ -8946,17 +8946,16 @@ test_do([[ proc->kill (9); return threads->wait() - ({-1}); ]], ({})) +]]) +cond([[ file_stat("/bin/sleep") && __builtin->TraceProcess && (cpp("__NT__")/"\n")[1]=="__NT__" ]], +[[ test_do([[ // Check that tracing works... - object proc = Process.create_process(({ "/bin/sleep", "99999" }), - (["trace":1])); - if (!proc->continue) { - // No trace support... - proc->kill(9); - return 0; - } - int code = proc->wait(1); + Process.TraceProcess proc = + Process.TraceProcess(({ "/bin/sleep", "99999" })); + + int code = proc->wait(); if (code != -2) { proc->kill(9); return sprintf("Bad returncode from wait():%d (expected -2)", code); @@ -8966,11 +8965,11 @@ test_do([[ proc->kill(9); return sprintf("Unexpected signal:%d (expected 5)", sig); } - proc->continue(); + proc->cont(); // Check that we can block deadly signals. proc->kill(15); // SIGTERM - code = proc->wait(1); + code = proc->wait(); if (code != -2) { proc->kill(9); return sprintf("Bad second returncode from wait():%d (expected -2)", code); @@ -8980,11 +8979,11 @@ test_do([[ proc->kill(9); return sprintf("Unexpected signal:%d (expected 15)", sig); } - proc->continue(); + proc->cont(); // Check that we can make harmless signals deadly. proc->kill(18); // SIGCONT - code = proc->wait(1); + code = proc->wait(); if (code != -2) { proc->kill(9); return sprintf("Bad third returncode from wait():%d (expected -2)", code); @@ -8994,9 +8993,9 @@ test_do([[ proc->kill(9); return sprintf("Unexpected signal:%d (expected 18)", sig); } - proc->continue(9); // Make it a SIGKILL + proc->cont(9); // Make it a SIGKILL - code = proc->wait(1); + code = proc->wait(); if (code != -1) { proc->kill(9); return sprintf("Bad fourth returncode from wait():%d (expected -1)", code); -- GitLab