[ltt-dev] New lttctl for debugfs-based ltt-trace-control
Mathieu Desnoyers
compudj at krystal.dyndns.org
Mon Dec 15 12:45:10 EST 2008
* Zhaolei (zhaolei at cn.fujitsu.com) wrote:
> Hi, Mathieu
>
> I modified lttctl for support debugfs-based ltt-trace-control.
> Command arguments are changed as we discussed in latest mail into following:
>
Hi Zhaolei,
I'm merging this in the next ltt-control version. I modified your code
to use readdir() to iterate on all channels to get the channel list.
Thanks !
Mathieu
> Usage: lttctl [OPTION]... [TRACENAME]
>
> Examples:
> lttctl -c trace1 # Create a trace named trace1.
> lttctl -s trace1 # start a trace named trace1.
> lttctl -p trace1 # pause a trace named trace1.
> lttctl -d trace1 # Destroy a trace named trace1.
> lttctl -C -w /tmp/trace1 trace1 # Create a trace named trace1, start it and
> # write non-overwrite channels' data to
> # /tmp/trace1, debugfs must be mounted for
> # auto-find
> lttctl -D -w /tmp/trace1 trace1 # Pause and destroy a trace named trace1 and
> # write overwrite channels' data to
> # /tmp/trace1, debugfs must be mounted for
> # auto-find
>
> Basic options:
> -c, --create
> Create a trace.
> -d, --destroy
> Destroy a trace.
> -s, --start
> Start a trace.
> -p, --pause
> Pause a trace.
> -h, --help
> Show this help.
>
> Advanced options:
> --transport TRANSPORT
> Set trace's transport. (ex. relay)
> -o, --option OPTION
> Set options, following operations are supported:
> channel.<channelname>.enable=
> channel.<channelname>.overwrite=
> channel.<channelname>.bufnum=
> channel.<channelname>.bufsize=
> <channelname> can be set to all for all channels
>
> Integration options:
> -C, --create_start
> Create and start a trace.
> -D, --pause_destroy
> Pause and destroy a trace.
> -w, --write PATH
> Path for write trace datas.
> For -c, -C, -d, -D options
> -a, --append
> Append to trace, For -w option
> -n, --dump_threads NUMBER
> Number of lttd threads, For -w option
> --channel_root PATH
> Set channels root path, For -w option. (ex. /mnt/debugfs/ltt)
>
> User-manual, and lttv also needs change to fit this patch.
>
> Because my English is poor, fix for help information of this patch is welcome.
>
> Signed-off-by: Zhao Lei <zhaolei at cn.fujitsu.com>
> ---
> diff -Nur ltt-control-0.59-25112008.org/liblttctl/liblttctl.c ltt-control-0.59-25112008.new/liblttctl/liblttctl.c
> --- ltt-control-0.59-25112008.org/liblttctl/liblttctl.c 2008-11-24 05:30:54.000000000 +0800
> +++ ltt-control-0.59-25112008.new/liblttctl/liblttctl.c 2008-12-15 10:56:47.000000000 +0800
> @@ -2,10 +2,7 @@
> *
> * Linux Trace Toolkit Netlink Control Library
> *
> - * Controls the ltt-control kernel module through a netlink socket.
> - *
> - * Heavily inspired from libipq.c (iptables) made by
> - * James Morris <jmorris at intercode.com.au>
> + * Controls the ltt-control kernel module through debugfs.
> *
> * Copyright 2005 -
> * Mathieu Desnoyers <mathieu.desnoyers at polymtl.ca>
> @@ -20,7 +17,7 @@
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> * GNU General Public License for more details.
> - *
> + *
> */
>
> #ifdef HAVE_CONFIG_H
> @@ -30,462 +27,612 @@
> #include <liblttctl/lttctl.h>
> #include <errno.h>
> #include <stdio.h>
> -#include <error.h>
> -#include <stdlib.h>
> -#include <sys/types.h>
> -#include <unistd.h>
> #include <string.h>
> +#include <dirent.h>
> +#include <limits.h>
> +#include <fcntl.h>
>
> +#define MAX_CHANNEL (256)
>
> +static char debugfsmntdir[PATH_MAX];
> +
> +static int initdebugfsmntdir(void)
> +{
> + char mnt_dir[PATH_MAX];
> + char mnt_type[PATH_MAX];
>
> -/* Private interface */
> + FILE *fp = fopen("/proc/mounts", "r");
> + if (!fp) {
> + fprintf(stderr, "%s: Can't open /proc/mounts\n", __func__);
> + return 1;
> + }
>
> -enum {
> - LTTCTL_ERR_NONE = 0,
> - LTTCTL_ERR_IMPL,
> - LTTCTL_ERR_HANDLE,
> - LTTCTL_ERR_SOCKET,
> - LTTCTL_ERR_BIND,
> - LTTCTL_ERR_BUFFER,
> - LTTCTL_ERR_RECV,
> - LTTCTL_ERR_NLEOF,
> - LTTCTL_ERR_ADDRLEN,
> - LTTCTL_ERR_STRUNC,
> - LTTCTL_ERR_RTRUNC,
> - LTTCTL_ERR_NLRECV,
> - LTTCTL_ERR_SEND,
> - LTTCTL_ERR_SUPP,
> - LTTCTL_ERR_RECVBUF,
> - LTTCTL_ERR_TIMEOUT,
> - LTTCTL_ERR_PROTOCOL,
> -};
> -#define LTTCTL_MAXERR LTTCTL_ERR_PROTOCOL
> -
> -
> -struct lttctl_errmap_t {
> - int errcode;
> - char *message;
> -} lttctl_errmap[] = {
> - { LTTCTL_ERR_NONE, "Unknown error" },
> - { LTTCTL_ERR_IMPL, "Implementation error" },
> - { LTTCTL_ERR_HANDLE, "Unable to create netlink handle" },
> - { LTTCTL_ERR_SOCKET, "Unable to create netlink socket" },
> - { LTTCTL_ERR_BIND, "Unable to bind netlink socket" },
> - { LTTCTL_ERR_BUFFER, "Unable to allocate buffer" },
> - { LTTCTL_ERR_RECV, "Failed to receive netlink message" },
> - { LTTCTL_ERR_NLEOF, "Received EOF on netlink socket" },
> - { LTTCTL_ERR_ADDRLEN, "Invalid peer address length" },
> - { LTTCTL_ERR_STRUNC, "Sent message truncated" },
> - { LTTCTL_ERR_RTRUNC, "Received message truncated" },
> - { LTTCTL_ERR_NLRECV, "Received error from netlink" },
> - { LTTCTL_ERR_SEND, "Failed to send netlink message" },
> - { LTTCTL_ERR_SUPP, "Operation not supported" },
> - { LTTCTL_ERR_RECVBUF, "Receive buffer size invalid" },
> - { LTTCTL_ERR_TIMEOUT, "Timeout"},
> - { LTTCTL_ERR_PROTOCOL, "Invalid protocol specified" }
> -};
> -
> -static int lttctl_errno = LTTCTL_ERR_NONE;
> -
> -
> -static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
> - const void *msg, size_t len);
> -
> -static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
> - unsigned char *buf, size_t len,
> - int timeout);
> -
> -static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
> - const struct msghdr *msg,
> - unsigned int flags);
> -
> -static char *lttctl_strerror(int errcode);
> -
> -void lttctl_perror(const char *s);
> -
> -static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
> - const void *msg, size_t len)
> -{
> - int status = sendto(h->fd, msg, len, 0,
> - (struct sockaddr *)&h->peer, sizeof(h->peer));
> - if (status < 0)
> - lttctl_errno = LTTCTL_ERR_SEND;
> -
> - return status;
> -}
> -
> -static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
> - const struct msghdr *msg,
> - unsigned int flags)
> -{
> - int status = sendmsg(h->fd, msg, flags);
> - if (status < 0)
> - lttctl_errno = LTTCTL_ERR_SEND;
> - return status;
> -}
> -
> -static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
> - unsigned char *buf, size_t len,
> - int timeout)
> -{
> - int addrlen, status;
> - struct nlmsghdr *nlh;
> -
> - if (len < sizeof(struct nlmsghdr)) {
> - lttctl_errno = LTTCTL_ERR_RECVBUF;
> - lttctl_perror("Netlink recvfrom");
> - return -1;
> - }
> - addrlen = sizeof(h->peer);
> -
> - if (timeout != 0) {
> - int ret;
> - struct timeval tv;
> - fd_set read_fds;
> -
> - if (timeout < 0) {
> - /* non-block non-timeout */
> - tv.tv_sec = 0;
> - tv.tv_usec = 0;
> - } else {
> - tv.tv_sec = timeout / 1000000;
> - tv.tv_usec = timeout % 1000000;
> - }
> -
> - FD_ZERO(&read_fds);
> - FD_SET(h->fd, &read_fds);
> - ret = select(h->fd+1, &read_fds, NULL, NULL, &tv);
> - if (ret < 0) {
> - if (errno == EINTR) {
> - printf("eintr\n");
> - return 0;
> - } else {
> - lttctl_errno = LTTCTL_ERR_RECV;
> - lttctl_perror("Netlink recvfrom");
> - return -1;
> - }
> - }
> - if (!FD_ISSET(h->fd, &read_fds)) {
> - lttctl_errno = LTTCTL_ERR_TIMEOUT;
> - printf("timeout\n");
> + while (1) {
> + if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type)
> + <= 0) {
> + fprintf(stderr, "%s: debugfs mountpoint not found\n",
> + __func__);
> + return 1;
> + }
> + if (!strcmp(mnt_type, "debugfs")) {
> + strcpy(debugfsmntdir, mnt_dir);
> return 0;
> }
> }
> - status = recvfrom(h->fd, buf, len, 0,
> - (struct sockaddr *)&h->peer, &addrlen);
> -
> - if (status < 0) {
> - lttctl_errno = LTTCTL_ERR_RECV;
> - lttctl_perror("Netlink recvfrom");
> - return status;
> - }
> - if (addrlen != sizeof(h->peer)) {
> - lttctl_errno = LTTCTL_ERR_RECV;
> - lttctl_perror("Netlink recvfrom");
> - return -1;
> - }
> - if (h->peer.nl_pid != 0) {
> - lttctl_errno = LTTCTL_ERR_RECV;
> - lttctl_perror("Netlink recvfrom");
> - return -1;
> - }
> - if (status == 0) {
> - lttctl_errno = LTTCTL_ERR_NLEOF;
> - lttctl_perror("Netlink recvfrom");
> - return -1;
> - }
> - nlh = (struct nlmsghdr *)buf;
> - if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) {
> - lttctl_errno = LTTCTL_ERR_RTRUNC;
> - lttctl_perror("Netlink recvfrom");
> - return -1;
> +}
> +
> +int lttctl_init(void)
> +{
> + int ret;
> + DIR *dir;
> + char controldirname[PATH_MAX];
> +
> + ret = initdebugfsmntdir();
> + if (ret) {
> + fprintf(stderr, "Debugfs mount point not found\n");
> + return 1;
> }
> -
>
> - return status;
> -}
> + /* check ltt control's debugfs dir */
> + sprintf(controldirname, "%s/ltt/control/", debugfsmntdir);
> +
> + dir = opendir(controldirname);
> + if (!dir) {
> + fprintf(stderr, "ltt-trace-control's debugfs dir not found\n");
> + closedir(dir);
> + return -errno;
> + }
>
> + closedir(dir);
>
> -static char *lttctl_strerror(int errcode)
> -{
> - if (errcode < 0 || errcode > LTTCTL_MAXERR)
> - errcode = LTTCTL_ERR_IMPL;
> - return lttctl_errmap[errcode].message;
> + return 0;
> }
>
> -
> -char *lttctl_errstr(void)
> +int lttctl_destroy(void)
> {
> - return lttctl_strerror(lttctl_errno);
> + return 0;
> }
>
> -void lttctl_perror(const char *s)
> +static int lttctl_sendop(const char *fname, const char *op)
> {
> - if (s)
> - fputs(s, stderr);
> - else
> - fputs("ERROR", stderr);
> - if (lttctl_errno)
> - fprintf(stderr, ": %s", lttctl_errstr());
> - if (errno)
> - fprintf(stderr, ": %s", strerror(-errno));
> - fputc('\n', stderr);
> -}
> + int fd;
> +
> + if (!fname) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + return 1;
> + }
>
> -/* public interface */
> + fd = open(fname, O_WRONLY);
> + if (fd == -1) {
> + fprintf(stderr, "%s: open %s failed: %s\n", __func__, fname,
> + strerror(errno));
> + return errno;
> + }
> +
> + if (write(fd, op, strlen(op)) == -1) {
> + fprintf(stderr, "%s: write %s to %s failed: %s\n", __func__, op,
> + fname, strerror(errno));
> + close(fd);
> + return 1;
> + }
> +
> + close(fd);
> +
> + return 0;
> +}
>
> /*
> - * Create and initialise an lttctl handle.
> + * check is trace exist(check debugfsmntdir too)
> + * expect:
> + * 0: expect that trace not exist
> + * !0: expect that trace exist
> + *
> + * ret:
> + * 0: check pass
> + * 1: check failed
> + * -ERRNO: error happened (no check)
> */
> -struct lttctl_handle *lttctl_create_handle(void)
> +static int lttctl_check_trace(const char *name, int expect)
> {
> - int status;
> - struct lttctl_handle *h;
> + char tracedirname[PATH_MAX];
> + DIR *dir;
> + int exist;
>
> - h = (struct lttctl_handle *)malloc(sizeof(struct lttctl_handle));
> - if (h == NULL) {
> - lttctl_errno = LTTCTL_ERR_HANDLE;
> - lttctl_perror("Create handle");
> - goto alloc_error;
> - }
> -
> - memset(h, 0, sizeof(struct lttctl_handle));
> -
> - h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_LTT);
> -
> - if (h->fd == -1) {
> - lttctl_errno = LTTCTL_ERR_SOCKET;
> - lttctl_perror("Create handle");
> - goto socket_error;
> - }
> - memset(&h->local, 0, sizeof(struct sockaddr_nl));
> - h->local.nl_family = AF_NETLINK;
> - h->local.nl_pid = getpid();
> - h->local.nl_groups = 0;
> - status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
> - if (status == -1) {
> - lttctl_errno = LTTCTL_ERR_BIND;
> - lttctl_perror("Create handle");
> - goto bind_error;
> - }
> - memset(&h->peer, 0, sizeof(struct sockaddr_nl));
> - h->peer.nl_family = AF_NETLINK;
> - h->peer.nl_pid = 0;
> - h->peer.nl_groups = 0;
> - return h;
> -
> - /* Error condition */
> -bind_error:
> -socket_error:
> - close(h->fd);
> -alloc_error:
> - free(h);
> - return NULL;
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + return -EINVAL;
> + }
> +
> + if (!debugfsmntdir[0]) {
> + fprintf(stderr, "%s: debugfsmntdir not valid\n", __func__);
> + return -EINVAL;
> + }
> +
> + sprintf(tracedirname, "%s/ltt/control/%s", debugfsmntdir, name);
> +
> + dir = opendir(tracedirname);
> + if (dir) {
> + exist = 1;
> + } else {
> + if (errno != ENOENT) {
> + fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
> + return -EINVAL;
> + }
> + exist = 0;
> + }
> +
> + closedir(dir);
> +
> + if (!expect != !exist) {
> + if (exist)
> + fprintf(stderr, "Trace %s already exist\n", name);
> + else
> + fprintf(stderr, "Trace %s not exist\n", name);
> + return 1;
> + }
> +
> + return 0;
> }
>
> /*
> - * No error condition is checked here at this stage, but it may happen
> - * if/when reliable messaging is implemented.
> + * get channel list of a trace
> + * don't include metadata channel when metadata is 0
> + *
> + * return number of channel on success
> + * return negative number on fail
> */
> -int lttctl_destroy_handle(struct lttctl_handle *h)
> +static int lttctl_get_channellist(const char *tracename,
> + char channellist[][PATH_MAX], int metadata)
> {
> - if (h) {
> - close(h->fd);
> - free(h);
> + /*
> + * Now using simple way
> + *
> + * Todo:
> + * iter each channel-dir in ltt-control dir to support dynamic channel
> + */
> +
> + strcpy(channellist[0], "cpu");
> + strcpy(channellist[1], "processes");
> + strcpy(channellist[2], "interrupts");
> + strcpy(channellist[3], "network");
> + strcpy(channellist[4], "modules");
> + if (metadata) {
> + strcpy(channellist[5], "metadata");
> + return 6;
> + } else
> + return 5;
> +}
> +
> +int lttctl_setup_trace(const char *name)
> +{
> + int ret;
> + char ctlfname[PATH_MAX];
> +
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 0);
> + if (ret)
> + goto arg_error;
> +
> + sprintf(ctlfname, "%s/ltt/setup_trace", debugfsmntdir);
> +
> + ret = lttctl_sendop(ctlfname, name);
> + if (ret) {
> + fprintf(stderr, "Setup trace failed\n");
> + goto op_err;
> }
> +
> return 0;
> -}
>
> +op_err:
> +arg_error:
> + return ret;
> +}
>
> -int lttctl_create_trace(const struct lttctl_handle *h,
> - char *name, enum trace_mode mode, char *trace_type,
> - unsigned subbuf_size_low, unsigned n_subbufs_low,
> - unsigned subbuf_size_med, unsigned n_subbufs_med,
> - unsigned subbuf_size_high, unsigned n_subbufs_high)
> +int lttctl_destroy_trace(const char *name)
> {
> - int err;
> -
> - struct {
> - struct nlmsghdr nlh;
> - lttctl_peer_msg_t msg;
> - } req;
> - struct {
> - struct nlmsghdr nlh;
> - struct nlmsgerr nlerr;
> - lttctl_peer_msg_t msg;
> - } ack;
> + int ret;
> + char ctlfname[PATH_MAX];
>
> - memset(&req, 0, sizeof(req));
> - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
> - req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
> - req.nlh.nlmsg_type = LTTCTLM_CONTROL;
> - req.nlh.nlmsg_pid = h->local.nl_pid;
> - req.nlh.nlmsg_seq = 0;
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
> +
> + sprintf(ctlfname, "%s/ltt/destroy_trace", debugfsmntdir);
> +
> + ret = lttctl_sendop(ctlfname, name);
> + if (ret) {
> + fprintf(stderr, "Destroy trace failed\n");
> + goto op_err;
> + }
>
> - strncpy(req.msg.trace_name, name, NAME_MAX);
> - strncpy(req.msg.trace_type, trace_type, NAME_MAX);
> - req.msg.op = OP_CREATE;
> - req.msg.args.new_trace.mode = mode;
> - req.msg.args.new_trace.subbuf_size_low = subbuf_size_low;
> - req.msg.args.new_trace.n_subbufs_low = n_subbufs_low;
> - req.msg.args.new_trace.subbuf_size_med = subbuf_size_med;
> - req.msg.args.new_trace.n_subbufs_med = n_subbufs_med;
> - req.msg.args.new_trace.subbuf_size_high = subbuf_size_high;
> - req.msg.args.new_trace.n_subbufs_high = n_subbufs_high;
> + return 0;
>
> - err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
> - if(err < 0) goto senderr;
> +op_err:
> +arg_error:
> + return ret;
> +}
>
> - err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
> - if(err < 0) goto senderr;
> +int lttctl_alloc_trace(const char *name)
> +{
> + int ret;
> + char ctlfname[PATH_MAX];
>
> - err = ack.nlerr.error;
> - if(err != 0) {
> - errno = err;
> - lttctl_perror("Create Trace Error");
> - return err;
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
> +
> + sprintf(ctlfname, "%s/ltt/control/%s/alloc", debugfsmntdir, name);
> +
> + ret = lttctl_sendop(ctlfname, "1");
> + if (ret) {
> + fprintf(stderr, "Allocate trace failed\n");
> + goto op_err;
> }
>
> return 0;
>
> -senderr:
> - lttctl_perror("Create Trace Error");
> - err = EPERM;
> - return err;
> +op_err:
> +arg_error:
> + return ret;
> }
>
> -int lttctl_destroy_trace(const struct lttctl_handle *h,
> - char *name)
> +int lttctl_start(const char *name)
> {
> - struct {
> - struct nlmsghdr nlh;
> - lttctl_peer_msg_t msg;
> - } req;
> - struct {
> - struct nlmsghdr nlh;
> - struct nlmsgerr nlerr;
> - lttctl_peer_msg_t msg;
> - } ack;
> - int err;
> + int ret;
> + char ctlfname[PATH_MAX];
> +
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
>
> - memset(&req, 0, sizeof(req));
> - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
> - req.nlh.nlmsg_flags = NLM_F_REQUEST;
> - req.nlh.nlmsg_type = LTTCTLM_CONTROL;
> - req.nlh.nlmsg_pid = h->local.nl_pid;
> + sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
>
> - strncpy(req.msg.trace_name, name, NAME_MAX);
> - req.msg.op = OP_DESTROY;
> + ret = lttctl_sendop(ctlfname, "1");
> + if (ret) {
> + fprintf(stderr, "Start trace failed\n");
> + goto op_err;
> + }
> +
> + return 0;
> +
> +op_err:
> +arg_error:
> + return ret;
> +}
> +
> +int lttctl_pause(const char *name)
> +{
> + int ret;
> + char ctlfname[PATH_MAX];
> +
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
>
> - err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
> - if(err < 0) goto senderr;
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
>
> - err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
> - if(err < 0) goto senderr;
> + sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
>
> - err = ack.nlerr.error;
> - if(err != 0) {
> - errno = err;
> - lttctl_perror("Destroy Trace Channels Error");
> - return err;
> + ret = lttctl_sendop(ctlfname, "0");
> + if (ret) {
> + fprintf(stderr, "Pause trace failed\n");
> + goto op_err;
> }
>
> return 0;
>
> -senderr:
> - lttctl_perror("Destroy Trace Channels Error");
> - err = EPERM;
> - return err;
> +op_err:
> +arg_error:
> + return ret;
> +}
> +
> +int lttctl_set_trans(const char *name, const char *trans)
> +{
> + int ret;
> + char ctlfname[PATH_MAX];
> +
> + if (!name) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
> +
> + sprintf(ctlfname, "%s/ltt/control/%s/trans", debugfsmntdir, name);
>
> + ret = lttctl_sendop(ctlfname, trans);
> + if (ret) {
> + fprintf(stderr, "Set transport failed\n");
> + goto op_err;
> + }
> +
> + return 0;
> +
> +op_err:
> +arg_error:
> + return ret;
> }
>
> -int lttctl_start(const struct lttctl_handle *h,
> - char *name)
> +static int __lttctl_set_channel_enable(const char *name, const char *channel,
> + int enable)
> {
> - struct {
> - struct nlmsghdr nlh;
> - lttctl_peer_msg_t msg;
> - } req;
> - struct {
> - struct nlmsghdr nlh;
> - struct nlmsgerr nlerr;
> - lttctl_peer_msg_t msg;
> - } ack;
> + int ret;
> + char ctlfname[PATH_MAX];
>
> - int err;
> + sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/enable", debugfsmntdir,
> + name, channel);
> +
> + ret = lttctl_sendop(ctlfname, enable ? "1" : "0");
> + if (ret)
> + fprintf(stderr, "Set channel's enable mode failed\n");
> +
> + return ret;
> +}
> +int lttctl_set_channel_enable(const char *name, const char *channel,
> + int enable)
> +{
> + int ret;
>
> - memset(&req, 0, sizeof(req));
> - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
> - req.nlh.nlmsg_flags = NLM_F_REQUEST;
> - req.nlh.nlmsg_type = LTTCTLM_CONTROL;
> - req.nlh.nlmsg_pid = h->local.nl_pid;
> + if (!name || !channel) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
>
> - strncpy(req.msg.trace_name, name, NAME_MAX);
> - req.msg.op = OP_START;
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
>
> - err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
> - if(err < 0) goto senderr;
> + if (strcmp(channel, "all")) {
> + ret = __lttctl_set_channel_enable(name, channel, enable);
> + if (ret)
> + goto op_err;
> + } else {
> + char channellist[MAX_CHANNEL][PATH_MAX];
> + int n_channel;
>
> - err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
> - if(err < 0) goto senderr;
> + /* Don't allow set enable state for metadata channel */
> + n_channel = lttctl_get_channellist(name, channellist, 0);
> + if (n_channel < 0) {
> + fprintf(stderr, "%s: lttctl_get_channellist failed\n",
> + __func__);
> + ret = -ENOENT;
> + goto op_err;
> + }
>
> - err = ack.nlerr.error;
> - if(err != 0) {
> - errno = err;
> - lttctl_perror("Start Trace Error");
> - return err;
> + for (; n_channel > 0; n_channel--) {
> + ret = __lttctl_set_channel_enable(name,
> + channellist[n_channel - 1], enable);
> + if (ret)
> + goto op_err;
> + }
> }
>
> return 0;
>
> -senderr:
> - err = EPERM;
> - lttctl_perror("Start Trace Error");
> - return err;
> -
> +op_err:
> +arg_error:
> + return ret;
> }
>
> -int lttctl_stop(const struct lttctl_handle *h,
> - char *name)
> +static int __lttctl_set_channel_overwrite(const char *name, const char *channel,
> + int overwrite)
> {
> - struct {
> - struct nlmsghdr nlh;
> - lttctl_peer_msg_t msg;
> - } req;
> - struct {
> - struct nlmsghdr nlh;
> - struct nlmsgerr nlerr;
> - lttctl_peer_msg_t msg;
> - } ack;
> - int err;
> + int ret;
> + char ctlfname[PATH_MAX];
>
> - memset(&req, 0, sizeof(req));
> - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
> - req.nlh.nlmsg_flags = NLM_F_REQUEST;
> - req.nlh.nlmsg_type = LTTCTLM_CONTROL;
> - req.nlh.nlmsg_pid = h->local.nl_pid;
> + sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/overwrite",
> + debugfsmntdir, name, channel);
>
> - strncpy(req.msg.trace_name, name, NAME_MAX);
> - req.msg.op = OP_STOP;
> + ret = lttctl_sendop(ctlfname, overwrite ? "1" : "0");
> + if (ret)
> + fprintf(stderr, "Set channel's overwrite mode failed\n");
>
> - err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
> - if(err < 0) goto senderr;
> + return ret;
> +}
> +int lttctl_set_channel_overwrite(const char *name, const char *channel,
> + int overwrite)
> +{
> + int ret;
> +
> + if (!name || !channel) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
>
> - err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
> - if(err < 0) goto senderr;
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
>
> - err = ack.nlerr.error;
> - if(err != 0) {
> - errno = err;
> - lttctl_perror("Stop Trace Error");
> - return err;
> + if (strcmp(channel, "all")) {
> + ret = __lttctl_set_channel_overwrite(name, channel, overwrite);
> + if (ret)
> + goto op_err;
> + } else {
> + char channellist[MAX_CHANNEL][PATH_MAX];
> + int n_channel;
> +
> + /* Don't allow set overwrite for metadata channel */
> + n_channel = lttctl_get_channellist(name, channellist, 0);
> + if (n_channel < 0) {
> + fprintf(stderr, "%s: lttctl_get_channellist failed\n",
> + __func__);
> + ret = -ENOENT;
> + goto op_err;
> + }
> +
> + for (; n_channel > 0; n_channel--) {
> + ret = __lttctl_set_channel_overwrite(name,
> + channellist[n_channel - 1], overwrite);
> + if (ret)
> + goto op_err;
> + }
> }
>
> return 0;
>
> -senderr:
> - err = EPERM;
> - lttctl_perror("Stop Trace Error");
> - return err;
> +op_err:
> +arg_error:
> + return ret;
> +}
> +
> +static int __lttctl_set_channel_subbuf_num(const char *name,
> + const char *channel, unsigned subbuf_num)
> +{
> + int ret;
> + char ctlfname[PATH_MAX];
> + char opstr[32];
> +
> + sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_num",
> + debugfsmntdir, name, channel);
> +
> + sprintf(opstr, "%u", subbuf_num);
> +
> + ret = lttctl_sendop(ctlfname, opstr);
> + if (ret)
> + fprintf(stderr, "Set channel's subbuf number failed\n");
> +
> + return ret;
> }
> +int lttctl_set_channel_subbuf_num(const char *name, const char *channel,
> + unsigned subbuf_num)
> +{
> + int ret;
> +
> + if (!name || !channel) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
> +
> + if (strcmp(channel, "all")) {
> + ret = __lttctl_set_channel_subbuf_num(name, channel,
> + subbuf_num);
> + if (ret)
> + goto op_err;
> + } else {
> + char channellist[MAX_CHANNEL][PATH_MAX];
> + int n_channel;
>
> + /* allow set subbuf_num for metadata channel */
> + n_channel = lttctl_get_channellist(name, channellist, 1);
> + if (n_channel < 0) {
> + fprintf(stderr, "%s: lttctl_get_channellist failed\n",
> + __func__);
> + ret = -ENOENT;
> + goto op_err;
> + }
> +
> + for (; n_channel > 0; n_channel--) {
> + ret = __lttctl_set_channel_subbuf_num(name,
> + channellist[n_channel - 1], subbuf_num);
> + if (ret)
> + goto op_err;
> + }
> + }
> +
> + return 0;
> +
> +op_err:
> +arg_error:
> + return ret;
> +}
> +
> +static int __lttctl_set_channel_subbuf_size(const char *name,
> + const char *channel, unsigned subbuf_size)
> +{
> + int ret;
> + char ctlfname[PATH_MAX];
> + char opstr[32];
> +
> + sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_size",
> + debugfsmntdir, name, channel);
> +
> + sprintf(opstr, "%u", subbuf_size);
> +
> + ret = lttctl_sendop(ctlfname, opstr);
> + if (ret)
> + fprintf(stderr, "Set channel's subbuf size failed\n");
> +}
> +int lttctl_set_channel_subbuf_size(const char *name, const char *channel,
> + unsigned subbuf_size)
> +{
> + int ret;
> +
> + if (!name || !channel) {
> + fprintf(stderr, "%s: args invalid\n", __func__);
> + ret = -EINVAL;
> + goto arg_error;
> + }
> +
> + ret = lttctl_check_trace(name, 1);
> + if (ret)
> + goto arg_error;
> +
> + if (strcmp(channel, "all")) {
> + ret = __lttctl_set_channel_subbuf_size(name, channel,
> + subbuf_size);
> + if (ret)
> + goto op_err;
> + } else {
> + char channellist[MAX_CHANNEL][PATH_MAX];
> + int n_channel;
> +
> + /* allow set subbuf_size for metadata channel */
> + n_channel = lttctl_get_channellist(name, channellist, 1);
> + if (n_channel < 0) {
> + fprintf(stderr, "%s: lttctl_get_channellist failed\n",
> + __func__);
> + ret = -ENOENT;
> + goto op_err;
> + }
> +
> + for (; n_channel > 0; n_channel--) {
> + ret = __lttctl_set_channel_subbuf_size(name,
> + channellist[n_channel - 1], subbuf_size);
> + if (ret)
> + goto op_err;
> + }
> + }
> +
> + return 0;
> +
> +op_err:
> +arg_error:
> + return ret;
> +}
> diff -Nur ltt-control-0.59-25112008.org/liblttctl/lttctl.h ltt-control-0.59-25112008.new/liblttctl/lttctl.h
> --- ltt-control-0.59-25112008.org/liblttctl/lttctl.h 2008-08-01 03:54:03.000000000 +0800
> +++ ltt-control-0.59-25112008.new/liblttctl/lttctl.h 2008-12-15 10:56:47.000000000 +0800
> @@ -14,86 +14,26 @@
> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> * GNU General Public License for more details.
> *
> - *
> - * Inspired from iptables, by James Morris <jmorris at intercode.com.au>.
> - *
> */
>
> #ifndef _LIBLTT_H
> #define _LIBLTT_H
>
> -#include <linux/limits.h>
> -#include <asm/types.h>
> -#include <sys/socket.h>
> -#include <linux/netlink.h>
> -
> -#ifndef NETLINK_LTT
> -#define NETLINK_LTT 31
> -#endif
> -
> -
> -enum trace_op {
> - OP_CREATE,
> - OP_DESTROY,
> - OP_START,
> - OP_STOP,
> - OP_NONE
> -};
> -
> -enum trace_mode {
> - LTT_TRACE_NORMAL,
> - LTT_TRACE_FLIGHT,
> - LTT_TRACE_HYBRID
> -};
> -
> -typedef struct lttctl_peer_msg {
> - char trace_name[NAME_MAX];
> - char trace_type[NAME_MAX];
> - enum trace_op op;
> - union {
> - struct {
> - enum trace_mode mode;
> - unsigned subbuf_size_low;
> - unsigned n_subbufs_low;
> - unsigned subbuf_size_med;
> - unsigned n_subbufs_med;
> - unsigned subbuf_size_high;
> - unsigned n_subbufs_high;
> - } new_trace;
> - } args;
> -} lttctl_peer_msg_t;
> -
> -
> -struct lttctl_handle
> -{
> - int fd;
> - //u_int8_t blocking;
> - struct sockaddr_nl local;
> - struct sockaddr_nl peer;
> -};
> -
> -typedef struct lttctl_resp_msg {
> - int err;
> -} lttctl_resp_msg_t;
> -
> -struct lttctl_handle *lttctl_create_handle(void);
> -
> -int lttctl_destroy_handle(struct lttctl_handle *h);
> -
> -
> -int lttctl_create_trace(const struct lttctl_handle *h,
> - char *name, enum trace_mode mode, char *trace_type,
> - unsigned subbuf_size_low, unsigned n_subbufs_low,
> - unsigned subbuf_size_med, unsigned n_subbufs_med,
> - unsigned subbuf_size_high, unsigned n_subbufs_high);
> -
> -int lttctl_destroy_trace(const struct lttctl_handle *handle, char *name);
> -
> -int lttctl_start(const struct lttctl_handle *handle, char *name);
> -
> -int lttctl_stop(const struct lttctl_handle *handle, char *name);
> -
> -#define LTTCTLM_BASE 0x10
> -#define LTTCTLM_CONTROL (LTTCTLM_BASE + 1) /* LTT control message */
> +int lttctl_init(void);
> +int lttctl_destroy(void);
> +int lttctl_setup_trace(const char *name);
> +int lttctl_destroy_trace(const char *name);
> +int lttctl_alloc_trace(const char *name);
> +int lttctl_start(const char *name);
> +int lttctl_pause(const char *name);
> +int lttctl_set_trans(const char *name, const char *trans);
> +int lttctl_set_channel_enable(const char *name, const char *channel,
> + int enable);
> +int lttctl_set_channel_overwrite(const char *name, const char *channel,
> + int overwrite);
> +int lttctl_set_channel_subbuf_num(const char *name, const char *channel,
> + unsigned subbuf_num);
> +int lttctl_set_channel_subbuf_size(const char *name, const char *channel,
> + unsigned subbuf_size);
>
> -#endif //_LIBLTT_H
> +#endif /*_LIBLTT_H */
> diff -Nur ltt-control-0.59-25112008.org/lttctl/lttctl.c ltt-control-0.59-25112008.new/lttctl/lttctl.c
> --- ltt-control-0.59-25112008.org/lttctl/lttctl.c 2008-10-17 05:41:38.000000000 +0800
> +++ ltt-control-0.59-25112008.new/lttctl/lttctl.c 2008-12-15 10:56:47.000000000 +0800
> @@ -16,98 +16,142 @@
> #include <errno.h>
> #include <stdio.h>
> #include <stdlib.h>
> -#include <sys/types.h>
> #include <sys/wait.h>
> #include <unistd.h>
> -#include <signal.h>
> -#include <dirent.h>
> #include <string.h>
> #include <limits.h>
> -#include <sys/stat.h>
> +#define _GNU_SOURCE
> +#include <getopt.h>
>
> -/* Buffer for file copy : 4k seems optimal. */
> -#define BUF_SIZE 4096
> +#define OPT_MAX (1024)
> +#define OPT_NAMELEN (256)
> +#define OPT_VALSTRINGLEN (256)
> +
> +enum lttcrl_option_type {
> + option_type_unknown,
> + option_type_string,
> + option_type_int,
> + option_type_uint,
> + option_type_positive,
> + option_type_bool,
> +};
>
> -enum trace_ctl_op {
> - CTL_OP_CREATE_START,
> - CTL_OP_CREATE,
> - CTL_OP_DESTROY,
> - CTL_OP_STOP_DESTROY,
> - CTL_OP_START,
> - CTL_OP_STOP,
> - CTL_OP_DAEMON,
> - CTL_OP_DAEMON_HYBRID_FINISH,
> - CTL_OP_NONE
> +struct lttctl_option {
> + char name1[OPT_NAMELEN];
> + char name2[OPT_NAMELEN];
> + char name3[OPT_NAMELEN];
> + union {
> + char v_string[OPT_VALSTRINGLEN];
> + int v_int;
> + unsigned int v_uint;
> + int v_bool:1;
> + } value;
> };
>
> -static char *trace_name = NULL;
> -static char *trace_type = "relay";
> -static char *mode_name = NULL;
> -static unsigned subbuf_size_low = 0;
> -static unsigned n_subbufs_low = 0;
> -static unsigned subbuf_size_med = 0;
> -static unsigned n_subbufs_med = 0;
> -static unsigned subbuf_size_high = 0;
> -static unsigned n_subbufs_high = 0;
> -static unsigned append_trace = 0;
> -static enum trace_mode mode = LTT_TRACE_NORMAL;
> -static enum trace_ctl_op op = CTL_OP_NONE;
> -static char *channel_root = NULL;
> +static int opt_create;
> +static int opt_destroy;
> +static int opt_start;
> +static int opt_pause;
> +static int opt_help;
> +static const char *opt_transport;
> +static struct lttctl_option opt_options[OPT_MAX];
> +static unsigned int opt_option_n;
> +static const char *opt_write;
> +static int opt_append;
> +static unsigned int opt_dump_threads;
> static char channel_root_default[PATH_MAX];
> -static char *trace_root = NULL;
> -static char *num_threads = "1";
> +static const char *opt_channel_root;
> +static const char *opt_tracename;
>
> /* Args :
> *
> */
> -void show_arguments(void)
> +static void show_arguments(void)
> {
> - printf("Please use the following arguments :\n");
> + printf("Linux Trace Toolkit Trace Control " VERSION"\n");
> + printf("\n");
> + printf("Usage: lttctl [OPTION]... [TRACENAME]\n");
> + printf("\n");
> + printf("Examples:\n");
> + printf(" lttctl -c trace1 "
> + "# Create a trace named trace1.\n");
> + printf(" lttctl -s trace1 "
> + "# start a trace named trace1.\n");
> + printf(" lttctl -p trace1 "
> + "# pause a trace named trace1.\n");
> + printf(" lttctl -d trace1 "
> + "# Destroy a trace named trace1.\n");
> + printf(" lttctl -C -w /tmp/trace1 trace1 "
> + "# Create a trace named trace1, start it and\n"
> + " "
> + "# write non-overwrite channels' data to\n"
> + " "
> + "# /tmp/trace1, debugfs must be mounted for\n"
> + " "
> + "# auto-find\n");
> + printf(" lttctl -D -w /tmp/trace1 trace1 "
> + "# Pause and destroy a trace named trace1 and\n"
> + " "
> + "# write overwrite channels' data to\n"
> + " "
> + "# /tmp/trace1, debugfs must be mounted for\n"
> + " "
> + "# auto-find\n");
> + printf("\n");
> + printf(" Basic options:\n");
> + printf(" -c, --create\n");
> + printf(" Create a trace.\n");
> + printf(" -d, --destroy\n");
> + printf(" Destroy a trace.\n");
> + printf(" -s, --start\n");
> + printf(" Start a trace.\n");
> + printf(" -p, --pause\n");
> + printf(" Pause a trace.\n");
> + printf(" -h, --help\n");
> + printf(" Show this help.\n");
> printf("\n");
> - printf("-n name Name of the trace.\n");
> - printf("-b Create trace channels and start tracing (no daemon).\n");
> - printf("-c Create trace channels.\n");
> - printf("-m mode Normal, flight recorder or hybrid mode.\n");
> - printf(" Mode values : normal (default), flight or hybrid.\n");
> - printf("-r Destroy trace channels.\n");
> - printf("-R Stop tracing and destroy trace channels.\n");
> - printf("-s Start tracing.\n");
> - //printf(" Note : will automatically create a normal trace if "
> - // "none exists.\n");
> - printf("-q Stop tracing.\n");
> - printf("-d Create trace, spawn a lttd daemon, start tracing.\n");
> - printf(" (optionally, you can set LTT_DAEMON\n");
> - printf(" env. var.)\n");
> - printf("-f Stop tracing, dump flight recorder trace, destroy channels\n");
> - printf(" (for hybrid traces)\n");
> - printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
> - printf("-T Type of trace (ex. relay)\n");
> - printf("-l LTT channels root path. (ex. /mnt/debugfs/ltt)\n");
> - printf("-Z Size of the low data rate subbuffers (will be rounded to next page size)\n");
> - printf("-X Number of low data rate subbuffers\n");
> - printf("-V Size of the medium data rate subbuffers (will be rounded to next page size)\n");
> - printf("-B Number of medium data rate subbuffers\n");
> - printf("-z Size of the high data rate subbuffers (will be rounded to next page size)\n");
> - printf("-x Number of high data rate subbuffers\n");
> - printf("-a Append to trace\n");
> - printf("-N Number of lttd threads\n");
> + printf(" Advanced options:\n");
> + printf(" --transport TRANSPORT\n");
> + printf(" Set trace's transport. (ex. relay)\n");
> + printf(" -o, --option OPTION\n");
> + printf(" Set options, following operations are supported:\n");
> + printf(" channel.<channelname>.enable=\n");
> + printf(" channel.<channelname>.overwrite=\n");
> + printf(" channel.<channelname>.bufnum=\n");
> + printf(" channel.<channelname>.bufsize=\n");
> + printf(" <channelname> can be set to all for all channels\n");
> + printf("\n");
> + printf(" Integration options:\n");
> + printf(" -C, --create_start\n");
> + printf(" Create and start a trace.\n");
> + printf(" -D, --pause_destroy\n");
> + printf(" Pause and destroy a trace.\n");
> + printf(" -w, --write PATH\n");
> + printf(" Path for write trace datas.\n");
> + printf(" For -c, -C, -d, -D options\n");
> + printf(" -a, --append\n");
> + printf(" Append to trace, For -w option\n");
> + printf(" -n, --dump_threads NUMBER\n");
> + printf(" Number of lttd threads, For -w option\n");
> + printf(" --channel_root PATH\n");
> + printf(" Set channels root path, For -w option."
> + " (ex. /mnt/debugfs/ltt)\n");
> printf("\n");
> }
>
> -int getdebugfsmntdir(char *mntdir)
> +static int getdebugfsmntdir(char *mntdir)
> {
> char mnt_dir[PATH_MAX];
> char mnt_type[PATH_MAX];
>
> FILE *fp = fopen("/proc/mounts", "r");
> - if (!fp) {
> - return EINVAL;
> - }
> + if (!fp)
> + return -EINVAL;
>
> while (1) {
> - if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0) {
> - return ENOENT;
> - }
> + if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0)
> + return -ENOENT;
> +
> if (!strcmp(mnt_type, "debugfs")) {
> strcpy(mntdir, mnt_dir);
> return 0;
> @@ -115,6 +159,275 @@
> }
> }
>
> +/*
> + * Separate option name to 3 fields
> + * Ex:
> + * Input: name = channel.cpu.bufsize
> + * Output: name1 = channel
> + * name2 = cpu
> + * name3 = bufsize
> + * Ret: 0 on success
> + * 1 on fail
> + *
> + * Note:
> + * Make sure that name1~3 longer than OPT_NAMELEN.
> + * name1~3 can be NULL to discard value
> + *
> + */
> +static int separate_opt(const char *name, char *name1, char *name2, char *name3)
> +{
> + char *p;
> +
> + if (!name)
> + return 1;
> +
> + /* segment1 */
> + p = strchr(name, '.');
> + if (!p)
> + return 1;
> + if (p - name >= OPT_NAMELEN)
> + return 1;
> + if (name1) {
> + memcpy(name1, name, p - name);
> + name1[p - name] = 0;
> + }
> + name = p + 1;
> +
> + /* segment2 */
> + p = strchr(name, '.');
> + if (!p)
> + return 1;
> + if (p - name >= OPT_NAMELEN)
> + return 1;
> + if (name2) {
> + memcpy(name2, name, p - name);
> + name2[p - name] = 0;
> + }
> + name = p + 1;
> +
> + /* segment3 */
> + if (strlen(name) >= OPT_NAMELEN)
> + return 1;
> + if (name3)
> + strcpy(name3, name);
> +
> + return 0;
> +}
> +
> +/*
> + * get option's type by its name,
> + * can also be used to check is option exists
> + * (return option_type_unknown when not exist)
> + */
> +static enum lttcrl_option_type opt_type(const char *name1, const char *name2,
> + const char *name3)
> +{
> + if (!name1 || !name2 || !name3)
> + return option_type_unknown;
> +
> + if (strlen(name1) >= OPT_NAMELEN
> + || strlen(name2) >= OPT_NAMELEN
> + || strlen(name3) >= OPT_NAMELEN)
> + return option_type_unknown;
> +
> + if (strcmp(name1, "channel") == 0) {
> + /* Option is channel class */
> + if (strcmp(name3, "enable") == 0)
> + return option_type_bool;
> + if (strcmp(name3, "overwrite") == 0)
> + return option_type_bool;
> + if (strcmp(name3, "bufnum") == 0)
> + return option_type_uint;
> + if (strcmp(name3, "bufsize") == 0)
> + return option_type_uint;
> + return option_type_unknown;
> + }
> +
> + /*
> + * Now we only support channel options
> + * other option class' will used in future
> + */
> +
> + return option_type_unknown;
> +}
> +
> +static struct lttctl_option *find_opt(const char *name1, const char *name2,
> + const char *name3)
> +{
> + int i;
> +
> + if (!name1 || !name2 || !name3)
> + return NULL;
> +
> + for (i = 0; i < opt_option_n; i++) {
> + if (strcmp(opt_options[i].name1, name1) == 0
> + && strcmp(opt_options[i].name2, name2) == 0
> + && strcmp(opt_options[i].name3, name3) == 0)
> + return opt_options + i;
> + }
> +
> + return NULL;
> +}
> +
> +static struct lttctl_option *get_opt(const char *name1, const char *name2,
> + const char *name3)
> +{
> + struct lttctl_option *opt;
> +
> + if (!name1 || !name2 || !name3)
> + return NULL;
> +
> + opt = find_opt(name1, name2, name3);
> + if (opt)
> + return opt;
> +
> + if (opt_option_n >= OPT_MAX) {
> + fprintf(stderr, "Option number out of range\n");
> + return NULL;
> + }
> +
> + if (strlen(name1) >= OPT_NAMELEN
> + || strlen(name2) >= OPT_NAMELEN
> + || strlen(name3) >= OPT_NAMELEN) {
> + fprintf(stderr, "Option name too long: %s.%s.%s\n",
> + name1, name2, name3);
> + return NULL;
> + }
> +
> + opt = &opt_options[opt_option_n];
> + strcpy(opt->name1, name1);
> + strcpy(opt->name2, name2);
> + strcpy(opt->name3, name3);
> + opt_option_n++;
> +
> + return opt;
> +}
> +
> +static int parst_opt(const char *optarg)
> +{
> + int ret;
> + char opt_name[OPT_NAMELEN * 3];
> + char opt_valstr[OPT_VALSTRINGLEN];
> + char *p;
> +
> + char name1[OPT_NAMELEN];
> + char name2[OPT_NAMELEN];
> + char name3[OPT_NAMELEN];
> +
> + enum lttcrl_option_type opttype;
> + int opt_intval;
> + unsigned int opt_uintval;
> + struct lttctl_option *newopt;
> +
> + if (!optarg) {
> + fprintf(stderr, "Option empty\n");
> + return -EINVAL;
> + }
> +
> + /* Get option name and val_str */
> + p = strchr(optarg, '=');
> + if (!p) {
> + fprintf(stderr, "Option format error: %s\n", optarg);
> + return -EINVAL;
> + }
> +
> + if (p - optarg >= sizeof(opt_name)/sizeof(opt_name[0])) {
> + fprintf(stderr, "Option name too long: %s\n", optarg);
> + return -EINVAL;
> + }
> +
> + if (strlen(p+1) >= OPT_VALSTRINGLEN) {
> + fprintf(stderr, "Option value too long: %s\n", optarg);
> + return -EINVAL;
> + }
> +
> + memcpy(opt_name, optarg, p - optarg);
> + opt_name[p - optarg] = 0;
> + strcpy(opt_valstr, p+1);
> +
> + /* separate option name into 3 fields */
> + ret = separate_opt(opt_name, name1, name2, name3);
> + if (ret != 0) {
> + fprintf(stderr, "Option name error: %s\n", optarg);
> + return -EINVAL;
> + }
> +
> + /*
> + * check and add option
> + */
> + opttype = opt_type(name1, name2, name3);
> + switch (opttype) {
> + case option_type_unknown:
> + fprintf(stderr, "Option not supported: %s\n", optarg);
> + return -EINVAL;
> + case option_type_string:
> + newopt = get_opt(name1, name2, name3);
> + if (!newopt)
> + return -EINVAL;
> + strcpy(newopt->value.v_string, opt_valstr);
> + return 0;
> + case option_type_int:
> + ret = sscanf(opt_valstr, "%d", &opt_intval);
> + if (ret != 1) {
> + fprintf(stderr, "Option format error: %s\n", optarg);
> + return -EINVAL;
> + }
> + newopt = get_opt(name1, name2, name3);
> + if (!newopt)
> + return -EINVAL;
> + newopt->value.v_int = opt_intval;
> + return 0;
> + case option_type_uint:
> + ret = sscanf(opt_valstr, "%u", &opt_uintval);
> + if (ret != 1) {
> + fprintf(stderr, "Option format error: %s\n", optarg);
> + return -EINVAL;
> + }
> + newopt = get_opt(name1, name2, name3);
> + if (!newopt)
> + return -EINVAL;
> + newopt->value.v_uint = opt_uintval;
> + return 0;
> + case option_type_positive:
> + ret = sscanf(opt_valstr, "%u", &opt_uintval);
> + if (ret != 1 || opt_uintval == 0) {
> + fprintf(stderr, "Option format error: %s\n", optarg);
> + return -EINVAL;
> + }
> + newopt = get_opt(name1, name2, name3);
> + if (!newopt)
> + return -EINVAL;
> + newopt->value.v_uint = opt_uintval;
> + return 0;
> + case option_type_bool:
> + if (opt_valstr[1] != 0) {
> + fprintf(stderr, "Option format error: %s\n", optarg);
> + return -EINVAL;
> + }
> + if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y'
> + || opt_valstr[0] == '1')
> + opt_intval = 1;
> + else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n'
> + || opt_valstr[0] == '0')
> + opt_intval = 0;
> + else {
> + fprintf(stderr, "Option format error: %s\n", optarg);
> + return -EINVAL;
> + }
> +
> + newopt = get_opt(name1, name2, name3);
> + if (!newopt)
> + return -EINVAL;
> + newopt->value.v_bool = opt_intval;
> + return 0;
> + default:
> + fprintf(stderr, "Internal error on opt %s\n", optarg);
> + return -EINVAL;
> + }
> +
> + return 0; /* should not run to here */
> +}
> +
> /* parse_arguments
> *
> * Parses the command line arguments.
> @@ -122,445 +435,466 @@
> * Returns -1 if the arguments were correct, but doesn't ask for program
> * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
> */
> -int parse_arguments(int argc, char **argv)
> +static int parse_arguments(int argc, char **argv)
> {
> int ret = 0;
> - int argn = 1;
> -
> - if(argc == 2) {
> - if(strcmp(argv[1], "-h") == 0) {
> - return -1;
> - }
> - }
> -
> - while(argn < argc) {
> -
> - switch(argv[argn][0]) {
> - case '-':
> - switch(argv[argn][1]) {
> - case 'n':
> - if(argn+1 < argc) {
> - trace_name = argv[argn+1];
> - argn++;
> - } else {
> - printf("Specify a trace name after -n.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> -
> - break;
> - case 'b':
> - op = CTL_OP_CREATE_START;
> - break;
> - case 'c':
> - op = CTL_OP_CREATE;
> - break;
> - case 'm':
> - if(argn+1 < argc) {
> - mode_name = argv[argn+1];
> - argn++;
> - if(strcmp(mode_name, "normal") == 0)
> - mode = LTT_TRACE_NORMAL;
> - else if(strcmp(mode_name, "flight") == 0)
> - mode = LTT_TRACE_FLIGHT;
> - else if(strcmp(mode_name, "hybrid") == 0)
> - mode = LTT_TRACE_HYBRID;
> - else {
> - printf("Invalid mode '%s'.\n", argv[argn]);
> - printf("\n");
> - ret = EINVAL;
> - }
> - } else {
> - printf("Specify a mode after -m.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'r':
> - op = CTL_OP_DESTROY;
> - break;
> - case 'R':
> - op = CTL_OP_STOP_DESTROY;
> - break;
> - case 's':
> - op = CTL_OP_START;
> - break;
> - case 'q':
> - op = CTL_OP_STOP;
> - break;
> - case 'Z':
> - if(argn+1 < argc) {
> - subbuf_size_low = (unsigned)atoi(argv[argn+1]);
> - argn++;
> - } else {
> - printf("Specify a number of low traffic subbuffers after -Z.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'X':
> - if(argn+1 < argc) {
> - n_subbufs_low = (unsigned)atoi(argv[argn+1]);
> - argn++;
> - } else {
> - printf("Specify a low traffic subbuffer size after -X.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'V':
> - if(argn+1 < argc) {
> - subbuf_size_med = (unsigned)atoi(argv[argn+1]);
> - argn++;
> - } else {
> - printf("Specify a number of medium traffic subbuffers after -V.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'B':
> - if(argn+1 < argc) {
> - n_subbufs_med = (unsigned)atoi(argv[argn+1]);
> - argn++;
> - } else {
> - printf("Specify a medium traffic subbuffer size after -B.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'z':
> - if(argn+1 < argc) {
> - subbuf_size_high = (unsigned)atoi(argv[argn+1]);
> - argn++;
> - } else {
> - printf("Specify a number of high traffic subbuffers after -z.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'x':
> - if(argn+1 < argc) {
> - n_subbufs_high = (unsigned)atoi(argv[argn+1]);
> - argn++;
> - } else {
> - printf("Specify a high traffic subbuffer size after -x.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'd':
> - op = CTL_OP_DAEMON;
> - break;
> - case 'f':
> - op = CTL_OP_DAEMON_HYBRID_FINISH;
> - break;
> - case 't':
> - if(argn+1 < argc) {
> - trace_root = argv[argn+1];
> - argn++;
> - } else {
> - printf("Specify a trace root path after -t.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'l':
> - if(argn+1 < argc) {
> - channel_root = argv[argn+1];
> - argn++;
> - } else {
> - printf("Specify a channel root path after -l.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - case 'a':
> - append_trace = 1;
> - break;
> - case 'N':
> - if(argn+1 < argc) {
> - num_threads = argv[argn+1];
> - argn++;
> - }
> - break;
> - case 'T':
> - if(argn+1 < argc) {
> - trace_type = argv[argn+1];
> - argn++;
> - } else {
> - printf("Specify a trace type after -T.\n");
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - default:
> - printf("Invalid argument '%s'.\n", argv[argn]);
> - printf("\n");
> - ret = EINVAL;
> - }
> - break;
> - default:
> - printf("Invalid argument '%s'.\n", argv[argn]);
> - printf("\n");
> - ret = EINVAL;
> - }
> - argn++;
> - }
> -
> - if(trace_name == NULL) {
> - printf("Please specify a trace name.\n");
> - printf("\n");
> - ret = EINVAL;
> +
> + static struct option longopts[] = {
> + {"create", no_argument, NULL, 'c'},
> + {"destroy", no_argument, NULL, 'd'},
> + {"start", no_argument, NULL, 's'},
> + {"pause", no_argument, NULL, 'p'},
> + {"help", no_argument, NULL, 'h'},
> + {"transport", required_argument, NULL, 2},
> + {"option", required_argument, NULL, 'o'},
> + {"create_start", no_argument, NULL, 'C'},
> + {"pause_destroy", no_argument, NULL, 'D'},
> + {"write", required_argument, NULL, 'w'},
> + {"append", no_argument, NULL, 'a'},
> + {"dump_threads", required_argument, NULL, 'n'},
> + {"channel_root", required_argument, NULL, 3},
> + { NULL, 0, NULL, 0 },
> + };
> +
> + /*
> + * Enable all channels in default
> + * To make novice users happy
> + */
> + parst_opt("channel.all.enable=1");
> +
> + opterr = 1; /* Print error message on getopt_long */
> + while (1) {
> + int c;
> + c = getopt_long(argc, argv, "cdspho:CDw:an:", longopts, NULL);
> + if (-1 == c) {
> + /* parse end */
> + break;
> + }
> + switch (c) {
> + case 'c':
> + opt_create = 1;
> + break;
> + case 'd':
> + opt_destroy = 1;
> + break;
> + case 's':
> + opt_start = 1;
> + break;
> + case 'p':
> + opt_pause = 1;
> + break;
> + case 'h':
> + opt_help = 1;
> + break;
> + case 2:
> + if (!opt_transport) {
> + opt_transport = optarg;
> + } else {
> + fprintf(stderr,
> + "Please specify only 1 transport\n");
> + return -EINVAL;
> + }
> + break;
> + case 'o':
> + ret = parst_opt(optarg);
> + if (ret)
> + return ret;
> + break;
> + case 'C':
> + opt_create = 1;
> + opt_start = 1;
> + break;
> + case 'D':
> + opt_pause = 1;
> + opt_destroy = 1;
> + break;
> + case 'w':
> + if (!opt_write) {
> + opt_write = optarg;
> + } else {
> + fprintf(stderr,
> + "Please specify only 1 write dir\n");
> + return -EINVAL;
> + }
> + break;
> + case 'a':
> + opt_append = 1;
> + break;
> + case 'n':
> + if (opt_dump_threads) {
> + fprintf(stderr,
> + "Please specify only 1 dump threads\n");
> + return -EINVAL;
> + }
> +
> + ret = sscanf(optarg, "%u", &opt_dump_threads);
> + if (ret != 1) {
> + fprintf(stderr,
> + "Dump threads not positive number\n");
> + return -EINVAL;
> + }
> + break;
> + case 3:
> + if (!opt_channel_root) {
> + opt_channel_root = optarg;
> + } else {
> + fprintf(stderr,
> + "Please specify only 1 channel root\n");
> + return -EINVAL;
> + }
> + break;
> + case '?':
> + return -EINVAL;
> + default:
> + break;
> + };
> + };
> +
> + /* Don't check args when user needs help */
> + if (opt_help)
> + return 0;
> +
> + /* Get tracename */
> + if (optind < argc - 1) {
> + fprintf(stderr, "Please specify only 1 trace name\n");
> + return -EINVAL;
> }
> + if (optind > argc - 1) {
> + fprintf(stderr, "Please specify trace name\n");
> + return -EINVAL;
> + }
> + opt_tracename = argv[optind];
>
> - if(op == CTL_OP_NONE) {
> - printf("Please specify an operation.\n");
> - printf("\n");
> - ret = EINVAL;
> + /*
> + * Check arguments
> + */
> + if (!opt_create && !opt_start && !opt_destroy && !opt_pause) {
> + fprintf(stderr,
> + "Please specify a option of "
> + "create, destroy, start, or pause\n");
> + return -EINVAL;
> }
>
> - if(op == CTL_OP_DAEMON || op == CTL_OP_DAEMON_HYBRID_FINISH) {
> - if(trace_root == NULL) {
> - printf("Please specify -t trace_root_path with the -d option.\n");
> - printf("\n");
> - ret = EINVAL;
> + if ((opt_create || opt_start) && (opt_destroy || opt_pause)) {
> + fprintf(stderr,
> + "Create and start conflict with destroy and pause\n");
> + return -EINVAL;
> + }
> +
> + if (opt_create) {
> + if (!opt_transport)
> + opt_transport = "relay";
> + }
> +
> + if (opt_transport) {
> + if (!opt_create) {
> + fprintf(stderr,
> + "Transport option must be combine with create"
> + " option\n");
> + return -EINVAL;
> }
> - if(channel_root == NULL) {
> + }
> +
> + if (opt_write) {
> + if (!opt_create && !opt_destroy) {
> + fprintf(stderr,
> + "Write option must be combine with create or"
> + " destroy option\n");
> + return -EINVAL;
> + }
> +
> + if (!opt_channel_root)
> if (getdebugfsmntdir(channel_root_default) == 0) {
> strcat(channel_root_default, "/ltt");
> - printf("No -l ltt_root_path with the -d option, using default: %s\n", channel_root_default);
> - printf("\n");
> - channel_root=channel_root_default;
> - } else {
> - printf("Please specify -l ltt_root_path with the -d option.\n");
> - printf("\n");
> - ret = EINVAL;
> + opt_channel_root = channel_root_default;
> }
> + /* Todo:
> + * if (!opt_channel_root)
> + * if (auto_mount_debugfs_dir(channel_root_default) == 0)
> + * opt_channel_root = debugfs_dir_mnt_point;
> + */
> + if (!opt_channel_root) {
> + fprintf(stderr,
> + "Channel_root is necessary for -w option,"
> + " but neither --channel_root option\n"
> + "specified, nor debugfs's mount dir found.\n");
> + return -EINVAL;
> + }
> +
> + if (opt_dump_threads == 0)
> + opt_dump_threads = 1;
> + }
> +
> + if (opt_append) {
> + if (!opt_write) {
> + fprintf(stderr,
> + "Append option must be combine with write"
> + " option\n");
> + return -EINVAL;
> }
> }
>
> - return ret;
> + if (opt_dump_threads) {
> + if (!opt_write) {
> + fprintf(stderr,
> + "Dump_threads option must be combine with write"
> + " option\n");
> + return -EINVAL;
> + }
> + }
> +
> + if (opt_channel_root) {
> + if (!opt_write) {
> + fprintf(stderr,
> + "Channel_root option must be combine with write"
> + " option\n");
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> }
>
> -void show_info(void)
> +static void show_info(void)
> {
> printf("Linux Trace Toolkit Trace Control " VERSION"\n");
> printf("\n");
> - if(trace_name != NULL) {
> - printf("Controlling trace : %s\n", trace_name);
> + if (opt_tracename != NULL) {
> + printf("Controlling trace : %s\n", opt_tracename);
> printf("\n");
> }
> }
>
> -int lttctl_daemon(struct lttctl_handle *handle, char *trace_name)
> +static int lttctl_create_trace(void)
> {
> - char channel_path[PATH_MAX] = "";
> - pid_t pid;
> int ret;
> - char *lttd_path = getenv("LTT_DAEMON");
> + int i;
>
> - if(lttd_path == NULL) lttd_path =
> - PACKAGE_BIN_DIR "/lttd";
> -
> - strcat(channel_path, channel_root);
> - strcat(channel_path, "/");
> - strcat(channel_path, trace_name);
> -
> -
> - ret = lttctl_create_trace(handle, trace_name, mode, trace_type,
> - subbuf_size_low, n_subbufs_low,
> - subbuf_size_med, n_subbufs_med,
> - subbuf_size_high, n_subbufs_high);
> - if(ret != 0) goto create_error;
> + ret = lttctl_setup_trace(opt_tracename);
> + if (ret)
> + goto setup_trace_fail;
>
> - pid = fork();
> + for (i = 0; i < opt_option_n; i++) {
> + if (strcmp(opt_options[i].name1, "channel") != 0)
> + continue;
>
> - if(pid > 0) {
> - int status = 0;
> - /* parent */
> -
> - ret = waitpid(pid, &status, 0);
> - if(ret == -1) {
> - ret = errno;
> - perror("Error in waitpid");
> - goto start_error;
> - }
> -
> - ret = 0;
> - if(WIFEXITED(status))
> - ret = WEXITSTATUS(status);
> - if(ret) goto start_error;
> + if (strcmp(opt_options[i].name3, "enable") == 0) {
> + ret = lttctl_set_channel_enable(opt_tracename,
> + opt_options[i].name2,
> + opt_options[i].value.v_bool);
> + if (ret)
> + goto set_option_fail;
> + }
>
> - } else if(pid == 0) {
> - /* child */
> - int ret;
> - if(mode != LTT_TRACE_HYBRID) {
> - if(append_trace)
> - ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
> - channel_path, "-d", "-a", "-N", num_threads, NULL);
> - else
> - ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
> - channel_path, "-d", "-N", num_threads, NULL);
> - } else {
> - if(append_trace)
> - ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
> - channel_path, "-d", "-a", "-N", num_threads, "-n", NULL);
> - else
> - ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
> - channel_path, "-d", "-N", num_threads, "-n", NULL);
> - }
> - if(ret) {
> - ret = errno;
> - perror("Error in executing the lttd daemon");
> - exit(ret);
> + if (strcmp(opt_options[i].name3, "overwrite") == 0) {
> + ret = lttctl_set_channel_overwrite(opt_tracename,
> + opt_options[i].name2,
> + opt_options[i].value.v_bool);
> + if (ret)
> + goto set_option_fail;
> + }
> +
> + if (strcmp(opt_options[i].name3, "bufnum") == 0) {
> + ret = lttctl_set_channel_subbuf_num(opt_tracename,
> + opt_options[i].name2,
> + opt_options[i].value.v_uint);
> + if (ret)
> + goto set_option_fail;
> + }
> +
> + if (strcmp(opt_options[i].name3, "bufsize") == 0) {
> + ret = lttctl_set_channel_subbuf_size(opt_tracename,
> + opt_options[i].name2,
> + opt_options[i].value.v_uint);
> + if (ret)
> + goto set_option_fail;
> }
> - } else {
> - /* error */
> - perror("Error in forking for lttd daemon");
> }
>
> - ret = lttctl_start(handle, trace_name);
> - if(ret != 0) goto start_error;
> + ret = lttctl_set_trans(opt_tracename, opt_transport);
> + if (ret)
> + goto set_option_fail;
> +
> + ret = lttctl_alloc_trace(opt_tracename);
> + if (ret)
> + goto alloc_trace_fail;
>
> return 0;
>
> - /* error handling */
> -start_error:
> - printf("Trace start error\n");
> - ret |= lttctl_destroy_trace(handle, trace_name);
> -create_error:
> +alloc_trace_fail:
> +set_option_fail:
> + lttctl_destroy_trace(opt_tracename);
> +setup_trace_fail:
> return ret;
> }
>
> -
> -
> -
> -int lttctl_daemon_hybrid_finish(struct lttctl_handle *handle, char *trace_name)
> +/*
> + * Start a lttd daemon to write trace datas
> + * Dump overwrite channels on overwrite!=0
> + * Dump normal(non-overwrite) channels on overwrite=0
> + *
> + * ret: 0 on success
> + * !0 on fail
> + */
> +static int lttctl_daemon(int overwrite)
> {
> - char channel_path[PATH_MAX] = "";
> pid_t pid;
> - int ret;
> - char *lttd_path = getenv("LTT_DAEMON");
> -
> - if(lttd_path == NULL) lttd_path =
> - PACKAGE_BIN_DIR "/lttd";
> -
> - strcat(channel_path, channel_root);
> - strcat(channel_path, "/");
> - strcat(channel_path, trace_name);
> -
> -
> - ret = lttctl_stop(handle, trace_name);
> - if(ret != 0) goto stop_error;
> + int status;
>
> pid = fork();
> + if (pid < 0) {
> + perror("Error in forking for lttd daemon");
> + return errno;
> + }
>
> - if(pid > 0) {
> - int status = 0;
> - /* parent */
> -
> - ret = waitpid(pid, &status, 0);
> - if(ret == -1) {
> - ret = errno;
> - perror("Error in waitpid");
> - goto destroy_error;
> - }
> -
> - ret = 0;
> - if(WIFEXITED(status))
> - ret = WEXITSTATUS(status);
> - if(ret) goto destroy_error;
> -
> - } else if(pid == 0) {
> + if (pid == 0) {
> /* child */
> - int ret;
> - if(append_trace)
> - ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
> - channel_path, "-d", "-a", "-N", num_threads, "-f", NULL);
> - else
> - ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
> - channel_path, "-d", "-N", num_threads, "-f", NULL);
> - if(ret) {
> - ret = errno;
> - perror("Error in executing the lttd daemon");
> - exit(ret);
> + char *argv[16];
> + int argc = 0;
> + char channel_path[PATH_MAX];
> + char thread_num[16];
> +
> + /* prog path */
> + argv[argc] = getenv("LTT_DAEMON");
> + if (argv[argc] == NULL)
> + argv[argc] = PACKAGE_BIN_DIR "/lttd";
> + argc++;
> +
> + /* -t option */
> + argv[argc] = "-t";
> + argc++;
> + /*
> + * we allow modify of opt_write's content in new process
> + * for get rid of warning of assign char * to const char *
> + */
> + argv[argc] = (char *)opt_write;
> + argc++;
> +
> + /* -c option */
> + strcpy(channel_path, opt_channel_root);
> + strcat(channel_path, "/");
> + strcat(channel_path, opt_tracename);
> + argv[argc] = "-c";
> + argc++;
> + argv[argc] = channel_path;
> + argc++;
> +
> + /* -N option */
> + sprintf(thread_num, "%u", opt_dump_threads);
> + argv[argc] = "-N";
> + argc++;
> + argv[argc] = thread_num;
> + argc++;
> +
> + /* -a option */
> + if (opt_append) {
> + argv[argc] = "-a";
> + argc++;
> + }
> +
> + /* -d option */
> + argv[argc] = "-d";
> + argc++;
> +
> + /* overwrite option */
> + if (overwrite) {
> + argv[argc] = "-f";
> + argc++;
> + } else {
> + argv[argc] = "-n";
> + argc++;
> }
> - } else {
> - /* error */
> - perror("Error in forking for lttd daemon");
> - }
>
> - ret = lttctl_destroy_trace(handle, trace_name);
> - if(ret != 0) goto destroy_error;
> + argv[argc] = NULL;
>
> - return 0;
> + execvp(argv[0], argv);
>
> - /* error handling */
> -destroy_error:
> - printf("Hybrid trace destroy error\n");
> -stop_error:
> - return ret;
> -}
> + perror("Error in executing the lttd daemon");
> + exit(errno);
> + }
>
> + /* parent */
> + if (waitpid(pid, &status, 0) == -1) {
> + perror("Error in waitpid\n");
> + return errno;
> + }
> +
> + if (!WIFEXITED(status)) {
> + fprintf(stderr, "lttd process interrupted\n");
> + return status;
> + }
>
> + if (WEXITSTATUS(status))
> + fprintf(stderr, "lttd process running failed\n");
>
> -int main(int argc, char ** argv)
> + return WEXITSTATUS(status);
> +}
> +
> +int main(int argc, char **argv)
> {
> int ret;
> - struct lttctl_handle *handle;
> -
> +
> ret = parse_arguments(argc, argv);
> + /* If user needs show help, we disregard other options */
> + if (opt_help) {
> + show_arguments();
> + return 0;
> + }
>
> - if(ret != 0) show_arguments();
> - if(ret == EINVAL) return EINVAL;
> - if(ret == -1) return 0;
> + /* exit program if arguments wrong */
> + if (ret)
> + return 1;
>
> show_info();
> -
> - handle = lttctl_create_handle();
> -
> - if(handle == NULL) return -1;
> -
> - switch(op) {
> - case CTL_OP_CREATE_START:
> - ret = lttctl_create_trace(handle, trace_name, mode, trace_type,
> - subbuf_size_low, n_subbufs_low,
> - subbuf_size_med, n_subbufs_med,
> - subbuf_size_high, n_subbufs_high);
> - if(!ret)
> - ret = lttctl_start(handle, trace_name);
> - break;
> - case CTL_OP_CREATE:
> - ret = lttctl_create_trace(handle, trace_name, mode, trace_type,
> - subbuf_size_low, n_subbufs_low,
> - subbuf_size_med, n_subbufs_med,
> - subbuf_size_high, n_subbufs_high);
> - break;
> - case CTL_OP_DESTROY:
> - ret = lttctl_destroy_trace(handle, trace_name);
> - break;
> - case CTL_OP_STOP_DESTROY:
> - ret = lttctl_stop(handle, trace_name);
> - if(!ret)
> - ret = lttctl_destroy_trace(handle, trace_name);
> - break;
> - case CTL_OP_START:
> - ret = lttctl_start(handle, trace_name);
> - break;
> - case CTL_OP_STOP:
> - ret = lttctl_stop(handle, trace_name);
> - break;
> - case CTL_OP_DAEMON:
> - ret = lttctl_daemon(handle, trace_name);
> - break;
> - case CTL_OP_DAEMON_HYBRID_FINISH:
> - ret = lttctl_daemon_hybrid_finish(handle, trace_name);
> - break;
> - case CTL_OP_NONE:
> - break;
> +
> + ret = lttctl_init();
> + if (ret != 0)
> + return ret;
> +
> + if (opt_create) {
> + printf("lttctl: Creating trace\n");
> + ret = lttctl_create_trace();
> + if (ret)
> + goto op_fail;
> +
> + if (opt_write) {
> + printf("lttctl: Forking lttd\n");
> + ret = lttctl_daemon(0);
> + if (ret)
> + goto op_fail;
> + }
> }
>
> - ret |= lttctl_destroy_handle(handle);
> -
> + if (opt_start) {
> + printf("lttctl: Starting trace\n");
> + ret = lttctl_start(opt_tracename);
> + if (ret)
> + goto op_fail;
> + }
> +
> + if (opt_pause) {
> + printf("lttctl: Pausing trace\n");
> + ret = lttctl_pause(opt_tracename);
> + if (ret)
> + goto op_fail;
> + }
> +
> + if (opt_destroy) {
> + if (opt_write) {
> + printf("lttctl: Forking lttd\n");
> + ret = lttctl_daemon(1);
> + if (ret)
> + goto op_fail;
> + }
> +
> + printf("lttctl: Destroying trace\n");
> + ret = lttctl_destroy_trace(opt_tracename);
> + if (ret)
> + goto op_fail;
> + }
> +
> +op_fail:
> + lttctl_destroy();
> +
> return ret;
> }
>
>
> _______________________________________________
> ltt-dev mailing list
> ltt-dev at lists.casi.polymtl.ca
> http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
>
--
Mathieu Desnoyers
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
More information about the lttng-dev
mailing list