From: Mathieu Desnoyers Date: Thu, 16 Jun 2011 18:59:54 +0000 (-0400) Subject: Move away files that will be deprecated X-Git-Tag: v1.9.1~344 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=c4001caa99402441a0bf62625a2f0c832078b176;p=lttng-ust.git Move away files that will be deprecated Signed-off-by: Mathieu Desnoyers --- diff --git a/deprecated/libustcomm/Makefile.am b/deprecated/libustcomm/Makefile.am new file mode 100644 index 00000000..3ae96d5e --- /dev/null +++ b/deprecated/libustcomm/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -fno-strict-aliasing + +noinst_LTLIBRARIES = libustcomm.la +libustcomm_la_SOURCES = \ + ustcomm.h \ + ustcomm.c + +libustcomm_la_LDFLAGS = -no-undefined -static +libustcomm_la_CFLAGS = -DUST_COMPONENT="libustcomm" -fPIC -fno-strict-aliasing diff --git a/deprecated/libustcomm/ustcomm.c b/deprecated/libustcomm/ustcomm.c new file mode 100644 index 00000000..07f7f874 --- /dev/null +++ b/deprecated/libustcomm/ustcomm.c @@ -0,0 +1,1028 @@ +/* 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 + */ + +/* API used by UST components to communicate with each other via sockets. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ustcomm.h" +#include "usterr.h" +#include "share.h" + +static int mkdir_p(const char *path, mode_t mode) +{ + const char *path_p; + char *tmp; + + int retval = 0; + int result; + mode_t old_umask; + + tmp = zmalloc(strlen(path) + 1); + if (tmp == NULL) + return -1; + + /* skip first / */ + path_p = path+1; + + old_umask = umask(0); + for(;;) { + while (*path_p != '/') { + if(*path_p == 0) + break; + ++path_p; + } + if (*path_p == '/') { + strncpy(tmp, path, path_p - path); + tmp[path_p-path] = '\0'; + if (tmp[path_p - path - 1] != '/') { + result = mkdir(tmp, mode); + if(result == -1) { + if (!(errno == EEXIST || errno == EACCES || errno == EROFS)) { + /* Then this is a real error */ + retval = -1; + break; + } + } + } + /* pass / */ + path_p++; + } else { + /* last component */ + result = mkdir(path, mode); + if (result == -1) + retval = -1; + break; + } + } + + free(tmp); + umask(old_umask); + return retval; +} + +static struct sockaddr_un * create_sock_addr(const char *name, + size_t *sock_addr_size) +{ + struct sockaddr_un * addr; + size_t alloc_size; + + alloc_size = (size_t) (((struct sockaddr_un *) 0)->sun_path) + + strlen(name) + 1; + + addr = malloc(alloc_size); + if (addr < 0) { + ERR("allocating addr failed"); + return NULL; + } + + addr->sun_family = AF_UNIX; + strcpy(addr->sun_path, name); + + *sock_addr_size = alloc_size; + + return addr; +} + +struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd, + struct cds_list_head *list) +{ + struct epoll_event ev; + struct ustcomm_sock *sock; + + sock = malloc(sizeof(struct ustcomm_sock)); + if (!sock) { + perror("malloc: couldn't allocate ustcomm_sock"); + return NULL; + } + + ev.events = EPOLLIN; + ev.data.ptr = sock; + sock->fd = fd; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock->fd, &ev) == -1) { + perror("epoll_ctl: failed to add socket\n"); + free(sock); + return NULL; + } + + sock->epoll_fd = epoll_fd; + if (list) { + cds_list_add(&sock->list, list); + } else { + CDS_INIT_LIST_HEAD(&sock->list); + } + + return sock; +} + +void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll) +{ + cds_list_del(&sock->list); + if (!keep_in_epoll) { + if (epoll_ctl(sock->epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL) == -1) { + PERROR("epoll_ctl: failed to delete socket"); + } + } + close(sock->fd); + free(sock); +} + +struct ustcomm_sock * ustcomm_init_named_socket(const char *name, + int epoll_fd) +{ + int result; + int fd; + size_t sock_addr_size; + struct sockaddr_un * addr; + struct ustcomm_sock *sock; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if(fd == -1) { + PERROR("socket"); + return NULL; + } + + addr = create_sock_addr(name, &sock_addr_size); + if (addr == NULL) { + ERR("allocating addr, UST thread bailing"); + goto close_sock; + } + + result = access(name, F_OK); + if(result == 0) { + /* file exists */ + result = unlink(name); + if(result == -1) { + PERROR("unlink of socket file"); + goto free_addr; + } + DBG("socket already exists; overwriting"); + } + + result = bind(fd, (struct sockaddr *)addr, sock_addr_size); + if(result == -1) { + PERROR("bind"); + goto free_addr; + } + + result = listen(fd, 1); + if(result == -1) { + PERROR("listen"); + goto free_addr; + } + + sock = ustcomm_init_sock(fd, epoll_fd, + NULL); + if (!sock) { + ERR("failed to create ustcomm_sock"); + goto free_addr; + } + + free(addr); + + return sock; + +free_addr: + free(addr); +close_sock: + close(fd); + + return NULL; +} + +void ustcomm_del_named_sock(struct ustcomm_sock *sock, + int keep_socket_file) +{ + int result, fd; + struct stat st; + struct sockaddr dummy; + struct sockaddr_un *sockaddr = NULL; + int alloc_size; + + fd = sock->fd; + + if(!keep_socket_file) { + + /* Get the socket name */ + alloc_size = sizeof(dummy); + if (getsockname(fd, &dummy, (socklen_t *)&alloc_size) < 0) { + PERROR("getsockname failed"); + goto del_sock; + } + + sockaddr = zmalloc(alloc_size); + if (!sockaddr) { + ERR("failed to allocate sockaddr"); + goto del_sock; + } + + if (getsockname(fd, sockaddr, (socklen_t *)&alloc_size) < 0) { + PERROR("getsockname failed"); + goto free_sockaddr; + } + + /* Destroy socket */ + result = stat(sockaddr->sun_path, &st); + if(result < 0) { + PERROR("stat (%s)", sockaddr->sun_path); + goto free_sockaddr; + } + + /* Paranoid check before deleting. */ + result = S_ISSOCK(st.st_mode); + if(!result) { + ERR("The socket we are about to delete is not a socket."); + goto free_sockaddr; + } + + result = unlink(sockaddr->sun_path); + if(result < 0) { + PERROR("unlink"); + } + } + +free_sockaddr: + free(sockaddr); + +del_sock: + ustcomm_del_sock(sock, keep_socket_file); +} + +int ustcomm_recv_alloc(int sock, + struct ustcomm_header *header, + char **data) { + int result; + struct ustcomm_header peek_header; + struct iovec iov[2]; + struct msghdr msg; + + /* Just to make the caller fail hard */ + *data = NULL; + + result = recv(sock, &peek_header, sizeof(peek_header), + MSG_PEEK | MSG_WAITALL); + if (result <= 0) { + if(errno == ECONNRESET) { + return 0; + } else if (errno == EINTR) { + return -1; + } else if (result < 0) { + PERROR("recv"); + return -1; + } + return 0; + } + + memset(&msg, 0, sizeof(msg)); + + iov[0].iov_base = (char *)header; + iov[0].iov_len = sizeof(struct ustcomm_header); + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + if (peek_header.size) { + *data = zmalloc(peek_header.size); + if (!*data) { + return -ENOMEM; + } + + iov[1].iov_base = *data; + iov[1].iov_len = peek_header.size; + + msg.msg_iovlen++; + } + + result = recvmsg(sock, &msg, MSG_WAITALL); + if (result < 0) { + free(*data); + PERROR("recvmsg failed"); + } + + return result; +} + +/* returns 1 to indicate a message was received + * returns 0 to indicate no message was received (end of stream) + * returns -1 to indicate an error + */ +int ustcomm_recv_fd(int sock, + struct ustcomm_header *header, + char *data, int *fd) +{ + int result; + struct ustcomm_header peek_header; + struct iovec iov[2]; + struct msghdr msg; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(int))]; + + result = recv(sock, &peek_header, sizeof(peek_header), + MSG_PEEK | MSG_WAITALL); + if (result <= 0) { + if(errno == ECONNRESET) { + return 0; + } else if (errno == EINTR) { + return -1; + } else if (result < 0) { + PERROR("recv"); + return -1; + } + return 0; + } + + memset(&msg, 0, sizeof(msg)); + + iov[0].iov_base = (char *)header; + iov[0].iov_len = sizeof(struct ustcomm_header); + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + if (peek_header.size && data) { + if (peek_header.size < 0 || + peek_header.size > USTCOMM_DATA_SIZE) { + ERR("big peek header! %ld", peek_header.size); + return 0; + } + + iov[1].iov_base = data; + iov[1].iov_len = peek_header.size; + + msg.msg_iovlen++; + } + + if (fd && peek_header.fd_included) { + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + } + + result = recvmsg(sock, &msg, MSG_WAITALL); + if (result <= 0) { + if (result < 0) { + PERROR("recvmsg failed"); + } + return result; + } + + if (fd && peek_header.fd_included) { + cmsg = CMSG_FIRSTHDR(&msg); + result = 0; + while (cmsg != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == SCM_RIGHTS) { + *fd = *(int *) CMSG_DATA(cmsg); + result = 1; + break; + } + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + if (!result) { + ERR("Failed to receive file descriptor\n"); + } + } + + return 1; +} + +int ustcomm_recv(int sock, + struct ustcomm_header *header, + char *data) +{ + return ustcomm_recv_fd(sock, header, data, NULL); +} + + +int ustcomm_send_fd(int sock, + const struct ustcomm_header *header, + const char *data, + int *fd) +{ + struct iovec iov[2]; + struct msghdr msg; + int result; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(int))]; + + memset(&msg, 0, sizeof(msg)); + + iov[0].iov_base = (char *)header; + iov[0].iov_len = sizeof(struct ustcomm_header); + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + if (header->size && data) { + iov[1].iov_base = (char *)data; + iov[1].iov_len = header->size; + + msg.msg_iovlen++; + + } + + if (fd && header->fd_included) { + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + *(int *) CMSG_DATA(cmsg) = *fd; + msg.msg_controllen = cmsg->cmsg_len; + } + + result = sendmsg(sock, &msg, MSG_NOSIGNAL); + if (result < 0 && errno != EPIPE) { + PERROR("sendmsg failed"); + } + return result; +} + +int ustcomm_send(int sock, + const struct ustcomm_header *header, + const char *data) +{ + return ustcomm_send_fd(sock, header, data, NULL); +} + +int ustcomm_req(int sock, + const struct ustcomm_header *req_header, + const char *req_data, + struct ustcomm_header *res_header, + char *res_data) +{ + int result; + + result = ustcomm_send(sock, req_header, req_data); + if ( result <= 0) { + return result; + } + + return ustcomm_recv(sock, res_header, res_data); +} + +/* Return value: + * 0: success + * -1: error + */ + +int ustcomm_connect_path(const char *name, int *connection_fd) +{ + int result, fd; + size_t sock_addr_size; + struct sockaddr_un *addr; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if(fd == -1) { + PERROR("socket"); + return -1; + } + + addr = create_sock_addr(name, &sock_addr_size); + if (addr == NULL) { + ERR("allocating addr failed"); + goto close_sock; + } + + result = connect(fd, (struct sockaddr *)addr, sock_addr_size); + if(result == -1) { + PERROR("connect (path=%s)", name); + goto free_sock_addr; + } + + *connection_fd = fd; + + free(addr); + + return 0; + +free_sock_addr: + free(addr); +close_sock: + close(fd); + + return -1; +} + +/* Returns the current users socket directory, must be freed */ +char *ustcomm_user_sock_dir(void) +{ + int result; + char *sock_dir = NULL; + + result = asprintf(&sock_dir, "%s%s", USER_SOCK_DIR, + cuserid(NULL)); + if (result < 0) { + ERR("string overflow allocating directory name"); + return NULL; + } + + 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: + * 0: success + * -1: error + */ + +static int connect_app_non_root(pid_t pid, int *app_fd) +{ + int result; + int retval = 0; + char *dir_name; + char sock_name[PATH_MAX]; + + dir_name = ustcomm_user_sock_dir(); + if (!dir_name) + return -ENOMEM; + + if (ustcomm_get_sock_name(dir_name, pid, sock_name)) { + retval = -ENOENT; + goto free_dir_name; + } + + result = ustcomm_connect_path(sock_name, app_fd); + if (result < 0) { + ERR("failed to connect to app"); + retval = -1; + goto free_dir_name; + } + +free_dir_name: + free(dir_name); + + return retval; +} + + + +static int connect_app_root(pid_t pid, int *app_fd) +{ + DIR *tmp_dir; + struct dirent *dirent; + char dir_name[PATH_MAX], sock_name[PATH_MAX]; + int result = -1; + + tmp_dir = opendir(USER_TMP_DIR); + if (!tmp_dir) { + return -1; + } + + while ((dirent = readdir(tmp_dir))) { + if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE, + strlen(USER_SOCK_DIR_BASE))) { + + if (snprintf(dir_name, PATH_MAX - 1, "%s/%s", USER_TMP_DIR, + dirent->d_name) < 0) { + continue; + } + + if (ustcomm_get_sock_name(dir_name, pid, sock_name)) { + continue; + } + + result = ustcomm_connect_path(sock_name, app_fd); + + if (result == 0) { + goto close_tmp_dir; + } + } + } + +close_tmp_dir: + closedir(tmp_dir); + + return result; +} + +int ustcomm_connect_app(pid_t pid, int *app_fd) +{ + *app_fd = 0; + + if (geteuid()) { + return connect_app_non_root(pid, app_fd); + } else { + return connect_app_root(pid, app_fd); + } + +} + +int ensure_dir_exists(const char *dir, mode_t mode) +{ + struct stat st; + int result; + + if (!strcmp(dir, "")) + return -1; + + result = stat(dir, &st); + if (result < 0 && errno != ENOENT) { + return -1; + } else if (result < 0) { + /* ENOENT */ + int result; + + result = mkdir_p(dir, mode); + if(result != 0) { + ERR("executing in recursive creation of directory %s", dir); + return -1; + } + } else { + if (st.st_mode != mode) { + result = chmod(dir, mode); + if (result < 0) { + ERR("couldn't set directory mode on %s", dir); + return -1; + } + } + } + + return 0; +} + +char * ustcomm_print_data(char *data_field, int field_size, + int *offset, const char *format, ...) +{ + va_list args; + int count, limit; + char *ptr = USTCOMM_POISON_PTR; + + limit = field_size - *offset; + va_start(args, format); + count = vsnprintf(&data_field[*offset], limit, format, args); + va_end(args); + + if (count < limit && count > -1) { + ptr = NULL + *offset; + *offset = *offset + count + 1; + } + + return ptr; +} + +char * ustcomm_restore_ptr(char *ptr, char *data_field, int data_field_size) +{ + if ((unsigned long)ptr > data_field_size || + ptr == USTCOMM_POISON_PTR) { + return NULL; + } + + return data_field + (long)ptr; +} + +int ustcomm_pack_single_field(struct ustcomm_header *header, + struct ustcomm_single_field *single_field, + const char *string) +{ + int offset = 0; + + single_field->field = ustcomm_print_data(single_field->data, + sizeof(single_field->data), + &offset, + string); + + if (single_field->field == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + header->size = COMPUTE_MSG_SIZE(single_field, offset); + + return 0; +} + +int ustcomm_unpack_single_field(struct ustcomm_single_field *single_field) +{ + single_field->field = ustcomm_restore_ptr(single_field->field, + single_field->data, + sizeof(single_field->data)); + if (!single_field->field) { + return -EINVAL; + } + + return 0; +} + +int ustcomm_pack_channel_info(struct ustcomm_header *header, + struct ustcomm_channel_info *ch_inf, + const char *trace, + const char *channel) +{ + int offset = 0; + + ch_inf->trace = ustcomm_print_data(ch_inf->data, + sizeof(ch_inf->data), + &offset, + trace); + + if (ch_inf->trace == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + ch_inf->channel = ustcomm_print_data(ch_inf->data, + sizeof(ch_inf->data), + &offset, + channel); + + if (ch_inf->channel == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + header->size = COMPUTE_MSG_SIZE(ch_inf, offset); + + return 0; +} + + +int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf) +{ + ch_inf->trace = ustcomm_restore_ptr(ch_inf->trace, + ch_inf->data, + sizeof(ch_inf->data)); + if (!ch_inf->trace) { + return -EINVAL; + } + + ch_inf->channel = ustcomm_restore_ptr(ch_inf->channel, + ch_inf->data, + sizeof(ch_inf->data)); + if (!ch_inf->channel) { + return -EINVAL; + } + + return 0; +} + +int ustcomm_pack_buffer_info(struct ustcomm_header *header, + struct ustcomm_buffer_info *buf_inf, + const char *trace, + const char *channel, + int channel_cpu) +{ + int offset = 0; + + buf_inf->trace = ustcomm_print_data(buf_inf->data, + sizeof(buf_inf->data), + &offset, + trace); + + if (buf_inf->trace == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + buf_inf->channel = ustcomm_print_data(buf_inf->data, + sizeof(buf_inf->data), + &offset, + channel); + + if (buf_inf->channel == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + buf_inf->ch_cpu = channel_cpu; + + header->size = COMPUTE_MSG_SIZE(buf_inf, offset); + + return 0; +} + + +int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf) +{ + buf_inf->trace = ustcomm_restore_ptr(buf_inf->trace, + buf_inf->data, + sizeof(buf_inf->data)); + if (!buf_inf->trace) { + return -EINVAL; + } + + buf_inf->channel = ustcomm_restore_ptr(buf_inf->channel, + buf_inf->data, + sizeof(buf_inf->data)); + if (!buf_inf->channel) { + return -EINVAL; + } + + return 0; +} + +int ustcomm_pack_ust_marker_info(struct ustcomm_header *header, + struct ustcomm_ust_marker_info *ust_marker_inf, + const char *trace, + const char *channel, + const char *ust_marker) +{ + int offset = 0; + + ust_marker_inf->trace = ustcomm_print_data(ust_marker_inf->data, + sizeof(ust_marker_inf->data), + &offset, + trace); + + if (ust_marker_inf->trace == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + + ust_marker_inf->channel = ustcomm_print_data(ust_marker_inf->data, + sizeof(ust_marker_inf->data), + &offset, + channel); + + if (ust_marker_inf->channel == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + + ust_marker_inf->ust_marker = ustcomm_print_data(ust_marker_inf->data, + sizeof(ust_marker_inf->data), + &offset, + ust_marker); + + if (ust_marker_inf->ust_marker == USTCOMM_POISON_PTR) { + return -ENOMEM; + } + + header->size = COMPUTE_MSG_SIZE(ust_marker_inf, offset); + + return 0; +} + +int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info *ust_marker_inf) +{ + ust_marker_inf->trace = ustcomm_restore_ptr(ust_marker_inf->trace, + ust_marker_inf->data, + sizeof(ust_marker_inf->data)); + if (!ust_marker_inf->trace) { + return -EINVAL; + } + + ust_marker_inf->channel = ustcomm_restore_ptr(ust_marker_inf->channel, + ust_marker_inf->data, + sizeof(ust_marker_inf->data)); + if (!ust_marker_inf->channel) { + return -EINVAL; + } + + ust_marker_inf->ust_marker = ustcomm_restore_ptr(ust_marker_inf->ust_marker, + ust_marker_inf->data, + sizeof(ust_marker_inf->data)); + if (!ust_marker_inf->ust_marker) { + return -EINVAL; + } + + return 0; +} + diff --git a/deprecated/libustcomm/ustcomm.h b/deprecated/libustcomm/ustcomm.h new file mode 100644 index 00000000..4706b72f --- /dev/null +++ b/deprecated/libustcomm/ustcomm.h @@ -0,0 +1,220 @@ +/* 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 USTCOMM_H +#define USTCOMM_H + +#include +#include +#include + +#include + +#define SOCK_DIR "/tmp/ust-app-socks" +#define USER_TMP_DIR "/tmp" +#define USER_SOCK_DIR_BASE "ust-socks-" +#define USER_SOCK_DIR USER_TMP_DIR "/" USER_SOCK_DIR_BASE + +struct ustcomm_sock { + struct cds_list_head list; + int fd; + int epoll_fd; +}; + +struct ustcomm_header { + int command; + long size; + int result; + int fd_included; +}; + +#define USTCOMM_BUFFER_SIZE ((1 << 12) - sizeof(struct ustcomm_header)) + +/* Specify a sata size that leaves margin at the end of a buffer + * in order to make sure that we never have more data than + * will fit in the buffer AND that the last chars (due to a + * pre-receive memset) will always be 0, terminating any string + */ +#define USTCOMM_DATA_SIZE (USTCOMM_BUFFER_SIZE - 20 * sizeof(void *)) + +enum tracectl_commands { + ALLOC_TRACE, + CONSUME_BUFFER, + CREATE_TRACE, + DESTROY_TRACE, + DISABLE_MARKER, + ENABLE_MARKER, + EXIT, + FORCE_SUBBUF_SWITCH, + GET_BUF_SHMID_PIPE_FD, + GET_PIDUNIQUE, + GET_SOCK_PATH, + GET_SUBBUFFER, + GET_SUBBUF_NUM_SIZE, + LIST_MARKERS, + LIST_TRACE_EVENTS, + LOAD_PROBE_LIB, + NOTIFY_BUF_MAPPED, + PRINT_MARKERS, + PRINT_TRACE_EVENTS, + PUT_SUBBUFFER, + SETUP_TRACE, + SET_SOCK_PATH, + SET_SUBBUF_NUM, + SET_SUBBUF_SIZE, + START, + START_TRACE, + STOP_TRACE, +}; + +struct ustcomm_single_field { + char *field; + char data[USTCOMM_DATA_SIZE]; +}; + +struct ustcomm_channel_info { + char *trace; + char *channel; + unsigned int subbuf_size; + unsigned int subbuf_num; + char data[USTCOMM_DATA_SIZE]; +}; + +struct ustcomm_buffer_info { + char *trace; + char *channel; + int ch_cpu; + pid_t pid; + int buf_shmid; + int buf_struct_shmid; + long consumed_old; + char data[USTCOMM_DATA_SIZE]; +}; + +struct ustcomm_ust_marker_info { + char *trace; + char *channel; + char *ust_marker; + char data[USTCOMM_DATA_SIZE]; +}; + +struct ustcomm_pidunique { + s64 pidunique; +}; + +struct ustcomm_notify_buf_mapped { + char data[USTCOMM_DATA_SIZE]; +}; + +/* Ensure directory existence, usefull for unix sockets */ +extern int ensure_dir_exists(const char *dir, mode_t mode); + +/* Create and delete sockets */ +extern struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd, + struct cds_list_head *list); +extern void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll); + +/* Create and delete named sockets */ +extern struct ustcomm_sock * ustcomm_init_named_socket(const char *name, + int epoll_fd); +extern void ustcomm_del_named_sock(struct ustcomm_sock *sock, + int keep_socket_file); + +/* Send and receive functions for file descriptors */ +extern int ustcomm_send_fd(int sock, const struct ustcomm_header *header, + const char *data, int *fd); +extern int ustcomm_recv_fd(int sock, struct ustcomm_header *header, + char *data, int *fd); + +/* Normal send and receive functions */ +extern int ustcomm_send(int sock, const struct ustcomm_header *header, + const char *data); +extern int ustcomm_recv(int sock, struct ustcomm_header *header, + char *data); + +/* Receive and allocate data, not to be used inside libust */ +extern int ustcomm_recv_alloc(int sock, + struct ustcomm_header *header, + char **data); + +/* Request function, send and receive */ +extern int ustcomm_req(int sock, + const struct ustcomm_header *req_header, + const char *req_data, + struct ustcomm_header *res_header, + char *res_data); + +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); + +extern int nth_token_is(const char *str, const char *token, int tok_no); + +extern char *nth_token(const char *str, int tok_no); + +/* String serialising functions, printf straight into a buffer */ +#define USTCOMM_POISON_PTR (void *)0x19831018 + +extern char * ustcomm_print_data(char *data_field, int field_size, + int *offset, const char *format, ...); +extern char * ustcomm_restore_ptr(char *ptr, char *data_field, + int data_field_size); + +#define COMPUTE_MSG_SIZE(struct_ptr, offset) \ + (size_t) (long)(struct_ptr)->data - (long)(struct_ptr) + (offset) + +/* Packing and unpacking functions, making life easier */ +extern int ustcomm_pack_single_field(struct ustcomm_header *header, + struct ustcomm_single_field *sf, + const char *trace); + +extern int ustcomm_unpack_single_field(struct ustcomm_single_field *sf); + +extern int ustcomm_pack_channel_info(struct ustcomm_header *header, + struct ustcomm_channel_info *ch_inf, + const char *trace, + const char *channel); + +extern int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf); + +extern int ustcomm_pack_buffer_info(struct ustcomm_header *header, + struct ustcomm_buffer_info *buf_inf, + const char *trace, + const char *channel, + int channel_cpu); + +extern int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf); + +extern int ustcomm_pack_ust_marker_info(struct ustcomm_header *header, + struct ustcomm_ust_marker_info *ust_marker_inf, + const char *trace, + const char *channel, + const char *ust_marker); + +extern int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info *ust_marker_inf); + +#endif /* USTCOMM_H */ diff --git a/deprecated/libustconsumer/Makefile.am b/deprecated/libustconsumer/Makefile.am new file mode 100644 index 00000000..1f874797 --- /dev/null +++ b/deprecated/libustconsumer/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \ + -I$(top_srcdir)/include +AM_CFLAGS = -fno-strict-aliasing + +lib_LTLIBRARIES = libustconsumer.la + +libustconsumer_la_SOURCES = libustconsumer.c lowlevel.c lowlevel.h + +libustconsumer_la_LDFLAGS = -no-undefined -version-info 0:0:0 + +libustconsumer_la_LIBADD = \ + -lpthread \ + $(top_builddir)/snprintf/libustsnprintf.la \ + $(top_builddir)/libustcomm/libustcomm.la + +libustconsumer_la_CFLAGS = -fno-strict-aliasing diff --git a/deprecated/libustconsumer/libustconsumer.c b/deprecated/libustconsumer/libustconsumer.c new file mode 100644 index 00000000..c6dd20c3 --- /dev/null +++ b/deprecated/libustconsumer/libustconsumer.c @@ -0,0 +1,923 @@ +/* Copyright (C) 2009 Pierre-Marc Fournier + * 2010 Alexis Halle + * + * 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 +#include +#include +#include +#include + +#include +#include "lowlevel.h" +#include "usterr_signal_safe.h" +#include "ustcomm.h" + +#define GET_SUBBUF_OK 1 +#define GET_SUBBUF_DONE 0 +#define GET_SUBBUF_DIED 2 + +#define PUT_SUBBUF_OK 1 +#define PUT_SUBBUF_DIED 0 +#define PUT_SUBBUF_PUSHED 2 +#define PUT_SUBBUF_DONE 3 + +#define UNIX_PATH_MAX 108 + +static int get_subbuffer(struct buffer_info *buf) +{ + struct ustcomm_header _send_hdr, *send_hdr; + struct ustcomm_header _recv_hdr, *recv_hdr; + struct ustcomm_buffer_info _send_msg, _recv_msg; + struct ustcomm_buffer_info *send_msg, *recv_msg; + int result; + + send_hdr = &_send_hdr; + recv_hdr = &_recv_hdr; + send_msg = &_send_msg; + recv_msg = &_recv_msg; + + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, + buf->channel, buf->channel_cpu); + if (result < 0) { + return result; + } + + send_hdr->command = GET_SUBBUFFER; + + result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg, + recv_hdr, (char *)recv_msg); + if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) || + result == 0) { + DBG("app died while being traced"); + return GET_SUBBUF_DIED; + } else if (result < 0) { + ERR("get_subbuffer: ustcomm_req failed"); + return result; + } + + if (!recv_hdr->result) { + DBG("got subbuffer %s", buf->name); + buf->consumed_old = recv_msg->consumed_old; + return GET_SUBBUF_OK; + } else if (recv_hdr->result == -ENODATA) { + DBG("For buffer %s, the trace was not found. This likely means" + " it was destroyed by the user.", buf->name); + return GET_SUBBUF_DIED; + } + + DBG("error getting subbuffer %s", buf->name); + return recv_hdr->result; +} + +static int put_subbuffer(struct buffer_info *buf) +{ + struct ustcomm_header _send_hdr, *send_hdr; + struct ustcomm_header _recv_hdr, *recv_hdr; + struct ustcomm_buffer_info _send_msg, *send_msg; + int result; + + send_hdr = &_send_hdr; + recv_hdr = &_recv_hdr; + send_msg = &_send_msg; + + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, + buf->channel, buf->channel_cpu); + if (result < 0) { + return result; + } + + send_hdr->command = PUT_SUBBUFFER; + send_msg->consumed_old = buf->consumed_old; + + result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg, + recv_hdr, NULL); + if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) || + result == 0) { + DBG("app died while being traced"); + return PUT_SUBBUF_DIED; + } else if (result < 0) { + ERR("put_subbuffer: ustcomm_req failed"); + return result; + } + + if (!recv_hdr->result) { + DBG("put subbuffer %s", buf->name); + return PUT_SUBBUF_OK; + } else if (recv_hdr->result == -ENODATA) { + DBG("For buffer %s, the trace was not found. This likely means" + " it was destroyed by the user.", buf->name); + return PUT_SUBBUF_DIED; + } + + DBG("error getting subbuffer %s", buf->name); + return recv_hdr->result; +} + +void decrement_active_buffers(void *arg) +{ + struct ustconsumer_instance *instance = arg; + pthread_mutex_lock(&instance->mutex); + instance->active_buffers--; + pthread_mutex_unlock(&instance->mutex); +} + +static int get_pidunique(int sock, int64_t *pidunique) +{ + struct ustcomm_header _send_hdr, *send_hdr; + struct ustcomm_header _recv_hdr, *recv_hdr; + struct ustcomm_pidunique _recv_msg, *recv_msg; + int result; + + send_hdr = &_send_hdr; + recv_hdr = &_recv_hdr; + recv_msg = &_recv_msg; + + memset(send_hdr, 0, sizeof(*send_hdr)); + + send_hdr->command = GET_PIDUNIQUE; + result = ustcomm_req(sock, send_hdr, NULL, recv_hdr, (char *)recv_msg); + if (result < 1) { + return -ENOTCONN; + } + if (recv_hdr->result < 0) { + ERR("App responded with error: %s", strerror(recv_hdr->result)); + return recv_hdr->result; + } + + *pidunique = recv_msg->pidunique; + + return 0; +} + +static int get_buf_shmid_pipe_fd(int sock, struct buffer_info *buf, + int *buf_shmid, int *buf_struct_shmid, + int *buf_pipe_fd) +{ + struct ustcomm_header _send_hdr, *send_hdr; + struct ustcomm_header _recv_hdr, *recv_hdr; + struct ustcomm_buffer_info _send_msg, *send_msg; + struct ustcomm_buffer_info _recv_msg, *recv_msg; + int result, recv_pipe_fd; + + send_hdr = &_send_hdr; + recv_hdr = &_recv_hdr; + send_msg = &_send_msg; + recv_msg = &_recv_msg; + + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, + buf->channel, buf->channel_cpu); + if (result < 0) { + ERR("Failed to pack buffer info"); + return result; + } + + send_hdr->command = GET_BUF_SHMID_PIPE_FD; + + result = ustcomm_send(sock, send_hdr, (char *)send_msg); + if (result < 1) { + ERR("Failed to send request"); + return -ENOTCONN; + } + result = ustcomm_recv_fd(sock, recv_hdr, (char *)recv_msg, &recv_pipe_fd); + if (result < 1) { + ERR("Failed to receive message and fd"); + return -ENOTCONN; + } + if (recv_hdr->result < 0) { + ERR("App responded with error %s", strerror(recv_hdr->result)); + return recv_hdr->result; + } + + *buf_shmid = recv_msg->buf_shmid; + *buf_struct_shmid = recv_msg->buf_struct_shmid; + *buf_pipe_fd = recv_pipe_fd; + + return 0; +} + +static int get_subbuf_num_size(int sock, struct buffer_info *buf, + int *subbuf_num, int *subbuf_size) +{ + struct ustcomm_header _send_hdr, *send_hdr; + struct ustcomm_header _recv_hdr, *recv_hdr; + struct ustcomm_channel_info _send_msg, *send_msg; + struct ustcomm_channel_info _recv_msg, *recv_msg; + int result; + + send_hdr = &_send_hdr; + recv_hdr = &_recv_hdr; + send_msg = &_send_msg; + recv_msg = &_recv_msg; + + result = ustcomm_pack_channel_info(send_hdr, send_msg, buf->trace, + buf->channel); + if (result < 0) { + return result; + } + + send_hdr->command = GET_SUBBUF_NUM_SIZE; + + result = ustcomm_req(sock, send_hdr, (char *)send_msg, + recv_hdr, (char *)recv_msg); + if (result < 1) { + return -ENOTCONN; + } + + *subbuf_num = recv_msg->subbuf_num; + *subbuf_size = recv_msg->subbuf_size; + + return recv_hdr->result; +} + + +static int notify_buffer_mapped(int sock, struct buffer_info *buf) +{ + struct ustcomm_header _send_hdr, *send_hdr; + struct ustcomm_header _recv_hdr, *recv_hdr; + struct ustcomm_buffer_info _send_msg, *send_msg; + int result; + + send_hdr = &_send_hdr; + recv_hdr = &_recv_hdr; + send_msg = &_send_msg; + + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, + buf->channel, buf->channel_cpu); + if (result < 0) { + return result; + } + + send_hdr->command = NOTIFY_BUF_MAPPED; + + result = ustcomm_req(sock, send_hdr, (char *)send_msg, + recv_hdr, NULL); + if (result < 1) { + return -ENOTCONN; + } + + return recv_hdr->result; +} + + +struct buffer_info *connect_buffer(struct ustconsumer_instance *instance, pid_t pid, + const char *trace, const char *channel, + int channel_cpu) +{ + struct buffer_info *buf; + int result; + struct shmid_ds shmds; + + buf = (struct buffer_info *) zmalloc(sizeof(struct buffer_info)); + if(buf == NULL) { + ERR("add_buffer: insufficient memory"); + return NULL; + } + + buf->trace = strdup(trace); + if (!buf->trace) { + goto free_buf; + } + + buf->channel = strdup(channel); + if (!buf->channel) { + goto free_buf_trace; + } + + result = asprintf(&buf->name, "%s_%d", channel, channel_cpu); + if (result < 0 || buf->name == NULL) { + goto free_buf_channel; + } + + buf->channel_cpu = channel_cpu; + buf->pid = pid; + + result = ustcomm_connect_app(buf->pid, &buf->app_sock); + if(result) { + WARN("unable to connect to process, it probably died before we were able to connect"); + goto free_buf_name; + } + + /* get pidunique */ + result = get_pidunique(buf->app_sock, &buf->pidunique); + if (result < 0) { + ERR("Failed to get pidunique"); + goto close_app_sock; + } + + /* get shmid and pipe fd */ + result = get_buf_shmid_pipe_fd(buf->app_sock, buf, &buf->shmid, + &buf->bufstruct_shmid, &buf->pipe_fd); + if (result < 0) { + ERR("Failed to get buf_shmid and pipe_fd"); + goto close_app_sock; + } else { + struct stat temp; + fstat(buf->pipe_fd, &temp); + if (!S_ISFIFO(temp.st_mode)) { + ERR("Didn't receive a fifo from the app"); + goto close_app_sock; + } + } + + + /* get number of subbufs and subbuf size */ + result = get_subbuf_num_size(buf->app_sock, buf, &buf->n_subbufs, + &buf->subbuf_size); + if (result < 0) { + ERR("Failed to get subbuf number and size"); + goto close_fifo; + } + + /* Set subbuffer's information */ + buf->subbuf_size_order = get_count_order(buf->subbuf_size); + buf->alloc_size = buf->subbuf_size * buf->n_subbufs; + + /* attach memory */ + buf->mem = shmat(buf->shmid, NULL, 0); + if(buf->mem == (void *) 0) { + PERROR("shmat"); + goto close_fifo; + } + DBG("successfully attached buffer memory"); + + buf->bufstruct_mem = shmat(buf->bufstruct_shmid, NULL, 0); + if(buf->bufstruct_mem == (void *) 0) { + PERROR("shmat"); + goto shmdt_mem; + } + DBG("successfully attached buffer bufstruct memory"); + + /* obtain info on the memory segment */ + result = shmctl(buf->shmid, IPC_STAT, &shmds); + if(result == -1) { + PERROR("shmctl"); + goto shmdt_bufstruct_mem; + } + buf->memlen = shmds.shm_segsz; + + /* Notify the application that we have mapped the buffer */ + result = notify_buffer_mapped(buf->app_sock, buf); + if (result < 0) { + goto shmdt_bufstruct_mem; + } + + if(instance->callbacks->on_open_buffer) + instance->callbacks->on_open_buffer(instance->callbacks, buf); + + pthread_mutex_lock(&instance->mutex); + instance->active_buffers++; + pthread_mutex_unlock(&instance->mutex); + + return buf; + +shmdt_bufstruct_mem: + shmdt(buf->bufstruct_mem); + +shmdt_mem: + shmdt(buf->mem); + +close_fifo: + close(buf->pipe_fd); + +close_app_sock: + close(buf->app_sock); + +free_buf_name: + free(buf->name); + +free_buf_channel: + free(buf->channel); + +free_buf_trace: + free(buf->trace); + +free_buf: + free(buf); + return NULL; +} + +static void destroy_buffer(struct ustconsumer_callbacks *callbacks, + struct buffer_info *buf) +{ + int result; + + result = close(buf->pipe_fd); + if(result == -1) { + WARN("problem closing the pipe fd"); + } + + result = close(buf->app_sock); + if(result == -1) { + WARN("problem calling ustcomm_close_app"); + } + + result = shmdt(buf->mem); + if(result == -1) { + PERROR("shmdt"); + } + + result = shmdt(buf->bufstruct_mem); + if(result == -1) { + PERROR("shmdt"); + } + + if(callbacks->on_close_buffer) + callbacks->on_close_buffer(callbacks, buf); + + free(buf); +} + +int consumer_loop(struct ustconsumer_instance *instance, struct buffer_info *buf) +{ + int result = 0; + int read_result; + char read_buf; + + pthread_cleanup_push(decrement_active_buffers, instance); + + for(;;) { + read_result = read(buf->pipe_fd, &read_buf, 1); + /* get the subbuffer */ + if (read_result == 1) { + result = get_subbuffer(buf); + if (result < 0) { + ERR("error getting subbuffer"); + continue; + } else if (result == GET_SUBBUF_DIED) { + finish_consuming_dead_subbuffer(instance->callbacks, buf); + break; + } + } else if ((read_result == -1 && (errno == ECONNRESET || errno == EPIPE)) || + result == 0) { + DBG("App died while being traced"); + finish_consuming_dead_subbuffer(instance->callbacks, buf); + break; + } else if (read_result == -1 && errno == EINTR) { + continue; + } + + if(instance->callbacks->on_read_subbuffer) + instance->callbacks->on_read_subbuffer(instance->callbacks, buf); + + /* put the subbuffer */ + result = put_subbuffer(buf); + if(result == -1) { + ERR("unknown error putting subbuffer (channel=%s)", buf->name); + break; + } + else if(result == PUT_SUBBUF_PUSHED) { + ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name); + break; + } + else if(result == PUT_SUBBUF_DIED) { + DBG("application died while putting subbuffer"); + /* Skip the first subbuffer. We are not sure it is trustable + * because the put_subbuffer() did not complete. + */ + /* TODO: check on_put_error return value */ + if(instance->callbacks->on_put_error) + instance->callbacks->on_put_error(instance->callbacks, buf); + + finish_consuming_dead_subbuffer(instance->callbacks, buf); + break; + } + else if(result == PUT_SUBBUF_DONE) { + /* Done with this subbuffer */ + /* FIXME: add a case where this branch is used? Upon + * normal trace termination, at put_subbuf time, a + * special last-subbuffer code could be returned by + * the listener. + */ + break; + } + else if(result == PUT_SUBBUF_OK) { + } + } + + DBG("thread for buffer %s is stopping", buf->name); + + /* FIXME: destroy, unalloc... */ + + pthread_cleanup_pop(1); + + return 0; +} + +struct consumer_thread_args { + pid_t pid; + const char *trace; + const char *channel; + int channel_cpu; + struct ustconsumer_instance *instance; +}; + +void *consumer_thread(void *arg) +{ + struct buffer_info *buf; + struct consumer_thread_args *args = (struct consumer_thread_args *) arg; + int result; + sigset_t sigset; + + pthread_mutex_lock(&args->instance->mutex); + args->instance->active_threads++; + pthread_mutex_unlock(&args->instance->mutex); + + if(args->instance->callbacks->on_new_thread) + args->instance->callbacks->on_new_thread(args->instance->callbacks); + + /* Block signals that should be handled by the main thread. */ + result = sigemptyset(&sigset); + if(result == -1) { + PERROR("sigemptyset"); + goto end; + } + result = sigaddset(&sigset, SIGTERM); + if(result == -1) { + PERROR("sigaddset"); + goto end; + } + result = sigaddset(&sigset, SIGINT); + if(result == -1) { + PERROR("sigaddset"); + goto end; + } + result = sigprocmask(SIG_BLOCK, &sigset, NULL); + if(result == -1) { + PERROR("sigprocmask"); + goto end; + } + + buf = connect_buffer(args->instance, args->pid, args->trace, + args->channel, args->channel_cpu); + if(buf == NULL) { + ERR("failed to connect to buffer"); + goto end; + } + + consumer_loop(args->instance, buf); + + destroy_buffer(args->instance->callbacks, buf); + + end: + + if(args->instance->callbacks->on_close_thread) + args->instance->callbacks->on_close_thread(args->instance->callbacks); + + pthread_mutex_lock(&args->instance->mutex); + args->instance->active_threads--; + pthread_mutex_unlock(&args->instance->mutex); + + free((void *)args->channel); + free(args); + return NULL; +} + +int start_consuming_buffer(struct ustconsumer_instance *instance, pid_t pid, + const char *trace, const char *channel, + int channel_cpu) +{ + pthread_t thr; + struct consumer_thread_args *args; + int result; + + DBG("beginning of start_consuming_buffer: args: pid %d bufname %s_%d", pid, channel, + channel_cpu); + + args = (struct consumer_thread_args *) zmalloc(sizeof(struct consumer_thread_args)); + if (!args) { + return -ENOMEM; + } + + args->pid = pid; + args->trace = strdup(trace); + args->channel = strdup(channel); + args->channel_cpu = channel_cpu; + args->instance = instance; + DBG("beginning2 of start_consuming_buffer: args: pid %d trace %s" + " bufname %s_%d", args->pid, args->trace, args->channel, args->channel_cpu); + + result = pthread_create(&thr, NULL, consumer_thread, args); + if(result == -1) { + ERR("pthread_create failed"); + return -1; + } + result = pthread_detach(thr); + if(result == -1) { + ERR("pthread_detach failed"); + return -1; + } + DBG("end of start_consuming_buffer: args: pid %d trace %s " + "bufname %s_%d", args->pid, args->channel, args->trace, args->channel_cpu); + + return 0; +} +static void process_client_cmd(int sock, struct ustcomm_header *req_header, + char *recvbuf, struct ustconsumer_instance *instance) +{ + int result; + struct ustcomm_header _res_header = {0}; + struct ustcomm_header *res_header = &_res_header; + struct ustcomm_buffer_info *buf_inf; + + DBG("Processing client command"); + + switch (req_header->command) { + case CONSUME_BUFFER: + + buf_inf = (struct ustcomm_buffer_info *)recvbuf; + result = ustcomm_unpack_buffer_info(buf_inf); + if (result < 0) { + ERR("Couldn't unpack buffer info"); + return; + } + + DBG("Going to consume trace %s buffer %s_%d in process %d", + buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu, + buf_inf->pid); + result = start_consuming_buffer(instance, buf_inf->pid, + buf_inf->trace, + buf_inf->channel, + buf_inf->ch_cpu); + if (result < 0) { + ERR("error in add_buffer"); + return; + } + + res_header->result = 0; + break; + case EXIT: + res_header->result = 0; + /* Only there to force poll to return */ + break; + default: + res_header->result = -EINVAL; + WARN("unknown command: %d", req_header->command); + } + + if (ustcomm_send(sock, res_header, NULL) <= 0) { + ERR("couldn't send command response"); + } +} + +#define MAX_EVENTS 10 + +int ustconsumer_start_instance(struct ustconsumer_instance *instance) +{ + struct ustcomm_header recv_hdr; + char recv_buf[USTCOMM_BUFFER_SIZE]; + struct ustcomm_sock *epoll_sock; + struct epoll_event events[MAX_EVENTS]; + struct sockaddr addr; + int result, epoll_fd, accept_fd, nfds, i, addr_size, timeout; + + if(!instance->is_init) { + ERR("libustconsumer instance not initialized"); + return 1; + } + epoll_fd = instance->epoll_fd; + + timeout = -1; + + /* app loop */ + for(;;) { + nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout); + if (nfds == -1 && errno == EINTR) { + /* Caught signal */ + } else if (nfds == -1) { + PERROR("ustconsumer_start_instance: epoll_wait failed"); + continue; + } + + for (i = 0; i < nfds; ++i) { + epoll_sock = (struct ustcomm_sock *)events[i].data.ptr; + if (epoll_sock == instance->listen_sock) { + addr_size = sizeof(struct sockaddr); + accept_fd = accept(epoll_sock->fd, + &addr, + (socklen_t *)&addr_size); + if (accept_fd == -1) { + PERROR("ustconsumer_start_instance: " + "accept failed"); + continue; + } + ustcomm_init_sock(accept_fd, epoll_fd, + &instance->connections); + } else { + result = ustcomm_recv(epoll_sock->fd, &recv_hdr, + recv_buf); + if (result < 1) { + ustcomm_del_sock(epoll_sock, 0); + } else { + process_client_cmd(epoll_sock->fd, + &recv_hdr, recv_buf, + instance); + } + + } + } + + if (instance->quit_program) { + pthread_mutex_lock(&instance->mutex); + if (instance->active_buffers == 0 && instance->active_threads == 0) { + pthread_mutex_unlock(&instance->mutex); + break; + } + pthread_mutex_unlock(&instance->mutex); + timeout = 100; + } + } + + if(instance->callbacks->on_trace_end) + instance->callbacks->on_trace_end(instance); + + ustconsumer_delete_instance(instance); + + return 0; +} + +/* FIXME: threads and connections !? */ +void ustconsumer_delete_instance(struct ustconsumer_instance *instance) +{ + if (instance->is_init) { + ustcomm_del_named_sock(instance->listen_sock, 0); + close(instance->epoll_fd); + } + + pthread_mutex_destroy(&instance->mutex); + free(instance->sock_path); + free(instance); +} + +/* FIXME: Do something about the fixed path length, maybe get rid + * of the whole concept and use a pipe? + */ +int ustconsumer_stop_instance(struct ustconsumer_instance *instance, int send_msg) +{ + int result; + int fd; + int bytes = 0; + + char msg[] = "exit"; + + instance->quit_program = 1; + + if(!send_msg) + return 0; + + /* Send a message through the socket to force poll to return */ + + struct sockaddr_un addr; + +socket_again: + result = fd = socket(PF_UNIX, SOCK_STREAM, 0); + if(result == -1) { + if (errno == EINTR) + goto socket_again; + PERROR("socket"); + return 1; + } + + addr.sun_family = AF_UNIX; + + strncpy(addr.sun_path, instance->sock_path, UNIX_PATH_MAX); + addr.sun_path[UNIX_PATH_MAX-1] = '\0'; + +connect_again: + result = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if(result == -1) { + if (errno == EINTR) + goto connect_again; + PERROR("connect"); + } + + while(bytes != sizeof(msg)) { + int inc = send(fd, msg, sizeof(msg), 0); + if (inc < 0 && errno != EINTR) + break; + else + bytes += inc; + } + + close(fd); + + return 0; +} + +struct ustconsumer_instance +*ustconsumer_new_instance(struct ustconsumer_callbacks *callbacks, + char *sock_path) +{ + struct ustconsumer_instance *instance = + zmalloc(sizeof(struct ustconsumer_instance)); + if(!instance) { + return NULL; + } + + instance->callbacks = callbacks; + instance->quit_program = 0; + instance->is_init = 0; + instance->active_buffers = 0; + pthread_mutex_init(&instance->mutex, NULL); + + if (sock_path) { + instance->sock_path = strdup(sock_path); + } else { + instance->sock_path = NULL; + } + + return instance; +} + +static int init_ustconsumer_socket(struct ustconsumer_instance *instance) +{ + char *name; + + if (instance->sock_path) { + if (asprintf(&name, "%s", instance->sock_path) < 0) { + ERR("ustcomm_init_ustconsumer : asprintf failed (sock_path %s)", + instance->sock_path); + return -1; + } + } else { + int result; + + /* Only check if socket dir exists if we are using the default directory */ + result = ensure_dir_exists(SOCK_DIR, S_IRWXU | S_IRWXG | S_IRWXO); + if (result == -1) { + ERR("Unable to create socket directory %s", SOCK_DIR); + return -1; + } + + if (asprintf(&name, "%s/%s", SOCK_DIR, "ustconsumer") < 0) { + ERR("ustcomm_init_ustconsumer : asprintf failed (%s/ustconsumer)", + SOCK_DIR); + return -1; + } + } + + /* Set up epoll */ + instance->epoll_fd = epoll_create(MAX_EVENTS); + if (instance->epoll_fd == -1) { + ERR("epoll_create failed, start instance bailing"); + goto free_name; + } + + /* Create the named socket */ + instance->listen_sock = ustcomm_init_named_socket(name, + instance->epoll_fd); + if(!instance->listen_sock) { + ERR("error initializing named socket at %s", name); + goto close_epoll; + } + + CDS_INIT_LIST_HEAD(&instance->connections); + + free(name); + + return 0; + +close_epoll: + close(instance->epoll_fd); +free_name: + free(name); + + return -1; +} + +int ustconsumer_init_instance(struct ustconsumer_instance *instance) +{ + int result; + result = init_ustconsumer_socket(instance); + if(result == -1) { + ERR("failed to initialize socket"); + return 1; + } + instance->is_init = 1; + return 0; +} + diff --git a/deprecated/libustconsumer/lowlevel.c b/deprecated/libustconsumer/lowlevel.c new file mode 100644 index 00000000..a54a8db0 --- /dev/null +++ b/deprecated/libustconsumer/lowlevel.c @@ -0,0 +1,207 @@ +/* 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 + */ + +#include +#include +#include + +#include "ust/ustconsumer.h" +#include "buffers.h" +#include "tracer.h" +#include "usterr_signal_safe.h" + +/* This truncates to an offset in the buffer. */ +#define USTD_BUFFER_TRUNC(offset, bufinfo) \ + ((offset) & (~(((bufinfo)->subbuf_size*(bufinfo)->n_subbufs)-1))) + +#define LTT_MAGIC_NUMBER 0x00D6B7ED +#define LTT_REV_MAGIC_NUMBER 0xEDB7D600 + + +static void ltt_relay_print_subbuffer_errors( + struct buffer_info *buf, + long cons_off, int cpu) +{ + struct ust_buffer *ust_buf = buf->bufstruct_mem; + long cons_idx, commit_count, commit_count_mask, write_offset; + + cons_idx = SUBBUF_INDEX(cons_off, buf); + commit_count = uatomic_read(&ust_buf->commit_seq[cons_idx]); + commit_count_mask = (~0UL >> get_count_order(buf->n_subbufs)); + + /* + * No need to order commit_count and write_offset reads because we + * execute after trace is stopped when there are no readers left. + */ + write_offset = uatomic_read(&ust_buf->offset); + WARN( "LTT : unread channel %s offset is %ld " + "and cons_off : %ld (cpu %d)\n", + buf->channel, write_offset, cons_off, cpu); + /* Check each sub-buffer for non filled commit count */ + if (((commit_count - buf->subbuf_size) & commit_count_mask) + - (BUFFER_TRUNC(cons_off, buf) >> get_count_order(buf->n_subbufs)) != 0) { + ERR("LTT : %s : subbuffer %lu has non filled " + "commit count [seq] [%lu].\n", + buf->channel, cons_idx, commit_count); + } + ERR("LTT : %s : commit count : %lu, subbuf size %d\n", + buf->channel, commit_count, + buf->subbuf_size); +} + +static void ltt_relay_print_errors(struct buffer_info *buf, int cpu) +{ + struct ust_buffer *ust_buf = buf->bufstruct_mem; + long cons_off; + + for (cons_off = uatomic_read(&ust_buf->consumed); + (SUBBUF_TRUNC(uatomic_read(&ust_buf->offset), buf) + - cons_off) > 0; + cons_off = SUBBUF_ALIGN(cons_off, buf)) + ltt_relay_print_subbuffer_errors(buf, cons_off, cpu); +} + +static void ltt_relay_print_buffer_errors(struct buffer_info *buf, int cpu) +{ + struct ust_buffer *ust_buf = buf->bufstruct_mem; + + if (uatomic_read(&ust_buf->events_lost)) + ERR("channel %s: %ld events lost (cpu %d)", + buf->channel, + uatomic_read(&ust_buf->events_lost), cpu); + if (uatomic_read(&ust_buf->corrupted_subbuffers)) + ERR("channel %s : %ld corrupted subbuffers (cpu %d)", + buf->channel, + uatomic_read(&ust_buf->corrupted_subbuffers), cpu); + + ltt_relay_print_errors(buf, cpu); +} + +/* Returns the size of a subbuffer size. This is the size that + * will need to be written to disk. + * + * @subbuffer: pointer to the beginning of the subbuffer (the + * beginning of its header) + */ + +size_t subbuffer_data_size(void *subbuf) +{ + struct ltt_subbuffer_header *header = subbuf; + int reverse; + u32 data_size; + + if(header->magic_number == LTT_MAGIC_NUMBER) { + reverse = 0; + } + else if(header->magic_number == LTT_REV_MAGIC_NUMBER) { + reverse = 1; + } + else { + return -1; + } + + data_size = header->sb_size; + if(reverse) + data_size = bswap_32(data_size); + + return data_size; +} + + +void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf) +{ + struct ust_buffer *ust_buf = buf->bufstruct_mem; + unsigned long n_subbufs_order = get_count_order(buf->n_subbufs); + unsigned long commit_seq_mask = (~0UL >> n_subbufs_order); + unsigned long cons_off; + int ret; + + DBG("processing dead buffer (%s)", buf->name); + DBG("consumed offset is %ld (%s)", uatomic_read(&ust_buf->consumed), + buf->name); + DBG("write offset is %ld (%s)", uatomic_read(&ust_buf->offset), + buf->name); + + /* + * Iterate on subbuffers to recover, including the one the writer + * just wrote data into. Using write position - 1 since the writer + * position points into the position that is going to be written. + */ + for (cons_off = uatomic_read(&ust_buf->consumed); + (long) (SUBBUF_TRUNC(uatomic_read(&ust_buf->offset) - 1, buf) + - cons_off) >= 0; + cons_off = SUBBUF_ALIGN(cons_off, buf)) { + /* + * commit_seq is the offset in the buffer of the end of the last sequential commit. + * Bytes beyond this limit cannot be recovered. This is a free-running counter. + */ + unsigned long commit_seq = + uatomic_read(&ust_buf->commit_seq[SUBBUF_INDEX(cons_off, buf)]); + struct ltt_subbuffer_header *header = + (struct ltt_subbuffer_header *)((char *) buf->mem + + SUBBUF_INDEX(cons_off, buf) * buf->subbuf_size); + unsigned long valid_length; + + /* Check if subbuf was fully written. This is from Mathieu's algorithm/paper. */ + if (((commit_seq - buf->subbuf_size) & commit_seq_mask) + - (USTD_BUFFER_TRUNC(uatomic_read(&ust_buf->consumed), buf) >> n_subbufs_order) == 0 + && header->data_size != 0xffffffff) { + assert(header->sb_size != 0xffffffff); + /* + * If it was fully written, we only check the data_size. + * This is the amount of valid data at the beginning of + * the subbuffer. + */ + valid_length = header->data_size; + DBG("writing full subbuffer (%ld) with valid_length = %ld", + SUBBUF_INDEX(cons_off, buf), valid_length); + } else { + /* + * If the subbuffer was not fully written, then we don't + * check data_size because it hasn't been written yet. + * Instead we check commit_seq and use it to choose a + * value for data_size. The viewer will need this value + * when parsing. Generally, this will happen only for + * the last subbuffer. However, if we have threads still + * holding reserved slots in the previous subbuffers, + * which could happen for other subbuffers prior to the + * last one. Note that when data_size is set, the + * commit_seq count is still at a value that shows the + * amount of valid data to read. It's only _after_ + * writing data_size that commit_seq is updated to + * include the end-of-buffer padding. + */ + valid_length = commit_seq & (buf->subbuf_size - 1); + DBG("writing unfull subbuffer (%ld) with valid_length = %ld", + SUBBUF_INDEX(cons_off, buf), valid_length); + header->data_size = valid_length; + header->sb_size = PAGE_ALIGN(valid_length); + } + + if (callbacks->on_read_partial_subbuffer) { + ret = callbacks->on_read_partial_subbuffer(callbacks, buf, + SUBBUF_INDEX(cons_off, buf), + valid_length); + if (ret < 0) + break; /* Error happened */ + } + } + /* Increment the consumed offset */ + uatomic_set(&ust_buf->consumed, cons_off); + ltt_relay_print_buffer_errors(buf, buf->channel_cpu); +} + diff --git a/deprecated/libustconsumer/lowlevel.h b/deprecated/libustconsumer/lowlevel.h new file mode 100644 index 00000000..6ae6476c --- /dev/null +++ b/deprecated/libustconsumer/lowlevel.h @@ -0,0 +1,35 @@ +/* + * lowlevel libustd header file + * + * Copyright 2005-2010 - + * Mathieu Desnoyers + * Copyright 2010- + * Oumarou Dicko + * Michael Sills-Lavoie + * Alexis Halle + * + * 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 LOWLEVEL_H +#define LOWLEVEL_H + +#include "ust/ustconsumer.h" + +void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf); +size_t subbuffer_data_size(void *subbuf); + +#endif /* LOWLEVEL_H */ + diff --git a/deprecated/libustctl/Makefile.am b/deprecated/libustctl/Makefile.am new file mode 100644 index 00000000..bc7526b9 --- /dev/null +++ b/deprecated/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/deprecated/libustctl/README b/deprecated/libustctl/README new file mode 100644 index 00000000..fd4cc978 --- /dev/null +++ b/deprecated/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/deprecated/libustctl/libustctl.c b/deprecated/libustctl/libustctl.c new file mode 100644 index 00000000..4e6c495c --- /dev/null +++ b/deprecated/libustctl/libustctl.c @@ -0,0 +1,770 @@ +/* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette + * Copyright (C) 2011 Ericsson AB + * + * 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(int sock, + const struct ustcomm_header *req_header, + const char *req_data, + struct ustcomm_header *res_header, + char **res_data) +{ + int result, saved_errno = 0; + char *recv_buf; + + recv_buf = zmalloc(USTCOMM_BUFFER_SIZE); + if (!recv_buf) { + saved_errno = ENOMEM; + goto out; + } + + result = ustcomm_req(sock, 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); + } + +out: + errno = saved_errno; + if (errno) { + return -1; + } + + return 0; +} + +int ustctl_connect_pid(pid_t pid) +{ + int sock; + + if (ustcomm_connect_app(pid, &sock)) { + ERR("could not connect to PID %u", (unsigned int) pid); + errno = ENOTCONN; + return -1; + } + + return sock; +} + +static int realloc_pid_list(pid_t **pid_list, unsigned int *pid_list_size) +{ + pid_t *new_pid_list; + unsigned int new_pid_list_size = 2 * *pid_list_size; + + new_pid_list = realloc(*pid_list, + new_pid_list_size * sizeof(pid_t)); + if (!*new_pid_list) { + return -1; + } + + *pid_list = new_pid_list; + *pid_list_size = new_pid_list_size; + + return 0; +} + +static int get_pids_in_dir(DIR *dir, pid_t **pid_list, + unsigned int *pid_list_index, + unsigned int *pid_list_size) +{ + struct dirent *dirent; + pid_t read_pid; + + while ((dirent = readdir(dir))) { + if (!strcmp(dirent->d_name, ".") || + !strcmp(dirent->d_name, "..") || + !strcmp(dirent->d_name, "ust-consumer") || + dirent->d_type == DT_DIR) { + + continue; + } + + if (ustcomm_is_socket_live(dirent->d_name, &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)) { + return -1; + } + } + } + } + + (*pid_list)[*pid_list_index] = 0; /* Array end */ + + return 0; +} + +static pid_t *get_pids_non_root(void) +{ + char *dir_name; + DIR *dir; + unsigned int pid_list_index = 0, pid_list_size = 1; + pid_t *pid_list = NULL; + + dir_name = ustcomm_user_sock_dir(); + if (!dir_name) { + return NULL; + } + + dir = opendir(dir_name); + if (!dir) { + goto free_dir_name; + } + + pid_list = malloc(pid_list_size * sizeof(pid_t)); + if (!pid_list) { + goto close_dir; + } + + if (get_pids_in_dir(dir, &pid_list, &pid_list_index, &pid_list_size)) { + /* if any errors are encountered, force freeing of the list */ + pid_list[0] = 0; + } + +close_dir: + closedir(dir); + +free_dir_name: + free(dir_name); + + return pid_list; +} + +static pid_t *get_pids_root(void) +{ + char *dir_name; + DIR *tmp_dir, *dir; + unsigned int pid_list_index = 0, pid_list_size = 1; + pid_t *pid_list = NULL; + struct dirent *dirent; + int result; + + tmp_dir = opendir(USER_TMP_DIR); + if (!tmp_dir) { + return NULL; + } + + pid_list = malloc(pid_list_size * sizeof(pid_t)); + if (!pid_list) { + goto close_tmp_dir; + } + + while ((dirent = readdir(tmp_dir))) { + /* Compare the dir to check for the USER_SOCK_DIR_BASE prefix */ + if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE, + strlen(USER_SOCK_DIR_BASE))) { + + if (asprintf(&dir_name, USER_TMP_DIR "/%s", + dirent->d_name) < 0) { + goto close_tmp_dir; + } + + dir = opendir(dir_name); + + free(dir_name); + + if (!dir) { + continue; + } + + result = get_pids_in_dir(dir, &pid_list, &pid_list_index, + &pid_list_size); + + closedir(dir); + + if (result) { + /* + * if any errors are encountered, + * force freeing of the list + */ + pid_list[0] = 0; + break; + } + } + } + +close_tmp_dir: + closedir(tmp_dir); + + return pid_list; +} + +pid_t *ustctl_get_online_pids(void) +{ + pid_t *pid_list; + + if (geteuid()) { + pid_list = get_pids_non_root(); + } else { + pid_list = get_pids_root(); + } + + if (pid_list && pid_list[0] == 0) { + /* No PID at all */ + free(pid_list); + pid_list = NULL; + } + + return pid_list; +} + +/** + * Sets ust_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_ust_marker_state(int sock, const char *trace, const char *channel, + const char *ust_marker, int state) +{ + struct ustcomm_header req_header, res_header; + struct ustcomm_ust_marker_info ust_marker_inf; + int result; + + result = ustcomm_pack_ust_marker_info(&req_header, + &ust_marker_inf, + trace, + channel, + ust_marker); + if (result < 0) { + errno = -result; + return -1; + } + + req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER; + + return do_cmd(sock, &req_header, (char *)&ust_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(int sock, const char *trace, const char *channel, + unsigned int subbuf_size) +{ + 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(sock, &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(int sock, const char *trace, const char *channel, + unsigned int num) +{ + 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(sock, &req_header, (char *)&ch_inf, + &res_header, NULL); + +} + + +static int ustctl_get_subbuf_num_size(int sock, const char *trace, const char *channel, + 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(sock, &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(int sock, const char *trace, const char *channel) +{ + int num, size, result; + + result = ustctl_get_subbuf_num_size(sock, trace, channel, + &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(int sock, const char *trace, const char *channel) +{ + int num, size, result; + + result = ustctl_get_subbuf_num_size(sock, trace, channel, + &num, &size); + if (result < 0) { + errno = -result; + return -1; + } + + return size; +} + +static int do_trace_cmd(int sock, const char *trace, 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(sock, &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(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, 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(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, 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(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, 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(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, 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(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, ALLOC_TRACE); +} + + +int ustctl_force_switch(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, FORCE_SUBBUF_SWITCH); +} + +/** + * 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(int sock, const char *trace) +{ + return do_trace_cmd(sock, trace, 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 ust_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].ust_marker); + free(cmsf[i].fs); + ++i; + } + free(cmsf); + + return 0; +} + +/** + * Gets channel/ust_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(int sock, struct ust_marker_status **cmsf) +{ + struct ustcomm_header req_header, res_header; + char *big_str = NULL; + int result; + struct ust_marker_status *tmp_cmsf = NULL; + unsigned int i = 0, cmsf_ind = 0; + + if (cmsf == NULL) { + return -1; + } + + req_header.command = LIST_MARKERS; + req_header.size = 0; + + result = ustcomm_send(sock, &req_header, NULL); + if (result <= 0) { + PERROR("error while requesting ust_marker list"); + return -1; + } + + result = ustcomm_recv_alloc(sock, &res_header, &big_str); + if (result <= 0) { + ERR("error while receiving ust_marker list"); + return -1; + } + + tmp_cmsf = (struct ust_marker_status *) zmalloc(sizeof(struct ust_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, "ust_marker: %a[^/]/%a[^ ] %c %a[^\n]", + &tmp_cmsf[cmsf_ind].channel, + &tmp_cmsf[cmsf_ind].ust_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].ust_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(int sock, struct trace_event_status **tes) +{ + struct ustcomm_header req_header, res_header; + char *big_str = NULL; + int result; + struct trace_event_status *tmp_tes = NULL; + unsigned int i = 0, tes_ind = 0; + + if (tes == NULL) { + return -1; + } + + req_header.command = LIST_TRACE_EVENTS; + req_header.size = 0; + + result = ustcomm_send(sock, &req_header, NULL); + if (result != 1) { + ERR("error while requesting trace_event list"); + return -1; + } + + result = ustcomm_recv_alloc(sock, &res_header, &big_str); + if (result != 1) { + ERR("error while receiving ust_marker list"); + return -1; + } + + 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 sock path + * + * @param sock_path Sock path + * @param pid Traced process ID + * @return 0 if successful, or error + */ +int ustctl_set_sock_path(int sock, const char *sock_path) +{ + 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(sock, &req_header, (char *)&sock_path_msg, + &res_header, NULL); +} + +/** + * Get sock path + * + * @param sock_path Pointer to where the sock path will be returned + * @param pid Traced process ID + * @return 0 if successful, or error + */ +int ustctl_get_sock_path(int sock, char **sock_path) +{ + 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(sock, &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; +} diff --git a/deprecated/ust-consumerd/Makefile.am b/deprecated/ust-consumerd/Makefile.am new file mode 100644 index 00000000..01e3b822 --- /dev/null +++ b/deprecated/ust-consumerd/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \ + -I$(top_srcdir)/include -I$(top_srcdir)/libustconsumer +AM_CFLAGS = -fno-strict-aliasing + +bin_PROGRAMS = ust-consumerd + +ust_consumerd_SOURCES = ust-consumerd.c + +ust_consumerd_LDADD = \ + $(top_builddir)/snprintf/libustsnprintf.la \ + $(top_builddir)/libustcomm/libustcomm.la \ + $(top_builddir)/libustconsumer/libustconsumer.la + +ust_consumerd_CFLAGS = -DUST_COMPONENT=ust-consumerd -fno-strict-aliasing diff --git a/deprecated/ust-consumerd/README b/deprecated/ust-consumerd/README new file mode 100644 index 00000000..6df40155 --- /dev/null +++ b/deprecated/ust-consumerd/README @@ -0,0 +1,3 @@ +This is ust-consumerd, the UST consumer daemon. + +This daemon is used to collect the traces for the traced programs and write them to disk. diff --git a/deprecated/ust-consumerd/ust-consumerd.c b/deprecated/ust-consumerd/ust-consumerd.c new file mode 100644 index 00000000..07612531 --- /dev/null +++ b/deprecated/ust-consumerd/ust-consumerd.c @@ -0,0 +1,516 @@ +/* Copyright (C) 2009 Pierre-Marc Fournier + * 2010 Alexis Halle + * + * 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 +#include +#include +#include +#include +#include + +#include "ust/ustconsumer.h" +#include "../libustconsumer/lowlevel.h" +#include "usterr.h" + +char *sock_path=NULL; +char *trace_path=NULL; +int daemon_mode = 0; +char *pidfile = NULL; + +struct ustconsumer_instance *instance; + +struct buffer_info_local { + /* output file */ + int file_fd; + /* the offset we must truncate to, to unput the last subbuffer */ + off_t previous_offset; +}; + +static int write_pidfile(const char *file_name, pid_t pid) +{ + FILE *pidfp; + + pidfp = fopen(file_name, "w"); + if(!pidfp) { + PERROR("fopen (%s)", file_name); + WARN("killing child process"); + return -1; + } + + fprintf(pidfp, "%d\n", pid); + + fclose(pidfp); + + return 0; +} + +int create_dir_if_needed(char *dir) +{ + int result; + result = mkdir(dir, 0777); + if(result == -1) { + if(errno != EEXIST) { + PERROR("mkdir"); + return -1; + } + } + + return 0; +} + +int unwrite_last_subbuffer(struct buffer_info *buf) +{ + int result; + struct buffer_info_local *buf_local = buf->user_data; + + result = ftruncate(buf_local->file_fd, buf_local->previous_offset); + if(result == -1) { + PERROR("ftruncate"); + return -1; + } + + result = lseek(buf_local->file_fd, buf_local->previous_offset, SEEK_SET); + if(result == (int)(off_t)-1) { + PERROR("lseek"); + return -1; + } + + return 0; +} + +int write_current_subbuffer(struct buffer_info *buf) +{ + int result; + struct buffer_info_local *buf_local = buf->user_data; + + void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1)); + + size_t cur_sb_size = subbuffer_data_size(subbuf_mem); + + off_t cur_offset = lseek(buf_local->file_fd, 0, SEEK_CUR); + if(cur_offset == (off_t)-1) { + PERROR("lseek"); + return -1; + } + + buf_local->previous_offset = cur_offset; + DBG("previous_offset: %ld", cur_offset); + + result = patient_write(buf_local->file_fd, subbuf_mem, cur_sb_size); + if(result == -1) { + PERROR("write"); + return -1; + } + + return 0; +} + +int on_read_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf) +{ + return write_current_subbuffer(buf); +} + +int on_read_partial_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf, + long subbuf_index, unsigned long valid_length) +{ + struct buffer_info_local *buf_local = buf->user_data; + char *tmp; + int result; + unsigned long pad_size; + + result = patient_write(buf_local->file_fd, buf->mem + subbuf_index * buf->subbuf_size, valid_length); + if(result == -1) { + ERR("Error writing to buffer file"); + return result; + } + + /* pad with empty bytes */ + pad_size = PAGE_ALIGN(valid_length)-valid_length; + if(pad_size) { + tmp = zmalloc(pad_size); + result = patient_write(buf_local->file_fd, tmp, pad_size); + if(result == -1) { + ERR("Error writing to buffer file"); + return result; + } + free(tmp); + } + return result; +} + +int on_open_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf) +{ + char *tmp; + int result; + int fd; + struct buffer_info_local *buf_local = + zmalloc(sizeof(struct buffer_info_local)); + + if(!buf_local) { + ERR("could not allocate buffer_info_local struct"); + return 1; + } + + buf->user_data = buf_local; + + /* open file for output */ + if(!trace_path) { + /* Only create the directory if using the default path, because + * of the risk of typo when using trace path override. We don't + * want to risk creating plenty of useless directories in that case. + */ + result = create_dir_if_needed(USTCONSUMER_DEFAULT_TRACE_PATH); + if(result == -1) { + ERR("could not create directory %s", USTCONSUMER_DEFAULT_TRACE_PATH); + return 1; + } + + trace_path = USTCONSUMER_DEFAULT_TRACE_PATH; + } + + if (asprintf(&tmp, "%s/%u_%" PRId64 "", trace_path, buf->pid, buf->pidunique) < 0) { + ERR("on_open_buffer : asprintf failed (%s/%u_%" PRId64 ")", + trace_path, buf->pid, buf->pidunique); + return 1; + } + result = create_dir_if_needed(tmp); + if(result == -1) { + ERR("could not create directory %s", tmp); + free(tmp); + return 1; + } + free(tmp); + + if (asprintf(&tmp, "%s/%u_%" PRId64 "/%s", trace_path, buf->pid, buf->pidunique, buf->name) < 0) { + ERR("on_open_buffer : asprintf failed (%s/%u_%" PRId64 "/%s)", + trace_path, buf->pid, buf->pidunique, buf->name); + return 1; + } +again: + result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600); + if (result == -1 && errno == EINTR) + goto again; + + if(result == -1) { + PERROR("open"); + ERR("failed opening trace file %s", tmp); + return 1; + } + buf_local->file_fd = fd; + free(tmp); + + return 0; +} + +int on_close_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf) +{ + struct buffer_info_local *buf_local = buf->user_data; + int result; + +again: + result = close(buf_local->file_fd); + if (result == -1 && errno == EINTR) + goto again; + free(buf_local); + if(result == -1) { + PERROR("close"); + } + return 0; +} + +int on_put_error(struct ustconsumer_callbacks *data, struct buffer_info *buf) +{ + return unwrite_last_subbuffer(buf); +} + +struct ustconsumer_callbacks *new_callbacks() +{ + struct ustconsumer_callbacks *callbacks = + zmalloc(sizeof(struct ustconsumer_callbacks)); + + if(!callbacks) + return NULL; + + callbacks->on_open_buffer = on_open_buffer; + callbacks->on_close_buffer = on_close_buffer; + callbacks->on_read_subbuffer = on_read_subbuffer; + callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer; + callbacks->on_put_error = on_put_error; + callbacks->on_new_thread = NULL; + callbacks->on_close_thread = NULL; + callbacks->on_trace_end = NULL; + + return callbacks; + +} + +int is_directory(const char *dir) +{ + int result; + struct stat st; + + result = stat(dir, &st); + if(result == -1) { + PERROR("stat"); + return 0; + } + + if(!S_ISDIR(st.st_mode)) { + return 0; + } + + return 1; +} + +void usage(void) +{ + fprintf(stderr, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n" + "\t-h\t\tDisplay this usage.\n" + "\t-o DIR\t\tSpecify the directory where to output the traces.\n" + "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n" + "\t-d\t\tStart as a daemon.\n" + "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n"); +} + +int parse_args(int argc, char **argv) +{ + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"pidfile", 1, 0, 'p'}, + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'V'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + printf("option %s", long_options[option_index].name); + if (optarg) + printf(" with arg %s", optarg); + printf("\n"); + break; + case 's': + sock_path = optarg; + break; + case 'o': + trace_path = optarg; + if(!is_directory(trace_path)) { + ERR("Not a valid directory. (%s)", trace_path); + return -1; + } + break; + case 'd': + daemon_mode = 1; + break; + case 'p': + pidfile = strdup(optarg); + break; + case 'h': + usage(); + exit(0); + case 'V': + printf("Version 0.0\n"); + break; + + default: + /* unknown option or other error; error is + printed by getopt, just return */ + return -1; + } + } + + return 0; +} + +void sigterm_handler(int sig) +{ + ustconsumer_stop_instance(instance, 0); +} + +int start_ustconsumer(int fd) +{ + int result; + sigset_t sigset; + struct sigaction sa; + + struct ustconsumer_callbacks *callbacks = new_callbacks(); + if(!callbacks) { + PERROR("new_callbacks"); + return 1; + } + + result = sigemptyset(&sigset); + if(result == -1) { + PERROR("sigemptyset"); + return 1; + } + sa.sa_handler = sigterm_handler; + sa.sa_mask = sigset; + sa.sa_flags = 0; + result = sigaction(SIGTERM, &sa, NULL); + if(result == -1) { + PERROR("sigaction"); + return 1; + } + result = sigaction(SIGINT, &sa, NULL); + if(result == -1) { + PERROR("sigaction"); + return 1; + } + + instance = ustconsumer_new_instance(callbacks, sock_path); + if(!instance) { + ERR("failed to create ustconsumer instance"); + return 1; + } + + result = ustconsumer_init_instance(instance); + if(result) { + ERR("failed to initialize ustconsumer instance"); + return 1; + } + + /* setup handler for SIGPIPE */ + result = sigemptyset(&sigset); + if(result == -1) { + PERROR("sigemptyset"); + return 1; + } + result = sigaddset(&sigset, SIGPIPE); + if(result == -1) { + PERROR("sigaddset"); + return 1; + } + result = sigprocmask(SIG_BLOCK, &sigset, NULL); + if(result == -1) { + PERROR("sigprocmask"); + return 1; + } + + /* Write pidfile */ + if(pidfile) { + result = write_pidfile(pidfile, getpid()); + if(result == -1) { + ERR("failed to write pidfile"); + return 1; + } + } + + /* Notify parent that we are successfully started. */ + if(fd != -1) { + /* write any one character */ + result = write(fd, "!", 1); + if(result == -1) { + PERROR("write"); + return -1; + } + if(result != 1) { + ERR("Problem sending confirmation of daemon start to parent"); + return -1; + } + result = close(fd); + if(result == -1) { + PERROR("close"); + } + } + + ustconsumer_start_instance(instance); + + free(callbacks); + + return 0; +} + +int start_ustconsumer_daemon() +{ + int result; + int fd[2]; + pid_t child_pid; + + result = pipe(fd); + + result = child_pid = fork(); + if(result == -1) { + PERROR("fork"); + return -1; + } + else if(result == 0) { + return start_ustconsumer(fd[1]); + } + else { + char buf; + + result = read(fd[0], &buf, 1); + if(result == -1) { + PERROR("read"); + return -1; + } + if(result != 1) { + ERR("did not receive valid confirmation that the daemon is started"); + return -1; + } + + result = close(fd[0]); + if(result == -1) { + PERROR("close"); + } + + DBG("The daemon is now successfully started"); + } + + /* Wait for confirmation that the server is ready. */ + + + return 0; +} + +int main(int argc, char **argv) +{ + int result; + + result = parse_args(argc, argv); + if(result == -1) { + exit(1); + } + + if(daemon_mode) { + result = start_ustconsumer_daemon(); + } + else { + result = start_ustconsumer(-1); + } + + return result; +} diff --git a/deprecated/ustctl/Makefile.am b/deprecated/ustctl/Makefile.am new file mode 100644 index 00000000..1e442a3f --- /dev/null +++ b/deprecated/ustctl/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm \ + -I$(top_srcdir)/libustctl $(KCOMPAT_CFLAGS) +AM_CFLAGS = -fno-strict-aliasing + +bin_PROGRAMS = ustctl + +ustctl_SOURCES = \ + 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)/libustctl/libustctl.la diff --git a/deprecated/ustctl/README b/deprecated/ustctl/README new file mode 100644 index 00000000..3fdfbbda --- /dev/null +++ b/deprecated/ustctl/README @@ -0,0 +1,3 @@ +ustctl is a helper application used to control tracing on programs that support tracing. + +It can list markers, enable/disable markers, start tracing and stop tracing. diff --git a/deprecated/ustctl/channel_cmds.c b/deprecated/ustctl/channel_cmds.c new file mode 100644 index 00000000..315fd56f --- /dev/null +++ b/deprecated/ustctl/channel_cmds.c @@ -0,0 +1,151 @@ +/* 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 sock, result = 0; + char *channel = NULL; + unsigned int size; + + sock = parse_and_connect_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(sock, argv[2], channel, size)) { + ERR("error while trying to set the size of subbuffers " + "for PID %s\n", + argv[1]); + result = -1; + } + + free(channel); + + return result; +} + +static int set_subbuf_num(int argc, char *argv[]) +{ + int sock, result = 0; + char *channel = NULL; + unsigned int num; + + sock = parse_and_connect_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(sock, argv[2], channel, num)) { + ERR("error while trying to set the number of subbuffers for PID %s\n", + argv[1]); + result = -1; + } + + free(channel); + + return result; +} + +static int get_subbuf_size(int argc, char *argv[]) +{ + int sock; + unsigned int size; + + sock = parse_and_connect_pid(argv[1]); + + if ((size = ustctl_get_subbuf_size(sock, argv[2], argv[3])) < 0) { + ERR("error while trying to get the subbuffer size from PID %s\n", + argv[1]); + return -1; + } + + printf("The subbufer size is %d bytes\n", size); + + return 0; +} + +static int get_subbuf_num(int argc, char *argv[]) +{ + int sock; + unsigned int num; + + sock = parse_and_connect_pid(argv[1]); + + if ((num = ustctl_get_subbuf_num(sock, argv[2], argv[3])) < 0) { + ERR("error while trying to get the subbuffer size from PID %s\n", + argv[1]); + 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/deprecated/ustctl/cli.c b/deprecated/ustctl/cli.c new file mode 100644 index 00000000..0ca9db5c --- /dev/null +++ b/deprecated/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/deprecated/ustctl/cli.h b/deprecated/ustctl/cli.h new file mode 100644 index 00000000..a1e4eed9 --- /dev/null +++ b/deprecated/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/deprecated/ustctl/marker_cmds.c b/deprecated/ustctl/marker_cmds.c new file mode 100644 index 00000000..8bcab832 --- /dev/null +++ b/deprecated/ustctl/marker_cmds.c @@ -0,0 +1,141 @@ +/* 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 ust_marker_status *cmsf = NULL; + int i, sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_get_cmsf(sock, &cmsf)) { + ERR("error while trying to list markers for PID %s\n", argv[1]); + return -1; + } + for (i = 0; cmsf[i].channel; i++) { + printf("{PID: %s, channel/marker: %s/%s, " + "state: %u, fmt: %s}\n", + argv[1], + cmsf[i].channel, + cmsf[i].ust_marker, + cmsf[i].state, + cmsf[i].fs); + } + ustctl_free_cmsf(cmsf); + return 0; +} + +static int enable_marker(int argc, char *argv[]) +{ + int i, sock, result = 0; + char *channel, *marker; + + sock = parse_and_connect_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_ust_marker_state(sock, argv[2], channel, marker, 1)) { + PERROR("error while trying to enable marker %s with PID %s", + argv[i], argv[1]); + result = -1; + } + free(channel); + free(marker); + } + + return result; +} + +static int disable_marker(int argc, char *argv[]) +{ + int i, sock, result = 0; + char *channel, *marker; + + sock = parse_and_connect_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_ust_marker_state(sock, argv[2], channel, marker, 0)) { + PERROR("error while trying to disable marker %s with PID %s", + argv[i], argv[1]); + result = -1; + } + free(channel); + free(marker); + } + + return result; +} + +struct cli_cmd __cli_cmds ust_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/deprecated/ustctl/scanning_functions.c b/deprecated/ustctl/scanning_functions.c new file mode 100644 index 00000000..4aa8c1c9 --- /dev/null +++ b/deprecated/ustctl/scanning_functions.c @@ -0,0 +1,91 @@ +/* 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" + + +int parse_and_connect_pid(const char *pid_string) +{ + pid_t pid; + int sock; + + errno = 0; + pid = strtoull(pid_string, NULL, 10); + if (errno) { + perror("Failed to parse pid"); + exit(EXIT_FAILURE); + } + + sock = ustctl_connect_pid(pid); + if (sock < 0) { + perror("Failed to connect to process"); + exit(EXIT_FAILURE); + } + + return sock; +} + +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/deprecated/ustctl/scanning_functions.h b/deprecated/ustctl/scanning_functions.h new file mode 100644 index 00000000..0f2d62ed --- /dev/null +++ b/deprecated/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 + +int parse_and_connect_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/deprecated/ustctl/trace_cmds.c b/deprecated/ustctl/trace_cmds.c new file mode 100644 index 00000000..a8f3a9cc --- /dev/null +++ b/deprecated/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[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_create_trace(sock, argv[2])) { + ERR("Failed to create trace %s for PID %s\n", argv[2], argv[1]); + return -1; + } + + return 0; +} + +static int alloc_trace(int argc, char *argv[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_alloc_trace(sock, argv[2])) { + ERR("Failed to allocate trace %s for PID %s\n", argv[2], argv[1]); + return -1; + } + return 0; +} + +static int start_trace(int argc, char *argv[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_start_trace(sock, argv[2])) { + ERR("Failed to start trace %s for PID %s\n", argv[2], argv[1]); + return -1; + } + return 0; +} + +static int stop_trace(int argc, char *argv[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_stop_trace(sock, argv[2])) { + ERR("Failed to stop trace %s for PID %s\n", argv[2], argv[1]); + return -1; + } + return 0; +} + +static int destroy_trace(int argc, char *argv[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_destroy_trace(sock, argv[2])) { + ERR("Failed to destroy trace %s for PID %s\n", argv[2], argv[1]); + return -1; + } + return 0; +} + +static int force_subbuf_switch(int argc, char *argv[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_force_switch(sock, argv[2])) { + ERR("error while trying to force switch for PID %s\n", argv[1]); + 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/deprecated/ustctl/ustctl.c b/deprecated/ustctl/ustctl.c new file mode 100644 index 00000000..18f7d307 --- /dev/null +++ b/deprecated/ustctl/ustctl.c @@ -0,0 +1,272 @@ +/* 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 + * 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 "ust/ustctl.h" +#include "usterr.h" +#include "cli.h" +#include "scanning_functions.h" + +void usage(const char *process_name) +{ + 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); +} + +/* + * Provide backward compatibility for scripts that make use of the + * --commands in ustctl version <= 0.11 + */ +enum command { + CREATE_TRACE=1000, + ALLOC_TRACE, + START_TRACE, + STOP_TRACE, + DESTROY_TRACE, + LIST_MARKERS, + LIST_TRACE_EVENTS, + ENABLE_MARKER, + DISABLE_MARKER, +}; + +struct option 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", 0, 0, ENABLE_MARKER }, + { "disable-marker", 0, 0, DISABLE_MARKER }, + {"help", 2, NULL, 'h'}, + {"list", 0, NULL, 'l'}, + {"extended-list", 0, NULL, 'e'}, + {NULL, 0, NULL, 0}, +}; + +int main(int argc, char *argv[]) +{ + struct cli_cmd *cli_cmd; + char **args = argv; + int opt; + int i; + + if(argc <= 1) { + fprintf(stderr, "No operation specified.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + 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; + case 'l': + list_cli_cmds(CLI_SIMPLE_LIST); + exit(EXIT_FAILURE); + break; + case 'e': + list_cli_cmds(CLI_EXTENDED_LIST); + exit(EXIT_FAILURE); + case LIST_MARKERS: + case LIST_TRACE_EVENTS: + case CREATE_TRACE: + case ALLOC_TRACE: + case START_TRACE: + case STOP_TRACE: + case DESTROY_TRACE: + case ENABLE_MARKER: + case DISABLE_MARKER: + args = (char **)malloc(sizeof(char *) * (argc + 3)); + optind--; + args[optind] = strdup(&argv[optind][2]); + for (i = optind + 1; i < argc; i++) { + args[i] = argv[i]; + } + if (opt >= CREATE_TRACE && opt <= DESTROY_TRACE) { + args[argc] = strdup("auto"); + argc++; + } + if (opt >= ENABLE_MARKER && opt <= DISABLE_MARKER) { + args[argc] = args[argc - 2]; + args[argc - 2] = args[argc - 1]; + args[argc - 1] = strdup("auto"); + argc++; + } + args[argc] = NULL; + goto do_cli; + default: + fprintf(stderr, "Unknown option\n"); + break; + } + } + +do_cli: + cli_cmd = find_cli_cmd(args[optind]); + if (!cli_cmd) { + fprintf(stderr, "No such command %s\n", + args[optind]); + exit(EXIT_FAILURE); + } + + cli_dispatch_cmd(cli_cmd, argc - optind, &args[optind]); + + return 0; +} + +static int list_trace_events(int argc, char *argv[]) +{ + struct trace_event_status *tes = NULL; + int i, sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_get_tes(sock, &tes)) { + ERR("error while trying to list " + "trace_events for PID %s\n", + argv[1]); + return -1; + } + i = 0; + for (i = 0; tes[i].name; i++) { + printf("{PID: %s, trace_event: %s}\n", + argv[1], + tes[i].name); + } + ustctl_free_tes(tes); + + return 0; +} + +static int set_sock_path(int argc, char *argv[]) +{ + int sock; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_set_sock_path(sock, argv[2])) { + ERR("error while trying to set sock path for PID %s\n", argv[1]); + return -1; + } + + return 0; +} + +static int get_sock_path(int argc, char *argv[]) +{ + int sock; + char *sock_path; + + sock = parse_and_connect_pid(argv[1]); + + if (ustctl_get_sock_path(sock, &sock_path)) { + ERR("error while trying to get sock path for PID %s\n", argv[1]); + return -1; + } + printf("The socket path is %s\n", sock_path); + free(sock_path); + + return 0; +} + +static int list_pids(int argc, char *argv[]) +{ + pid_t *pid_list; + int i; + + pid_list = ustctl_get_online_pids(); + if (!pid_list) { + return -1; + } + + for (i = 0; pid_list[i]; i++) { + printf("%ld\n", (long)pid_list[i]); + } + + free(pid_list); + + 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, + }, + { + .name = "list-pids", + .description = "List traceable pids", + .help_text = "list-pids\n" + "List the traceable pids for the current user\n", + .function = list_pids, + .desired_args = 0, + .desired_args_op = CLI_EQ, + }, +}; diff --git a/libustcomm/Makefile.am b/libustcomm/Makefile.am deleted file mode 100644 index 3ae96d5e..00000000 --- a/libustcomm/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -AM_CFLAGS = -fno-strict-aliasing - -noinst_LTLIBRARIES = libustcomm.la -libustcomm_la_SOURCES = \ - ustcomm.h \ - ustcomm.c - -libustcomm_la_LDFLAGS = -no-undefined -static -libustcomm_la_CFLAGS = -DUST_COMPONENT="libustcomm" -fPIC -fno-strict-aliasing diff --git a/libustcomm/ustcomm.c b/libustcomm/ustcomm.c deleted file mode 100644 index 07f7f874..00000000 --- a/libustcomm/ustcomm.c +++ /dev/null @@ -1,1028 +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 - */ - -/* API used by UST components to communicate with each other via sockets. */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "ustcomm.h" -#include "usterr.h" -#include "share.h" - -static int mkdir_p(const char *path, mode_t mode) -{ - const char *path_p; - char *tmp; - - int retval = 0; - int result; - mode_t old_umask; - - tmp = zmalloc(strlen(path) + 1); - if (tmp == NULL) - return -1; - - /* skip first / */ - path_p = path+1; - - old_umask = umask(0); - for(;;) { - while (*path_p != '/') { - if(*path_p == 0) - break; - ++path_p; - } - if (*path_p == '/') { - strncpy(tmp, path, path_p - path); - tmp[path_p-path] = '\0'; - if (tmp[path_p - path - 1] != '/') { - result = mkdir(tmp, mode); - if(result == -1) { - if (!(errno == EEXIST || errno == EACCES || errno == EROFS)) { - /* Then this is a real error */ - retval = -1; - break; - } - } - } - /* pass / */ - path_p++; - } else { - /* last component */ - result = mkdir(path, mode); - if (result == -1) - retval = -1; - break; - } - } - - free(tmp); - umask(old_umask); - return retval; -} - -static struct sockaddr_un * create_sock_addr(const char *name, - size_t *sock_addr_size) -{ - struct sockaddr_un * addr; - size_t alloc_size; - - alloc_size = (size_t) (((struct sockaddr_un *) 0)->sun_path) + - strlen(name) + 1; - - addr = malloc(alloc_size); - if (addr < 0) { - ERR("allocating addr failed"); - return NULL; - } - - addr->sun_family = AF_UNIX; - strcpy(addr->sun_path, name); - - *sock_addr_size = alloc_size; - - return addr; -} - -struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd, - struct cds_list_head *list) -{ - struct epoll_event ev; - struct ustcomm_sock *sock; - - sock = malloc(sizeof(struct ustcomm_sock)); - if (!sock) { - perror("malloc: couldn't allocate ustcomm_sock"); - return NULL; - } - - ev.events = EPOLLIN; - ev.data.ptr = sock; - sock->fd = fd; - - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock->fd, &ev) == -1) { - perror("epoll_ctl: failed to add socket\n"); - free(sock); - return NULL; - } - - sock->epoll_fd = epoll_fd; - if (list) { - cds_list_add(&sock->list, list); - } else { - CDS_INIT_LIST_HEAD(&sock->list); - } - - return sock; -} - -void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll) -{ - cds_list_del(&sock->list); - if (!keep_in_epoll) { - if (epoll_ctl(sock->epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL) == -1) { - PERROR("epoll_ctl: failed to delete socket"); - } - } - close(sock->fd); - free(sock); -} - -struct ustcomm_sock * ustcomm_init_named_socket(const char *name, - int epoll_fd) -{ - int result; - int fd; - size_t sock_addr_size; - struct sockaddr_un * addr; - struct ustcomm_sock *sock; - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(fd == -1) { - PERROR("socket"); - return NULL; - } - - addr = create_sock_addr(name, &sock_addr_size); - if (addr == NULL) { - ERR("allocating addr, UST thread bailing"); - goto close_sock; - } - - result = access(name, F_OK); - if(result == 0) { - /* file exists */ - result = unlink(name); - if(result == -1) { - PERROR("unlink of socket file"); - goto free_addr; - } - DBG("socket already exists; overwriting"); - } - - result = bind(fd, (struct sockaddr *)addr, sock_addr_size); - if(result == -1) { - PERROR("bind"); - goto free_addr; - } - - result = listen(fd, 1); - if(result == -1) { - PERROR("listen"); - goto free_addr; - } - - sock = ustcomm_init_sock(fd, epoll_fd, - NULL); - if (!sock) { - ERR("failed to create ustcomm_sock"); - goto free_addr; - } - - free(addr); - - return sock; - -free_addr: - free(addr); -close_sock: - close(fd); - - return NULL; -} - -void ustcomm_del_named_sock(struct ustcomm_sock *sock, - int keep_socket_file) -{ - int result, fd; - struct stat st; - struct sockaddr dummy; - struct sockaddr_un *sockaddr = NULL; - int alloc_size; - - fd = sock->fd; - - if(!keep_socket_file) { - - /* Get the socket name */ - alloc_size = sizeof(dummy); - if (getsockname(fd, &dummy, (socklen_t *)&alloc_size) < 0) { - PERROR("getsockname failed"); - goto del_sock; - } - - sockaddr = zmalloc(alloc_size); - if (!sockaddr) { - ERR("failed to allocate sockaddr"); - goto del_sock; - } - - if (getsockname(fd, sockaddr, (socklen_t *)&alloc_size) < 0) { - PERROR("getsockname failed"); - goto free_sockaddr; - } - - /* Destroy socket */ - result = stat(sockaddr->sun_path, &st); - if(result < 0) { - PERROR("stat (%s)", sockaddr->sun_path); - goto free_sockaddr; - } - - /* Paranoid check before deleting. */ - result = S_ISSOCK(st.st_mode); - if(!result) { - ERR("The socket we are about to delete is not a socket."); - goto free_sockaddr; - } - - result = unlink(sockaddr->sun_path); - if(result < 0) { - PERROR("unlink"); - } - } - -free_sockaddr: - free(sockaddr); - -del_sock: - ustcomm_del_sock(sock, keep_socket_file); -} - -int ustcomm_recv_alloc(int sock, - struct ustcomm_header *header, - char **data) { - int result; - struct ustcomm_header peek_header; - struct iovec iov[2]; - struct msghdr msg; - - /* Just to make the caller fail hard */ - *data = NULL; - - result = recv(sock, &peek_header, sizeof(peek_header), - MSG_PEEK | MSG_WAITALL); - if (result <= 0) { - if(errno == ECONNRESET) { - return 0; - } else if (errno == EINTR) { - return -1; - } else if (result < 0) { - PERROR("recv"); - return -1; - } - return 0; - } - - memset(&msg, 0, sizeof(msg)); - - iov[0].iov_base = (char *)header; - iov[0].iov_len = sizeof(struct ustcomm_header); - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - if (peek_header.size) { - *data = zmalloc(peek_header.size); - if (!*data) { - return -ENOMEM; - } - - iov[1].iov_base = *data; - iov[1].iov_len = peek_header.size; - - msg.msg_iovlen++; - } - - result = recvmsg(sock, &msg, MSG_WAITALL); - if (result < 0) { - free(*data); - PERROR("recvmsg failed"); - } - - return result; -} - -/* returns 1 to indicate a message was received - * returns 0 to indicate no message was received (end of stream) - * returns -1 to indicate an error - */ -int ustcomm_recv_fd(int sock, - struct ustcomm_header *header, - char *data, int *fd) -{ - int result; - struct ustcomm_header peek_header; - struct iovec iov[2]; - struct msghdr msg; - struct cmsghdr *cmsg; - char buf[CMSG_SPACE(sizeof(int))]; - - result = recv(sock, &peek_header, sizeof(peek_header), - MSG_PEEK | MSG_WAITALL); - if (result <= 0) { - if(errno == ECONNRESET) { - return 0; - } else if (errno == EINTR) { - return -1; - } else if (result < 0) { - PERROR("recv"); - return -1; - } - return 0; - } - - memset(&msg, 0, sizeof(msg)); - - iov[0].iov_base = (char *)header; - iov[0].iov_len = sizeof(struct ustcomm_header); - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - if (peek_header.size && data) { - if (peek_header.size < 0 || - peek_header.size > USTCOMM_DATA_SIZE) { - ERR("big peek header! %ld", peek_header.size); - return 0; - } - - iov[1].iov_base = data; - iov[1].iov_len = peek_header.size; - - msg.msg_iovlen++; - } - - if (fd && peek_header.fd_included) { - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - } - - result = recvmsg(sock, &msg, MSG_WAITALL); - if (result <= 0) { - if (result < 0) { - PERROR("recvmsg failed"); - } - return result; - } - - if (fd && peek_header.fd_included) { - cmsg = CMSG_FIRSTHDR(&msg); - result = 0; - while (cmsg != NULL) { - if (cmsg->cmsg_level == SOL_SOCKET - && cmsg->cmsg_type == SCM_RIGHTS) { - *fd = *(int *) CMSG_DATA(cmsg); - result = 1; - break; - } - cmsg = CMSG_NXTHDR(&msg, cmsg); - } - if (!result) { - ERR("Failed to receive file descriptor\n"); - } - } - - return 1; -} - -int ustcomm_recv(int sock, - struct ustcomm_header *header, - char *data) -{ - return ustcomm_recv_fd(sock, header, data, NULL); -} - - -int ustcomm_send_fd(int sock, - const struct ustcomm_header *header, - const char *data, - int *fd) -{ - struct iovec iov[2]; - struct msghdr msg; - int result; - struct cmsghdr *cmsg; - char buf[CMSG_SPACE(sizeof(int))]; - - memset(&msg, 0, sizeof(msg)); - - iov[0].iov_base = (char *)header; - iov[0].iov_len = sizeof(struct ustcomm_header); - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - if (header->size && data) { - iov[1].iov_base = (char *)data; - iov[1].iov_len = header->size; - - msg.msg_iovlen++; - - } - - if (fd && header->fd_included) { - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - *(int *) CMSG_DATA(cmsg) = *fd; - msg.msg_controllen = cmsg->cmsg_len; - } - - result = sendmsg(sock, &msg, MSG_NOSIGNAL); - if (result < 0 && errno != EPIPE) { - PERROR("sendmsg failed"); - } - return result; -} - -int ustcomm_send(int sock, - const struct ustcomm_header *header, - const char *data) -{ - return ustcomm_send_fd(sock, header, data, NULL); -} - -int ustcomm_req(int sock, - const struct ustcomm_header *req_header, - const char *req_data, - struct ustcomm_header *res_header, - char *res_data) -{ - int result; - - result = ustcomm_send(sock, req_header, req_data); - if ( result <= 0) { - return result; - } - - return ustcomm_recv(sock, res_header, res_data); -} - -/* Return value: - * 0: success - * -1: error - */ - -int ustcomm_connect_path(const char *name, int *connection_fd) -{ - int result, fd; - size_t sock_addr_size; - struct sockaddr_un *addr; - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(fd == -1) { - PERROR("socket"); - return -1; - } - - addr = create_sock_addr(name, &sock_addr_size); - if (addr == NULL) { - ERR("allocating addr failed"); - goto close_sock; - } - - result = connect(fd, (struct sockaddr *)addr, sock_addr_size); - if(result == -1) { - PERROR("connect (path=%s)", name); - goto free_sock_addr; - } - - *connection_fd = fd; - - free(addr); - - return 0; - -free_sock_addr: - free(addr); -close_sock: - close(fd); - - return -1; -} - -/* Returns the current users socket directory, must be freed */ -char *ustcomm_user_sock_dir(void) -{ - int result; - char *sock_dir = NULL; - - result = asprintf(&sock_dir, "%s%s", USER_SOCK_DIR, - cuserid(NULL)); - if (result < 0) { - ERR("string overflow allocating directory name"); - return NULL; - } - - 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: - * 0: success - * -1: error - */ - -static int connect_app_non_root(pid_t pid, int *app_fd) -{ - int result; - int retval = 0; - char *dir_name; - char sock_name[PATH_MAX]; - - dir_name = ustcomm_user_sock_dir(); - if (!dir_name) - return -ENOMEM; - - if (ustcomm_get_sock_name(dir_name, pid, sock_name)) { - retval = -ENOENT; - goto free_dir_name; - } - - result = ustcomm_connect_path(sock_name, app_fd); - if (result < 0) { - ERR("failed to connect to app"); - retval = -1; - goto free_dir_name; - } - -free_dir_name: - free(dir_name); - - return retval; -} - - - -static int connect_app_root(pid_t pid, int *app_fd) -{ - DIR *tmp_dir; - struct dirent *dirent; - char dir_name[PATH_MAX], sock_name[PATH_MAX]; - int result = -1; - - tmp_dir = opendir(USER_TMP_DIR); - if (!tmp_dir) { - return -1; - } - - while ((dirent = readdir(tmp_dir))) { - if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE, - strlen(USER_SOCK_DIR_BASE))) { - - if (snprintf(dir_name, PATH_MAX - 1, "%s/%s", USER_TMP_DIR, - dirent->d_name) < 0) { - continue; - } - - if (ustcomm_get_sock_name(dir_name, pid, sock_name)) { - continue; - } - - result = ustcomm_connect_path(sock_name, app_fd); - - if (result == 0) { - goto close_tmp_dir; - } - } - } - -close_tmp_dir: - closedir(tmp_dir); - - return result; -} - -int ustcomm_connect_app(pid_t pid, int *app_fd) -{ - *app_fd = 0; - - if (geteuid()) { - return connect_app_non_root(pid, app_fd); - } else { - return connect_app_root(pid, app_fd); - } - -} - -int ensure_dir_exists(const char *dir, mode_t mode) -{ - struct stat st; - int result; - - if (!strcmp(dir, "")) - return -1; - - result = stat(dir, &st); - if (result < 0 && errno != ENOENT) { - return -1; - } else if (result < 0) { - /* ENOENT */ - int result; - - result = mkdir_p(dir, mode); - if(result != 0) { - ERR("executing in recursive creation of directory %s", dir); - return -1; - } - } else { - if (st.st_mode != mode) { - result = chmod(dir, mode); - if (result < 0) { - ERR("couldn't set directory mode on %s", dir); - return -1; - } - } - } - - return 0; -} - -char * ustcomm_print_data(char *data_field, int field_size, - int *offset, const char *format, ...) -{ - va_list args; - int count, limit; - char *ptr = USTCOMM_POISON_PTR; - - limit = field_size - *offset; - va_start(args, format); - count = vsnprintf(&data_field[*offset], limit, format, args); - va_end(args); - - if (count < limit && count > -1) { - ptr = NULL + *offset; - *offset = *offset + count + 1; - } - - return ptr; -} - -char * ustcomm_restore_ptr(char *ptr, char *data_field, int data_field_size) -{ - if ((unsigned long)ptr > data_field_size || - ptr == USTCOMM_POISON_PTR) { - return NULL; - } - - return data_field + (long)ptr; -} - -int ustcomm_pack_single_field(struct ustcomm_header *header, - struct ustcomm_single_field *single_field, - const char *string) -{ - int offset = 0; - - single_field->field = ustcomm_print_data(single_field->data, - sizeof(single_field->data), - &offset, - string); - - if (single_field->field == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - header->size = COMPUTE_MSG_SIZE(single_field, offset); - - return 0; -} - -int ustcomm_unpack_single_field(struct ustcomm_single_field *single_field) -{ - single_field->field = ustcomm_restore_ptr(single_field->field, - single_field->data, - sizeof(single_field->data)); - if (!single_field->field) { - return -EINVAL; - } - - return 0; -} - -int ustcomm_pack_channel_info(struct ustcomm_header *header, - struct ustcomm_channel_info *ch_inf, - const char *trace, - const char *channel) -{ - int offset = 0; - - ch_inf->trace = ustcomm_print_data(ch_inf->data, - sizeof(ch_inf->data), - &offset, - trace); - - if (ch_inf->trace == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - ch_inf->channel = ustcomm_print_data(ch_inf->data, - sizeof(ch_inf->data), - &offset, - channel); - - if (ch_inf->channel == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - header->size = COMPUTE_MSG_SIZE(ch_inf, offset); - - return 0; -} - - -int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf) -{ - ch_inf->trace = ustcomm_restore_ptr(ch_inf->trace, - ch_inf->data, - sizeof(ch_inf->data)); - if (!ch_inf->trace) { - return -EINVAL; - } - - ch_inf->channel = ustcomm_restore_ptr(ch_inf->channel, - ch_inf->data, - sizeof(ch_inf->data)); - if (!ch_inf->channel) { - return -EINVAL; - } - - return 0; -} - -int ustcomm_pack_buffer_info(struct ustcomm_header *header, - struct ustcomm_buffer_info *buf_inf, - const char *trace, - const char *channel, - int channel_cpu) -{ - int offset = 0; - - buf_inf->trace = ustcomm_print_data(buf_inf->data, - sizeof(buf_inf->data), - &offset, - trace); - - if (buf_inf->trace == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - buf_inf->channel = ustcomm_print_data(buf_inf->data, - sizeof(buf_inf->data), - &offset, - channel); - - if (buf_inf->channel == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - buf_inf->ch_cpu = channel_cpu; - - header->size = COMPUTE_MSG_SIZE(buf_inf, offset); - - return 0; -} - - -int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf) -{ - buf_inf->trace = ustcomm_restore_ptr(buf_inf->trace, - buf_inf->data, - sizeof(buf_inf->data)); - if (!buf_inf->trace) { - return -EINVAL; - } - - buf_inf->channel = ustcomm_restore_ptr(buf_inf->channel, - buf_inf->data, - sizeof(buf_inf->data)); - if (!buf_inf->channel) { - return -EINVAL; - } - - return 0; -} - -int ustcomm_pack_ust_marker_info(struct ustcomm_header *header, - struct ustcomm_ust_marker_info *ust_marker_inf, - const char *trace, - const char *channel, - const char *ust_marker) -{ - int offset = 0; - - ust_marker_inf->trace = ustcomm_print_data(ust_marker_inf->data, - sizeof(ust_marker_inf->data), - &offset, - trace); - - if (ust_marker_inf->trace == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - - ust_marker_inf->channel = ustcomm_print_data(ust_marker_inf->data, - sizeof(ust_marker_inf->data), - &offset, - channel); - - if (ust_marker_inf->channel == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - - ust_marker_inf->ust_marker = ustcomm_print_data(ust_marker_inf->data, - sizeof(ust_marker_inf->data), - &offset, - ust_marker); - - if (ust_marker_inf->ust_marker == USTCOMM_POISON_PTR) { - return -ENOMEM; - } - - header->size = COMPUTE_MSG_SIZE(ust_marker_inf, offset); - - return 0; -} - -int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info *ust_marker_inf) -{ - ust_marker_inf->trace = ustcomm_restore_ptr(ust_marker_inf->trace, - ust_marker_inf->data, - sizeof(ust_marker_inf->data)); - if (!ust_marker_inf->trace) { - return -EINVAL; - } - - ust_marker_inf->channel = ustcomm_restore_ptr(ust_marker_inf->channel, - ust_marker_inf->data, - sizeof(ust_marker_inf->data)); - if (!ust_marker_inf->channel) { - return -EINVAL; - } - - ust_marker_inf->ust_marker = ustcomm_restore_ptr(ust_marker_inf->ust_marker, - ust_marker_inf->data, - sizeof(ust_marker_inf->data)); - if (!ust_marker_inf->ust_marker) { - return -EINVAL; - } - - return 0; -} - diff --git a/libustcomm/ustcomm.h b/libustcomm/ustcomm.h deleted file mode 100644 index 4706b72f..00000000 --- a/libustcomm/ustcomm.h +++ /dev/null @@ -1,220 +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 USTCOMM_H -#define USTCOMM_H - -#include -#include -#include - -#include - -#define SOCK_DIR "/tmp/ust-app-socks" -#define USER_TMP_DIR "/tmp" -#define USER_SOCK_DIR_BASE "ust-socks-" -#define USER_SOCK_DIR USER_TMP_DIR "/" USER_SOCK_DIR_BASE - -struct ustcomm_sock { - struct cds_list_head list; - int fd; - int epoll_fd; -}; - -struct ustcomm_header { - int command; - long size; - int result; - int fd_included; -}; - -#define USTCOMM_BUFFER_SIZE ((1 << 12) - sizeof(struct ustcomm_header)) - -/* Specify a sata size that leaves margin at the end of a buffer - * in order to make sure that we never have more data than - * will fit in the buffer AND that the last chars (due to a - * pre-receive memset) will always be 0, terminating any string - */ -#define USTCOMM_DATA_SIZE (USTCOMM_BUFFER_SIZE - 20 * sizeof(void *)) - -enum tracectl_commands { - ALLOC_TRACE, - CONSUME_BUFFER, - CREATE_TRACE, - DESTROY_TRACE, - DISABLE_MARKER, - ENABLE_MARKER, - EXIT, - FORCE_SUBBUF_SWITCH, - GET_BUF_SHMID_PIPE_FD, - GET_PIDUNIQUE, - GET_SOCK_PATH, - GET_SUBBUFFER, - GET_SUBBUF_NUM_SIZE, - LIST_MARKERS, - LIST_TRACE_EVENTS, - LOAD_PROBE_LIB, - NOTIFY_BUF_MAPPED, - PRINT_MARKERS, - PRINT_TRACE_EVENTS, - PUT_SUBBUFFER, - SETUP_TRACE, - SET_SOCK_PATH, - SET_SUBBUF_NUM, - SET_SUBBUF_SIZE, - START, - START_TRACE, - STOP_TRACE, -}; - -struct ustcomm_single_field { - char *field; - char data[USTCOMM_DATA_SIZE]; -}; - -struct ustcomm_channel_info { - char *trace; - char *channel; - unsigned int subbuf_size; - unsigned int subbuf_num; - char data[USTCOMM_DATA_SIZE]; -}; - -struct ustcomm_buffer_info { - char *trace; - char *channel; - int ch_cpu; - pid_t pid; - int buf_shmid; - int buf_struct_shmid; - long consumed_old; - char data[USTCOMM_DATA_SIZE]; -}; - -struct ustcomm_ust_marker_info { - char *trace; - char *channel; - char *ust_marker; - char data[USTCOMM_DATA_SIZE]; -}; - -struct ustcomm_pidunique { - s64 pidunique; -}; - -struct ustcomm_notify_buf_mapped { - char data[USTCOMM_DATA_SIZE]; -}; - -/* Ensure directory existence, usefull for unix sockets */ -extern int ensure_dir_exists(const char *dir, mode_t mode); - -/* Create and delete sockets */ -extern struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd, - struct cds_list_head *list); -extern void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll); - -/* Create and delete named sockets */ -extern struct ustcomm_sock * ustcomm_init_named_socket(const char *name, - int epoll_fd); -extern void ustcomm_del_named_sock(struct ustcomm_sock *sock, - int keep_socket_file); - -/* Send and receive functions for file descriptors */ -extern int ustcomm_send_fd(int sock, const struct ustcomm_header *header, - const char *data, int *fd); -extern int ustcomm_recv_fd(int sock, struct ustcomm_header *header, - char *data, int *fd); - -/* Normal send and receive functions */ -extern int ustcomm_send(int sock, const struct ustcomm_header *header, - const char *data); -extern int ustcomm_recv(int sock, struct ustcomm_header *header, - char *data); - -/* Receive and allocate data, not to be used inside libust */ -extern int ustcomm_recv_alloc(int sock, - struct ustcomm_header *header, - char **data); - -/* Request function, send and receive */ -extern int ustcomm_req(int sock, - const struct ustcomm_header *req_header, - const char *req_data, - struct ustcomm_header *res_header, - char *res_data); - -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); - -extern int nth_token_is(const char *str, const char *token, int tok_no); - -extern char *nth_token(const char *str, int tok_no); - -/* String serialising functions, printf straight into a buffer */ -#define USTCOMM_POISON_PTR (void *)0x19831018 - -extern char * ustcomm_print_data(char *data_field, int field_size, - int *offset, const char *format, ...); -extern char * ustcomm_restore_ptr(char *ptr, char *data_field, - int data_field_size); - -#define COMPUTE_MSG_SIZE(struct_ptr, offset) \ - (size_t) (long)(struct_ptr)->data - (long)(struct_ptr) + (offset) - -/* Packing and unpacking functions, making life easier */ -extern int ustcomm_pack_single_field(struct ustcomm_header *header, - struct ustcomm_single_field *sf, - const char *trace); - -extern int ustcomm_unpack_single_field(struct ustcomm_single_field *sf); - -extern int ustcomm_pack_channel_info(struct ustcomm_header *header, - struct ustcomm_channel_info *ch_inf, - const char *trace, - const char *channel); - -extern int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf); - -extern int ustcomm_pack_buffer_info(struct ustcomm_header *header, - struct ustcomm_buffer_info *buf_inf, - const char *trace, - const char *channel, - int channel_cpu); - -extern int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf); - -extern int ustcomm_pack_ust_marker_info(struct ustcomm_header *header, - struct ustcomm_ust_marker_info *ust_marker_inf, - const char *trace, - const char *channel, - const char *ust_marker); - -extern int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info *ust_marker_inf); - -#endif /* USTCOMM_H */ diff --git a/libustconsumer/Makefile.am b/libustconsumer/Makefile.am deleted file mode 100644 index 1f874797..00000000 --- a/libustconsumer/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \ - -I$(top_srcdir)/include -AM_CFLAGS = -fno-strict-aliasing - -lib_LTLIBRARIES = libustconsumer.la - -libustconsumer_la_SOURCES = libustconsumer.c lowlevel.c lowlevel.h - -libustconsumer_la_LDFLAGS = -no-undefined -version-info 0:0:0 - -libustconsumer_la_LIBADD = \ - -lpthread \ - $(top_builddir)/snprintf/libustsnprintf.la \ - $(top_builddir)/libustcomm/libustcomm.la - -libustconsumer_la_CFLAGS = -fno-strict-aliasing diff --git a/libustconsumer/libustconsumer.c b/libustconsumer/libustconsumer.c deleted file mode 100644 index c6dd20c3..00000000 --- a/libustconsumer/libustconsumer.c +++ /dev/null @@ -1,923 +0,0 @@ -/* Copyright (C) 2009 Pierre-Marc Fournier - * 2010 Alexis Halle - * - * 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 -#include -#include -#include -#include - -#include -#include "lowlevel.h" -#include "usterr_signal_safe.h" -#include "ustcomm.h" - -#define GET_SUBBUF_OK 1 -#define GET_SUBBUF_DONE 0 -#define GET_SUBBUF_DIED 2 - -#define PUT_SUBBUF_OK 1 -#define PUT_SUBBUF_DIED 0 -#define PUT_SUBBUF_PUSHED 2 -#define PUT_SUBBUF_DONE 3 - -#define UNIX_PATH_MAX 108 - -static int get_subbuffer(struct buffer_info *buf) -{ - struct ustcomm_header _send_hdr, *send_hdr; - struct ustcomm_header _recv_hdr, *recv_hdr; - struct ustcomm_buffer_info _send_msg, _recv_msg; - struct ustcomm_buffer_info *send_msg, *recv_msg; - int result; - - send_hdr = &_send_hdr; - recv_hdr = &_recv_hdr; - send_msg = &_send_msg; - recv_msg = &_recv_msg; - - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, - buf->channel, buf->channel_cpu); - if (result < 0) { - return result; - } - - send_hdr->command = GET_SUBBUFFER; - - result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg, - recv_hdr, (char *)recv_msg); - if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) || - result == 0) { - DBG("app died while being traced"); - return GET_SUBBUF_DIED; - } else if (result < 0) { - ERR("get_subbuffer: ustcomm_req failed"); - return result; - } - - if (!recv_hdr->result) { - DBG("got subbuffer %s", buf->name); - buf->consumed_old = recv_msg->consumed_old; - return GET_SUBBUF_OK; - } else if (recv_hdr->result == -ENODATA) { - DBG("For buffer %s, the trace was not found. This likely means" - " it was destroyed by the user.", buf->name); - return GET_SUBBUF_DIED; - } - - DBG("error getting subbuffer %s", buf->name); - return recv_hdr->result; -} - -static int put_subbuffer(struct buffer_info *buf) -{ - struct ustcomm_header _send_hdr, *send_hdr; - struct ustcomm_header _recv_hdr, *recv_hdr; - struct ustcomm_buffer_info _send_msg, *send_msg; - int result; - - send_hdr = &_send_hdr; - recv_hdr = &_recv_hdr; - send_msg = &_send_msg; - - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, - buf->channel, buf->channel_cpu); - if (result < 0) { - return result; - } - - send_hdr->command = PUT_SUBBUFFER; - send_msg->consumed_old = buf->consumed_old; - - result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg, - recv_hdr, NULL); - if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) || - result == 0) { - DBG("app died while being traced"); - return PUT_SUBBUF_DIED; - } else if (result < 0) { - ERR("put_subbuffer: ustcomm_req failed"); - return result; - } - - if (!recv_hdr->result) { - DBG("put subbuffer %s", buf->name); - return PUT_SUBBUF_OK; - } else if (recv_hdr->result == -ENODATA) { - DBG("For buffer %s, the trace was not found. This likely means" - " it was destroyed by the user.", buf->name); - return PUT_SUBBUF_DIED; - } - - DBG("error getting subbuffer %s", buf->name); - return recv_hdr->result; -} - -void decrement_active_buffers(void *arg) -{ - struct ustconsumer_instance *instance = arg; - pthread_mutex_lock(&instance->mutex); - instance->active_buffers--; - pthread_mutex_unlock(&instance->mutex); -} - -static int get_pidunique(int sock, int64_t *pidunique) -{ - struct ustcomm_header _send_hdr, *send_hdr; - struct ustcomm_header _recv_hdr, *recv_hdr; - struct ustcomm_pidunique _recv_msg, *recv_msg; - int result; - - send_hdr = &_send_hdr; - recv_hdr = &_recv_hdr; - recv_msg = &_recv_msg; - - memset(send_hdr, 0, sizeof(*send_hdr)); - - send_hdr->command = GET_PIDUNIQUE; - result = ustcomm_req(sock, send_hdr, NULL, recv_hdr, (char *)recv_msg); - if (result < 1) { - return -ENOTCONN; - } - if (recv_hdr->result < 0) { - ERR("App responded with error: %s", strerror(recv_hdr->result)); - return recv_hdr->result; - } - - *pidunique = recv_msg->pidunique; - - return 0; -} - -static int get_buf_shmid_pipe_fd(int sock, struct buffer_info *buf, - int *buf_shmid, int *buf_struct_shmid, - int *buf_pipe_fd) -{ - struct ustcomm_header _send_hdr, *send_hdr; - struct ustcomm_header _recv_hdr, *recv_hdr; - struct ustcomm_buffer_info _send_msg, *send_msg; - struct ustcomm_buffer_info _recv_msg, *recv_msg; - int result, recv_pipe_fd; - - send_hdr = &_send_hdr; - recv_hdr = &_recv_hdr; - send_msg = &_send_msg; - recv_msg = &_recv_msg; - - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, - buf->channel, buf->channel_cpu); - if (result < 0) { - ERR("Failed to pack buffer info"); - return result; - } - - send_hdr->command = GET_BUF_SHMID_PIPE_FD; - - result = ustcomm_send(sock, send_hdr, (char *)send_msg); - if (result < 1) { - ERR("Failed to send request"); - return -ENOTCONN; - } - result = ustcomm_recv_fd(sock, recv_hdr, (char *)recv_msg, &recv_pipe_fd); - if (result < 1) { - ERR("Failed to receive message and fd"); - return -ENOTCONN; - } - if (recv_hdr->result < 0) { - ERR("App responded with error %s", strerror(recv_hdr->result)); - return recv_hdr->result; - } - - *buf_shmid = recv_msg->buf_shmid; - *buf_struct_shmid = recv_msg->buf_struct_shmid; - *buf_pipe_fd = recv_pipe_fd; - - return 0; -} - -static int get_subbuf_num_size(int sock, struct buffer_info *buf, - int *subbuf_num, int *subbuf_size) -{ - struct ustcomm_header _send_hdr, *send_hdr; - struct ustcomm_header _recv_hdr, *recv_hdr; - struct ustcomm_channel_info _send_msg, *send_msg; - struct ustcomm_channel_info _recv_msg, *recv_msg; - int result; - - send_hdr = &_send_hdr; - recv_hdr = &_recv_hdr; - send_msg = &_send_msg; - recv_msg = &_recv_msg; - - result = ustcomm_pack_channel_info(send_hdr, send_msg, buf->trace, - buf->channel); - if (result < 0) { - return result; - } - - send_hdr->command = GET_SUBBUF_NUM_SIZE; - - result = ustcomm_req(sock, send_hdr, (char *)send_msg, - recv_hdr, (char *)recv_msg); - if (result < 1) { - return -ENOTCONN; - } - - *subbuf_num = recv_msg->subbuf_num; - *subbuf_size = recv_msg->subbuf_size; - - return recv_hdr->result; -} - - -static int notify_buffer_mapped(int sock, struct buffer_info *buf) -{ - struct ustcomm_header _send_hdr, *send_hdr; - struct ustcomm_header _recv_hdr, *recv_hdr; - struct ustcomm_buffer_info _send_msg, *send_msg; - int result; - - send_hdr = &_send_hdr; - recv_hdr = &_recv_hdr; - send_msg = &_send_msg; - - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace, - buf->channel, buf->channel_cpu); - if (result < 0) { - return result; - } - - send_hdr->command = NOTIFY_BUF_MAPPED; - - result = ustcomm_req(sock, send_hdr, (char *)send_msg, - recv_hdr, NULL); - if (result < 1) { - return -ENOTCONN; - } - - return recv_hdr->result; -} - - -struct buffer_info *connect_buffer(struct ustconsumer_instance *instance, pid_t pid, - const char *trace, const char *channel, - int channel_cpu) -{ - struct buffer_info *buf; - int result; - struct shmid_ds shmds; - - buf = (struct buffer_info *) zmalloc(sizeof(struct buffer_info)); - if(buf == NULL) { - ERR("add_buffer: insufficient memory"); - return NULL; - } - - buf->trace = strdup(trace); - if (!buf->trace) { - goto free_buf; - } - - buf->channel = strdup(channel); - if (!buf->channel) { - goto free_buf_trace; - } - - result = asprintf(&buf->name, "%s_%d", channel, channel_cpu); - if (result < 0 || buf->name == NULL) { - goto free_buf_channel; - } - - buf->channel_cpu = channel_cpu; - buf->pid = pid; - - result = ustcomm_connect_app(buf->pid, &buf->app_sock); - if(result) { - WARN("unable to connect to process, it probably died before we were able to connect"); - goto free_buf_name; - } - - /* get pidunique */ - result = get_pidunique(buf->app_sock, &buf->pidunique); - if (result < 0) { - ERR("Failed to get pidunique"); - goto close_app_sock; - } - - /* get shmid and pipe fd */ - result = get_buf_shmid_pipe_fd(buf->app_sock, buf, &buf->shmid, - &buf->bufstruct_shmid, &buf->pipe_fd); - if (result < 0) { - ERR("Failed to get buf_shmid and pipe_fd"); - goto close_app_sock; - } else { - struct stat temp; - fstat(buf->pipe_fd, &temp); - if (!S_ISFIFO(temp.st_mode)) { - ERR("Didn't receive a fifo from the app"); - goto close_app_sock; - } - } - - - /* get number of subbufs and subbuf size */ - result = get_subbuf_num_size(buf->app_sock, buf, &buf->n_subbufs, - &buf->subbuf_size); - if (result < 0) { - ERR("Failed to get subbuf number and size"); - goto close_fifo; - } - - /* Set subbuffer's information */ - buf->subbuf_size_order = get_count_order(buf->subbuf_size); - buf->alloc_size = buf->subbuf_size * buf->n_subbufs; - - /* attach memory */ - buf->mem = shmat(buf->shmid, NULL, 0); - if(buf->mem == (void *) 0) { - PERROR("shmat"); - goto close_fifo; - } - DBG("successfully attached buffer memory"); - - buf->bufstruct_mem = shmat(buf->bufstruct_shmid, NULL, 0); - if(buf->bufstruct_mem == (void *) 0) { - PERROR("shmat"); - goto shmdt_mem; - } - DBG("successfully attached buffer bufstruct memory"); - - /* obtain info on the memory segment */ - result = shmctl(buf->shmid, IPC_STAT, &shmds); - if(result == -1) { - PERROR("shmctl"); - goto shmdt_bufstruct_mem; - } - buf->memlen = shmds.shm_segsz; - - /* Notify the application that we have mapped the buffer */ - result = notify_buffer_mapped(buf->app_sock, buf); - if (result < 0) { - goto shmdt_bufstruct_mem; - } - - if(instance->callbacks->on_open_buffer) - instance->callbacks->on_open_buffer(instance->callbacks, buf); - - pthread_mutex_lock(&instance->mutex); - instance->active_buffers++; - pthread_mutex_unlock(&instance->mutex); - - return buf; - -shmdt_bufstruct_mem: - shmdt(buf->bufstruct_mem); - -shmdt_mem: - shmdt(buf->mem); - -close_fifo: - close(buf->pipe_fd); - -close_app_sock: - close(buf->app_sock); - -free_buf_name: - free(buf->name); - -free_buf_channel: - free(buf->channel); - -free_buf_trace: - free(buf->trace); - -free_buf: - free(buf); - return NULL; -} - -static void destroy_buffer(struct ustconsumer_callbacks *callbacks, - struct buffer_info *buf) -{ - int result; - - result = close(buf->pipe_fd); - if(result == -1) { - WARN("problem closing the pipe fd"); - } - - result = close(buf->app_sock); - if(result == -1) { - WARN("problem calling ustcomm_close_app"); - } - - result = shmdt(buf->mem); - if(result == -1) { - PERROR("shmdt"); - } - - result = shmdt(buf->bufstruct_mem); - if(result == -1) { - PERROR("shmdt"); - } - - if(callbacks->on_close_buffer) - callbacks->on_close_buffer(callbacks, buf); - - free(buf); -} - -int consumer_loop(struct ustconsumer_instance *instance, struct buffer_info *buf) -{ - int result = 0; - int read_result; - char read_buf; - - pthread_cleanup_push(decrement_active_buffers, instance); - - for(;;) { - read_result = read(buf->pipe_fd, &read_buf, 1); - /* get the subbuffer */ - if (read_result == 1) { - result = get_subbuffer(buf); - if (result < 0) { - ERR("error getting subbuffer"); - continue; - } else if (result == GET_SUBBUF_DIED) { - finish_consuming_dead_subbuffer(instance->callbacks, buf); - break; - } - } else if ((read_result == -1 && (errno == ECONNRESET || errno == EPIPE)) || - result == 0) { - DBG("App died while being traced"); - finish_consuming_dead_subbuffer(instance->callbacks, buf); - break; - } else if (read_result == -1 && errno == EINTR) { - continue; - } - - if(instance->callbacks->on_read_subbuffer) - instance->callbacks->on_read_subbuffer(instance->callbacks, buf); - - /* put the subbuffer */ - result = put_subbuffer(buf); - if(result == -1) { - ERR("unknown error putting subbuffer (channel=%s)", buf->name); - break; - } - else if(result == PUT_SUBBUF_PUSHED) { - ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name); - break; - } - else if(result == PUT_SUBBUF_DIED) { - DBG("application died while putting subbuffer"); - /* Skip the first subbuffer. We are not sure it is trustable - * because the put_subbuffer() did not complete. - */ - /* TODO: check on_put_error return value */ - if(instance->callbacks->on_put_error) - instance->callbacks->on_put_error(instance->callbacks, buf); - - finish_consuming_dead_subbuffer(instance->callbacks, buf); - break; - } - else if(result == PUT_SUBBUF_DONE) { - /* Done with this subbuffer */ - /* FIXME: add a case where this branch is used? Upon - * normal trace termination, at put_subbuf time, a - * special last-subbuffer code could be returned by - * the listener. - */ - break; - } - else if(result == PUT_SUBBUF_OK) { - } - } - - DBG("thread for buffer %s is stopping", buf->name); - - /* FIXME: destroy, unalloc... */ - - pthread_cleanup_pop(1); - - return 0; -} - -struct consumer_thread_args { - pid_t pid; - const char *trace; - const char *channel; - int channel_cpu; - struct ustconsumer_instance *instance; -}; - -void *consumer_thread(void *arg) -{ - struct buffer_info *buf; - struct consumer_thread_args *args = (struct consumer_thread_args *) arg; - int result; - sigset_t sigset; - - pthread_mutex_lock(&args->instance->mutex); - args->instance->active_threads++; - pthread_mutex_unlock(&args->instance->mutex); - - if(args->instance->callbacks->on_new_thread) - args->instance->callbacks->on_new_thread(args->instance->callbacks); - - /* Block signals that should be handled by the main thread. */ - result = sigemptyset(&sigset); - if(result == -1) { - PERROR("sigemptyset"); - goto end; - } - result = sigaddset(&sigset, SIGTERM); - if(result == -1) { - PERROR("sigaddset"); - goto end; - } - result = sigaddset(&sigset, SIGINT); - if(result == -1) { - PERROR("sigaddset"); - goto end; - } - result = sigprocmask(SIG_BLOCK, &sigset, NULL); - if(result == -1) { - PERROR("sigprocmask"); - goto end; - } - - buf = connect_buffer(args->instance, args->pid, args->trace, - args->channel, args->channel_cpu); - if(buf == NULL) { - ERR("failed to connect to buffer"); - goto end; - } - - consumer_loop(args->instance, buf); - - destroy_buffer(args->instance->callbacks, buf); - - end: - - if(args->instance->callbacks->on_close_thread) - args->instance->callbacks->on_close_thread(args->instance->callbacks); - - pthread_mutex_lock(&args->instance->mutex); - args->instance->active_threads--; - pthread_mutex_unlock(&args->instance->mutex); - - free((void *)args->channel); - free(args); - return NULL; -} - -int start_consuming_buffer(struct ustconsumer_instance *instance, pid_t pid, - const char *trace, const char *channel, - int channel_cpu) -{ - pthread_t thr; - struct consumer_thread_args *args; - int result; - - DBG("beginning of start_consuming_buffer: args: pid %d bufname %s_%d", pid, channel, - channel_cpu); - - args = (struct consumer_thread_args *) zmalloc(sizeof(struct consumer_thread_args)); - if (!args) { - return -ENOMEM; - } - - args->pid = pid; - args->trace = strdup(trace); - args->channel = strdup(channel); - args->channel_cpu = channel_cpu; - args->instance = instance; - DBG("beginning2 of start_consuming_buffer: args: pid %d trace %s" - " bufname %s_%d", args->pid, args->trace, args->channel, args->channel_cpu); - - result = pthread_create(&thr, NULL, consumer_thread, args); - if(result == -1) { - ERR("pthread_create failed"); - return -1; - } - result = pthread_detach(thr); - if(result == -1) { - ERR("pthread_detach failed"); - return -1; - } - DBG("end of start_consuming_buffer: args: pid %d trace %s " - "bufname %s_%d", args->pid, args->channel, args->trace, args->channel_cpu); - - return 0; -} -static void process_client_cmd(int sock, struct ustcomm_header *req_header, - char *recvbuf, struct ustconsumer_instance *instance) -{ - int result; - struct ustcomm_header _res_header = {0}; - struct ustcomm_header *res_header = &_res_header; - struct ustcomm_buffer_info *buf_inf; - - DBG("Processing client command"); - - switch (req_header->command) { - case CONSUME_BUFFER: - - buf_inf = (struct ustcomm_buffer_info *)recvbuf; - result = ustcomm_unpack_buffer_info(buf_inf); - if (result < 0) { - ERR("Couldn't unpack buffer info"); - return; - } - - DBG("Going to consume trace %s buffer %s_%d in process %d", - buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu, - buf_inf->pid); - result = start_consuming_buffer(instance, buf_inf->pid, - buf_inf->trace, - buf_inf->channel, - buf_inf->ch_cpu); - if (result < 0) { - ERR("error in add_buffer"); - return; - } - - res_header->result = 0; - break; - case EXIT: - res_header->result = 0; - /* Only there to force poll to return */ - break; - default: - res_header->result = -EINVAL; - WARN("unknown command: %d", req_header->command); - } - - if (ustcomm_send(sock, res_header, NULL) <= 0) { - ERR("couldn't send command response"); - } -} - -#define MAX_EVENTS 10 - -int ustconsumer_start_instance(struct ustconsumer_instance *instance) -{ - struct ustcomm_header recv_hdr; - char recv_buf[USTCOMM_BUFFER_SIZE]; - struct ustcomm_sock *epoll_sock; - struct epoll_event events[MAX_EVENTS]; - struct sockaddr addr; - int result, epoll_fd, accept_fd, nfds, i, addr_size, timeout; - - if(!instance->is_init) { - ERR("libustconsumer instance not initialized"); - return 1; - } - epoll_fd = instance->epoll_fd; - - timeout = -1; - - /* app loop */ - for(;;) { - nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout); - if (nfds == -1 && errno == EINTR) { - /* Caught signal */ - } else if (nfds == -1) { - PERROR("ustconsumer_start_instance: epoll_wait failed"); - continue; - } - - for (i = 0; i < nfds; ++i) { - epoll_sock = (struct ustcomm_sock *)events[i].data.ptr; - if (epoll_sock == instance->listen_sock) { - addr_size = sizeof(struct sockaddr); - accept_fd = accept(epoll_sock->fd, - &addr, - (socklen_t *)&addr_size); - if (accept_fd == -1) { - PERROR("ustconsumer_start_instance: " - "accept failed"); - continue; - } - ustcomm_init_sock(accept_fd, epoll_fd, - &instance->connections); - } else { - result = ustcomm_recv(epoll_sock->fd, &recv_hdr, - recv_buf); - if (result < 1) { - ustcomm_del_sock(epoll_sock, 0); - } else { - process_client_cmd(epoll_sock->fd, - &recv_hdr, recv_buf, - instance); - } - - } - } - - if (instance->quit_program) { - pthread_mutex_lock(&instance->mutex); - if (instance->active_buffers == 0 && instance->active_threads == 0) { - pthread_mutex_unlock(&instance->mutex); - break; - } - pthread_mutex_unlock(&instance->mutex); - timeout = 100; - } - } - - if(instance->callbacks->on_trace_end) - instance->callbacks->on_trace_end(instance); - - ustconsumer_delete_instance(instance); - - return 0; -} - -/* FIXME: threads and connections !? */ -void ustconsumer_delete_instance(struct ustconsumer_instance *instance) -{ - if (instance->is_init) { - ustcomm_del_named_sock(instance->listen_sock, 0); - close(instance->epoll_fd); - } - - pthread_mutex_destroy(&instance->mutex); - free(instance->sock_path); - free(instance); -} - -/* FIXME: Do something about the fixed path length, maybe get rid - * of the whole concept and use a pipe? - */ -int ustconsumer_stop_instance(struct ustconsumer_instance *instance, int send_msg) -{ - int result; - int fd; - int bytes = 0; - - char msg[] = "exit"; - - instance->quit_program = 1; - - if(!send_msg) - return 0; - - /* Send a message through the socket to force poll to return */ - - struct sockaddr_un addr; - -socket_again: - result = fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(result == -1) { - if (errno == EINTR) - goto socket_again; - PERROR("socket"); - return 1; - } - - addr.sun_family = AF_UNIX; - - strncpy(addr.sun_path, instance->sock_path, UNIX_PATH_MAX); - addr.sun_path[UNIX_PATH_MAX-1] = '\0'; - -connect_again: - result = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); - if(result == -1) { - if (errno == EINTR) - goto connect_again; - PERROR("connect"); - } - - while(bytes != sizeof(msg)) { - int inc = send(fd, msg, sizeof(msg), 0); - if (inc < 0 && errno != EINTR) - break; - else - bytes += inc; - } - - close(fd); - - return 0; -} - -struct ustconsumer_instance -*ustconsumer_new_instance(struct ustconsumer_callbacks *callbacks, - char *sock_path) -{ - struct ustconsumer_instance *instance = - zmalloc(sizeof(struct ustconsumer_instance)); - if(!instance) { - return NULL; - } - - instance->callbacks = callbacks; - instance->quit_program = 0; - instance->is_init = 0; - instance->active_buffers = 0; - pthread_mutex_init(&instance->mutex, NULL); - - if (sock_path) { - instance->sock_path = strdup(sock_path); - } else { - instance->sock_path = NULL; - } - - return instance; -} - -static int init_ustconsumer_socket(struct ustconsumer_instance *instance) -{ - char *name; - - if (instance->sock_path) { - if (asprintf(&name, "%s", instance->sock_path) < 0) { - ERR("ustcomm_init_ustconsumer : asprintf failed (sock_path %s)", - instance->sock_path); - return -1; - } - } else { - int result; - - /* Only check if socket dir exists if we are using the default directory */ - result = ensure_dir_exists(SOCK_DIR, S_IRWXU | S_IRWXG | S_IRWXO); - if (result == -1) { - ERR("Unable to create socket directory %s", SOCK_DIR); - return -1; - } - - if (asprintf(&name, "%s/%s", SOCK_DIR, "ustconsumer") < 0) { - ERR("ustcomm_init_ustconsumer : asprintf failed (%s/ustconsumer)", - SOCK_DIR); - return -1; - } - } - - /* Set up epoll */ - instance->epoll_fd = epoll_create(MAX_EVENTS); - if (instance->epoll_fd == -1) { - ERR("epoll_create failed, start instance bailing"); - goto free_name; - } - - /* Create the named socket */ - instance->listen_sock = ustcomm_init_named_socket(name, - instance->epoll_fd); - if(!instance->listen_sock) { - ERR("error initializing named socket at %s", name); - goto close_epoll; - } - - CDS_INIT_LIST_HEAD(&instance->connections); - - free(name); - - return 0; - -close_epoll: - close(instance->epoll_fd); -free_name: - free(name); - - return -1; -} - -int ustconsumer_init_instance(struct ustconsumer_instance *instance) -{ - int result; - result = init_ustconsumer_socket(instance); - if(result == -1) { - ERR("failed to initialize socket"); - return 1; - } - instance->is_init = 1; - return 0; -} - diff --git a/libustconsumer/lowlevel.c b/libustconsumer/lowlevel.c deleted file mode 100644 index a54a8db0..00000000 --- a/libustconsumer/lowlevel.c +++ /dev/null @@ -1,207 +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 - */ - -#include -#include -#include - -#include "ust/ustconsumer.h" -#include "buffers.h" -#include "tracer.h" -#include "usterr_signal_safe.h" - -/* This truncates to an offset in the buffer. */ -#define USTD_BUFFER_TRUNC(offset, bufinfo) \ - ((offset) & (~(((bufinfo)->subbuf_size*(bufinfo)->n_subbufs)-1))) - -#define LTT_MAGIC_NUMBER 0x00D6B7ED -#define LTT_REV_MAGIC_NUMBER 0xEDB7D600 - - -static void ltt_relay_print_subbuffer_errors( - struct buffer_info *buf, - long cons_off, int cpu) -{ - struct ust_buffer *ust_buf = buf->bufstruct_mem; - long cons_idx, commit_count, commit_count_mask, write_offset; - - cons_idx = SUBBUF_INDEX(cons_off, buf); - commit_count = uatomic_read(&ust_buf->commit_seq[cons_idx]); - commit_count_mask = (~0UL >> get_count_order(buf->n_subbufs)); - - /* - * No need to order commit_count and write_offset reads because we - * execute after trace is stopped when there are no readers left. - */ - write_offset = uatomic_read(&ust_buf->offset); - WARN( "LTT : unread channel %s offset is %ld " - "and cons_off : %ld (cpu %d)\n", - buf->channel, write_offset, cons_off, cpu); - /* Check each sub-buffer for non filled commit count */ - if (((commit_count - buf->subbuf_size) & commit_count_mask) - - (BUFFER_TRUNC(cons_off, buf) >> get_count_order(buf->n_subbufs)) != 0) { - ERR("LTT : %s : subbuffer %lu has non filled " - "commit count [seq] [%lu].\n", - buf->channel, cons_idx, commit_count); - } - ERR("LTT : %s : commit count : %lu, subbuf size %d\n", - buf->channel, commit_count, - buf->subbuf_size); -} - -static void ltt_relay_print_errors(struct buffer_info *buf, int cpu) -{ - struct ust_buffer *ust_buf = buf->bufstruct_mem; - long cons_off; - - for (cons_off = uatomic_read(&ust_buf->consumed); - (SUBBUF_TRUNC(uatomic_read(&ust_buf->offset), buf) - - cons_off) > 0; - cons_off = SUBBUF_ALIGN(cons_off, buf)) - ltt_relay_print_subbuffer_errors(buf, cons_off, cpu); -} - -static void ltt_relay_print_buffer_errors(struct buffer_info *buf, int cpu) -{ - struct ust_buffer *ust_buf = buf->bufstruct_mem; - - if (uatomic_read(&ust_buf->events_lost)) - ERR("channel %s: %ld events lost (cpu %d)", - buf->channel, - uatomic_read(&ust_buf->events_lost), cpu); - if (uatomic_read(&ust_buf->corrupted_subbuffers)) - ERR("channel %s : %ld corrupted subbuffers (cpu %d)", - buf->channel, - uatomic_read(&ust_buf->corrupted_subbuffers), cpu); - - ltt_relay_print_errors(buf, cpu); -} - -/* Returns the size of a subbuffer size. This is the size that - * will need to be written to disk. - * - * @subbuffer: pointer to the beginning of the subbuffer (the - * beginning of its header) - */ - -size_t subbuffer_data_size(void *subbuf) -{ - struct ltt_subbuffer_header *header = subbuf; - int reverse; - u32 data_size; - - if(header->magic_number == LTT_MAGIC_NUMBER) { - reverse = 0; - } - else if(header->magic_number == LTT_REV_MAGIC_NUMBER) { - reverse = 1; - } - else { - return -1; - } - - data_size = header->sb_size; - if(reverse) - data_size = bswap_32(data_size); - - return data_size; -} - - -void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf) -{ - struct ust_buffer *ust_buf = buf->bufstruct_mem; - unsigned long n_subbufs_order = get_count_order(buf->n_subbufs); - unsigned long commit_seq_mask = (~0UL >> n_subbufs_order); - unsigned long cons_off; - int ret; - - DBG("processing dead buffer (%s)", buf->name); - DBG("consumed offset is %ld (%s)", uatomic_read(&ust_buf->consumed), - buf->name); - DBG("write offset is %ld (%s)", uatomic_read(&ust_buf->offset), - buf->name); - - /* - * Iterate on subbuffers to recover, including the one the writer - * just wrote data into. Using write position - 1 since the writer - * position points into the position that is going to be written. - */ - for (cons_off = uatomic_read(&ust_buf->consumed); - (long) (SUBBUF_TRUNC(uatomic_read(&ust_buf->offset) - 1, buf) - - cons_off) >= 0; - cons_off = SUBBUF_ALIGN(cons_off, buf)) { - /* - * commit_seq is the offset in the buffer of the end of the last sequential commit. - * Bytes beyond this limit cannot be recovered. This is a free-running counter. - */ - unsigned long commit_seq = - uatomic_read(&ust_buf->commit_seq[SUBBUF_INDEX(cons_off, buf)]); - struct ltt_subbuffer_header *header = - (struct ltt_subbuffer_header *)((char *) buf->mem - + SUBBUF_INDEX(cons_off, buf) * buf->subbuf_size); - unsigned long valid_length; - - /* Check if subbuf was fully written. This is from Mathieu's algorithm/paper. */ - if (((commit_seq - buf->subbuf_size) & commit_seq_mask) - - (USTD_BUFFER_TRUNC(uatomic_read(&ust_buf->consumed), buf) >> n_subbufs_order) == 0 - && header->data_size != 0xffffffff) { - assert(header->sb_size != 0xffffffff); - /* - * If it was fully written, we only check the data_size. - * This is the amount of valid data at the beginning of - * the subbuffer. - */ - valid_length = header->data_size; - DBG("writing full subbuffer (%ld) with valid_length = %ld", - SUBBUF_INDEX(cons_off, buf), valid_length); - } else { - /* - * If the subbuffer was not fully written, then we don't - * check data_size because it hasn't been written yet. - * Instead we check commit_seq and use it to choose a - * value for data_size. The viewer will need this value - * when parsing. Generally, this will happen only for - * the last subbuffer. However, if we have threads still - * holding reserved slots in the previous subbuffers, - * which could happen for other subbuffers prior to the - * last one. Note that when data_size is set, the - * commit_seq count is still at a value that shows the - * amount of valid data to read. It's only _after_ - * writing data_size that commit_seq is updated to - * include the end-of-buffer padding. - */ - valid_length = commit_seq & (buf->subbuf_size - 1); - DBG("writing unfull subbuffer (%ld) with valid_length = %ld", - SUBBUF_INDEX(cons_off, buf), valid_length); - header->data_size = valid_length; - header->sb_size = PAGE_ALIGN(valid_length); - } - - if (callbacks->on_read_partial_subbuffer) { - ret = callbacks->on_read_partial_subbuffer(callbacks, buf, - SUBBUF_INDEX(cons_off, buf), - valid_length); - if (ret < 0) - break; /* Error happened */ - } - } - /* Increment the consumed offset */ - uatomic_set(&ust_buf->consumed, cons_off); - ltt_relay_print_buffer_errors(buf, buf->channel_cpu); -} - diff --git a/libustconsumer/lowlevel.h b/libustconsumer/lowlevel.h deleted file mode 100644 index 6ae6476c..00000000 --- a/libustconsumer/lowlevel.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * lowlevel libustd header file - * - * Copyright 2005-2010 - - * Mathieu Desnoyers - * Copyright 2010- - * Oumarou Dicko - * Michael Sills-Lavoie - * Alexis Halle - * - * 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 LOWLEVEL_H -#define LOWLEVEL_H - -#include "ust/ustconsumer.h" - -void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf); -size_t subbuffer_data_size(void *subbuf); - -#endif /* LOWLEVEL_H */ - diff --git a/libustctl/Makefile.am b/libustctl/Makefile.am deleted file mode 100644 index bc7526b9..00000000 --- a/libustctl/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 = 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 deleted file mode 100644 index fd4cc978..00000000 --- a/libustctl/README +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index 4e6c495c..00000000 --- a/libustctl/libustctl.c +++ /dev/null @@ -1,770 +0,0 @@ -/* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette - * Copyright (C) 2011 Ericsson AB - * - * 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(int sock, - const struct ustcomm_header *req_header, - const char *req_data, - struct ustcomm_header *res_header, - char **res_data) -{ - int result, saved_errno = 0; - char *recv_buf; - - recv_buf = zmalloc(USTCOMM_BUFFER_SIZE); - if (!recv_buf) { - saved_errno = ENOMEM; - goto out; - } - - result = ustcomm_req(sock, 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); - } - -out: - errno = saved_errno; - if (errno) { - return -1; - } - - return 0; -} - -int ustctl_connect_pid(pid_t pid) -{ - int sock; - - if (ustcomm_connect_app(pid, &sock)) { - ERR("could not connect to PID %u", (unsigned int) pid); - errno = ENOTCONN; - return -1; - } - - return sock; -} - -static int realloc_pid_list(pid_t **pid_list, unsigned int *pid_list_size) -{ - pid_t *new_pid_list; - unsigned int new_pid_list_size = 2 * *pid_list_size; - - new_pid_list = realloc(*pid_list, - new_pid_list_size * sizeof(pid_t)); - if (!*new_pid_list) { - return -1; - } - - *pid_list = new_pid_list; - *pid_list_size = new_pid_list_size; - - return 0; -} - -static int get_pids_in_dir(DIR *dir, pid_t **pid_list, - unsigned int *pid_list_index, - unsigned int *pid_list_size) -{ - struct dirent *dirent; - pid_t read_pid; - - while ((dirent = readdir(dir))) { - if (!strcmp(dirent->d_name, ".") || - !strcmp(dirent->d_name, "..") || - !strcmp(dirent->d_name, "ust-consumer") || - dirent->d_type == DT_DIR) { - - continue; - } - - if (ustcomm_is_socket_live(dirent->d_name, &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)) { - return -1; - } - } - } - } - - (*pid_list)[*pid_list_index] = 0; /* Array end */ - - return 0; -} - -static pid_t *get_pids_non_root(void) -{ - char *dir_name; - DIR *dir; - unsigned int pid_list_index = 0, pid_list_size = 1; - pid_t *pid_list = NULL; - - dir_name = ustcomm_user_sock_dir(); - if (!dir_name) { - return NULL; - } - - dir = opendir(dir_name); - if (!dir) { - goto free_dir_name; - } - - pid_list = malloc(pid_list_size * sizeof(pid_t)); - if (!pid_list) { - goto close_dir; - } - - if (get_pids_in_dir(dir, &pid_list, &pid_list_index, &pid_list_size)) { - /* if any errors are encountered, force freeing of the list */ - pid_list[0] = 0; - } - -close_dir: - closedir(dir); - -free_dir_name: - free(dir_name); - - return pid_list; -} - -static pid_t *get_pids_root(void) -{ - char *dir_name; - DIR *tmp_dir, *dir; - unsigned int pid_list_index = 0, pid_list_size = 1; - pid_t *pid_list = NULL; - struct dirent *dirent; - int result; - - tmp_dir = opendir(USER_TMP_DIR); - if (!tmp_dir) { - return NULL; - } - - pid_list = malloc(pid_list_size * sizeof(pid_t)); - if (!pid_list) { - goto close_tmp_dir; - } - - while ((dirent = readdir(tmp_dir))) { - /* Compare the dir to check for the USER_SOCK_DIR_BASE prefix */ - if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE, - strlen(USER_SOCK_DIR_BASE))) { - - if (asprintf(&dir_name, USER_TMP_DIR "/%s", - dirent->d_name) < 0) { - goto close_tmp_dir; - } - - dir = opendir(dir_name); - - free(dir_name); - - if (!dir) { - continue; - } - - result = get_pids_in_dir(dir, &pid_list, &pid_list_index, - &pid_list_size); - - closedir(dir); - - if (result) { - /* - * if any errors are encountered, - * force freeing of the list - */ - pid_list[0] = 0; - break; - } - } - } - -close_tmp_dir: - closedir(tmp_dir); - - return pid_list; -} - -pid_t *ustctl_get_online_pids(void) -{ - pid_t *pid_list; - - if (geteuid()) { - pid_list = get_pids_non_root(); - } else { - pid_list = get_pids_root(); - } - - if (pid_list && pid_list[0] == 0) { - /* No PID at all */ - free(pid_list); - pid_list = NULL; - } - - return pid_list; -} - -/** - * Sets ust_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_ust_marker_state(int sock, const char *trace, const char *channel, - const char *ust_marker, int state) -{ - struct ustcomm_header req_header, res_header; - struct ustcomm_ust_marker_info ust_marker_inf; - int result; - - result = ustcomm_pack_ust_marker_info(&req_header, - &ust_marker_inf, - trace, - channel, - ust_marker); - if (result < 0) { - errno = -result; - return -1; - } - - req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER; - - return do_cmd(sock, &req_header, (char *)&ust_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(int sock, const char *trace, const char *channel, - unsigned int subbuf_size) -{ - 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(sock, &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(int sock, const char *trace, const char *channel, - unsigned int num) -{ - 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(sock, &req_header, (char *)&ch_inf, - &res_header, NULL); - -} - - -static int ustctl_get_subbuf_num_size(int sock, const char *trace, const char *channel, - 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(sock, &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(int sock, const char *trace, const char *channel) -{ - int num, size, result; - - result = ustctl_get_subbuf_num_size(sock, trace, channel, - &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(int sock, const char *trace, const char *channel) -{ - int num, size, result; - - result = ustctl_get_subbuf_num_size(sock, trace, channel, - &num, &size); - if (result < 0) { - errno = -result; - return -1; - } - - return size; -} - -static int do_trace_cmd(int sock, const char *trace, 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(sock, &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(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, 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(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, 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(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, 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(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, 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(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, ALLOC_TRACE); -} - - -int ustctl_force_switch(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, FORCE_SUBBUF_SWITCH); -} - -/** - * 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(int sock, const char *trace) -{ - return do_trace_cmd(sock, trace, 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 ust_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].ust_marker); - free(cmsf[i].fs); - ++i; - } - free(cmsf); - - return 0; -} - -/** - * Gets channel/ust_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(int sock, struct ust_marker_status **cmsf) -{ - struct ustcomm_header req_header, res_header; - char *big_str = NULL; - int result; - struct ust_marker_status *tmp_cmsf = NULL; - unsigned int i = 0, cmsf_ind = 0; - - if (cmsf == NULL) { - return -1; - } - - req_header.command = LIST_MARKERS; - req_header.size = 0; - - result = ustcomm_send(sock, &req_header, NULL); - if (result <= 0) { - PERROR("error while requesting ust_marker list"); - return -1; - } - - result = ustcomm_recv_alloc(sock, &res_header, &big_str); - if (result <= 0) { - ERR("error while receiving ust_marker list"); - return -1; - } - - tmp_cmsf = (struct ust_marker_status *) zmalloc(sizeof(struct ust_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, "ust_marker: %a[^/]/%a[^ ] %c %a[^\n]", - &tmp_cmsf[cmsf_ind].channel, - &tmp_cmsf[cmsf_ind].ust_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].ust_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(int sock, struct trace_event_status **tes) -{ - struct ustcomm_header req_header, res_header; - char *big_str = NULL; - int result; - struct trace_event_status *tmp_tes = NULL; - unsigned int i = 0, tes_ind = 0; - - if (tes == NULL) { - return -1; - } - - req_header.command = LIST_TRACE_EVENTS; - req_header.size = 0; - - result = ustcomm_send(sock, &req_header, NULL); - if (result != 1) { - ERR("error while requesting trace_event list"); - return -1; - } - - result = ustcomm_recv_alloc(sock, &res_header, &big_str); - if (result != 1) { - ERR("error while receiving ust_marker list"); - return -1; - } - - 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 sock path - * - * @param sock_path Sock path - * @param pid Traced process ID - * @return 0 if successful, or error - */ -int ustctl_set_sock_path(int sock, const char *sock_path) -{ - 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(sock, &req_header, (char *)&sock_path_msg, - &res_header, NULL); -} - -/** - * Get sock path - * - * @param sock_path Pointer to where the sock path will be returned - * @param pid Traced process ID - * @return 0 if successful, or error - */ -int ustctl_get_sock_path(int sock, char **sock_path) -{ - 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(sock, &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; -} diff --git a/ust-consumerd/Makefile.am b/ust-consumerd/Makefile.am deleted file mode 100644 index 01e3b822..00000000 --- a/ust-consumerd/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \ - -I$(top_srcdir)/include -I$(top_srcdir)/libustconsumer -AM_CFLAGS = -fno-strict-aliasing - -bin_PROGRAMS = ust-consumerd - -ust_consumerd_SOURCES = ust-consumerd.c - -ust_consumerd_LDADD = \ - $(top_builddir)/snprintf/libustsnprintf.la \ - $(top_builddir)/libustcomm/libustcomm.la \ - $(top_builddir)/libustconsumer/libustconsumer.la - -ust_consumerd_CFLAGS = -DUST_COMPONENT=ust-consumerd -fno-strict-aliasing diff --git a/ust-consumerd/README b/ust-consumerd/README deleted file mode 100644 index 6df40155..00000000 --- a/ust-consumerd/README +++ /dev/null @@ -1,3 +0,0 @@ -This is ust-consumerd, the UST consumer daemon. - -This daemon is used to collect the traces for the traced programs and write them to disk. diff --git a/ust-consumerd/ust-consumerd.c b/ust-consumerd/ust-consumerd.c deleted file mode 100644 index 07612531..00000000 --- a/ust-consumerd/ust-consumerd.c +++ /dev/null @@ -1,516 +0,0 @@ -/* Copyright (C) 2009 Pierre-Marc Fournier - * 2010 Alexis Halle - * - * 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 -#include -#include -#include -#include -#include - -#include "ust/ustconsumer.h" -#include "../libustconsumer/lowlevel.h" -#include "usterr.h" - -char *sock_path=NULL; -char *trace_path=NULL; -int daemon_mode = 0; -char *pidfile = NULL; - -struct ustconsumer_instance *instance; - -struct buffer_info_local { - /* output file */ - int file_fd; - /* the offset we must truncate to, to unput the last subbuffer */ - off_t previous_offset; -}; - -static int write_pidfile(const char *file_name, pid_t pid) -{ - FILE *pidfp; - - pidfp = fopen(file_name, "w"); - if(!pidfp) { - PERROR("fopen (%s)", file_name); - WARN("killing child process"); - return -1; - } - - fprintf(pidfp, "%d\n", pid); - - fclose(pidfp); - - return 0; -} - -int create_dir_if_needed(char *dir) -{ - int result; - result = mkdir(dir, 0777); - if(result == -1) { - if(errno != EEXIST) { - PERROR("mkdir"); - return -1; - } - } - - return 0; -} - -int unwrite_last_subbuffer(struct buffer_info *buf) -{ - int result; - struct buffer_info_local *buf_local = buf->user_data; - - result = ftruncate(buf_local->file_fd, buf_local->previous_offset); - if(result == -1) { - PERROR("ftruncate"); - return -1; - } - - result = lseek(buf_local->file_fd, buf_local->previous_offset, SEEK_SET); - if(result == (int)(off_t)-1) { - PERROR("lseek"); - return -1; - } - - return 0; -} - -int write_current_subbuffer(struct buffer_info *buf) -{ - int result; - struct buffer_info_local *buf_local = buf->user_data; - - void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1)); - - size_t cur_sb_size = subbuffer_data_size(subbuf_mem); - - off_t cur_offset = lseek(buf_local->file_fd, 0, SEEK_CUR); - if(cur_offset == (off_t)-1) { - PERROR("lseek"); - return -1; - } - - buf_local->previous_offset = cur_offset; - DBG("previous_offset: %ld", cur_offset); - - result = patient_write(buf_local->file_fd, subbuf_mem, cur_sb_size); - if(result == -1) { - PERROR("write"); - return -1; - } - - return 0; -} - -int on_read_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf) -{ - return write_current_subbuffer(buf); -} - -int on_read_partial_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf, - long subbuf_index, unsigned long valid_length) -{ - struct buffer_info_local *buf_local = buf->user_data; - char *tmp; - int result; - unsigned long pad_size; - - result = patient_write(buf_local->file_fd, buf->mem + subbuf_index * buf->subbuf_size, valid_length); - if(result == -1) { - ERR("Error writing to buffer file"); - return result; - } - - /* pad with empty bytes */ - pad_size = PAGE_ALIGN(valid_length)-valid_length; - if(pad_size) { - tmp = zmalloc(pad_size); - result = patient_write(buf_local->file_fd, tmp, pad_size); - if(result == -1) { - ERR("Error writing to buffer file"); - return result; - } - free(tmp); - } - return result; -} - -int on_open_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf) -{ - char *tmp; - int result; - int fd; - struct buffer_info_local *buf_local = - zmalloc(sizeof(struct buffer_info_local)); - - if(!buf_local) { - ERR("could not allocate buffer_info_local struct"); - return 1; - } - - buf->user_data = buf_local; - - /* open file for output */ - if(!trace_path) { - /* Only create the directory if using the default path, because - * of the risk of typo when using trace path override. We don't - * want to risk creating plenty of useless directories in that case. - */ - result = create_dir_if_needed(USTCONSUMER_DEFAULT_TRACE_PATH); - if(result == -1) { - ERR("could not create directory %s", USTCONSUMER_DEFAULT_TRACE_PATH); - return 1; - } - - trace_path = USTCONSUMER_DEFAULT_TRACE_PATH; - } - - if (asprintf(&tmp, "%s/%u_%" PRId64 "", trace_path, buf->pid, buf->pidunique) < 0) { - ERR("on_open_buffer : asprintf failed (%s/%u_%" PRId64 ")", - trace_path, buf->pid, buf->pidunique); - return 1; - } - result = create_dir_if_needed(tmp); - if(result == -1) { - ERR("could not create directory %s", tmp); - free(tmp); - return 1; - } - free(tmp); - - if (asprintf(&tmp, "%s/%u_%" PRId64 "/%s", trace_path, buf->pid, buf->pidunique, buf->name) < 0) { - ERR("on_open_buffer : asprintf failed (%s/%u_%" PRId64 "/%s)", - trace_path, buf->pid, buf->pidunique, buf->name); - return 1; - } -again: - result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600); - if (result == -1 && errno == EINTR) - goto again; - - if(result == -1) { - PERROR("open"); - ERR("failed opening trace file %s", tmp); - return 1; - } - buf_local->file_fd = fd; - free(tmp); - - return 0; -} - -int on_close_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf) -{ - struct buffer_info_local *buf_local = buf->user_data; - int result; - -again: - result = close(buf_local->file_fd); - if (result == -1 && errno == EINTR) - goto again; - free(buf_local); - if(result == -1) { - PERROR("close"); - } - return 0; -} - -int on_put_error(struct ustconsumer_callbacks *data, struct buffer_info *buf) -{ - return unwrite_last_subbuffer(buf); -} - -struct ustconsumer_callbacks *new_callbacks() -{ - struct ustconsumer_callbacks *callbacks = - zmalloc(sizeof(struct ustconsumer_callbacks)); - - if(!callbacks) - return NULL; - - callbacks->on_open_buffer = on_open_buffer; - callbacks->on_close_buffer = on_close_buffer; - callbacks->on_read_subbuffer = on_read_subbuffer; - callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer; - callbacks->on_put_error = on_put_error; - callbacks->on_new_thread = NULL; - callbacks->on_close_thread = NULL; - callbacks->on_trace_end = NULL; - - return callbacks; - -} - -int is_directory(const char *dir) -{ - int result; - struct stat st; - - result = stat(dir, &st); - if(result == -1) { - PERROR("stat"); - return 0; - } - - if(!S_ISDIR(st.st_mode)) { - return 0; - } - - return 1; -} - -void usage(void) -{ - fprintf(stderr, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n" - "\t-h\t\tDisplay this usage.\n" - "\t-o DIR\t\tSpecify the directory where to output the traces.\n" - "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n" - "\t-d\t\tStart as a daemon.\n" - "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n"); -} - -int parse_args(int argc, char **argv) -{ - int c; - - while (1) { - int option_index = 0; - static struct option long_options[] = { - {"pidfile", 1, 0, 'p'}, - {"help", 0, 0, 'h'}, - {"version", 0, 0, 'V'}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 0: - printf("option %s", long_options[option_index].name); - if (optarg) - printf(" with arg %s", optarg); - printf("\n"); - break; - case 's': - sock_path = optarg; - break; - case 'o': - trace_path = optarg; - if(!is_directory(trace_path)) { - ERR("Not a valid directory. (%s)", trace_path); - return -1; - } - break; - case 'd': - daemon_mode = 1; - break; - case 'p': - pidfile = strdup(optarg); - break; - case 'h': - usage(); - exit(0); - case 'V': - printf("Version 0.0\n"); - break; - - default: - /* unknown option or other error; error is - printed by getopt, just return */ - return -1; - } - } - - return 0; -} - -void sigterm_handler(int sig) -{ - ustconsumer_stop_instance(instance, 0); -} - -int start_ustconsumer(int fd) -{ - int result; - sigset_t sigset; - struct sigaction sa; - - struct ustconsumer_callbacks *callbacks = new_callbacks(); - if(!callbacks) { - PERROR("new_callbacks"); - return 1; - } - - result = sigemptyset(&sigset); - if(result == -1) { - PERROR("sigemptyset"); - return 1; - } - sa.sa_handler = sigterm_handler; - sa.sa_mask = sigset; - sa.sa_flags = 0; - result = sigaction(SIGTERM, &sa, NULL); - if(result == -1) { - PERROR("sigaction"); - return 1; - } - result = sigaction(SIGINT, &sa, NULL); - if(result == -1) { - PERROR("sigaction"); - return 1; - } - - instance = ustconsumer_new_instance(callbacks, sock_path); - if(!instance) { - ERR("failed to create ustconsumer instance"); - return 1; - } - - result = ustconsumer_init_instance(instance); - if(result) { - ERR("failed to initialize ustconsumer instance"); - return 1; - } - - /* setup handler for SIGPIPE */ - result = sigemptyset(&sigset); - if(result == -1) { - PERROR("sigemptyset"); - return 1; - } - result = sigaddset(&sigset, SIGPIPE); - if(result == -1) { - PERROR("sigaddset"); - return 1; - } - result = sigprocmask(SIG_BLOCK, &sigset, NULL); - if(result == -1) { - PERROR("sigprocmask"); - return 1; - } - - /* Write pidfile */ - if(pidfile) { - result = write_pidfile(pidfile, getpid()); - if(result == -1) { - ERR("failed to write pidfile"); - return 1; - } - } - - /* Notify parent that we are successfully started. */ - if(fd != -1) { - /* write any one character */ - result = write(fd, "!", 1); - if(result == -1) { - PERROR("write"); - return -1; - } - if(result != 1) { - ERR("Problem sending confirmation of daemon start to parent"); - return -1; - } - result = close(fd); - if(result == -1) { - PERROR("close"); - } - } - - ustconsumer_start_instance(instance); - - free(callbacks); - - return 0; -} - -int start_ustconsumer_daemon() -{ - int result; - int fd[2]; - pid_t child_pid; - - result = pipe(fd); - - result = child_pid = fork(); - if(result == -1) { - PERROR("fork"); - return -1; - } - else if(result == 0) { - return start_ustconsumer(fd[1]); - } - else { - char buf; - - result = read(fd[0], &buf, 1); - if(result == -1) { - PERROR("read"); - return -1; - } - if(result != 1) { - ERR("did not receive valid confirmation that the daemon is started"); - return -1; - } - - result = close(fd[0]); - if(result == -1) { - PERROR("close"); - } - - DBG("The daemon is now successfully started"); - } - - /* Wait for confirmation that the server is ready. */ - - - return 0; -} - -int main(int argc, char **argv) -{ - int result; - - result = parse_args(argc, argv); - if(result == -1) { - exit(1); - } - - if(daemon_mode) { - result = start_ustconsumer_daemon(); - } - else { - result = start_ustconsumer(-1); - } - - return result; -} diff --git a/ustctl/Makefile.am b/ustctl/Makefile.am deleted file mode 100644 index 1e442a3f..00000000 --- a/ustctl/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm \ - -I$(top_srcdir)/libustctl $(KCOMPAT_CFLAGS) -AM_CFLAGS = -fno-strict-aliasing - -bin_PROGRAMS = ustctl - -ustctl_SOURCES = \ - 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)/libustctl/libustctl.la diff --git a/ustctl/README b/ustctl/README deleted file mode 100644 index 3fdfbbda..00000000 --- a/ustctl/README +++ /dev/null @@ -1,3 +0,0 @@ -ustctl is a helper application used to control tracing on programs that support tracing. - -It can list markers, enable/disable markers, start tracing and stop tracing. diff --git a/ustctl/channel_cmds.c b/ustctl/channel_cmds.c deleted file mode 100644 index 315fd56f..00000000 --- a/ustctl/channel_cmds.c +++ /dev/null @@ -1,151 +0,0 @@ -/* 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 sock, result = 0; - char *channel = NULL; - unsigned int size; - - sock = parse_and_connect_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(sock, argv[2], channel, size)) { - ERR("error while trying to set the size of subbuffers " - "for PID %s\n", - argv[1]); - result = -1; - } - - free(channel); - - return result; -} - -static int set_subbuf_num(int argc, char *argv[]) -{ - int sock, result = 0; - char *channel = NULL; - unsigned int num; - - sock = parse_and_connect_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(sock, argv[2], channel, num)) { - ERR("error while trying to set the number of subbuffers for PID %s\n", - argv[1]); - result = -1; - } - - free(channel); - - return result; -} - -static int get_subbuf_size(int argc, char *argv[]) -{ - int sock; - unsigned int size; - - sock = parse_and_connect_pid(argv[1]); - - if ((size = ustctl_get_subbuf_size(sock, argv[2], argv[3])) < 0) { - ERR("error while trying to get the subbuffer size from PID %s\n", - argv[1]); - return -1; - } - - printf("The subbufer size is %d bytes\n", size); - - return 0; -} - -static int get_subbuf_num(int argc, char *argv[]) -{ - int sock; - unsigned int num; - - sock = parse_and_connect_pid(argv[1]); - - if ((num = ustctl_get_subbuf_num(sock, argv[2], argv[3])) < 0) { - ERR("error while trying to get the subbuffer size from PID %s\n", - argv[1]); - 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 deleted file mode 100644 index 0ca9db5c..00000000 --- a/ustctl/cli.c +++ /dev/null @@ -1,207 +0,0 @@ -/* 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 deleted file mode 100644 index a1e4eed9..00000000 --- a/ustctl/cli.h +++ /dev/null @@ -1,50 +0,0 @@ -/* 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 deleted file mode 100644 index 8bcab832..00000000 --- a/ustctl/marker_cmds.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 ust_marker_status *cmsf = NULL; - int i, sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_get_cmsf(sock, &cmsf)) { - ERR("error while trying to list markers for PID %s\n", argv[1]); - return -1; - } - for (i = 0; cmsf[i].channel; i++) { - printf("{PID: %s, channel/marker: %s/%s, " - "state: %u, fmt: %s}\n", - argv[1], - cmsf[i].channel, - cmsf[i].ust_marker, - cmsf[i].state, - cmsf[i].fs); - } - ustctl_free_cmsf(cmsf); - return 0; -} - -static int enable_marker(int argc, char *argv[]) -{ - int i, sock, result = 0; - char *channel, *marker; - - sock = parse_and_connect_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_ust_marker_state(sock, argv[2], channel, marker, 1)) { - PERROR("error while trying to enable marker %s with PID %s", - argv[i], argv[1]); - result = -1; - } - free(channel); - free(marker); - } - - return result; -} - -static int disable_marker(int argc, char *argv[]) -{ - int i, sock, result = 0; - char *channel, *marker; - - sock = parse_and_connect_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_ust_marker_state(sock, argv[2], channel, marker, 0)) { - PERROR("error while trying to disable marker %s with PID %s", - argv[i], argv[1]); - result = -1; - } - free(channel); - free(marker); - } - - return result; -} - -struct cli_cmd __cli_cmds ust_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 deleted file mode 100644 index 4aa8c1c9..00000000 --- a/ustctl/scanning_functions.c +++ /dev/null @@ -1,91 +0,0 @@ -/* 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" - - -int parse_and_connect_pid(const char *pid_string) -{ - pid_t pid; - int sock; - - errno = 0; - pid = strtoull(pid_string, NULL, 10); - if (errno) { - perror("Failed to parse pid"); - exit(EXIT_FAILURE); - } - - sock = ustctl_connect_pid(pid); - if (sock < 0) { - perror("Failed to connect to process"); - exit(EXIT_FAILURE); - } - - return sock; -} - -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 deleted file mode 100644 index 0f2d62ed..00000000 --- a/ustctl/scanning_functions.h +++ /dev/null @@ -1,26 +0,0 @@ -/* 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 - -int parse_and_connect_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 deleted file mode 100644 index a8f3a9cc..00000000 --- a/ustctl/trace_cmds.c +++ /dev/null @@ -1,162 +0,0 @@ -/* 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[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_create_trace(sock, argv[2])) { - ERR("Failed to create trace %s for PID %s\n", argv[2], argv[1]); - return -1; - } - - return 0; -} - -static int alloc_trace(int argc, char *argv[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_alloc_trace(sock, argv[2])) { - ERR("Failed to allocate trace %s for PID %s\n", argv[2], argv[1]); - return -1; - } - return 0; -} - -static int start_trace(int argc, char *argv[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_start_trace(sock, argv[2])) { - ERR("Failed to start trace %s for PID %s\n", argv[2], argv[1]); - return -1; - } - return 0; -} - -static int stop_trace(int argc, char *argv[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_stop_trace(sock, argv[2])) { - ERR("Failed to stop trace %s for PID %s\n", argv[2], argv[1]); - return -1; - } - return 0; -} - -static int destroy_trace(int argc, char *argv[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_destroy_trace(sock, argv[2])) { - ERR("Failed to destroy trace %s for PID %s\n", argv[2], argv[1]); - return -1; - } - return 0; -} - -static int force_subbuf_switch(int argc, char *argv[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_force_switch(sock, argv[2])) { - ERR("error while trying to force switch for PID %s\n", argv[1]); - 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 deleted file mode 100644 index 18f7d307..00000000 --- a/ustctl/ustctl.c +++ /dev/null @@ -1,272 +0,0 @@ -/* 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 - * 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 "ust/ustctl.h" -#include "usterr.h" -#include "cli.h" -#include "scanning_functions.h" - -void usage(const char *process_name) -{ - 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); -} - -/* - * Provide backward compatibility for scripts that make use of the - * --commands in ustctl version <= 0.11 - */ -enum command { - CREATE_TRACE=1000, - ALLOC_TRACE, - START_TRACE, - STOP_TRACE, - DESTROY_TRACE, - LIST_MARKERS, - LIST_TRACE_EVENTS, - ENABLE_MARKER, - DISABLE_MARKER, -}; - -struct option 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", 0, 0, ENABLE_MARKER }, - { "disable-marker", 0, 0, DISABLE_MARKER }, - {"help", 2, NULL, 'h'}, - {"list", 0, NULL, 'l'}, - {"extended-list", 0, NULL, 'e'}, - {NULL, 0, NULL, 0}, -}; - -int main(int argc, char *argv[]) -{ - struct cli_cmd *cli_cmd; - char **args = argv; - int opt; - int i; - - if(argc <= 1) { - fprintf(stderr, "No operation specified.\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - - 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; - case 'l': - list_cli_cmds(CLI_SIMPLE_LIST); - exit(EXIT_FAILURE); - break; - case 'e': - list_cli_cmds(CLI_EXTENDED_LIST); - exit(EXIT_FAILURE); - case LIST_MARKERS: - case LIST_TRACE_EVENTS: - case CREATE_TRACE: - case ALLOC_TRACE: - case START_TRACE: - case STOP_TRACE: - case DESTROY_TRACE: - case ENABLE_MARKER: - case DISABLE_MARKER: - args = (char **)malloc(sizeof(char *) * (argc + 3)); - optind--; - args[optind] = strdup(&argv[optind][2]); - for (i = optind + 1; i < argc; i++) { - args[i] = argv[i]; - } - if (opt >= CREATE_TRACE && opt <= DESTROY_TRACE) { - args[argc] = strdup("auto"); - argc++; - } - if (opt >= ENABLE_MARKER && opt <= DISABLE_MARKER) { - args[argc] = args[argc - 2]; - args[argc - 2] = args[argc - 1]; - args[argc - 1] = strdup("auto"); - argc++; - } - args[argc] = NULL; - goto do_cli; - default: - fprintf(stderr, "Unknown option\n"); - break; - } - } - -do_cli: - cli_cmd = find_cli_cmd(args[optind]); - if (!cli_cmd) { - fprintf(stderr, "No such command %s\n", - args[optind]); - exit(EXIT_FAILURE); - } - - cli_dispatch_cmd(cli_cmd, argc - optind, &args[optind]); - - return 0; -} - -static int list_trace_events(int argc, char *argv[]) -{ - struct trace_event_status *tes = NULL; - int i, sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_get_tes(sock, &tes)) { - ERR("error while trying to list " - "trace_events for PID %s\n", - argv[1]); - return -1; - } - i = 0; - for (i = 0; tes[i].name; i++) { - printf("{PID: %s, trace_event: %s}\n", - argv[1], - tes[i].name); - } - ustctl_free_tes(tes); - - return 0; -} - -static int set_sock_path(int argc, char *argv[]) -{ - int sock; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_set_sock_path(sock, argv[2])) { - ERR("error while trying to set sock path for PID %s\n", argv[1]); - return -1; - } - - return 0; -} - -static int get_sock_path(int argc, char *argv[]) -{ - int sock; - char *sock_path; - - sock = parse_and_connect_pid(argv[1]); - - if (ustctl_get_sock_path(sock, &sock_path)) { - ERR("error while trying to get sock path for PID %s\n", argv[1]); - return -1; - } - printf("The socket path is %s\n", sock_path); - free(sock_path); - - return 0; -} - -static int list_pids(int argc, char *argv[]) -{ - pid_t *pid_list; - int i; - - pid_list = ustctl_get_online_pids(); - if (!pid_list) { - return -1; - } - - for (i = 0; pid_list[i]; i++) { - printf("%ld\n", (long)pid_list[i]); - } - - free(pid_list); - - 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, - }, - { - .name = "list-pids", - .description = "List traceable pids", - .help_text = "list-pids\n" - "List the traceable pids for the current user\n", - .function = list_pids, - .desired_args = 0, - .desired_args_op = CLI_EQ, - }, -};