From mboxrd@z Thu Jan 1 00:00:00 1970 From: compudj@krystal.dyndns.org (Mathieu Desnoyers) Date: Mon, 15 Dec 2008 12:45:10 -0500 Subject: [ltt-dev] New lttctl for debugfs-based ltt-trace-control In-Reply-To: <4945CA56.7050100@cn.fujitsu.com> References: <4945CA56.7050100@cn.fujitsu.com> Message-ID: <20081215174510.GA29020@Krystal> * 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..enable= > channel..overwrite= > channel..bufnum= > channel..bufsize= > 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 > --- > 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 > + * Controls the ltt-control kernel module through debugfs. > * > * Copyright 2005 - > * Mathieu Desnoyers > @@ -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 > #include > #include > -#include > -#include > -#include > -#include > #include > +#include > +#include > +#include > > +#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 . > - * > */ > > #ifndef _LIBLTT_H > #define _LIBLTT_H > > -#include > -#include > -#include > -#include > - > -#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 > #include > #include > -#include > #include > #include > -#include > -#include > #include > #include > -#include > +#define _GNU_SOURCE > +#include > > -/* 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..enable=\n"); > + printf(" channel..overwrite=\n"); > + printf(" channel..bufnum=\n"); > + printf(" channel..bufsize=\n"); > + printf(" 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