From: Philippe Proulx Date: Tue, 1 Sep 2009 17:21:07 +0000 (-0400) Subject: add libustcmd X-Git-Tag: v1.9.1~939 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=ab33e65c8f105124ed19855105ed7196845616f6;p=lttng-ust.git add libustcmd --- diff --git a/libustcmd/ustcmd.c b/libustcmd/ustcmd.c new file mode 100644 index 00000000..3f09c503 --- /dev/null +++ b/libustcmd/ustcmd.c @@ -0,0 +1,321 @@ +/* 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 + */ + +#include +#include +#include +#include +#include +#include +#include +# + +#include "ustcomm.h" +#include "ustcmd.h" + +#define _GNU_SOURCE + +pid_t* ustcmd_get_online_pids(void) { + struct dirent* dirent; + DIR* dir; + char* ping_res; + + dir = opendir(SOCK_DIR); + if (!dir) { + return NULL; + } + + unsigned int ret_size = 1 * sizeof(pid_t), i = 0; + 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, "ustd")) { + + sscanf(dirent->d_name, "%u", (unsigned int*) &ret[i]); + if (pid_is_online(ret[i])) { + 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* mn, int state, pid_t pid) { + if (mn == NULL) { + return USTCMD_ERR_ARG; + } + + char* cmd_str [] = {"disable_marker", "enable_marker"}; + char* cmd; + asprintf(&cmd, "%s %s", cmd_str[state], mn); + + int tres; + if (tres = ustcmd_shoot(cmd, pid, NULL)) { + free(cmd); + return USTCMD_ERR_GEN; + } + + free(cmd); + return 0; +} + +/** + * 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(pid_t pid) { + int tres; + + if (tres = ustcmd_shoot("destroy", pid, NULL)) { + return USTCMD_ERR_GEN; + } + + return 0; +} + +/** + * 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(pid_t pid) { + int tres; + + if (tres = ustcmd_shoot("start", pid, NULL)) { + return USTCMD_ERR_GEN; + } + + return 0; +} + +/** + * 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(pid_t pid) { + int tres; + + if (tres = ustcmd_shoot("trace_start", pid, NULL)) { + return USTCMD_ERR_GEN; + } + + return 0; +} + +/** + * 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(pid_t pid) { + int tres; + + if (tres = ustcmd_shoot("trace_stop", pid, NULL)) { + return USTCMD_ERR_GEN; + } + + return 0; +} + +/** + * 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 USTcmd_cmsf* 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 errors {USTCMD_ERR_ARG, USTCMD_ERR_GEN} + */ +int ustcmd_get_cmsf(struct USTcmd_cmsf** cmsf, const pid_t pid) { + if (cmsf == NULL) { + return USTCMD_ERR_ARG; + } + char* big_str = NULL; + int tres; + + if (tres = ustcmd_shoot("list_markers", pid, &big_str)) { + return USTCMD_ERR_GEN; + } + + if (big_str == NULL) { + fprintf(stderr, "ustcmd: error while getting markers list\n"); + return USTCMD_ERR_GEN; + } + + struct USTcmd_cmsf* tmp_cmsf = NULL; + tmp_cmsf = (struct USTcmd_cmsf*) malloc(sizeof(struct USTcmd_cmsf) * + (ustcmd_count_nl(big_str) + 1)); + if (tmp_cmsf == NULL) { + return USTCMD_ERR_GEN; + } + + // Parse received reply string (format: "[chan]/[mark] [st] [fs]"): + unsigned int i = 0, cur_st, cmsf_ind = 0; + while (big_str[i] != '\0') { + /* RAW METHOD (REPLACED BY SSCANF): + cur_st = i; // Set current start at beginning of current line + while (big_str[i] != '/') { + ++i; // Go to next '/' + } + tmp_cmsf[cmsf_ind].channel = + strndup(big_str + cur_st, i - cur_st); + + ++i; // Go after '/' + cur_st = i; // Set current start at beginning of marker name + while (big_str[i] != ' ') { + ++i; // Go to next ' ' + } + tmp_cmsf[cmsf_ind].marker = + strndup(big_str + cur_st, i - cur_st); + + ++i; // Go after ' ' + tmp_cmsf[cmsf_ind].state = (big_str[i] == USTCMD_MS_CHR_ON ? + USTCMD_MS_ON : USTCMD_MS_OFF); // Marker state + + i += 2; // Go to format string (after state and another ' ') + cur_st = i; // Set current start at beginning of format string + while (big_str[i] != '\n') { + ++i; // Go to next '\n' + } + tmp_cmsf[cmsf_ind].fs = + strndup(big_str + cur_st, i - cur_st); + */ + + char state; + sscanf(big_str + i, "%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; +} + +/** + * Shoots a given command using ustcomm. + * + * @param cmd Null-terminated command to shoot + * @param pid Targeted PID + * @param reply Pointer to string to be filled with a reply string (must + * be NULL if no reply is needed for the given command). + * @return 0 if successful, or errors {USTCMD_ERR_ARG, USTCMD_ERR_CONN} + */ +int ustcmd_shoot(const char* cmd, const pid_t pid, char** reply) { + if (cmd == NULL) { + return USTCMD_ERR_ARG; + } + + struct ustcomm_connection conn; + if (ustcomm_connect_app(pid, &conn)) { + fprintf(stderr, "ustcmd_shoot: could not connect to PID %u\n", + (unsigned int) pid); + return USTCMD_ERR_CONN; + } + + ustcomm_send_request(&conn, cmd, reply); + + return 0; +} + diff --git a/libustcmd/ustcmd.h b/libustcmd/ustcmd.h new file mode 100644 index 00000000..ad6c5318 --- /dev/null +++ b/libustcmd/ustcmd.h @@ -0,0 +1,43 @@ +#ifndef _USTCMD_H +#define _USTCMD_H + +#include +#include +#include +#include +#include + +#include "ustcomm.h" +#include "ustcmd.h" + +#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/" // UST sockets directory + +// Channel/marker/state/format string (cmsf) info. structure +struct USTcmd_cmsf { + char* channel; // Channel name (end of USTcmd_cmsf array if NULL) + char* marker; // Marker name (end of USTcmd_cmsf array if NULL) + int state; // State (0 := marker disabled, 1 := marker enabled) + char* fs; // Format string (end of USTcmd_cmsf array if NULL) +}; + +pid_t* ustcmd_get_online_pids(void); +int ustcmd_set_marker_state(const char*, int, pid_t); +int ustcmd_destroy_trace(pid_t); +int ustcmd_setup_and_start(pid_t); +int ustcmd_stop_trace(pid_t); +int ustcmd_start_trace(pid_t); +int ustcmd_free_cmsf(struct USTcmd_cmsf*); +unsigned int ustcmd_count_nl(const char*); +int ustcmd_shoot(const char*, pid_t, char**); +int ustcmd_get_cmsf(struct USTcmd_cmsf**, pid_t); + +#endif // _USTCMD_H diff --git a/libustcomm/ustcomm.c b/libustcomm/ustcomm.c index 0a5ab6aa..f3263582 100644 --- a/libustcomm/ustcomm.c +++ b/libustcomm/ustcomm.c @@ -33,8 +33,6 @@ #include "localerr.h" #define UNIX_PATH_MAX 108 -#define SOCK_DIR "/tmp/socks" -#define UST_SIGNAL SIGIO #define MSG_MAX 1000 @@ -82,6 +80,10 @@ static int signal_process(pid_t pid) return 0; } +int pid_is_online(pid_t pid) { + return kill(pid, UST_SIGNAL) != -1; +} + static int send_message_fd(int fd, const char *msg) { int result; diff --git a/libustcomm/ustcomm.h b/libustcomm/ustcomm.h index 17bd9c10..fed23359 100644 --- a/libustcomm/ustcomm.h +++ b/libustcomm/ustcomm.h @@ -23,6 +23,9 @@ #include "kcompat.h" +#define SOCK_DIR "/tmp/socks" +#define UST_SIGNAL SIGIO + struct ustcomm_connection { struct list_head list; int fd; @@ -71,4 +74,6 @@ int nth_token_is(char *str, char *token, int tok_no); char *nth_token(char *str, int tok_no); +int pid_is_online(pid_t); + #endif /* USTCOMM_H */