From 0f79e1ef1d4f31a91476f5a84e367f2c49ce4723 Mon Sep 17 00:00:00 2001 From: Nils Carlson Date: Mon, 16 May 2011 15:57:15 +0200 Subject: [PATCH] Make libustctl list only online pids v3 Changes since v2: Botox. Changes since v1: Cosmetic surgery at a european cost Previously libustctl would list all pids. This patch changes this so only online pids are listed. This is done by appending on each socket name the mtime from the proc/ directory. This way a socket can be checked to see if the appended mtime matches the mtime of the proc dir for the current pid, thus allowing us to distinguish between old and new socket files. Signed-off-by: Nils Carlson Acked-by: Mathieu Desnoyers --- libust/tracectl.c | 9 ++- libustcomm/ustcomm.c | 151 +++++++++++++++++++++++++++++++++++++----- libustcomm/ustcomm.h | 7 ++ libustctl/libustctl.c | 18 +---- 4 files changed, 154 insertions(+), 31 deletions(-) diff --git a/libust/tracectl.c b/libust/tracectl.c index bc0a07c..2f45d6b 100644 --- a/libust/tracectl.c +++ b/libust/tracectl.c @@ -1228,12 +1228,19 @@ static struct ustcomm_sock * init_app_socket(int epoll_fd) char *dir_name, *sock_name; int result; struct ustcomm_sock *sock = NULL; + time_t mtime; dir_name = ustcomm_user_sock_dir(); if (!dir_name) return NULL; - result = asprintf(&sock_name, "%s/%d", dir_name, (int)getpid()); + mtime = ustcomm_pid_st_mtime(getpid()); + if (!mtime) { + goto free_dir_name; + } + + result = asprintf(&sock_name, "%s/%d.%ld", dir_name, + (int) getpid(), (long) mtime); if (result < 0) { ERR("string overflow allocating socket name, " "UST thread bailing"); diff --git a/libustcomm/ustcomm.c b/libustcomm/ustcomm.c index ed6d8f1..3c7c0bb 100644 --- a/libustcomm/ustcomm.c +++ b/libustcomm/ustcomm.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -550,6 +551,127 @@ char *ustcomm_user_sock_dir(void) return sock_dir; } +static int time_and_pid_from_socket_name(char *sock_name, unsigned long *time, + pid_t *pid) +{ + char *saveptr, *pid_m_time_str; + char *sock_basename = strdup(basename(sock_name)); + + if (!sock_basename) { + return -1; + } + + /* This is the pid */ + pid_m_time_str = strtok_r(sock_basename, ".", &saveptr); + if (!pid_m_time_str) { + goto out_err; + } + + errno = 0; + *pid = (pid_t)strtoul(pid_m_time_str, NULL, 10); + if (errno) { + goto out_err; + } + + /* This should be the time-stamp */ + pid_m_time_str = strtok_r(NULL, ".", &saveptr); + if (!pid_m_time_str) { + goto out_err; + } + + errno = 0; + *time = strtoul(pid_m_time_str, NULL, 10); + if (errno) { + goto out_err; + } + + return 0; + +out_err: + free(sock_basename); + return -1; +} + +time_t ustcomm_pid_st_mtime(pid_t pid) +{ + struct stat proc_stat; + char proc_name[PATH_MAX]; + + if (snprintf(proc_name, PATH_MAX - 1, "/proc/%ld", (long) pid) < 0) { + return 0; + } + + if (stat(proc_name, &proc_stat)) { + return 0; + } + + return proc_stat.st_mtime; +} + +int ustcomm_is_socket_live(char *sock_name, pid_t *read_pid) +{ + time_t time_from_pid; + unsigned long time_from_sock; + pid_t pid; + + if (time_and_pid_from_socket_name(sock_name, &time_from_sock, &pid)) { + return 0; + } + + if (read_pid) { + *read_pid = pid; + } + + time_from_pid = ustcomm_pid_st_mtime(pid); + if (!time_from_pid) { + return 0; + } + + if ((unsigned long) time_from_pid == time_from_sock) { + return 1; + } + + return 0; +} + +#define MAX_SOCK_PATH_BASE_LEN 100 + +static int ustcomm_get_sock_name(char *dir_name, pid_t pid, char *sock_name) +{ + struct dirent *dirent; + char sock_path_base[MAX_SOCK_PATH_BASE_LEN]; + int len; + DIR *dir = opendir(dir_name); + + snprintf(sock_path_base, MAX_SOCK_PATH_BASE_LEN - 1, + "%ld.", (long) pid); + len = strlen(sock_path_base); + + while ((dirent = readdir(dir))) { + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..") || + !strcmp(dirent->d_name, "ust-consumer") || + dirent->d_type == DT_DIR || + strncmp(dirent->d_name, sock_path_base, len)) { + continue; + } + + if (ustcomm_is_socket_live(dirent->d_name, NULL)) { + if (snprintf(sock_name, PATH_MAX - 1, "%s/%s", + dir_name, dirent->d_name) < 0) { + PERROR("path longer than PATH_MAX?"); + goto out_err; + } + closedir(dir); + return 0; + } + } + +out_err: + closedir(dir); + return -1; +} + /* Open a connection to a traceable app. * * Return value: @@ -561,16 +683,15 @@ static int connect_app_non_root(pid_t pid, int *app_fd) { int result; int retval = 0; - char *dir_name, *sock_name; + char *dir_name; + char sock_name[PATH_MAX]; dir_name = ustcomm_user_sock_dir(); if (!dir_name) return -ENOMEM; - result = asprintf(&sock_name, "%s/%d", dir_name, pid); - if (result < 0) { - ERR("failed to allocate socket name"); - retval = -1; + if (ustcomm_get_sock_name(dir_name, pid, sock_name)) { + retval = -ENOENT; goto free_dir_name; } @@ -578,11 +699,9 @@ static int connect_app_non_root(pid_t pid, int *app_fd) if (result < 0) { ERR("failed to connect to app"); retval = -1; - goto free_sock_name; + goto free_dir_name; } -free_sock_name: - free(sock_name); free_dir_name: free(dir_name); @@ -595,8 +714,8 @@ static int connect_app_root(pid_t pid, int *app_fd) { DIR *tmp_dir; struct dirent *dirent; - char *sock_name; - int result; + char dir_name[PATH_MAX], sock_name[PATH_MAX]; + int result = -1; tmp_dir = opendir(USER_TMP_DIR); if (!tmp_dir) { @@ -607,14 +726,16 @@ static int connect_app_root(pid_t pid, int *app_fd) if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE, strlen(USER_SOCK_DIR_BASE))) { - if (asprintf(&sock_name, USER_TMP_DIR "/%s/%u", - dirent->d_name, pid) < 0) { - goto close_tmp_dir; + if (snprintf(dir_name, PATH_MAX - 1, "%s/%s", USER_TMP_DIR, + dirent->d_name) < 0) { + continue; } - result = ustcomm_connect_path(sock_name, app_fd); + if (ustcomm_get_sock_name(dir_name, pid, sock_name)) { + continue; + } - free(sock_name); + result = ustcomm_connect_path(sock_name, app_fd); if (result == 0) { goto close_tmp_dir; diff --git a/libustcomm/ustcomm.h b/libustcomm/ustcomm.h index a91c111..4706b72 100644 --- a/libustcomm/ustcomm.h +++ b/libustcomm/ustcomm.h @@ -162,6 +162,13 @@ extern int ustcomm_request_consumer(pid_t pid, const char *channel); /* Returns the current users socket directory, must be freed */ extern char *ustcomm_user_sock_dir(void); + +/* Get the st_m_time from proc*/ +extern time_t ustcomm_pid_st_mtime(pid_t pid); + +/* Check that a socket is live */ +extern int ustcomm_is_socket_live(char *sock_name, pid_t *read_pid); + extern int ustcomm_connect_app(pid_t pid, int *app_fd); extern int ustcomm_connect_path(const char *path, int *connection_fd); diff --git a/libustctl/libustctl.c b/libustctl/libustctl.c index 8b0dfc1..4e6c495 100644 --- a/libustctl/libustctl.c +++ b/libustctl/libustctl.c @@ -110,7 +110,7 @@ static int get_pids_in_dir(DIR *dir, pid_t **pid_list, unsigned int *pid_list_size) { struct dirent *dirent; - long read_pid; + pid_t read_pid; while ((dirent = readdir(dir))) { if (!strcmp(dirent->d_name, ".") || @@ -121,21 +121,9 @@ static int get_pids_in_dir(DIR *dir, pid_t **pid_list, continue; } - errno = 0; - read_pid = strtol(dirent->d_name, NULL, 10); - if (errno) { - continue; - } - - /* - * 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) { + if (ustcomm_is_socket_live(dirent->d_name, &read_pid)) { - (*pid_list)[(*pid_list_index)++] = read_pid; + (*pid_list)[(*pid_list_index)++] = (long) read_pid; if (*pid_list_index == *pid_list_size) { if (realloc_pid_list(pid_list, pid_list_size)) { -- 2.39.5