[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