diff options
Diffstat (limited to 'runtime/staprun/mainloop.c')
-rw-r--r-- | runtime/staprun/mainloop.c | 302 |
1 files changed, 107 insertions, 195 deletions
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 7b8c5e31..4acfb001 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -11,23 +11,12 @@ */ #include "staprun.h" +#include <sys/utsname.h> /* globals */ -int control_channel = 0; int ncpus; int use_old_transport = 0; -#define ERR_MSG "\nUNEXPECTED FATAL ERROR in staprun. Please file a bug report.\n" -void fatal_handler (int signum) -{ - int rc; - char *str = strsignal(signum); - rc = write (STDERR_FILENO, ERR_MSG, sizeof(ERR_MSG)); - rc = write (STDERR_FILENO, str, strlen(str)); - rc = write (STDERR_FILENO, "\n", 1); - _exit(-1); -} - static void sigproc(int signum) { dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum)); @@ -60,56 +49,6 @@ static void setup_main_signals(int cleanup) sigaction(SIGQUIT, &a, NULL); } -void setup_signals(void) -{ - sigset_t s; - struct sigaction a; - - /* blocking all signals while we set things up */ - sigfillset(&s); - pthread_sigmask(SIG_SETMASK, &s, NULL); - - /* set some of them to be ignored */ - memset(&a, 0, sizeof(a)); - sigfillset(&a.sa_mask); - a.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &a, NULL); - sigaction(SIGUSR2, &a, NULL); - - /* for serious errors, handle them in fatal_handler */ - a.sa_handler = fatal_handler; - sigaction(SIGBUS, &a, NULL); - sigaction(SIGFPE, &a, NULL); - sigaction(SIGILL, &a, NULL); - sigaction(SIGSEGV, &a, NULL); - sigaction(SIGXCPU, &a, NULL); - sigaction(SIGXFSZ, &a, NULL); - - /* unblock all signals */ - sigemptyset(&s); - pthread_sigmask(SIG_SETMASK, &s, NULL); -} - - -/** - * send_request - send request to kernel over control channel - * @type: the relay-app command id - * @data: pointer to the data to be sent - * @len: length of the data to be sent - * - * Returns 0 on success, negative otherwise. - */ -int send_request(int type, void *data, int len) -{ - char buf[1024]; - if (len > (int)sizeof(buf)) { - err("exceeded maximum send_request size.\n"); - return -1; - } - memcpy(buf, &type, 4); - memcpy(&buf[4],data,len); - return write(control_channel, buf, len+4); -} /* * start_cmd forks the command given on the command line @@ -131,23 +70,17 @@ void start_cmd(void) dbug (1, "execing target_cmd %s\n", target_cmd); if ((pid = fork()) < 0) { - perror ("fork"); - exit(-1); + _perr("fork"); + exit(1); } else if (pid == 0) { int signum; - if (setregid(cmd_gid, cmd_gid) < 0) { - perror("setregid"); - } - if (setreuid(cmd_uid, cmd_uid) < 0) { - perror("setreuid"); - } /* wait here until signaled */ sigwait(&usrset, &signum); if (execl("/bin/sh", "sh", "-c", target_cmd, NULL) < 0) perror(target_cmd); - _exit(-1); + _exit(1); } target_pid = pid; } @@ -156,8 +89,6 @@ void start_cmd(void) * system_cmd() executes system commands in response * to an STP_SYSTEM message from the module. These * messages are sent by the system() systemtap function. - * uid and gid are set because staprun is running as root and - * it is best to run commands as the real user. */ void system_cmd(char *cmd) { @@ -165,57 +96,104 @@ void system_cmd(char *cmd) dbug (2, "system %s\n", cmd); if ((pid = fork()) < 0) { - perror ("fork"); + _perr("fork"); } else if (pid == 0) { - if (setregid(cmd_gid, cmd_gid) < 0) { - perror("setregid"); - } - if (setreuid(cmd_uid, cmd_uid) < 0) { - perror("setreuid"); - } if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) - perror(cmd); - _exit(-1); + perr("%s", cmd); + _exit(1); } } +static int using_old_transport(void) +{ + struct utsname utsbuf; + int i; + long int kver[3]; + char *start, *end; -/* stp_check script */ -#ifdef PKGLIBDIR -char *stp_check=PKGLIBDIR "/stp_check"; -#else -char *stp_check="stp_check"; -#endif + if (uname(&utsbuf) != 0) { + _perr("Unable to determine kernel version, uname failed"); + return -1; + } + + start = utsbuf.release; + for (i = 0; i < 3; i++) { + errno = 0; + kver[i] = strtol(start, &end, 10); + if (errno != 0) { + _perr("Unable to parse kernel version, strtol failed"); + return -1; + } + start = end; + start++; + } -static int run_stp_check (void) + if (KERNEL_VERSION(kver[0], kver[1], kver[2]) + <= KERNEL_VERSION(2, 6, 15)) { + dbug(2, "Using OLD TRANSPORT\n"); + return 1; + } + return 0; +} + +/* This is only used in the old relayfs code */ +static void read_buffer_info(void) { - int ret ; - /* run the _stp_check script */ - dbug(2, "executing %s\n", stp_check); - ret = system(stp_check); - return ret; + char buf[PATH_MAX]; + struct statfs st; + int fd, len, ret; + + if (!use_old_transport) + return; + + if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) + return; + + if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname)) + return; + fd = open(buf, O_RDONLY); + if (fd < 0) + return; + + len = read(fd, buf, sizeof(buf)); + if (len <= 0) { + perr("Couldn't read bufsize"); + close(fd); + return; + } + ret = sscanf(buf, "%u,%u", &n_subbufs, &subbuf_size); + if (ret != 2) + perr("Couldn't read bufsize"); + + dbug(2, "n_subbufs= %u, size=%u\n", n_subbufs, subbuf_size); + close(fd); + return; } + /** - * init_stp - initialize the app + * init_stapio - initialize the app * @print_summary: boolean, print summary or not at end of run * * Returns 0 on success, negative otherwise. */ -int init_staprun(void) +int init_stapio(void) { - char bufcmd[128]; - int rstatus; - int pid; + dbug(2, "init_stapio\n"); - if (system(VERSION_CMD)) { - dbug(2, "Using OLD TRANSPORT\n"); - use_old_transport = 1; + use_old_transport = using_old_transport(); + if (use_old_transport < 0) + return -1; + + /* create control channel */ + if (init_ctl_channel() < 0) { + err("Failed to initialize control channel.\n"); + return -1; } + read_buffer_info(); if (attach_mod) { - if (init_ctl_channel() < 0) - return -1; + dbug(2, "Attaching\n"); if (use_old_transport) { if (init_oldrelayfs() < 0) { close_ctl_channel(); @@ -230,57 +208,22 @@ int init_staprun(void) return 0; } - if (run_stp_check() < 0) - return -1; - - /* insert module */ - sprintf(bufcmd, "_stp_bufsize=%d", buffer_size); - modoptions[0] = "insmod"; - modoptions[1] = modpath; - modoptions[2] = bufcmd; - /* modoptions[3...N] set by command line parser. */ - - if ((pid = fork()) < 0) { - perror ("fork"); - exit(-1); - } else if (pid == 0) { - if (execvp("/sbin/insmod", modoptions) < 0) - _exit(-1); - } - if (waitpid(pid, &rstatus, 0) < 0) { - perror("waitpid"); - exit(-1); - } - if (WIFEXITED(rstatus) && WEXITSTATUS(rstatus)) { - fprintf(stderr, "ERROR, couldn't insmod probe module %s\n", modpath); - return -1; - } - - /* create control channel */ - if (init_ctl_channel() < 0) { - err("Failed to initialize control channel.\n"); - goto exit1; - } - /* fork target_cmd if requested. */ /* It will not actually exec until signalled. */ if (target_cmd) start_cmd(); return 0; - -exit1: - snprintf(bufcmd, sizeof(bufcmd), "/sbin/rmmod -w %s", modname); - if (system(bufcmd)) - fprintf(stderr, "ERROR: couldn't rmmod probe module %s.\n", modname); - return -1; } - - +/* cleanup_and_exit() closed channels and frees memory + * then exits with the following status codes: + * 1 - failed to initialize. + * 2 - disconnected + * 3 - initialized + */ void cleanup_and_exit (int closed) { - char tmpbuf[128]; pid_t err; static int exiting = 0; @@ -295,7 +238,7 @@ void cleanup_and_exit (int closed) /* what about child processes? we will wait for them here. */ err = waitpid(-1, NULL, WNOHANG); if (err >= 0) - fprintf(stderr,"\nWaiting for processes to exit\n"); + err("\nWaiting for processes to exit\n"); while(wait(NULL) > 0) ; if (use_old_transport) @@ -306,22 +249,16 @@ void cleanup_and_exit (int closed) dbug(1, "closing control channel\n"); close_ctl_channel(); - if (closed == 0) { - dbug(1, "removing module\n"); - snprintf(tmpbuf, sizeof(tmpbuf), "/sbin/rmmod -w %s", modname); - if (system(tmpbuf)) { - fprintf(stderr, "ERROR: couldn't rmmod probe module %s.\n", modname); - exit(1); - } - } else if (closed == 2) { - fprintf(stderr, "\nDisconnecting from systemtap module.\n"); - fprintf(stderr, "To reconnect, type \"staprun -A %s\"\n", modname); - } - - exit(0); + if (initialized == 2 && closed == 2) { + err("\nDisconnecting from systemtap module.\n" \ + "To reconnect, type \"staprun -A %s\"\n", modname); + } else if (initialized) + closed = 3; + else + closed = 1; + exit(closed); } - /** * stp_main_loop - loop forever reading data */ @@ -342,13 +279,11 @@ int stp_main_loop(void) while (1) { /* handle messages from control channel */ nb = read(control_channel, recvbuf, sizeof(recvbuf)); if (nb <= 0) { - if (errno != EINTR) { - perror("recv"); - fprintf(stderr, "WARNING: unexpected EOF. nb=%ld\n", (long)nb); - } + if (errno != EINTR) + _perr("Unexpected EOF in read (nb=%ld)", (long)nb); continue; } - + type = *(int *)recvbuf; data = (void *)(recvbuf + sizeof(int)); @@ -362,10 +297,8 @@ int stp_main_loop(void) bw = write(out_fd[0], data, nb - sizeof(int)); } if (bw != (nb - (ssize_t)sizeof(int))) { - perror("write"); - fprintf(stderr, - "ERROR: write error. nb=%ld\n", (long)nb); - cleanup_and_exit(0); + _perr("write error (nb=%ld)", (long)nb); + cleanup_and_exit(1); } break; } @@ -388,7 +321,7 @@ int stp_main_loop(void) if (t->res < 0) { if (target_cmd) kill (target_pid, SIGKILL); - cleanup_and_exit(0); + cleanup_and_exit(1); } else if (target_cmd) kill (target_pid, SIGUSR1); break; @@ -405,41 +338,20 @@ int stp_main_loop(void) struct _stp_msg_start ts; if (use_old_transport) { if (init_oldrelayfs() < 0) - cleanup_and_exit(0); + cleanup_and_exit(1); } else { if (init_relayfs() < 0) - cleanup_and_exit(0); + cleanup_and_exit(1); } ts.target = target_pid; + initialized = 2; send_request(STP_START, &ts, sizeof(ts)); if (load_only) cleanup_and_exit(2); break; } - case STP_MODULE: - { - dbug(2, "STP_MODULES request received\n"); - do_module(data); - break; - } - case STP_SYMBOLS: - { - struct _stp_msg_symbol *req = (struct _stp_msg_symbol *)data; - dbug(2, "STP_SYMBOLS request received\n"); - if (req->endian != 0x1234) { - fprintf(stderr,"ERROR: staprun is compiled with different endianess than the kernel!\n"); - cleanup_and_exit(0); - } - if (req->ptr_size != sizeof(char *)) { - fprintf(stderr,"ERROR: staprun is compiled with %d-bit pointers and the kernel uses %d-bit.\n", - 8*(int)sizeof(char *), 8*req->ptr_size); - cleanup_and_exit(0); - } - do_kernel_symbols(); - break; - } default: - fprintf(stderr, "WARNING: ignored message of type %d\n", (type)); + err("WARNING: ignored message of type %d\n", (type)); } } fclose(ofp); |