[ltt-dev] New lttctl for debugfs-based ltt-trace-control

Zhaolei zhaolei at cn.fujitsu.com
Sun Dec 14 22:09:10 EST 2008


Hi, Mathieu

I modified lttctl for support debugfs-based ltt-trace-control.
Command arguments are changed as we discussed in latest mail into following:

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;
 }





More information about the lttng-dev mailing list