From: Mathieu Desnoyers Date: Wed, 2 Feb 2011 21:59:17 +0000 (-0500) Subject: Merge branch 'master' of ssh://git.dorsal.polymtl.ca/home/git/ust X-Git-Tag: v0.12~72 X-Git-Url: http://git.lttng.org/?a=commitdiff_plain;h=cacf036243594e11fc8a7e0f47f07af97a79042f;hp=2268755fbbfbb275621b1d88edad172d91afb528;p=ust.git Merge branch 'master' of ssh://git.dorsal.polymtl.ca/home/git/ust --- diff --git a/Makefile.am b/Makefile.am index 249bf02..6957f07 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ ACLOCAL_AMFLAGS = -I config # libust and '.' (that contains the linker script). However, '.' # must be installed after libust so it can overwrite libust.so with # the linker script. -SUBDIRS = snprintf libustcomm libustcmd libust . tests libustinstr-malloc libustconsumer ust-consumerd ustctl libustfork include doc +SUBDIRS = snprintf libustcomm libustctl libust . tests libustinstr-malloc libustconsumer ust-consumerd ustctl libustfork include doc EXTRA_DIST = libust.ldscript.in libust-initializer.c libust-initializer.h dist_bin_SCRIPTS = usttrace diff --git a/README b/README index a381c95..b09a1ab 100644 --- a/README +++ b/README @@ -79,11 +79,11 @@ PACKAGE CONTENTS: calls in order to trace across these calls. It _has_ to be LD_PRELOAD'ed in order to hijack calls. In contrast, libust may be linked at build time. - - libustcmd + - libustctl A library to control tracing in other processes. Used by ustctl. - libustcomm - A static library shared between libust, ust-consumerd and libustcmd, that + A static library shared between libust, ust-consumerd and libustctl, that provides functions that allow these components to communicate together. - libustconsumer diff --git a/configure.ac b/configure.ac index c7d966b..2b2962a 100644 --- a/configure.ac +++ b/configure.ac @@ -130,14 +130,14 @@ AC_CONFIG_FILES([ tests/tracepoint/Makefile tests/tracepoint/benchmark/Makefile tests/register_test/Makefile - tests/ustcmd_function_tests/Makefile + tests/libustctl_function_tests/Makefile libustinstr-malloc/Makefile libustfork/Makefile libustconsumer/Makefile ust-consumerd/Makefile ustctl/Makefile libustcomm/Makefile - libustcmd/Makefile + libustctl/Makefile snprintf/Makefile ]) AC_OUTPUT diff --git a/doc/info/ust.texi b/doc/info/ust.texi index efad0f6..83c91e0 100644 --- a/doc/info/ust.texi +++ b/doc/info/ust.texi @@ -91,7 +91,7 @@ Components licensed as LGPL v2.1: Components licensed as GPL v2: @itemize @bullet @item ustctl -@item libustcmd +@item libustctl @item ust-consumerd @end itemize @@ -395,25 +395,25 @@ $ ust-consumerd # it has pid 1234. # List the available markers -$ ustctl --list-markers 1234 +$ ustctl list-markers 1234 # A column indicates 0 for an inactive marker and 1 for an active marker. # Enable a marker -$ ustctl --enable-marker ust/mymark 1234 +$ ustctl enable-marker 1234 auto ust/mymark # Create a trace -$ ustctl --create-trace 1234 +$ ustctl create-trace 1234 auto # Start tracing -$ ustctl --start-trace 1234 +$ ustctl start-trace 1234 auto # Do things... # Stop tracing -$ ustctl --stop-trace 1234 +$ ustctl stop-trace 1234 auto # Destroy the trace -$ ustctl --destroy-trace 1234 +$ ustctl destroy-trace 1234 auto @end verbatim @end example diff --git a/doc/man/ustctl.1 b/doc/man/ustctl.1 index b0f97d9..2250b31 100644 --- a/doc/man/ustctl.1 +++ b/doc/man/ustctl.1 @@ -1,150 +1,119 @@ -.\" generated with Ronn/v0.5 -.\" http://github.com/rtomayko/ronn/ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "USTCTL" "1" "August 2010" "" "" +.TH "USTCTL" "1" "January 2011" "" "" . .SH "NAME" -\fBustctl\fR \-\- a program to control the tracing of userspace applications +\fBustctl\fR \- a program to control the tracing of userspace applications . .SH "SYNOPSIS" -\fBustctl\fR [\fIcommand\fR] [\fIPIDs\fR]... +\fBustctl\fR [\fICOMMAND\fR] [\fIARGS\fR]\.\.\. . .SH "DESCRIPTION" -\fBustctl\fR is a program to control the tracing of userspace applications. It can -list markers, start the tracing, stop the tracing, enable/disable markers, etc. +\fBustctl\fR is a program to control the tracing of userspace applications\. It can list markers, start the tracing, stop the tracing, enable/disable markers, etc\. . .SH "OPTIONS" -These programs follow the usual GNU command line syntax, with long options -starting with two dashes(`\-'). A summary of options is included below. +These programs follow the usual GNU command line syntax, with long options starting with two dashes(`\-\')\. A summary of options is included below\. . .TP \fB\-h\fR, \fB\-\-help\fR -Show summary of options. +Show summary of commands\. +. +.SH "COMMANDS" +\fBustctl\fR accepts commands followed by arguments for each respective command\. Most commands require the pid of the application being traced\. . .TP -\fB\-\-create\-trace\fR -Create trace. +\fBcreate\-trace\fR \fIPID\fR \fITRACE\fR +Create trace\. . .TP -\fB\-\-alloc\-trace\fR -Allocate trace. +\fBalloc\-trace\fR \fIPID\fR \fITRACE\fR +Allocate trace\. . .TP -\fB\-\-start\-trace\fR -Start tracing. +\fBstart\-trace\fR \fIPID\fR \fITRACE\fR +Start tracing\. . .TP -\fB\-\-stop\-trace\fR -Stop tracing. +\fBstop\-trace\fR \fIPID\fR \fITRACE\fR +Stop tracing\. . .TP -\fB\-\-destroy\-trace\fR -Destroy the trace. +\fBdestroy\-trace\fR \fIPID\fR \fITRACE\fR +Destroy the trace\. . .TP -\fB\-\-set\-subbuf\-size\fR \fICHANNEL\fR/\fIbytes\fR -Set the size of subbuffers in CHANNEL. +\fBset\-subbuf\-size\fR \fIPID\fR \fITRACE\fR \fICHANNEL\fR/\fIbytes\fR +Set the size of subbuffers in CHANNEL\. . .TP -\fB\-\-set\-subbuf\-num\fR \fICHANNEL\fR -Set the number of subbuffers per buffer for CHANNEL. Must be a power of 2. +\fBset\-subbuf\-num\fR \fIPID\fR \fITRACE\fR \fICHANNEL\fR/\fInr\fR +Set the number of subbuffers per buffer for CHANNEL\. Must be a power of 2\. . .TP -\fB\-\-set\-sock\-path\fR -Set the path of the daemon socket. +\fBset\-sock\-path\fR \fIPID\fR \fISOCKPATH\fR +Set the path of the daemon socket\. . .TP -\fB\-\-get\-subbuf\-size\fR \fICHANNEL\fR -Print the size of subbuffers per buffer for CHANNEL. +\fBget\-subbuf\-size\fR \fIPID\fR \fITRACE\fR \fICHANNEL\fR +Print the size of subbuffers per buffer for CHANNEL\. . .TP -\fB\-\-get\-subbuf\-num\fR \fICHANNEL\fR -Print the number of subbuffers per buffer for CHANNEL. +\fBget\-subbuf\-num\fR \fIPID\fR \fITRACE\fR \fICHANNEL\fR +Print the number of subbuffers per buffer for CHANNEL\. . .TP -\fB\-\-get\-sock\-path\fR -Get the path of the daemon socket. +\fBget\-sock\-path\fR \fIPID\fR +Get the path of the daemon socket\. . .TP -\fB\-\-enable\-marker\fR \fICHANNEL\fR/\fIMARKER\fR -Enable a marker. +\fBenable\-marker\fR \fIPID\fR \fITRACE\fR \fICHANNEL\fR/\fIMARKER\fR +Enable a marker\. . .TP -\fB\-\-disable\-marker\fR \fICHANNEL\fR/\fIMARKER\fR -Disable a marker. +\fBdisable\-marker\fR \fIPID\fR \fITRACE\fR \fICHANNEL\fR/\fIMARKER\fR +Disable a marker\. . .TP -\fB\-\-list\-markers\fR -List the markers of the process, their state and format string. +\fBlist\-markers\fR \fIPID\fR +List the markers of the process, their state and format string\. . .TP -\fB\-\-force\-switch\fR -Force a subbuffer switch. This will flush all the data currently held. +\fBforce\-subbuf\-switch\fR \fIPID\fR \fITRACE\fR +Force a subbuffer switch\. This will flush all the data currently held\. . .SH "LIFE CYCLE OF A TRACE" -Typically, the first step is to enable markers with \fB\-\-enable\-marker\fR. An -enabled marker generates an event when the control flow passes over it -(assuming the trace is recording). A disabled marker produces nothing. Enabling -and disabling markers may however be done at any point, including while the -trace is being recorded. +Typically, the first step is to enable markers with \fBenable\-marker\fR\. An enabled marker generates an event when the control flow passes over it (assuming the trace is recording)\. A disabled marker produces nothing\. Enabling and disabling markers may however be done at any point, including while the trace is being recorded\. . .P -In order to record events, a trace is first created with \fB\-\-create\-trace\fR. At -this point, the subbuffer count and size may be changed with \fB\-\-set\-subbuf\-num\fR -and \fB\-\-set\-subbuf\-size\fR. +In order to record events, a trace is first created with \fBcreate\-trace\fR\. At this point, the subbuffer count and size may be changed with \fBset\-subbuf\-num\fR and \fBset\-subbuf\-size\fR\. . .P -Afterward, the trace may be allocated with \fB\-\-alloc\-trace\fR. This allocates the -buffers in memory, so once this is done, the subbuffer size and count can not -be changed. Trace allocation also causes the daemon to connect to the trace -buffers and wait for data to arrive. Explicit allocation is optional, as it is -done automatically at trace start. +Afterward, the trace may be allocated with \fBalloc\-trace\fR\. This allocates the buffers in memory, so once this is done, the subbuffer size and count can not be changed\. Trace allocation also causes the daemon to connect to the trace buffers and wait for data to arrive\. Explicit allocation is optional, as it is done automatically at trace start\. . .P -The trace may then be started with \fB\-\-start\-trace\fR. This results in events -being recorded in the buffer. The daemon automatically collects these events. +The trace may then be started with \fBstart\-trace\fR\. This results in events being recorded in the buffer\. The daemon automatically collects these events\. . .P -The trace may be stopped with \fB\-\-stop\-trace\fR, either definitely after all the -wanted information is collected, or temporarily, before being started again -with \fB\-\-start\-trace\fR. This results in effectively 'pausing' the recording. -After using \fB\-\-stop\-trace\fR, if a daemon is collecting the trace, it may not -have flushed to the disk the full contents of the buffer yet. +The trace may be stopped with \fBstop\-trace\fR, either definitely after all the wanted information is collected, or temporarily, before being started again with \fBstart\-trace\fR\. This results in effectively \'pausing\' the recording\. After using \fBstop\-trace\fR, if a daemon is collecting the trace, it may not have flushed to the disk the full contents of the buffer yet\. . .P -Finally, when \fB\-\-destroy\-trace\fR is used, the trace buffers are unallocated. -However, the memory may not be effectively freed until the daemon finishes to -collect them. When the trace is being collected by \fBust-consumerd\fR, this command -guarantees its full contents is flushed to the disk. +Finally, when \fBdestroy\-trace\fR is used, the trace buffers are unallocated\. However, the memory may not be effectively freed until the daemon finishes to collect them\. When the trace is being collected by \fBust\-consumerd\fR, this command guarantees its full contents is flushed to the disk\. . .SH "STRUCTURE OF A TRACE" -Each instrumentation point that is added in a program is associated to a -channel. +Each instrumentation point that is added in a program is associated to a channel\. . .P -Trace events are put in buffers. There is one buffer per channel, per cpu. -For example, on a system with 4 cores and tracing an application with 3 -channels, there will be 12 buffers in total. The content of each of these -buffers is put in a distinct file in the trace directory. For example, the \fBmetadata_2\fR file contains the data that was extracted from the buffer that -contained the events from the metadata channel and having occurred on cpu 2. +Trace events are put in buffers\. There is one buffer per channel, per cpu\. For example, on a system with 4 cores and tracing an application with 3 channels, there will be 12 buffers in total\. The content of each of these buffers is put in a distinct file in the trace directory\. For example, the \fBmetadata_2\fR file contains the data that was extracted from the buffer that contained the events from the metadata channel and having occurred on cpu 2\. . .P -In memory, each buffer is divided in subbuffers. Subbuffers are equally\-sized, -contiguous parts of a buffer. The size of a buffer is equal to the number of -subbuffers it contains times the size of each subbuffer. When a subbuffer is -full, it is collected by the daemon while the others are filled. If, however, -the buffer size is too small, buffer overflows may occur and result in event -loss. By default, the number of subbuffers per buffer is 2. Subbuffer size -for a given channel may be chosen with \fB\-\-set\-subbuf\-size\fR while the subbuffer -count is set with \fB\-\-set\-subbuf\-num\fR. +In memory, each buffer is divided in subbuffers\. Subbuffers are equally\-sized, contiguous parts of a buffer\. The size of a buffer is equal to the number of subbuffers it contains times the size of each subbuffer\. When a subbuffer is full, it is collected by the daemon while the others are filled\. If, however, the buffer size is too small, buffer overflows may occur and result in event loss\. By default, the number of subbuffers per buffer is 2\. Subbuffer size for a given channel may be chosen with \fBset\-subbuf\-size\fR while the subbuffer count is set with \fBset\-subbuf\-num\fR\. . .SH "SEE ALSO" -usttrace(1), ust-consumerd(1) +usttrace(1), ust\-consumerd(1) . .SH "AUTHOR" -\fBustctl\fR was written by Pierre\-Marc Fournier. +\fBustctl\fR was written by Pierre\-Marc Fournier\. . .P -This manual page was written by Jon Bernard , for -the Debian project (and may be used by others). It was updated by Pierre\-Marc -Fournier. +This manual page was written by Jon Bernard , for the Debian project (and may be used by others)\. It was updated by Pierre\-Marc Fournier\. diff --git a/doc/man/ustctl.1.md b/doc/man/ustctl.1.md index c8ad1f1..89a952a 100644 --- a/doc/man/ustctl.1.md +++ b/doc/man/ustctl.1.md @@ -3,7 +3,7 @@ ustctl(1) -- a program to control the tracing of userspace applications ## SYNOPSIS -`ustctl` [] []... +`ustctl` [] []... ## DESCRIPTION @@ -16,81 +16,86 @@ These programs follow the usual GNU command line syntax, with long options starting with two dashes(`-'). A summary of options is included below. * `-h`, `--help`: - Show summary of options. + Show summary of commands. - * `--create-trace`: +## COMMANDS + +`ustctl` accepts commands followed by arguments for each respective command. +Most commands require the pid of the application being traced. + + * `create-trace` : Create trace. - * `--alloc-trace`: + * `alloc-trace` : Allocate trace. - * `--start-trace`: + * `start-trace` : Start tracing. - * `--stop-trace`: + * `stop-trace` : Stop tracing. - * `--destroy-trace`: + * `destroy-trace` : Destroy the trace. - * `--set-subbuf-size` /: + * `set-subbuf-size` /: Set the size of subbuffers in CHANNEL. - * `--set-subbuf-num` : + * `set-subbuf-num` /: Set the number of subbuffers per buffer for CHANNEL. Must be a power of 2. - * `--set-sock-path`: + * `set-sock-path` : Set the path of the daemon socket. - * `--get-subbuf-size` : + * `get-subbuf-size` : Print the size of subbuffers per buffer for CHANNEL. - * `--get-subbuf-num` : + * `get-subbuf-num` : Print the number of subbuffers per buffer for CHANNEL. - * `--get-sock-path`: + * `get-sock-path` : Get the path of the daemon socket. - * `--enable-marker` /: + * `enable-marker` /: Enable a marker. - * `--disable-marker` /: + * `disable-marker` /: Disable a marker. - * `--list-markers`: + * `list-markers` : List the markers of the process, their state and format string. - * `--force-switch`: + * `force-subbuf-switch` : Force a subbuffer switch. This will flush all the data currently held. ## LIFE CYCLE OF A TRACE -Typically, the first step is to enable markers with `--enable-marker`. An +Typically, the first step is to enable markers with `enable-marker`. An enabled marker generates an event when the control flow passes over it (assuming the trace is recording). A disabled marker produces nothing. Enabling and disabling markers may however be done at any point, including while the trace is being recorded. -In order to record events, a trace is first created with `--create-trace`. At -this point, the subbuffer count and size may be changed with `--set-subbuf-num` -and `--set-subbuf-size`. +In order to record events, a trace is first created with `create-trace`. At +this point, the subbuffer count and size may be changed with `set-subbuf-num` +and `set-subbuf-size`. -Afterward, the trace may be allocated with `--alloc-trace`. This allocates the +Afterward, the trace may be allocated with `alloc-trace`. This allocates the buffers in memory, so once this is done, the subbuffer size and count can not be changed. Trace allocation also causes the daemon to connect to the trace buffers and wait for data to arrive. Explicit allocation is optional, as it is done automatically at trace start. -The trace may then be started with `--start-trace`. This results in events +The trace may then be started with `start-trace`. This results in events being recorded in the buffer. The daemon automatically collects these events. -The trace may be stopped with `--stop-trace`, either definitely after all the +The trace may be stopped with `stop-trace`, either definitely after all the wanted information is collected, or temporarily, before being started again -with `--start-trace`. This results in effectively 'pausing' the recording. -After using `--stop-trace`, if a daemon is collecting the trace, it may not +with `start-trace`. This results in effectively 'pausing' the recording. +After using `stop-trace`, if a daemon is collecting the trace, it may not have flushed to the disk the full contents of the buffer yet. -Finally, when `--destroy-trace` is used, the trace buffers are unallocated. +Finally, when `destroy-trace` is used, the trace buffers are unallocated. However, the memory may not be effectively freed until the daemon finishes to collect them. When the trace is being collected by `ust-consumerd`, this command guarantees its full contents is flushed to the disk. @@ -113,8 +118,8 @@ subbuffers it contains times the size of each subbuffer. When a subbuffer is full, it is collected by the daemon while the others are filled. If, however, the buffer size is too small, buffer overflows may occur and result in event loss. By default, the number of subbuffers per buffer is 2. Subbuffer size -for a given channel may be chosen with `--set-subbuf-size` while the subbuffer -count is set with `--set-subbuf-num`. +for a given channel may be chosen with `set-subbuf-size` while the subbuffer +count is set with `set-subbuf-num`. ## SEE ALSO diff --git a/include/Makefile.am b/include/Makefile.am index 400e8b1..e703ffd 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -17,7 +17,7 @@ nobase_include_HEADERS = \ ust/kcompat/simple.h \ ust/kcompat/types.h \ ust/kcompat/stringify.h \ - ust/ustcmd.h \ + ust/ustctl.h \ ust/ustconsumer.h noinst_HEADERS = share.h usterr.h ust_snprintf.h diff --git a/include/ust/ustcmd.h b/include/ust/ustcmd.h deleted file mode 100644 index 6273575..0000000 --- a/include/ust/ustcmd.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (C) 2009 Pierre-Marc Fournier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _USTCMD_H -#define _USTCMD_H - -#include -#include -#include -#include -#include - -#define USTCMD_ERR_CONN 1 /* Process connection error */ -#define USTCMD_ERR_ARG 2 /* Invalid function argument */ -#define USTCMD_ERR_GEN 3 /* General ustcmd error */ - -#define USTCMD_MS_CHR_OFF '0' /* Marker state 'on' character */ -#define USTCMD_MS_CHR_ON '1' /* Marker state 'on' character */ -#define USTCMD_MS_OFF 0 /* Marker state 'on' value */ -#define USTCMD_MS_ON 1 /* Marker state 'on' value */ - -#define USTCMD_SOCK_PATH "/tmp/socks/" - -/* Channel/marker/state/format string (cmsf) info. structure */ -struct marker_status { - char *channel; /* Channel name (end of marker_status array if NULL) */ - char *marker; /* Marker name (end of marker_status array if NULL) */ - int state; /* State (0 := marker disabled, 1 := marker enabled) */ - char *fs; /* Format string (end of marker_status array if NULL) */ -}; - -struct trace_event_status { - char *name; -}; - -extern pid_t *ustcmd_get_online_pids(void); -extern int ustcmd_set_marker_state(const char *trace, const char *channel, - const char *marker, int state, pid_t pid); -extern int ustcmd_set_subbuf_size(const char *trace, const char *channel, - unsigned int subbuf_size, pid_t pid); -extern int ustcmd_set_subbuf_num(const char *trace, const char *channel, - unsigned int num, pid_t pid); -extern int ustcmd_get_subbuf_size(const char *trace, const char *channel, - pid_t pid); -extern int ustcmd_get_subbuf_num(const char *trace, const char *channel, - pid_t pid); -extern int ustcmd_destroy_trace(const char *trace, pid_t pid); -extern int ustcmd_setup_and_start(const char *trace, pid_t pid); -extern int ustcmd_stop_trace(const char *trace, pid_t pid); -extern int ustcmd_create_trace(const char *trace, pid_t pid); -extern int ustcmd_start_trace(const char *trace, pid_t pid); -extern int ustcmd_alloc_trace(const char *trace, pid_t pid); -extern int ustcmd_free_cmsf(struct marker_status *); -extern unsigned int ustcmd_count_nl(const char *); -extern int ustcmd_get_cmsf(struct marker_status **, pid_t); -extern int ustcmd_free_tes(struct trace_event_status *); -extern int ustcmd_get_tes(struct trace_event_status **, pid_t); -extern int ustcmd_set_sock_path(const char *sock_path, pid_t pid); -extern int ustcmd_get_sock_path(char **sock_path, pid_t pid); -extern int ustcmd_force_switch(pid_t pid); - -#endif /* _USTCMD_H */ diff --git a/include/ust/ustctl.h b/include/ust/ustctl.h new file mode 100644 index 0000000..195ee26 --- /dev/null +++ b/include/ust/ustctl.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2009 Pierre-Marc Fournier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _USTCTL_H +#define _USTCTL_H + +#include +#include +#include +#include +#include + +#define USTCTL_ERR_CONN 1 /* Process connection error */ +#define USTCTL_ERR_ARG 2 /* Invalid function argument */ +#define USTCTL_ERR_GEN 3 /* General ustctl error */ + +#define USTCTL_MS_CHR_OFF '0' /* Marker state 'on' character */ +#define USTCTL_MS_CHR_ON '1' /* Marker state 'on' character */ +#define USTCTL_MS_OFF 0 /* Marker state 'on' value */ +#define USTCTL_MS_ON 1 /* Marker state 'on' value */ + +#define USTCTL_SOCK_PATH "/tmp/socks/" + +/* Channel/marker/state/format string (cmsf) info. structure */ +struct marker_status { + char *channel; /* Channel name (end of marker_status array if NULL) */ + char *marker; /* Marker name (end of marker_status array if NULL) */ + int state; /* State (0 := marker disabled, 1 := marker enabled) */ + char *fs; /* Format string (end of marker_status array if NULL) */ +}; + +struct trace_event_status { + char *name; +}; + +extern pid_t *ustctl_get_online_pids(void); +extern int ustctl_set_marker_state(const char *trace, const char *channel, + const char *marker, int state, pid_t pid); +extern int ustctl_set_subbuf_size(const char *trace, const char *channel, + unsigned int subbuf_size, pid_t pid); +extern int ustctl_set_subbuf_num(const char *trace, const char *channel, + unsigned int num, pid_t pid); +extern int ustctl_get_subbuf_size(const char *trace, const char *channel, + pid_t pid); +extern int ustctl_get_subbuf_num(const char *trace, const char *channel, + pid_t pid); +extern int ustctl_destroy_trace(const char *trace, pid_t pid); +extern int ustctl_setup_and_start(const char *trace, pid_t pid); +extern int ustctl_stop_trace(const char *trace, pid_t pid); +extern int ustctl_create_trace(const char *trace, pid_t pid); +extern int ustctl_start_trace(const char *trace, pid_t pid); +extern int ustctl_alloc_trace(const char *trace, pid_t pid); +extern int ustctl_free_cmsf(struct marker_status *); +extern unsigned int ustctl_count_nl(const char *); +extern int ustctl_get_cmsf(struct marker_status **, pid_t); +extern int ustctl_free_tes(struct trace_event_status *); +extern int ustctl_get_tes(struct trace_event_status **, pid_t); +extern int ustctl_set_sock_path(const char *sock_path, pid_t pid); +extern int ustctl_get_sock_path(char **sock_path, pid_t pid); +extern int ustctl_force_switch(pid_t pid); + +#endif /* _USTCTL_H */ diff --git a/libustcmd/Makefile.am b/libustcmd/Makefile.am deleted file mode 100644 index f467244..0000000 --- a/libustcmd/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm -AM_CFLAGS = -fno-strict-aliasing - -lib_LTLIBRARIES = libustcmd.la - -libustcmd_la_SOURCES = \ - ustcmd.c - -libustcmd_la_LDFLAGS = -no-undefined -version-info 0:0:0 - -libustcmd_la_LIBADD = \ - $(top_builddir)/libustcomm/libustcomm.la - -libustcmd_la_CFLAGS = -DUST_COMPONENT="libustcmd" -fno-strict-aliasing diff --git a/libustcmd/README b/libustcmd/README deleted file mode 100644 index 8c2819a..0000000 --- a/libustcmd/README +++ /dev/null @@ -1,2 +0,0 @@ -libustcmd is a library that provides an API and its implementation to send -commands to traceable processes. diff --git a/libustcmd/ustcmd.c b/libustcmd/ustcmd.c deleted file mode 100644 index 62c117f..0000000 --- a/libustcmd/ustcmd.c +++ /dev/null @@ -1,671 +0,0 @@ -/* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -#include "ustcomm.h" -#include "ust/ustcmd.h" -#include "usterr.h" - -static int do_cmd(const pid_t pid, - const struct ustcomm_header *req_header, - const char *req_data, - struct ustcomm_header *res_header, - char **res_data) -{ - int app_fd, result, saved_errno = 0; - char *recv_buf; - - if (ustcomm_connect_app(pid, &app_fd)) { - ERR("could not connect to PID %u", (unsigned int) pid); - errno = ENOTCONN; - return -1; - } - - recv_buf = zmalloc(USTCOMM_BUFFER_SIZE); - if (!recv_buf) { - saved_errno = ENOMEM; - goto close_app_fd; - } - - result = ustcomm_req(app_fd, req_header, req_data, res_header, recv_buf); - if (result > 0) { - saved_errno = -res_header->result; - if (res_header->size == 0 || saved_errno > 0) { - free(recv_buf); - } else { - if (res_data) { - *res_data = recv_buf; - } else { - free(recv_buf); - } - } - } else { - ERR("ustcomm req failed"); - if (result == 0) { - saved_errno = ENOTCONN; - } else { - saved_errno = -result; - } - free(recv_buf); - } - -close_app_fd: - close(app_fd); - - errno = saved_errno; - - if (errno) { - return -1; - } - - return 0; -} - -pid_t *ustcmd_get_online_pids(void) -{ - struct dirent *dirent; - DIR *dir; - unsigned int ret_size = 1 * sizeof(pid_t), i = 0; - - dir = opendir(SOCK_DIR); - if (!dir) { - return NULL; - } - - pid_t *ret = (pid_t *) malloc(ret_size); - - while ((dirent = readdir(dir))) { - if (!strcmp(dirent->d_name, ".") || - !strcmp(dirent->d_name, "..")) { - - continue; - } - - if (dirent->d_type != DT_DIR && - !!strcmp(dirent->d_name, "ust-consumer")) { - - sscanf(dirent->d_name, "%u", (unsigned int *) &ret[i]); - /* FIXME: Here we previously called pid_is_online, which - * always returned 1, now I replaced it with just 1. - * We need to figure out an intelligent way of solving - * this, maybe connect-disconnect. - */ - if (1) { - ret_size += sizeof(pid_t); - ret = (pid_t *) realloc(ret, ret_size); - ++i; - } - } - } - - ret[i] = 0; /* Array end */ - - if (ret[0] == 0) { - /* No PID at all */ - free(ret); - return NULL; - } - - closedir(dir); - return ret; -} - -/** - * Sets marker state (USTCMD_MS_ON or USTCMD_MS_OFF). - * - * @param mn Marker name - * @param state Marker's new state - * @param pid Traced process ID - * @return 0 if successful, or errors {USTCMD_ERR_GEN, USTCMD_ERR_ARG} - */ -int ustcmd_set_marker_state(const char *trace, const char *channel, - const char *marker, int state, pid_t pid) -{ - struct ustcomm_header req_header, res_header; - struct ustcomm_marker_info marker_inf; - int result; - - result = ustcomm_pack_marker_info(&req_header, - &marker_inf, - trace, - channel, - marker); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER; - - return do_cmd(pid, &req_header, (char *)&marker_inf, - &res_header, NULL); -} - -/** - * Set subbuffer size. - * - * @param channel_size Channel name and size - * @param pid Traced process ID - * @return 0 if successful, or error - */ -int ustcmd_set_subbuf_size(const char *trace, const char *channel, - unsigned int subbuf_size, pid_t pid) -{ - struct ustcomm_header req_header, res_header; - struct ustcomm_channel_info ch_inf; - int result; - - result = ustcomm_pack_channel_info(&req_header, - &ch_inf, - trace, - channel); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = SET_SUBBUF_SIZE; - ch_inf.subbuf_size = subbuf_size; - - return do_cmd(pid, &req_header, (char *)&ch_inf, - &res_header, NULL); -} - -/** - * Set subbuffer num. - * - * @param channel_num Channel name and num - * @param pid Traced process ID - * @return 0 if successful, or error - */ -int ustcmd_set_subbuf_num(const char *trace, const char *channel, - unsigned int num, pid_t pid) -{ - struct ustcomm_header req_header, res_header; - struct ustcomm_channel_info ch_inf; - int result; - - result = ustcomm_pack_channel_info(&req_header, - &ch_inf, - trace, - channel); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = SET_SUBBUF_NUM; - ch_inf.subbuf_num = num; - - return do_cmd(pid, &req_header, (char *)&ch_inf, - &res_header, NULL); - -} - -static int ustcmd_get_subbuf_num_size(const char *trace, const char *channel, - pid_t pid, int *num, int *size) -{ - struct ustcomm_header req_header, res_header; - struct ustcomm_channel_info ch_inf, *ch_inf_res; - int result; - - - result = ustcomm_pack_channel_info(&req_header, - &ch_inf, - trace, - channel); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = GET_SUBBUF_NUM_SIZE; - - result = do_cmd(pid, &req_header, (char *)&ch_inf, - &res_header, (char **)&ch_inf_res); - if (result < 0) { - return -1; - } - - *num = ch_inf_res->subbuf_num; - *size = ch_inf_res->subbuf_size; - - free(ch_inf_res); - - return 0; -} - -/** - * Get subbuffer num. - * - * @param channel Channel name - * @param pid Traced process ID - * @return subbuf cnf if successful, or error - */ -int ustcmd_get_subbuf_num(const char *trace, const char *channel, pid_t pid) -{ - int num, size, result; - - result = ustcmd_get_subbuf_num_size(trace, channel, pid, - &num, &size); - if (result < 0) { - errno = -result; - return -1; - } - - return num; -} - -/** - * Get subbuffer size. - * - * @param channel Channel name - * @param pid Traced process ID - * @return subbuf size if successful, or error - */ -int ustcmd_get_subbuf_size(const char *trace, const char *channel, pid_t pid) -{ - int num, size, result; - - result = ustcmd_get_subbuf_num_size(trace, channel, pid, - &num, &size); - if (result < 0) { - errno = -result; - return -1; - } - - return size; -} - - -static int do_trace_cmd(const char *trace, pid_t pid, int command) -{ - struct ustcomm_header req_header, res_header; - struct ustcomm_single_field trace_inf; - int result; - - result = ustcomm_pack_single_field(&req_header, - &trace_inf, - trace); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = command; - - return do_cmd(pid, &req_header, (char *)&trace_inf, &res_header, NULL); -} - -/** - * Destroys an UST trace according to a PID. - * - * @param pid Traced process ID - * @return 0 if successful, or error USTCMD_ERR_GEN - */ -int ustcmd_destroy_trace(const char *trace, pid_t pid) -{ - return do_trace_cmd(trace, pid, DESTROY_TRACE); -} - -/** - * Starts an UST trace (and setups it) according to a PID. - * - * @param pid Traced process ID - * @return 0 if successful, or error USTCMD_ERR_GEN - */ -int ustcmd_setup_and_start(const char *trace, pid_t pid) -{ - return do_trace_cmd(trace, pid, START); -} - -/** - * Creates an UST trace according to a PID. - * - * @param pid Traced process ID - * @return 0 if successful, or error USTCMD_ERR_GEN - */ -int ustcmd_create_trace(const char *trace, pid_t pid) -{ - return do_trace_cmd(trace, pid, CREATE_TRACE); -} - -/** - * Starts an UST trace according to a PID. - * - * @param pid Traced process ID - * @return 0 if successful, or error USTCMD_ERR_GEN - */ -int ustcmd_start_trace(const char *trace, pid_t pid) -{ - return do_trace_cmd(trace, pid, START_TRACE); -} - -/** - * Alloc an UST trace according to a PID. - * - * @param pid Traced process ID - * @return 0 if successful, or error USTCMD_ERR_GEN - */ -int ustcmd_alloc_trace(const char *trace, pid_t pid) -{ - return do_trace_cmd(trace, pid, ALLOC_TRACE); -} - -/** - * Stops an UST trace according to a PID. - * - * @param pid Traced process ID - * @return 0 if successful, or error USTCMD_ERR_GEN - */ -int ustcmd_stop_trace(const char *trace, pid_t pid) -{ - return do_trace_cmd(trace, pid, STOP_TRACE); -} - -/** - * Counts newlines ('\n') in a string. - * - * @param str String to search in - * @return Total newlines count - */ -unsigned int ustcmd_count_nl(const char *str) -{ - unsigned int i = 0, tot = 0; - - while (str[i] != '\0') { - if (str[i] == '\n') { - ++tot; - } - ++i; - } - - return tot; -} - -/** - * Frees a CMSF array. - * - * @param cmsf CMSF array to free - * @return 0 if successful, or error USTCMD_ERR_ARG - */ -int ustcmd_free_cmsf(struct marker_status *cmsf) -{ - if (cmsf == NULL) { - return USTCMD_ERR_ARG; - } - - unsigned int i = 0; - while (cmsf[i].channel != NULL) { - free(cmsf[i].channel); - free(cmsf[i].marker); - free(cmsf[i].fs); - ++i; - } - free(cmsf); - - return 0; -} - -/** - * Gets channel/marker/state/format string for a given PID. - * - * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller - * frees with `ustcmd_free_cmsf') - * @param pid Targeted PID - * @return 0 if successful, or -1 on error - */ -int ustcmd_get_cmsf(struct marker_status **cmsf, const pid_t pid) -{ - struct ustcomm_header req_header, res_header; - char *big_str = NULL; - int result, app_fd; - struct marker_status *tmp_cmsf = NULL; - unsigned int i = 0, cmsf_ind = 0; - - if (cmsf == NULL) { - return -1; - } - - if (ustcomm_connect_app(pid, &app_fd)) { - ERR("could not connect to PID %u", (unsigned int) pid); - return -1; - } - - req_header.command = LIST_MARKERS; - req_header.size = 0; - - result = ustcomm_send(app_fd, &req_header, NULL); - if (result <= 0) { - PERROR("error while requesting markers list for process %d", pid); - return -1; - } - - result = ustcomm_recv_alloc(app_fd, &res_header, &big_str); - if (result <= 0) { - ERR("error while receiving markers list"); - return -1; - } - - close(app_fd); - - tmp_cmsf = (struct marker_status *) zmalloc(sizeof(struct marker_status) * - (ustcmd_count_nl(big_str) + 1)); - if (tmp_cmsf == NULL) { - ERR("Failed to allocate CMSF array"); - return -1; - } - - /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */ - while (big_str[i] != '\0') { - char state; - - sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]", - &tmp_cmsf[cmsf_ind].channel, - &tmp_cmsf[cmsf_ind].marker, - &state, - &tmp_cmsf[cmsf_ind].fs); - tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ? - USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */ - - while (big_str[i] != '\n') { - ++i; /* Go to next '\n' */ - } - ++i; /* Skip current pointed '\n' */ - ++cmsf_ind; - } - tmp_cmsf[cmsf_ind].channel = NULL; - tmp_cmsf[cmsf_ind].marker = NULL; - tmp_cmsf[cmsf_ind].fs = NULL; - - *cmsf = tmp_cmsf; - - free(big_str); - return 0; -} - - -/** - * Frees a TES array. - * - * @param tes TES array to free - * @return 0 if successful, or error USTCMD_ERR_ARG - */ -int ustcmd_free_tes(struct trace_event_status *tes) -{ - if (tes == NULL) { - return USTCMD_ERR_ARG; - } - - unsigned int i = 0; - while (tes[i].name != NULL) { - free(tes[i].name); - ++i; - } - free(tes); - - return 0; -} - -/** - * Gets trace_events string for a given PID. - * - * @param tes Pointer to TES array to be filled (callee allocates, caller - * frees with `ustcmd_free_tes') - * @param pid Targeted PID - * @return 0 if successful, or -1 on error - */ -int ustcmd_get_tes(struct trace_event_status **tes, - const pid_t pid) -{ - struct ustcomm_header req_header, res_header; - char *big_str = NULL; - int result, app_fd; - struct trace_event_status *tmp_tes = NULL; - unsigned int i = 0, tes_ind = 0; - - if (tes == NULL) { - return -1; - } - - if (ustcomm_connect_app(pid, &app_fd)) { - ERR("could not connect to PID %u", (unsigned int) pid); - return -1; - } - - req_header.command = LIST_TRACE_EVENTS; - req_header.size = 0; - - result = ustcomm_send(app_fd, &req_header, NULL); - if (result != 1) { - ERR("error while requesting trace_event list"); - return -1; - } - - result = ustcomm_recv_alloc(app_fd, &res_header, &big_str); - if (result != 1) { - ERR("error while receiving markers list"); - return -1; - } - - close(app_fd); - - tmp_tes = (struct trace_event_status *) - zmalloc(sizeof(struct trace_event_status) * - (ustcmd_count_nl(big_str) + 1)); - if (tmp_tes == NULL) { - ERR("Failed to allocate TES array"); - return -1; - } - - /* Parse received reply string (format: "[name]"): */ - while (big_str[i] != '\0') { - sscanf(big_str + i, "trace_event: %a[^\n]", - &tmp_tes[tes_ind].name); - while (big_str[i] != '\n') { - ++i; /* Go to next '\n' */ - } - ++i; /* Skip current pointed '\n' */ - ++tes_ind; - } - tmp_tes[tes_ind].name = NULL; - - *tes = tmp_tes; - - free(big_str); - return 0; -} - -/** - * Set socket path - * - * @param sock_path Socket path - * @param pid Traced process ID - * @return 0 if successful, or error - */ -int ustcmd_set_sock_path(const char *sock_path, pid_t pid) -{ - int result; - struct ustcomm_header req_header, res_header; - struct ustcomm_single_field sock_path_msg; - - result = ustcomm_pack_single_field(&req_header, - &sock_path_msg, - sock_path); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = SET_SOCK_PATH; - - return do_cmd(pid, &req_header, (char *)&sock_path_msg, - &res_header, NULL); -} - -/** - * Get socket path - * - * @param sock_path Pointer to where the socket path will be returned - * @param pid Traced process ID - * @return 0 if successful, or error - */ -int ustcmd_get_sock_path(char **sock_path, pid_t pid) -{ - int result; - struct ustcomm_header req_header, res_header; - struct ustcomm_single_field *sock_path_msg; - - req_header.command = GET_SOCK_PATH; - req_header.size = 0; - - result = do_cmd(pid, &req_header, NULL, &res_header, - (char **)&sock_path_msg); - if (result < 0) { - return -1; - } - - result = ustcomm_unpack_single_field(sock_path_msg); - if (result < 0) { - return result; - } - - *sock_path = strdup(sock_path_msg->field); - - free(sock_path_msg); - - return 0; -} - -int ustcmd_force_switch(pid_t pid) -{ - struct ustcomm_header req_header, res_header; - - req_header.command = FORCE_SUBBUF_SWITCH; - req_header.size = 0; - - return do_cmd(pid, &req_header, NULL, &res_header, NULL); -} - diff --git a/libustctl/Makefile.am b/libustctl/Makefile.am new file mode 100644 index 0000000..bc7526b --- /dev/null +++ b/libustctl/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm +AM_CFLAGS = -fno-strict-aliasing + +lib_LTLIBRARIES = libustctl.la + +libustctl_la_SOURCES = \ + libustctl.c + +libustctl_la_LDFLAGS = -no-undefined -version-info 0:0:0 + +libustctl_la_LIBADD = \ + $(top_builddir)/libustcomm/libustcomm.la + +libustctl_la_CFLAGS = -DUST_COMPONENT="libustctl" -fno-strict-aliasing diff --git a/libustctl/README b/libustctl/README new file mode 100644 index 0000000..fd4cc97 --- /dev/null +++ b/libustctl/README @@ -0,0 +1,2 @@ +libustctl is a library that provides an API and its implementation to send +commands to traceable processes. diff --git a/libustctl/libustctl.c b/libustctl/libustctl.c new file mode 100644 index 0000000..9c4ced2 --- /dev/null +++ b/libustctl/libustctl.c @@ -0,0 +1,671 @@ +/* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "ustcomm.h" +#include "ust/ustctl.h" +#include "usterr.h" + +static int do_cmd(const pid_t pid, + const struct ustcomm_header *req_header, + const char *req_data, + struct ustcomm_header *res_header, + char **res_data) +{ + int app_fd, result, saved_errno = 0; + char *recv_buf; + + if (ustcomm_connect_app(pid, &app_fd)) { + ERR("could not connect to PID %u", (unsigned int) pid); + errno = ENOTCONN; + return -1; + } + + recv_buf = zmalloc(USTCOMM_BUFFER_SIZE); + if (!recv_buf) { + saved_errno = ENOMEM; + goto close_app_fd; + } + + result = ustcomm_req(app_fd, req_header, req_data, res_header, recv_buf); + if (result > 0) { + saved_errno = -res_header->result; + if (res_header->size == 0 || saved_errno > 0) { + free(recv_buf); + } else { + if (res_data) { + *res_data = recv_buf; + } else { + free(recv_buf); + } + } + } else { + ERR("ustcomm req failed"); + if (result == 0) { + saved_errno = ENOTCONN; + } else { + saved_errno = -result; + } + free(recv_buf); + } + +close_app_fd: + close(app_fd); + + errno = saved_errno; + + if (errno) { + return -1; + } + + return 0; +} + +pid_t *ustctl_get_online_pids(void) +{ + struct dirent *dirent; + DIR *dir; + unsigned int ret_size = 1 * sizeof(pid_t), i = 0; + + dir = opendir(SOCK_DIR); + if (!dir) { + return NULL; + } + + pid_t *ret = (pid_t *) malloc(ret_size); + + while ((dirent = readdir(dir))) { + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..")) { + + continue; + } + + if (dirent->d_type != DT_DIR && + !!strcmp(dirent->d_name, "ust-consumer")) { + + sscanf(dirent->d_name, "%u", (unsigned int *) &ret[i]); + /* FIXME: Here we previously called pid_is_online, which + * always returned 1, now I replaced it with just 1. + * We need to figure out an intelligent way of solving + * this, maybe connect-disconnect. + */ + if (1) { + ret_size += sizeof(pid_t); + ret = (pid_t *) realloc(ret, ret_size); + ++i; + } + } + } + + ret[i] = 0; /* Array end */ + + if (ret[0] == 0) { + /* No PID at all */ + free(ret); + return NULL; + } + + closedir(dir); + return ret; +} + +/** + * Sets marker state (USTCTL_MS_ON or USTCTL_MS_OFF). + * + * @param mn Marker name + * @param state Marker's new state + * @param pid Traced process ID + * @return 0 if successful, or errors {USTCTL_ERR_GEN, USTCTL_ERR_ARG} + */ +int ustctl_set_marker_state(const char *trace, const char *channel, + const char *marker, int state, pid_t pid) +{ + struct ustcomm_header req_header, res_header; + struct ustcomm_marker_info marker_inf; + int result; + + result = ustcomm_pack_marker_info(&req_header, + &marker_inf, + trace, + channel, + marker); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER; + + return do_cmd(pid, &req_header, (char *)&marker_inf, + &res_header, NULL); +} + +/** + * Set subbuffer size. + * + * @param channel_size Channel name and size + * @param pid Traced process ID + * @return 0 if successful, or error + */ +int ustctl_set_subbuf_size(const char *trace, const char *channel, + unsigned int subbuf_size, pid_t pid) +{ + struct ustcomm_header req_header, res_header; + struct ustcomm_channel_info ch_inf; + int result; + + result = ustcomm_pack_channel_info(&req_header, + &ch_inf, + trace, + channel); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = SET_SUBBUF_SIZE; + ch_inf.subbuf_size = subbuf_size; + + return do_cmd(pid, &req_header, (char *)&ch_inf, + &res_header, NULL); +} + +/** + * Set subbuffer num. + * + * @param channel_num Channel name and num + * @param pid Traced process ID + * @return 0 if successful, or error + */ +int ustctl_set_subbuf_num(const char *trace, const char *channel, + unsigned int num, pid_t pid) +{ + struct ustcomm_header req_header, res_header; + struct ustcomm_channel_info ch_inf; + int result; + + result = ustcomm_pack_channel_info(&req_header, + &ch_inf, + trace, + channel); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = SET_SUBBUF_NUM; + ch_inf.subbuf_num = num; + + return do_cmd(pid, &req_header, (char *)&ch_inf, + &res_header, NULL); + +} + +static int ustctl_get_subbuf_num_size(const char *trace, const char *channel, + pid_t pid, int *num, int *size) +{ + struct ustcomm_header req_header, res_header; + struct ustcomm_channel_info ch_inf, *ch_inf_res; + int result; + + + result = ustcomm_pack_channel_info(&req_header, + &ch_inf, + trace, + channel); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = GET_SUBBUF_NUM_SIZE; + + result = do_cmd(pid, &req_header, (char *)&ch_inf, + &res_header, (char **)&ch_inf_res); + if (result < 0) { + return -1; + } + + *num = ch_inf_res->subbuf_num; + *size = ch_inf_res->subbuf_size; + + free(ch_inf_res); + + return 0; +} + +/** + * Get subbuffer num. + * + * @param channel Channel name + * @param pid Traced process ID + * @return subbuf cnf if successful, or error + */ +int ustctl_get_subbuf_num(const char *trace, const char *channel, pid_t pid) +{ + int num, size, result; + + result = ustctl_get_subbuf_num_size(trace, channel, pid, + &num, &size); + if (result < 0) { + errno = -result; + return -1; + } + + return num; +} + +/** + * Get subbuffer size. + * + * @param channel Channel name + * @param pid Traced process ID + * @return subbuf size if successful, or error + */ +int ustctl_get_subbuf_size(const char *trace, const char *channel, pid_t pid) +{ + int num, size, result; + + result = ustctl_get_subbuf_num_size(trace, channel, pid, + &num, &size); + if (result < 0) { + errno = -result; + return -1; + } + + return size; +} + + +static int do_trace_cmd(const char *trace, pid_t pid, int command) +{ + struct ustcomm_header req_header, res_header; + struct ustcomm_single_field trace_inf; + int result; + + result = ustcomm_pack_single_field(&req_header, + &trace_inf, + trace); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = command; + + return do_cmd(pid, &req_header, (char *)&trace_inf, &res_header, NULL); +} + +/** + * Destroys an UST trace according to a PID. + * + * @param pid Traced process ID + * @return 0 if successful, or error USTCTL_ERR_GEN + */ +int ustctl_destroy_trace(const char *trace, pid_t pid) +{ + return do_trace_cmd(trace, pid, DESTROY_TRACE); +} + +/** + * Starts an UST trace (and setups it) according to a PID. + * + * @param pid Traced process ID + * @return 0 if successful, or error USTCTL_ERR_GEN + */ +int ustctl_setup_and_start(const char *trace, pid_t pid) +{ + return do_trace_cmd(trace, pid, START); +} + +/** + * Creates an UST trace according to a PID. + * + * @param pid Traced process ID + * @return 0 if successful, or error USTCTL_ERR_GEN + */ +int ustctl_create_trace(const char *trace, pid_t pid) +{ + return do_trace_cmd(trace, pid, CREATE_TRACE); +} + +/** + * Starts an UST trace according to a PID. + * + * @param pid Traced process ID + * @return 0 if successful, or error USTCTL_ERR_GEN + */ +int ustctl_start_trace(const char *trace, pid_t pid) +{ + return do_trace_cmd(trace, pid, START_TRACE); +} + +/** + * Alloc an UST trace according to a PID. + * + * @param pid Traced process ID + * @return 0 if successful, or error USTCTL_ERR_GEN + */ +int ustctl_alloc_trace(const char *trace, pid_t pid) +{ + return do_trace_cmd(trace, pid, ALLOC_TRACE); +} + +/** + * Stops an UST trace according to a PID. + * + * @param pid Traced process ID + * @return 0 if successful, or error USTCTL_ERR_GEN + */ +int ustctl_stop_trace(const char *trace, pid_t pid) +{ + return do_trace_cmd(trace, pid, STOP_TRACE); +} + +/** + * Counts newlines ('\n') in a string. + * + * @param str String to search in + * @return Total newlines count + */ +unsigned int ustctl_count_nl(const char *str) +{ + unsigned int i = 0, tot = 0; + + while (str[i] != '\0') { + if (str[i] == '\n') { + ++tot; + } + ++i; + } + + return tot; +} + +/** + * Frees a CMSF array. + * + * @param cmsf CMSF array to free + * @return 0 if successful, or error USTCTL_ERR_ARG + */ +int ustctl_free_cmsf(struct marker_status *cmsf) +{ + if (cmsf == NULL) { + return USTCTL_ERR_ARG; + } + + unsigned int i = 0; + while (cmsf[i].channel != NULL) { + free(cmsf[i].channel); + free(cmsf[i].marker); + free(cmsf[i].fs); + ++i; + } + free(cmsf); + + return 0; +} + +/** + * Gets channel/marker/state/format string for a given PID. + * + * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller + * frees with `ustctl_free_cmsf') + * @param pid Targeted PID + * @return 0 if successful, or -1 on error + */ +int ustctl_get_cmsf(struct marker_status **cmsf, const pid_t pid) +{ + struct ustcomm_header req_header, res_header; + char *big_str = NULL; + int result, app_fd; + struct marker_status *tmp_cmsf = NULL; + unsigned int i = 0, cmsf_ind = 0; + + if (cmsf == NULL) { + return -1; + } + + if (ustcomm_connect_app(pid, &app_fd)) { + ERR("could not connect to PID %u", (unsigned int) pid); + return -1; + } + + req_header.command = LIST_MARKERS; + req_header.size = 0; + + result = ustcomm_send(app_fd, &req_header, NULL); + if (result <= 0) { + PERROR("error while requesting markers list for process %d", pid); + return -1; + } + + result = ustcomm_recv_alloc(app_fd, &res_header, &big_str); + if (result <= 0) { + ERR("error while receiving markers list"); + return -1; + } + + close(app_fd); + + tmp_cmsf = (struct marker_status *) zmalloc(sizeof(struct marker_status) * + (ustctl_count_nl(big_str) + 1)); + if (tmp_cmsf == NULL) { + ERR("Failed to allocate CMSF array"); + return -1; + } + + /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */ + while (big_str[i] != '\0') { + char state; + + sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]", + &tmp_cmsf[cmsf_ind].channel, + &tmp_cmsf[cmsf_ind].marker, + &state, + &tmp_cmsf[cmsf_ind].fs); + tmp_cmsf[cmsf_ind].state = (state == USTCTL_MS_CHR_ON ? + USTCTL_MS_ON : USTCTL_MS_OFF); /* Marker state */ + + while (big_str[i] != '\n') { + ++i; /* Go to next '\n' */ + } + ++i; /* Skip current pointed '\n' */ + ++cmsf_ind; + } + tmp_cmsf[cmsf_ind].channel = NULL; + tmp_cmsf[cmsf_ind].marker = NULL; + tmp_cmsf[cmsf_ind].fs = NULL; + + *cmsf = tmp_cmsf; + + free(big_str); + return 0; +} + + +/** + * Frees a TES array. + * + * @param tes TES array to free + * @return 0 if successful, or error USTCTL_ERR_ARG + */ +int ustctl_free_tes(struct trace_event_status *tes) +{ + if (tes == NULL) { + return USTCTL_ERR_ARG; + } + + unsigned int i = 0; + while (tes[i].name != NULL) { + free(tes[i].name); + ++i; + } + free(tes); + + return 0; +} + +/** + * Gets trace_events string for a given PID. + * + * @param tes Pointer to TES array to be filled (callee allocates, caller + * frees with `ustctl_free_tes') + * @param pid Targeted PID + * @return 0 if successful, or -1 on error + */ +int ustctl_get_tes(struct trace_event_status **tes, + const pid_t pid) +{ + struct ustcomm_header req_header, res_header; + char *big_str = NULL; + int result, app_fd; + struct trace_event_status *tmp_tes = NULL; + unsigned int i = 0, tes_ind = 0; + + if (tes == NULL) { + return -1; + } + + if (ustcomm_connect_app(pid, &app_fd)) { + ERR("could not connect to PID %u", (unsigned int) pid); + return -1; + } + + req_header.command = LIST_TRACE_EVENTS; + req_header.size = 0; + + result = ustcomm_send(app_fd, &req_header, NULL); + if (result != 1) { + ERR("error while requesting trace_event list"); + return -1; + } + + result = ustcomm_recv_alloc(app_fd, &res_header, &big_str); + if (result != 1) { + ERR("error while receiving markers list"); + return -1; + } + + close(app_fd); + + tmp_tes = (struct trace_event_status *) + zmalloc(sizeof(struct trace_event_status) * + (ustctl_count_nl(big_str) + 1)); + if (tmp_tes == NULL) { + ERR("Failed to allocate TES array"); + return -1; + } + + /* Parse received reply string (format: "[name]"): */ + while (big_str[i] != '\0') { + sscanf(big_str + i, "trace_event: %a[^\n]", + &tmp_tes[tes_ind].name); + while (big_str[i] != '\n') { + ++i; /* Go to next '\n' */ + } + ++i; /* Skip current pointed '\n' */ + ++tes_ind; + } + tmp_tes[tes_ind].name = NULL; + + *tes = tmp_tes; + + free(big_str); + return 0; +} + +/** + * Set socket path + * + * @param sock_path Socket path + * @param pid Traced process ID + * @return 0 if successful, or error + */ +int ustctl_set_sock_path(const char *sock_path, pid_t pid) +{ + int result; + struct ustcomm_header req_header, res_header; + struct ustcomm_single_field sock_path_msg; + + result = ustcomm_pack_single_field(&req_header, + &sock_path_msg, + sock_path); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = SET_SOCK_PATH; + + return do_cmd(pid, &req_header, (char *)&sock_path_msg, + &res_header, NULL); +} + +/** + * Get socket path + * + * @param sock_path Pointer to where the socket path will be returned + * @param pid Traced process ID + * @return 0 if successful, or error + */ +int ustctl_get_sock_path(char **sock_path, pid_t pid) +{ + int result; + struct ustcomm_header req_header, res_header; + struct ustcomm_single_field *sock_path_msg; + + req_header.command = GET_SOCK_PATH; + req_header.size = 0; + + result = do_cmd(pid, &req_header, NULL, &res_header, + (char **)&sock_path_msg); + if (result < 0) { + return -1; + } + + result = ustcomm_unpack_single_field(sock_path_msg); + if (result < 0) { + return result; + } + + *sock_path = strdup(sock_path_msg->field); + + free(sock_path_msg); + + return 0; +} + +int ustctl_force_switch(pid_t pid) +{ + struct ustcomm_header req_header, res_header; + + req_header.command = FORCE_SUBBUF_SWITCH; + req_header.size = 0; + + return do_cmd(pid, &req_header, NULL, &res_header, NULL); +} + diff --git a/tests/Makefile.am b/tests/Makefile.am index 526f81c..e4e06ce 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . hello hello2 basic basic_long fork simple_include snprintf test-nevents test-libustinstr-malloc dlopen same_line_marker trace_event register_test tracepoint ustcmd_function_tests +SUBDIRS = . hello hello2 basic basic_long fork simple_include snprintf test-nevents test-libustinstr-malloc dlopen same_line_marker trace_event register_test tracepoint libustctl_function_tests dist_noinst_SCRIPTS = test_loop runtests trace_matches diff --git a/tests/libustctl_function_tests/Makefile.am b/tests/libustctl_function_tests/Makefile.am new file mode 100644 index 0000000..723b456 --- /dev/null +++ b/tests/libustctl_function_tests/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/tests/ + +noinst_PROGRAMS = libustctl_function_tests +libustctl_function_tests_SOURCES = libustctl_function_tests.c +libustctl_function_tests_LDADD = $(top_builddir)/libust/libust.la \ + $(top_builddir)/libustctl/libustctl.la \ + $(top_builddir)/libust-initializer.o \ + $(top_builddir)/tests/libtap.la \ + -lpthread + diff --git a/tests/libustctl_function_tests/libustctl_function_tests.c b/tests/libustctl_function_tests/libustctl_function_tests.c new file mode 100644 index 0000000..784ff5d --- /dev/null +++ b/tests/libustctl_function_tests/libustctl_function_tests.c @@ -0,0 +1,184 @@ +/* Copyright (C) 2010 Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Simple function tests for ustctl */ + +#include +#include +#include + +#include +#include + +#include "tap.h" + +static void ustctl_function_tests(pid_t pid) +{ + int result; + unsigned int subbuf_size, subbuf_num; + unsigned int new_subbuf_size, new_subbuf_num; + struct marker_status *marker_status, *ms_ptr; + char *old_socket_path, *new_socket_path; + char *tmp_ustd_socket = "/tmp/tmp_ustd_socket"; + char *trace = "auto"; + + printf("Connecting to pid %d\n", pid); + + /* marker status array functions */ + result = ustctl_get_cmsf(&marker_status, pid); + tap_ok(!result, "ustctl_get_cmsf"); + + result = 0; + for (ms_ptr = marker_status; ms_ptr->channel; ms_ptr++) { + if (!strcmp(ms_ptr->channel, "ust") && + !strcmp(ms_ptr->marker, "bar")) { + result = 1; + } + } + tap_ok(result, "Found channel \"ust\", marker \"bar\""); + + tap_ok(!ustctl_free_cmsf(marker_status), "ustctl_free_cmsf"); + + /* Get and set the socket path */ + tap_ok(!ustctl_get_sock_path(&old_socket_path, pid), + "ustctl_get_sock_path"); + + printf("Socket path: %s\n", old_socket_path); + + tap_ok(!ustctl_set_sock_path(tmp_ustd_socket, pid), + "ustctl_set_sock_path - set a new path"); + + tap_ok(!ustctl_get_sock_path(&new_socket_path, pid), + "ustctl_get_sock_path - get the new path"); + + tap_ok(!strcmp(new_socket_path, tmp_ustd_socket), + "Compare the set path and the retrieved path"); + + free(new_socket_path); + + tap_ok(!ustctl_set_sock_path(old_socket_path, pid), + "Reset the socket path"); + + free(old_socket_path); + + /* Enable, disable markers */ + tap_ok(!ustctl_set_marker_state(trace, "ust", "bar", 1, pid), + "ustctl_set_marker_state - existing marker ust bar"); + + /* Create and allocate a trace */ + tap_ok(!ustctl_create_trace(trace, pid), "ustctl_create_trace"); + + tap_ok(!ustctl_alloc_trace(trace, pid), "ustctl_alloc_trace"); + + /* Get subbuf size and number */ + subbuf_num = ustctl_get_subbuf_num(trace, "ust", pid); + tap_ok(subbuf_num > 0, "ustctl_get_subbuf_num - %d sub-buffers", + subbuf_num); + + subbuf_size = ustctl_get_subbuf_size(trace, "ust", pid); + tap_ok(subbuf_size, "ustctl_get_subbuf_size - sub-buffer size is %d", + subbuf_size); + + /* Start the trace */ + tap_ok(!ustctl_start_trace(trace, pid), "ustctl_start_trace"); + + + /* Stop the trace and destroy it*/ + tap_ok(!ustctl_stop_trace(trace, pid), "ustctl_stop_trace"); + + tap_ok(!ustctl_destroy_trace(trace, pid), "ustctl_destroy_trace"); + + /* Create a new trace */ + tap_ok(!ustctl_create_trace(trace, pid), "ustctl_create_trace - create a new trace"); + + printf("Setting new subbufer number and sizes (doubling)\n"); + new_subbuf_num = 2 * subbuf_num; + new_subbuf_size = 2 * subbuf_size; + + tap_ok(!ustctl_set_subbuf_num(trace, "ust", new_subbuf_num, pid), + "ustctl_set_subbuf_num"); + + tap_ok(!ustctl_set_subbuf_size(trace, "ust", new_subbuf_size, pid), + "ustctl_set_subbuf_size"); + + + /* Allocate the new trace */ + tap_ok(!ustctl_alloc_trace(trace, pid), "ustctl_alloc_trace - allocate the new trace"); + + + /* Get subbuf size and number and compare with what was set */ + subbuf_num = ustctl_get_subbuf_num(trace, "ust", pid); + + subbuf_size = ustctl_get_subbuf_size(trace, "ust", pid); + + tap_ok(subbuf_num == new_subbuf_num, "Set a new subbuf number, %d == %d", + subbuf_num, new_subbuf_num); + + + result = ustctl_get_subbuf_size(trace, "ust", pid); + tap_ok(subbuf_size == new_subbuf_size, "Set a new subbuf size, %d == %d", + subbuf_size, new_subbuf_size); + + tap_ok(!ustctl_destroy_trace(trace, pid), "ustctl_destroy_trace - without ever starting"); + + + printf("##### Tests that definetly should work are completed #####\n"); + printf("############## Start expected failure cases ##############\n"); + + tap_ok(ustctl_set_marker_state(trace, "ust","bar", 1, pid), + "Enable already enabled marker ust/bar"); + + tap_ok(ustctl_set_marker_state(trace, "ustl", "blar", 1, pid), + "Enable non-existent marker ustl blar"); + + tap_ok(ustctl_start_trace(trace, pid), + "Start a non-existent trace"); + + tap_ok(ustctl_destroy_trace(trace, pid), + "Destroy non-existent trace"); + + exit(tap_status() ? EXIT_FAILURE : EXIT_SUCCESS); + +} + + +int main() +{ + int i, status, pipefd[2]; + pid_t parent_pid, child_pid; + FILE *pipe_file; + + tap_plan(27); + + printf("Function tests for ustctl\n"); + + parent_pid = getpid(); + child_pid = fork(); + if (child_pid) { + for(i=0; i<10; i++) { + trace_mark(ust, bar, "str %s", "FOOBAZ"); + trace_mark(ust, bar2, "number1 %d number2 %d", 53, 9800); + usleep(100000); + } + + wait(&status); + } else { + ustctl_function_tests(parent_pid); + } + + exit(status ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/tests/manual_mode_tracing.sh b/tests/manual_mode_tracing.sh index b0df338..b60a957 100755 --- a/tests/manual_mode_tracing.sh +++ b/tests/manual_mode_tracing.sh @@ -42,17 +42,18 @@ UST_CONSUMERD_PID="$(<$pidfilepath)" LD_PRELOAD=/usr/local/lib/libust.so.0.0.0:/usr/local/lib/libustinstr-malloc.so find -L / >/dev/null 2>&1 & PID=$! +TRACE=auto sleep 0.1 -okx ustctl --list-markers "$PID" -okx ustctl --enable-marker ust/malloc $PID -okx ustctl --enable-marker ust/free $PID -okx ustctl --create-trace $PID -okx ustctl --alloc-trace $PID -okx ustctl --start-trace $PID +okx ustctl list-markers $PID +okx ustctl enable-marker $PID $TRACE ust/malloc +okx ustctl enable-marker $PID $TRACE ust/free +okx ustctl create-trace $PID $TRACE +okx ustctl alloc-trace $PID $TRACE +okx ustctl start-trace $PID $TRACE sleep 0.5 -okx ustctl --stop-trace $PID -okx ustctl --destroy-trace $PID +okx ustctl stop-trace $PID $TRACE +okx ustctl destroy-trace $PID $TRACE kill $PID kill -SIGTERM ${UST_CONSUMERD_PID} wait ${UST_CONSUMERD_PID} diff --git a/tests/runtests b/tests/runtests index afc1e21..68427f2 100755 --- a/tests/runtests +++ b/tests/runtests @@ -45,7 +45,7 @@ simple_harness_run same_line_marker/same_line_marker.sh simple_harness_run tracepoint/run -simple_harness_run ustcmd_function_tests/ustcmd_function_tests +simple_harness_run libustctl_function_tests/libustctl_function_tests echo "************************************" if [[ $tests_failed -eq 0 ]]; then diff --git a/tests/ustcmd_function_tests/Makefile.am b/tests/ustcmd_function_tests/Makefile.am deleted file mode 100644 index b70e784..0000000 --- a/tests/ustcmd_function_tests/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/tests/ - -noinst_PROGRAMS = ustcmd_function_tests -ustcmd_function_tests_SOURCES = ustcmd_function_tests.c -ustcmd_function_tests_LDADD = $(top_builddir)/libust/libust.la \ - $(top_builddir)/libustcmd/libustcmd.la \ - $(top_builddir)/libust-initializer.o \ - $(top_builddir)/tests/libtap.la \ - -lpthread - diff --git a/tests/ustcmd_function_tests/ustcmd_function_tests.c b/tests/ustcmd_function_tests/ustcmd_function_tests.c deleted file mode 100644 index d44dafc..0000000 --- a/tests/ustcmd_function_tests/ustcmd_function_tests.c +++ /dev/null @@ -1,184 +0,0 @@ -/* Copyright (C) 2010 Nils Carlson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Simple function tests for ustcmd */ - -#include -#include -#include - -#include -#include - -#include "tap.h" - -static void ustcmd_function_tests(pid_t pid) -{ - int result; - unsigned int subbuf_size, subbuf_num; - unsigned int new_subbuf_size, new_subbuf_num; - struct marker_status *marker_status, *ms_ptr; - char *old_socket_path, *new_socket_path; - char *tmp_ustd_socket = "/tmp/tmp_ustd_socket"; - char *trace = "auto"; - - printf("Connecting to pid %d\n", pid); - - /* marker status array functions */ - result = ustcmd_get_cmsf(&marker_status, pid); - tap_ok(!result, "ustcmd_get_cmsf"); - - result = 0; - for (ms_ptr = marker_status; ms_ptr->channel; ms_ptr++) { - if (!strcmp(ms_ptr->channel, "ust") && - !strcmp(ms_ptr->marker, "bar")) { - result = 1; - } - } - tap_ok(result, "Found channel \"ust\", marker \"bar\""); - - tap_ok(!ustcmd_free_cmsf(marker_status), "ustcmd_free_cmsf"); - - /* Get and set the socket path */ - tap_ok(!ustcmd_get_sock_path(&old_socket_path, pid), - "ustcmd_get_sock_path"); - - printf("Socket path: %s\n", old_socket_path); - - tap_ok(!ustcmd_set_sock_path(tmp_ustd_socket, pid), - "ustcmd_set_sock_path - set a new path"); - - tap_ok(!ustcmd_get_sock_path(&new_socket_path, pid), - "ustcmd_get_sock_path - get the new path"); - - tap_ok(!strcmp(new_socket_path, tmp_ustd_socket), - "Compare the set path and the retrieved path"); - - free(new_socket_path); - - tap_ok(!ustcmd_set_sock_path(old_socket_path, pid), - "Reset the socket path"); - - free(old_socket_path); - - /* Enable, disable markers */ - tap_ok(!ustcmd_set_marker_state(trace, "ust", "bar", 1, pid), - "ustcmd_set_marker_state - existing marker ust bar"); - - /* Create and allocate a trace */ - tap_ok(!ustcmd_create_trace(trace, pid), "ustcmd_create_trace"); - - tap_ok(!ustcmd_alloc_trace(trace, pid), "ustcmd_alloc_trace"); - - /* Get subbuf size and number */ - subbuf_num = ustcmd_get_subbuf_num(trace, "ust", pid); - tap_ok(subbuf_num > 0, "ustcmd_get_subbuf_num - %d sub-buffers", - subbuf_num); - - subbuf_size = ustcmd_get_subbuf_size(trace, "ust", pid); - tap_ok(subbuf_size, "ustcmd_get_subbuf_size - sub-buffer size is %d", - subbuf_size); - - /* Start the trace */ - tap_ok(!ustcmd_start_trace(trace, pid), "ustcmd_start_trace"); - - - /* Stop the trace and destroy it*/ - tap_ok(!ustcmd_stop_trace(trace, pid), "ustcmd_stop_trace"); - - tap_ok(!ustcmd_destroy_trace(trace, pid), "ustcmd_destroy_trace"); - - /* Create a new trace */ - tap_ok(!ustcmd_create_trace(trace, pid), "ustcmd_create_trace - create a new trace"); - - printf("Setting new subbufer number and sizes (doubling)\n"); - new_subbuf_num = 2 * subbuf_num; - new_subbuf_size = 2 * subbuf_size; - - tap_ok(!ustcmd_set_subbuf_num(trace, "ust", new_subbuf_num, pid), - "ustcmd_set_subbuf_num"); - - tap_ok(!ustcmd_set_subbuf_size(trace, "ust", new_subbuf_size, pid), - "ustcmd_set_subbuf_size"); - - - /* Allocate the new trace */ - tap_ok(!ustcmd_alloc_trace(trace, pid), "ustcmd_alloc_trace - allocate the new trace"); - - - /* Get subbuf size and number and compare with what was set */ - subbuf_num = ustcmd_get_subbuf_num(trace, "ust", pid); - - subbuf_size = ustcmd_get_subbuf_size(trace, "ust", pid); - - tap_ok(subbuf_num == new_subbuf_num, "Set a new subbuf number, %d == %d", - subbuf_num, new_subbuf_num); - - - result = ustcmd_get_subbuf_size(trace, "ust", pid); - tap_ok(subbuf_size == new_subbuf_size, "Set a new subbuf size, %d == %d", - subbuf_size, new_subbuf_size); - - tap_ok(!ustcmd_destroy_trace(trace, pid), "ustcmd_destroy_trace - without ever starting"); - - - printf("##### Tests that definetly should work are completed #####\n"); - printf("############## Start expected failure cases ##############\n"); - - tap_ok(ustcmd_set_marker_state(trace, "ust","bar", 1, pid), - "Enable already enabled marker ust/bar"); - - tap_ok(ustcmd_set_marker_state(trace, "ustl", "blar", 1, pid), - "Enable non-existent marker ustl blar"); - - tap_ok(ustcmd_start_trace(trace, pid), - "Start a non-existent trace"); - - tap_ok(ustcmd_destroy_trace(trace, pid), - "Destroy non-existent trace"); - - exit(tap_status() ? EXIT_FAILURE : EXIT_SUCCESS); - -} - - -int main() -{ - int i, status, pipefd[2]; - pid_t parent_pid, child_pid; - FILE *pipe_file; - - tap_plan(27); - - printf("Function tests for ustcmd\n"); - - parent_pid = getpid(); - child_pid = fork(); - if (child_pid) { - for(i=0; i<10; i++) { - trace_mark(ust, bar, "str %s", "FOOBAZ"); - trace_mark(ust, bar2, "number1 %d number2 %d", 53, 9800); - usleep(100000); - } - - wait(&status); - } else { - ustcmd_function_tests(parent_pid); - } - - exit(status ? EXIT_FAILURE : EXIT_SUCCESS); -} diff --git a/ustctl/Makefile.am b/ustctl/Makefile.am index 49e46f0..1e442a3 100644 --- a/ustctl/Makefile.am +++ b/ustctl/Makefile.am @@ -1,15 +1,15 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm \ - -I$(top_srcdir)/libustcmd $(KCOMPAT_CFLAGS) + -I$(top_srcdir)/libustctl $(KCOMPAT_CFLAGS) AM_CFLAGS = -fno-strict-aliasing bin_PROGRAMS = ustctl ustctl_SOURCES = \ - ustctl.c + ustctl.c marker_cmds.c trace_cmds.c channel_cmds.c cli.c cli.h scanning_functions.c scanning_functions.h ustctl_CFLAGS = -DUST_COMPONENT=ustctl -fno-strict-aliasing ustctl_LDADD = \ $(top_builddir)/snprintf/libustsnprintf.la \ $(top_builddir)/libustcomm/libustcomm.la \ - $(top_builddir)/libustcmd/libustcmd.la + $(top_builddir)/libustctl/libustctl.la diff --git a/ustctl/channel_cmds.c b/ustctl/channel_cmds.c new file mode 100644 index 0000000..2ccf460 --- /dev/null +++ b/ustctl/channel_cmds.c @@ -0,0 +1,153 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include "scanning_functions.h" +#include "usterr.h" +#include "cli.h" + +static int set_subbuf_size(int argc, char *argv[]) +{ + int result = 0; + pid_t pid; + char *channel = NULL; + unsigned int size; + + pid = parse_pid(argv[1]); + + if (scan_ch_and_num(argv[3], &channel, &size)) { + fprintf(stderr, "Failed to scan channel and size from" + " %s\n", argv[3]); + if (channel) + free(channel); + return -1; + } + if (ustctl_set_subbuf_size(argv[2], channel, size, pid)) { + ERR("error while trying to set the size of subbuffers " + "for PID %u\n", + pid); + result = -1; + } + + free(channel); + + return result; +} + +static int set_subbuf_num(int argc, char *argv[]) +{ + int result = 0; + pid_t pid; + char *channel = NULL; + unsigned int num; + + pid = parse_pid(argv[1]); + + if (scan_ch_and_num(argv[3], &channel, &num)) { + fprintf(stderr, "Failed to scan channel and number from" + " %s\n", argv[3]); + if (channel) + free(channel); + return -1; + } + if (ustctl_set_subbuf_num(argv[2], channel, num, pid)) { + ERR("error while trying to set the number of subbuffers for PID %u\n", + pid); + result = -1; + } + + free(channel); + + return result; +} + +static int get_subbuf_size(int argc, char *argv[]) +{ + pid_t pid; + unsigned int size; + + pid = parse_pid(argv[1]); + + if ((size = ustctl_get_subbuf_size(argv[2], argv[3], pid)) < 0) { + ERR("error while trying to get the subbuffer size from PID %u\n", + pid); + return -1; + } + + printf("The subbufer size is %d bytes\n", size); + + return 0; +} + +static int get_subbuf_num(int argc, char *argv[]) +{ + pid_t pid; + unsigned int num; + + pid = parse_pid(argv[1]); + + if ((num = ustctl_get_subbuf_num(argv[2], argv[3], pid)) < 0) { + ERR("error while trying to get the subbuffer size from PID %u\n", + pid); + return -1; + } + + printf("There are %u subbufers in each buffer\n", num); + + return 0; +} + +struct cli_cmd __cli_cmds channel_cmds[] = { + { + .name = "set-subbuf-size", + .description = "Set the subbuffer size for a channel", + .help_text = "set-subbuf-size / \n" + "Set the subbuffer size for a channel\n", + .function = set_subbuf_size, + .desired_args = 3, + .desired_args_op = CLI_EQ, + }, + { + .name = "set-subbuf-num", + .description = "Set the number of subbuffers for a channel", + .help_text = "set-subbuf-num / \n" + "Set the number of subbuffers for a channel\n", + .function = set_subbuf_num, + .desired_args = 3, + .desired_args_op = CLI_EQ, + }, + { + .name = "get-subbuf-size", + .description = "Get the subbuffer size for a channel", + .help_text = "get-subbuf-size \n" + "Get the subbuffer size for a channel\n", + .function = get_subbuf_size, + .desired_args = 3, + .desired_args_op = CLI_EQ, + }, + { + .name = "get-subbuf-num", + .description = "Get the number of subbuffers for a channel", + .help_text = "get-subbuf-num \n" + "Get the number of subbuffers for a channel\n", + .function = get_subbuf_num, + .desired_args = 3, + .desired_args_op = CLI_EQ, + }, +}; diff --git a/ustctl/cli.c b/ustctl/cli.c new file mode 100644 index 0000000..0ca9db5 --- /dev/null +++ b/ustctl/cli.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "cli.h" + +/* This dummy command is needed to create the sections in cli.o before + * other .o files have these sections, usefull for development. + */ +static int _dummy(int argc, char *argv[]) { + return 0; +} + +/* Define a dummy cmd to guarantee existence of the builtin variables */ +struct cli_cmd __cli_cmds __dummy_cli_cmd[] = { + { + .name = "_dummy", + .description = NULL, + .help_text = NULL, + .function = _dummy, + .desired_args = 0, + .desired_args_op = 0, + }, +}; + +extern struct cli_cmd __start___cli_cmds[] __attribute__((visibility("hidden"))); +extern struct cli_cmd __stop___cli_cmds[] __attribute__((visibility("hidden"))); + +static struct cli_cmd **cli_cmd_list; +static int cli_cmd_list_size; + +static char *process_name; + +static int compute_cli_cmds_size(void) +{ + long cli_cmds_start, cli_cmds_end; + + cli_cmds_start = (long)__start___cli_cmds; + cli_cmds_end = (long)__stop___cli_cmds; + + return (cli_cmds_end - cli_cmds_start) / sizeof(struct cli_cmd); +} + +static void __attribute__((constructor)) generate_cli_cmd_list(int argc, char *argv[]) +{ + struct cli_cmd *cli_cmd; + int section_size, i; + + process_name = basename(argv[0]); + + section_size = compute_cli_cmds_size(); + + cli_cmd_list = malloc(section_size * sizeof(void *)); + if (!cli_cmd_list) { + fprintf(stderr, "Failed to allocate command list!"); + exit(EXIT_FAILURE); + } + + cli_cmd_list_size = 0; + + cli_cmd = __start___cli_cmds; + for (i = 0; i < section_size; i++) { + if (&cli_cmd[i] == &__dummy_cli_cmd[0]) { + continue; + } + + if (cli_cmd[i].name) { + cli_cmd_list[cli_cmd_list_size++] = &cli_cmd[i]; + } + } +} + +struct cli_cmd *find_cli_cmd(const char *command) +{ + int i; + + for (i = 0; i < cli_cmd_list_size; i++) { + if (!strcmp(cli_cmd_list[i]->name, command)) { + return cli_cmd_list[i]; + } + } + + return NULL; +} + +static int cmpcli_cmds(const void *p1, const void *p2) +{ + return strcmp(* (char * const *) ((struct cli_cmd *)p1)->name, + * (char * const *) ((struct cli_cmd *)p2)->name); +} + +#define HELP_BUFFER_SIZE 4096 + +static void print_cmd_help(const char *prefix, const char *infix, + struct cli_cmd *cli_cmd) +{ + if (cli_cmd->help_text) { + fprintf(stderr, "%s%s%s", + prefix, + infix, + cli_cmd->help_text); + } else if (cli_cmd->description) { + fprintf(stderr, "%s%s%s\n%s\n", + prefix, + infix, + cli_cmd->name, + cli_cmd->description); + } else { + fprintf(stderr, "No help available for %s\n", + cli_cmd->name); + } +} + +void list_cli_cmds(int option) +{ + int i; + + qsort(cli_cmd_list, cli_cmd_list_size, sizeof(void *), cmpcli_cmds); + + for (i = 0; i < cli_cmd_list_size; i++) { + switch (option) { + case CLI_SIMPLE_LIST: + fprintf(stderr, "%s ", cli_cmd_list[i]->name); + break; + case CLI_DESCRIPTIVE_LIST: + fprintf(stderr, " %-25s%s\n", cli_cmd_list[i]->name, + cli_cmd_list[i]->description); + break; + case CLI_EXTENDED_LIST: + print_cmd_help("", "", cli_cmd_list[i]); + fprintf(stderr, "\n"); + break; + } + } + + if (option == CLI_SIMPLE_LIST) { + fprintf(stderr, "\n"); + } +} + +int cli_print_help(const char *command) +{ + struct cli_cmd *cli_cmd; + + cli_cmd = find_cli_cmd(command); + if (!cli_cmd) { + return -1; + } + + print_cmd_help(process_name, " ", cli_cmd); + + return 0; +} + +static void cli_check_argc(const char *command, int args, + int operator, int desired_args) +{ + switch(operator) { + case CLI_EQ: + if (args != desired_args) + goto print_error; + break; + case CLI_GE: + if (args < desired_args) + goto print_error; + break; + } + + return; + +print_error: + fprintf(stderr, "%s %s requires %s%d argument%s, see usage.\n", + process_name, command, operator == CLI_EQ ? "" : "at least ", + desired_args, desired_args > 1 ? "s" : ""); + cli_print_help(command); + exit(EXIT_FAILURE); +} + + +void cli_dispatch_cmd(struct cli_cmd *cmd, int argc, char *argv[]) +{ + cli_check_argc(cmd->name, argc - 1, cmd->desired_args_op, + cmd->desired_args); + + if (cmd->function(argc, argv)) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} diff --git a/ustctl/cli.h b/ustctl/cli.h new file mode 100644 index 0000000..a1e4eed --- /dev/null +++ b/ustctl/cli.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _CLI_H +#define _CLI_H + +struct cli_cmd { + const char *name; + const char *description; + const char *help_text; + int (*function)(int, char **); + int desired_args; + int desired_args_op; +} __attribute__((aligned(8))); + +#define __cli_cmds __attribute__((section("__cli_cmds"), aligned(8), used)) + +struct cli_cmd *find_cli_cmd(const char *command); + +enum cli_list_opts { + CLI_SIMPLE_LIST, + CLI_DESCRIPTIVE_LIST, + CLI_EXTENDED_LIST, +}; + +void list_cli_cmds(int option); + +int cli_print_help(const char *command); + +enum cli_arg_ops { + CLI_EQ, + CLI_GE, +}; + +void cli_dispatch_cmd(struct cli_cmd *cmd, int argc, char *argv[]); + +#endif /* _CLI_H */ diff --git a/ustctl/marker_cmds.c b/ustctl/marker_cmds.c new file mode 100644 index 0000000..6544669 --- /dev/null +++ b/ustctl/marker_cmds.c @@ -0,0 +1,144 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include "scanning_functions.h" +#include "usterr.h" +#include "cli.h" + +static int list_markers(int argc, char *argv[]) +{ + struct marker_status *cmsf = NULL; + int i; + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_get_cmsf(&cmsf, pid)) { + ERR("error while trying to list markers for PID %u\n", pid); + return -1; + } + for (i = 0; cmsf[i].channel; i++) { + printf("{PID: %u, channel/marker: %s/%s, " + "state: %u, fmt: %s}\n", + (unsigned int) pid, + cmsf[i].channel, + cmsf[i].marker, + cmsf[i].state, + cmsf[i].fs); + } + ustctl_free_cmsf(cmsf); + return 0; +} + +static int enable_marker(int argc, char *argv[]) +{ + int i, result = 0; + pid_t pid; + char *channel, *marker; + + pid = parse_pid(argv[1]); + + for (i = 3; i < argc; i++) { + channel = NULL; + marker = NULL; + if (scan_ch_marker(argv[i], + &channel, &marker)) { + result = -1; + fprintf(stderr, "Failed to scan channel and marker from" + " %s\n", argv[i]); + if (channel) + free(channel); + if (marker) + free(marker); + } + if (ustctl_set_marker_state(argv[2], channel, marker, 1, pid)) { + PERROR("error while trying to enable marker %s with PID %u", + argv[i], pid); + result = -1; + } + free(channel); + free(marker); + } + + return result; +} + +static int disable_marker(int argc, char *argv[]) +{ + int i, result = 0; + pid_t pid; + char *channel, *marker; + + pid = parse_pid(argv[1]); + + for (i = 3; i < argc; i++) { + channel = NULL; + marker = NULL; + if (scan_ch_marker(argv[i], + &channel, &marker)) { + fprintf(stderr, "Failed to scan channel and marker from" + " %s\n", argv[i]); + if (channel) + free(channel); + if (marker) + free(marker); + return -1; + } + if (ustctl_set_marker_state(argv[2], channel, marker, 0, pid)) { + PERROR("error while trying to disable marker %s with PID %u", + argv[i], pid); + result = -1; + } + free(channel); + free(marker); + } + + return result; +} + +struct cli_cmd __cli_cmds marker_cmds[] = { + { + .name = "list-markers", + .description = "List markers for a given pid", + .help_text = "list-markers \n" + "List the markers in a process\n", + .function = list_markers, + .desired_args = 1, + .desired_args_op = CLI_EQ, + }, + { + .name = "enable-marker", + .description = "Enable markers for a given pid", + .help_text = "enable-marker /... \n" + "Enable the listed markers for the trace in process pid\n", + .function = enable_marker, + .desired_args = 3, + .desired_args_op = CLI_GE, + }, + { + .name = "disable-marker", + .description = "Disable markers for a given pid", + .help_text = "disable-marker /... \n" + "Disable the listed markers for the trace in process pid\n", + .function = disable_marker, + .desired_args = 3, + .desired_args_op = CLI_GE, + } +}; diff --git a/ustctl/scanning_functions.c b/ustctl/scanning_functions.c new file mode 100644 index 0000000..a3eceb5 --- /dev/null +++ b/ustctl/scanning_functions.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include "usterr.h" + + +pid_t parse_pid(const char *pid_string) +{ + pid_t pid; + + errno = 0; + pid = strtoull(pid_string, NULL, 10); + if (errno) { + perror("Failed to parse pid"); + exit(EXIT_FAILURE); + } + + return pid; +} + +int scan_ch_marker(const char *channel_marker, char **channel, char **marker) +{ + int result; + + *channel = NULL; + *marker = NULL; + + result = sscanf(channel_marker, "%a[^/]/%as", channel, marker); + if (result != 2) { + if (errno) { + PERROR("Failed to read channel and marker names"); + } else { + ERR("Failed to parse marker and channel names"); + } + if (*channel) { + free(*channel); + } + if (*marker) { + free(*marker); + } + return -1; + } + + return 0; +} + +int scan_ch_and_num(const char *ch_num, char **channel, unsigned int *num) +{ + int result; + + *channel = NULL; + + result = sscanf(ch_num, "%a[^/]/%u", channel, num); + if (result != 2) { + if (errno) { + PERROR("Failed to parse channel and number"); + } else { + ERR("Failed to parse channel and number"); + } + if (*channel) { + free(*channel); + } + return -1; + } + + return 0; +} diff --git a/ustctl/scanning_functions.h b/ustctl/scanning_functions.h new file mode 100644 index 0000000..c37eba1 --- /dev/null +++ b/ustctl/scanning_functions.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __SCANNING_FUNCTIONS_H +#define __SCANNING_FUNCTIONS_H + +pid_t parse_pid(const char *pid_string); + +int scan_ch_marker(const char *channel_marker, char **channel, char **marker); + +int scan_ch_and_num(const char *ch_num, char **channel, unsigned int *num); + +#endif /* __SCANNING_FUNCTIONS_H */ diff --git a/ustctl/trace_cmds.c b/ustctl/trace_cmds.c new file mode 100644 index 0000000..020e5b2 --- /dev/null +++ b/ustctl/trace_cmds.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2011 Ericsson AB, Nils Carlson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include "scanning_functions.h" +#include "usterr.h" +#include "cli.h" + + +static int create_trace(int argc, char *argv[]) +{ + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_create_trace(argv[2], pid)) { + ERR("Failed to create trace %s for PID %u\n", argv[2], pid); + return -1; + } + + return 0; +} + +static int alloc_trace(int argc, char *argv[]) +{ + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_alloc_trace(argv[2], pid)) { + ERR("Failed to allocate trace %s for PID %u\n", argv[2], pid); + return -1; + } + return 0; +} + +static int start_trace(int argc, char *argv[]) +{ + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_start_trace(argv[2], pid)) { + ERR("Failed to start trace %s for PID %u\n", argv[2], pid); + return -1; + } + return 0; +} + +static int stop_trace(int argc, char *argv[]) +{ + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_stop_trace(argv[2], pid)) { + ERR("Failed to stop trace %s for PID %u\n", argv[2], pid); + return -1; + } + return 0; +} + +static int destroy_trace(int argc, char *argv[]) +{ + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_destroy_trace(argv[2], pid)) { + ERR("Failed to destroy trace %s for PID %u\n", argv[2], pid); + return -1; + } + return 0; +} + +static int force_subbuf_switch(int argc, char *argv[]) +{ + pid_t pid; + + pid = parse_pid(argv[1]); + + if (ustctl_force_switch(pid)) { + ERR("error while trying to force switch for PID %u\n", pid); + return -1; + } + + return 0; +} + +struct cli_cmd __cli_cmds trace_cmds[] = { + { + .name = "create-trace", + .description = "Create a trace for a process", + .help_text = "create-trace \n" + "Create a trace for a process\n", + .function = create_trace, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, + { + .name = "alloc-trace", + .description = "Allocate a trace for a process", + .help_text = "alloc-trace \n" + "Allocate a trace for a process\n", + .function = alloc_trace, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, + { + .name = "start-trace", + .description = "Start a trace for a process", + .help_text = "start-trace \n" + "Start a trace for a process\n", + .function = start_trace, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, + { + .name = "stop-trace", + .description = "Stop a trace for a process", + .help_text = "stop-trace \n" + "Stop a trace for a process\n", + .function = stop_trace, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, + { + .name = "destroy-trace", + .description = "Destroy a trace for a process", + .help_text = "destroy-trace \n" + "Destroy a trace for a process\n", + .function = destroy_trace, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, + { + .name = "force-subbuf-switch", + .description = "Force a subbuffer switch", + .help_text = "force-subbuf-switch \n" + "Force a subbuffer switch for a trace, currently this forces\n" + "a subbuffer switch for all traces in a process\n", + .function = force_subbuf_switch, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, +}; diff --git a/ustctl/ustctl.c b/ustctl/ustctl.c index aad3834..c1bbe8c 100644 --- a/ustctl/ustctl.c +++ b/ustctl/ustctl.c @@ -1,4 +1,5 @@ /* Copyright (C) 2009 Pierre-Marc Fournier + * Copyright (C) 2011 Ericsson AB, Nils Carlson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,478 +23,168 @@ #include #include -#include "ust/ustcmd.h" +#include "ust/ustctl.h" #include "usterr.h" +#include "cli.h" +#include "scanning_functions.h" -enum command { - CREATE_TRACE=1000, - ALLOC_TRACE, - START_TRACE, - STOP_TRACE, - DESTROY_TRACE, - LIST_MARKERS, - LIST_TRACE_EVENTS, - ENABLE_MARKER, - DISABLE_MARKER, - GET_ONLINE_PIDS, - SET_SUBBUF_SIZE, - SET_SUBBUF_NUM, - GET_SUBBUF_SIZE, - GET_SUBBUF_NUM, - GET_SOCK_PATH, - SET_SOCK_PATH, - FORCE_SWITCH, - UNKNOWN -}; - -struct ust_opts { - enum command cmd; - pid_t *pids; - char *regex; -}; - -char *progname = NULL; - -void usage(void) +void usage(const char *process_name) { - fprintf(stderr, "usage: %s COMMAND PIDs...\n", progname); - fprintf(stderr, "\nControl the tracing of a process that supports LTTng Userspace Tracing.\n\ -\n\ -Commands:\n\ - --create-trace\t\t\tCreate trace\n\ - --alloc-trace\t\t\tAlloc trace\n\ - --start-trace\t\t\tStart tracing\n\ - --stop-trace\t\t\tStop tracing\n\ - --destroy-trace\t\t\tDestroy the trace\n\ - --set-subbuf-size \"CHANNEL/bytes\"\tSet the size of subbuffers per channel\n\ - --set-subbuf-num \"CHANNEL/n\"\tSet the number of subbuffers per channel\n\ - --set-sock-path\t\t\tSet the path of the daemon socket\n\ - --get-subbuf-size \"CHANNEL\"\t\tGet the size of subbuffers per channel\n\ - --get-subbuf-num \"CHANNEL\"\t\tGet the number of subbuffers per channel\n\ - --get-sock-path\t\t\tGet the path of the daemon socket\n\ - --enable-marker \"CHANNEL/MARKER\"\tEnable a marker\n\ - --disable-marker \"CHANNEL/MARKER\"\tDisable a marker\n\ - --list-markers\t\t\tList the markers of the process, their\n\t\t\t\t\t state and format string\n\ - --list-trace-events\t\t\tList the trace-events of the process\n\ - --force-switch\t\t\tForce a subbuffer switch\n\ -\ -"); + fprintf(stderr, "Usage: %s COMMAND [ARGS]...\n", process_name); + fprintf(stderr, + "Control tracing within a process that supports UST,\n" + " the Userspace Tracing libary\n" + "Options:\n" + " -h[], --help[=] " + "help, for a command if provided\n" + " -l, --list " + "short list of commands\n" + " -e, --extended-list " + "extented list of commands with help\n" + "Commands:\n"); + list_cli_cmds(CLI_DESCRIPTIVE_LIST); } -int parse_opts_long(int argc, char **argv, struct ust_opts *opts) +struct option options[] = { - int c; + {"help", 2, NULL, 'h'}, + {"list", 0, NULL, 'l'}, + {"extended-list", 0, NULL, 'e'}, + {NULL, 0, NULL, 0}, +}; - opts->pids = NULL; - opts->regex = NULL; +int main(int argc, char *argv[]) +{ + struct cli_cmd *cli_cmd; + int opt; - while (1) { - int option_index = 0; - static struct option long_options[] = { - { "create-trace", 0, 0, CREATE_TRACE }, - { "alloc-trace", 0, 0, ALLOC_TRACE }, - { "start-trace", 0, 0, START_TRACE }, - { "stop-trace", 0, 0, STOP_TRACE }, - { "destroy-trace", 0, 0, DESTROY_TRACE }, - { "list-markers", 0, 0, LIST_MARKERS }, - { "list-trace-events", 0, 0, LIST_TRACE_EVENTS}, - { "enable-marker", 1, 0, ENABLE_MARKER }, - { "disable-marker", 1, 0, DISABLE_MARKER }, - { "help", 0, 0, 'h' }, - { "online-pids", 0, 0, GET_ONLINE_PIDS }, - { "set-subbuf-size", 1, 0, SET_SUBBUF_SIZE }, - { "set-subbuf-num", 1, 0, SET_SUBBUF_NUM }, - { "get-subbuf-size", 1, 0, GET_SUBBUF_SIZE }, - { "get-subbuf-num", 1, 0, GET_SUBBUF_NUM }, - { "get-sock-path", 0, 0, GET_SOCK_PATH }, - { "set-sock-path", 1, 0, SET_SOCK_PATH }, - { "force-switch", 0, 0, FORCE_SWITCH }, - { 0, 0, 0, 0 } - }; + if(argc <= 1) { + fprintf(stderr, "No operation specified.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } - c = getopt_long(argc, argv, "h", long_options, &option_index); - if (c == -1) + while ((opt = getopt_long(argc, argv, "+h::le", + options, NULL)) != -1) { + switch (opt) { + case 'h': + if (!optarg) { + usage(argv[0]); + } else { + if (cli_print_help(optarg)) { + fprintf(stderr, "No such command %s\n", + optarg); + } + } + exit(EXIT_FAILURE); break; - - if(c >= 1000) - opts->cmd = c; - - switch (c) { - case 0: - printf("option %s", long_options[option_index].name); - if (optarg) - printf(" with arg %s", optarg); - printf("\n"); + case 'l': + list_cli_cmds(CLI_SIMPLE_LIST); + exit(EXIT_FAILURE); break; - - case ENABLE_MARKER: - case DISABLE_MARKER: - case SET_SUBBUF_SIZE: - case SET_SUBBUF_NUM: - case GET_SUBBUF_SIZE: - case GET_SUBBUF_NUM: - case SET_SOCK_PATH: - opts->regex = strdup(optarg); + case 'e': + list_cli_cmds(CLI_EXTENDED_LIST); + exit(EXIT_FAILURE); + default: + fprintf(stderr, "Unknown option\n"); break; - - case 'h': - usage(); - exit(0); - - case '?': - fprintf(stderr, "Invalid argument\n\n"); - usage(); - exit(1); } } - if (argc - optind > 0 && opts->cmd != GET_ONLINE_PIDS) { - int i; - int pididx=0; - opts->pids = zmalloc((argc-optind+1) * sizeof(pid_t)); - - for(i=optind; ipids[pididx++] = (pid_t) tmp; - } - opts->pids[pididx] = -1; + cli_cmd = find_cli_cmd(argv[optind]); + if (!cli_cmd) { + fprintf(stderr, "No such command %s\n", + argv[optind]); + exit(EXIT_FAILURE); } + cli_dispatch_cmd(cli_cmd, argc - optind, &argv[optind]); + return 0; } -static int scan_ch_marker(const char *channel_marker, char **channel, - char **marker) +static int list_trace_events(int argc, char *argv[]) { - int result; + struct trace_event_status *tes = NULL; + int i; + pid_t pid; - *channel = NULL; - *marker = NULL; + pid = parse_pid(argv[1]); - result = sscanf(channel_marker, "%a[^/]/%as", channel, marker); - if (result != 2) { - if (errno) { - PERROR("Failed to read channel and marker names"); - } else { - ERR("Failed to parse marker and channel names"); - } - if (*channel) { - free(*channel); - } - if (*marker) { - free(*marker); - } + if (ustctl_get_tes(&tes, pid)) { + ERR("error while trying to list " + "trace_events for PID %u\n", + pid); return -1; - } else { - return 0; } + i = 0; + for (i = 0; tes[i].name; i++) { + printf("{PID: %u, trace_event: %s}\n", + pid, + tes[i].name); + } + ustctl_free_tes(tes); + + return 0; } -static int scan_ch_and_num(const char *ch_num, char **channel, unsigned int *num) +static int set_sock_path(int argc, char *argv[]) { - int result; + pid_t pid; - *channel = NULL; + pid = parse_pid(argv[1]); - result = sscanf(ch_num, "%a[^/]/%u", channel, num); - if (result != 2) { - if (errno) { - PERROR("Failed to parse channel and number"); - } else { - ERR("Failed to parse channel and number"); - } - if (*channel) { - free(*channel); - } + if (ustctl_set_sock_path(argv[2], pid)) { + ERR("error while trying to set sock path for PID %u\n", pid); return -1; } -} -char *trace = "auto"; + return 0; +} -int main(int argc, char *argv[]) +static int get_sock_path(int argc, char *argv[]) { - pid_t *pidit; - int result; - int retval = EXIT_SUCCESS; - char *tmp; - struct ust_opts opts; + pid_t pid; + char *sock_path; - progname = argv[0]; + pid = parse_pid(argv[1]); - if(argc <= 1) { - fprintf(stderr, "No operation specified.\n"); - usage(); - exit(EXIT_FAILURE); - } - - result = parse_opts_long(argc, argv, &opts); - if(result) { - fprintf(stderr, "\n"); - usage(); - exit(EXIT_FAILURE); - } - - if(opts.pids == NULL && opts.cmd != GET_ONLINE_PIDS) { - fprintf(stderr, "No pid specified.\n"); - usage(); - exit(EXIT_FAILURE); - } - if(opts.cmd == UNKNOWN) { - fprintf(stderr, "No command specified.\n"); - usage(); - exit(EXIT_FAILURE); - } - if (opts.cmd == GET_ONLINE_PIDS) { - pid_t *pp = ustcmd_get_online_pids(); - unsigned int i = 0; - - if (pp) { - while (pp[i] != 0) { - printf("%u\n", (unsigned int) pp[i]); - ++i; - } - free(pp); - } - - exit(EXIT_SUCCESS); - } - - pidit = opts.pids; - struct marker_status *cmsf = NULL; - struct trace_event_status *tes = NULL; - unsigned int i = 0; - - while(*pidit != -1) { - switch (opts.cmd) { - case CREATE_TRACE: - result = ustcmd_create_trace(trace, *pidit); - if (result) { - ERR("error while trying to create trace with PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - break; - - case START_TRACE: - result = ustcmd_start_trace(trace, *pidit); - if (result) { - ERR("error while trying to for trace with PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - break; - - case STOP_TRACE: - result = ustcmd_stop_trace(trace, *pidit); - if (result) { - ERR("error while trying to stop trace for PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - break; - - case DESTROY_TRACE: - result = ustcmd_destroy_trace(trace, *pidit); - if (result) { - ERR("error while trying to destroy trace with PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - break; - - case LIST_MARKERS: - cmsf = NULL; - if (ustcmd_get_cmsf(&cmsf, *pidit)) { - ERR("error while trying to list markers for PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - i = 0; - while (cmsf[i].channel != NULL) { - printf("{PID: %u, channel/marker: %s/%s, " - "state: %u, fmt: %s}\n", - (unsigned int) *pidit, - cmsf[i].channel, - cmsf[i].marker, - cmsf[i].state, - cmsf[i].fs); - ++i; - } - ustcmd_free_cmsf(cmsf); - break; - - case LIST_TRACE_EVENTS: - tes = NULL; - if (ustcmd_get_tes(&tes, *pidit)) { - ERR("error while trying to list " - "trace_events for PID %u\n", - (unsigned int) *pidit); - break; - } - i = 0; - while (tes[i].name != NULL) { - printf("{PID: %u, trace_event: %s}\n", - (unsigned int) *pidit, - tes[i].name); - ++i; - } - ustcmd_free_tes(tes); - - break; - case ENABLE_MARKER: - if (opts.regex) { - char *channel, *marker; - - if (scan_ch_marker(opts.regex, - &channel, &marker)) { - retval = EXIT_FAILURE; - break; - } - if (ustcmd_set_marker_state(trace, channel, marker, 1, *pidit)) { - PERROR("error while trying to enable marker %s with PID %u", - opts.regex, (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - } - - break; - case DISABLE_MARKER: - if (opts.regex) { - char *channel, *marker; - - if (scan_ch_marker(opts.regex, - &channel, &marker)) { - retval = EXIT_FAILURE; - break; - } - if (ustcmd_set_marker_state(trace, channel, marker, 0, *pidit)) { - ERR("error while trying to disable marker %s with PID %u\n", - opts.regex, (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - } - break; - - case SET_SUBBUF_SIZE: - if (opts.regex) { - char *channel; - unsigned int size; - if (scan_ch_and_num(opts.regex, &channel, &size)) { - retval = EXIT_FAILURE; - break; - } - - if (ustcmd_set_subbuf_size(trace, channel, size, *pidit)) { - ERR("error while trying to set the size of subbuffers with PID %u\n", - (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - } - break; - - case SET_SUBBUF_NUM: - if (opts.regex) { - char *channel; - unsigned int num; - if (scan_ch_and_num(opts.regex, &channel, &num)) { - retval = EXIT_FAILURE; - break; - } - - if (num < 2) { - ERR("Subbuffer count should be greater or equal to 2"); - retval = EXIT_FAILURE; - break; - } - if (ustcmd_set_subbuf_num(trace, channel, num, *pidit)) { - ERR("error while trying to set the number of subbuffers with PID %u\n", - (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - } - break; - - case GET_SUBBUF_SIZE: - result = ustcmd_get_subbuf_size(trace, opts.regex, *pidit); - if (result == -1) { - ERR("error while trying to get_subuf_size with PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - - printf("the size of subbufers is %d\n", result); - break; - - case GET_SUBBUF_NUM: - result = ustcmd_get_subbuf_num(trace, opts.regex, *pidit); - if (result == -1) { - ERR("error while trying to get_subuf_num with PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - - printf("the number of subbufers is %d\n", result); - break; - - case ALLOC_TRACE: - result = ustcmd_alloc_trace(trace, *pidit); - if (result) { - ERR("error while trying to alloc trace with PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - break; - - case GET_SOCK_PATH: - result = ustcmd_get_sock_path(&tmp, *pidit); - if (result) { - ERR("error while trying to get sock path for PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - break; - } - printf("the socket path is %s\n", tmp); - free(tmp); - break; - - case SET_SOCK_PATH: - result = ustcmd_set_sock_path(opts.regex, *pidit); - if (result) { - ERR("error while trying to set sock path for PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - break; - - case FORCE_SWITCH: - result = ustcmd_force_switch(*pidit); - if (result) { - ERR("error while trying to force switch for PID %u\n", (unsigned int) *pidit); - retval = EXIT_FAILURE; - } - break; - - default: - ERR("unknown command\n"); - retval = EXIT_FAILURE; - break; - } - - pidit++; - } - - if (opts.pids != NULL) { - free(opts.pids); - } - if (opts.regex != NULL) { - free(opts.regex); + if (ustctl_get_sock_path(&sock_path, pid)) { + ERR("error while trying to get sock path for PID %u\n", pid); + return -1; } + printf("The socket path is %s\n", sock_path); + free(sock_path); - return retval; + return 0; } +struct cli_cmd __cli_cmds general_cmds[] = { + { + .name = "list-trace-events", + .description = "List trace-events for a given pid", + .help_text = "list-trace-events \n" + "List the trace-events in a process\n", + .function = list_trace_events, + .desired_args = 1, + .desired_args_op = CLI_EQ, + }, + { + .name = "set-sock-path", + .description = "Set the path to the consumer daemon socket", + .help_text = "set-sock-path \n" + "Set the path to the consumer daemon socket\n", + .function = set_sock_path, + .desired_args = 2, + .desired_args_op = CLI_EQ, + }, + { + .name = "get-sock-path", + .description = "Get the path to the consumer daemon socket", + .help_text = "get-sock-path \n" + "Get the path to the consumer daemon socket\n", + .function = get_sock_path, + .desired_args = 1, + .desired_args_op = CLI_EQ, + }, +};