[Ocfs2-tools-devel] [PATCH 6/7] Ocfs2-tools: Add main.c to o2info.

Sunil Mushran sunil.mushran at oracle.com
Mon Nov 30 15:58:14 PST 2009


Again, remove extra code. e.g., freefrag, etc.

Tristan Ye wrote:
> It handles the parsing of options, links the operational
> tasks to list, then schedules to run task one bye one.
>
> To add a new operation task for o2info(such as --volinfo)
>
> 1. declare a new extern operation structure.
>    extern struct o2info_operation volinfo_op;
>
> 2. add a new option:
>    static struct o2info_option volinfo_option = {
>         .opt_option     = {
>                 .name           = "volinfo",
>                 .val            = 'V',
>                 .has_arg        = 0,
>                 .flag           = NULL,
>         },
>         .opt_help       =
>                 "-V|--volinfo",
>         .opt_handler    = NULL,
>         .opt_op         = &volinfo_op,
>         .opt_private    = NULL,
> };
>
> 3. Implement the real code for volinfo_op in o2info_operation.c
>
> Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
> ---
>  o2info/main.c |  555 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 555 insertions(+), 0 deletions(-)
>  create mode 100644 o2info/main.c
>
> diff --git a/o2info/main.c b/o2info/main.c
> new file mode 100644
> index 0000000..8d7f265
> --- /dev/null
> +++ b/o2info/main.c
> @@ -0,0 +1,555 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * main.c
> + *
> + * Ocfs2 utility to gather and report fs information.
> + *
> + * Copyright (C) 2009 Oracle.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#include "o2info_utils.h"
> +
> +extern struct o2info_operation freefrag_op;
> +extern struct o2info_operation freeinode_op;
> +extern struct o2info_operation filestat_op;
> +extern struct o2info_operation usage_op;
> +extern struct o2info_operation volinfo_op;
> +extern struct o2info_operation fs_features_op;
> +
> +static LIST_HEAD(o2info_op_task_list);
> +
> +static int o2info_op_task_count;
> +
> +static void print_usage(int rc);
> +static int help_handler(struct o2info_option *opt, char *arg)
> +{
> +	print_usage(0);
> +	exit(0);
> +}
> +
> +static int version_handler(struct o2info_option *opt, char *arg)
> +{
> +	tools_version();
> +	exit(0);
> +}
> +
> +static struct o2info_option help_option = {
> +	.opt_option	= {
> +		.name		= "help",
> +		.val		= 'h',
> +		.has_arg	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_handler	= help_handler,
> +	.opt_op		= NULL,
> +	.opt_private = NULL,
> +};
> +
> +static struct o2info_option version_option = {
> +	.opt_option	= {
> +		.name		= "version",
> +		.val		= 'v',
> +		.has_arg 	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_handler	= version_handler,
> +	.opt_op		= NULL,
> +	.opt_private = NULL,
> +};
> +
> +static struct o2info_option freefrag_option = {
> +	.opt_option	= {
> +		.name		= "freefrag",
> +		.val		= 'F',
> +		.has_arg	= 1,
> +		.flag		= NULL,
> +	},
> +	.opt_help	=
> +		"-F|--freefrag <chunksize> <device or file>",
> +	.opt_handler	= NULL,
> +	.opt_op		= &freefrag_op,
> +};
> +
> +static struct o2info_option freeinode_option = {
> +	.opt_option	= {
> +		.name		= "freeinode",
> +		.val		= 'I',
> +		.has_arg	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_help	=
> +		"-I|--freeinode <device or file>",
> +	.opt_handler	= NULL,
> +	.opt_op		= &freeinode_op,
> +};
> +
> +static struct o2info_option filestat_option = {
> +	.opt_option	= {
> +		.name		= "filestat",
> +		.val		= 'S',
> +		.has_arg	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_help	=
> +		"-S|--filestat <file>",
> +	.opt_handler	= NULL,
> +	.opt_op		= &filestat_op,
> +	.opt_private	= NULL,
> +};
> +
> +static struct o2info_option usage_option = {
> +	.opt_option	= {
> +		.name		= "usage",
> +		.val		= 'U',
> +		.has_arg	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_help	=
> +		"-U|--usage <file>",
> +	.opt_handler	= NULL,
> +	.opt_op		= &usage_op,
> +};
> +
> +static struct o2info_option volinfo_option = {
> +	.opt_option	= {
> +		.name		= "volinfo",
> +		.val		= 'V',
> +		.has_arg	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_help	=
> +		"-V|--volinfo <device or file>",
> +	.opt_handler	= NULL,
> +	.opt_op		= &volinfo_op,
> +	.opt_private	= NULL,
> +};
> +
> +static struct o2info_option fs_features_option = {
> +	.opt_option	= {
> +		.name		= "fs-features",
> +		.val		= CHAR_MAX,
> +		.has_arg	= 0,
> +		.flag		= NULL,
> +	},
> +	.opt_help	= "   --fs-features <device or file>",
> +	.opt_handler	= NULL,
> +	.opt_op		= &fs_features_op,
> +};
> +
> +static struct o2info_option *options[] = {
> +	&help_option,
> +	&version_option,
> +	&freefrag_option,
> +	&freeinode_option,
> +	&filestat_option,
> +	&usage_option,
> +	&volinfo_option,
> +	&fs_features_option,
> +	NULL,
> +};
> +
> +static void print_usage(int rc)
> +{
> +	int i;
> +	enum tools_verbosity_level level = VL_ERR;
> +
> +	if (!rc)
> +		level = VL_OUT;
> +
> +	verbosef(level, "Usage: %s [options] <device or file>\n",
> +		 tools_progname());
> +	verbosef(level, "       %s -h|--help\n", tools_progname());
> +	verbosef(level, "       %s -v|--version\n", tools_progname());
> +	verbosef(level, "[options] can be followings:\n");
> +
> +	for (i = 0; options[i]; i++) {
> +		if (options[i]->opt_help)
> +			verbosef(level, "\t%s\n", options[i]->opt_help);
> +	}
> +
> +	exit(rc);
> +}
> +
> +static int build_options(char **optstring, struct option **longopts)
> +{
> +	errcode_t err;
> +	int i, num_opts, rc = 0;
> +	int unprintable_counter;
> +	size_t optstring_len;
> +	char *p, *str = NULL;
> +	struct option *lopts = NULL;
> +	struct o2info_option *opt;
> +
> +	unprintable_counter = 1;	/* Start unique at CHAR_MAX + 1*/
> +	optstring_len = 1;		/* For the leading ':' */
> +	for (i = 0; options[i]; i++) {
> +		opt = options[i];
> +
> +		/*
> +		 * Any option with a val of CHAR_MAX wants an unique but
> +		 * unreadable ->val.  Only readable characters go into
> +		 * optstring.
> +		 */
> +		if (opt->opt_option.val == CHAR_MAX) {
> +			opt->opt_option.val =
> +				CHAR_MAX + unprintable_counter;
> +			unprintable_counter++;
> +			continue;
> +		}
> +
> +		/*
> +		 * A given option has a single character in optstring.
> +		 * If it takes a mandatory argument, has_arg==1 and you add
> +		 * a ":" to optstring.  If it takes an optional argument,
> +		 * has_arg==2 and you add "::" to optstring.  Thus,
> +		 * 1 + has_arg is the total space needed in opstring.
> +		 */
> +		optstring_len += 1 + opt->opt_option.has_arg;
> +	}
> +
> +	num_opts = i;
> +
> +	err = ocfs2_malloc0(sizeof(char) * (optstring_len + 1), &str);
> +	if (!err)
> +		err = ocfs2_malloc(sizeof(struct option) * (num_opts + 1),
> +				   &lopts);
> +	if (err) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	p = str;
> +	*p++ = ':';
> +	for (i = 0; options[i]; i++) {
> +		assert(p < (str + optstring_len + 1));
> +		opt = options[i];
> +
> +		memcpy(&lopts[i], &opt->opt_option, sizeof(struct option));
> +
> +		if (opt->opt_option.val >= CHAR_MAX)
> +			continue;
> +
> +		*p = opt->opt_option.val;
> +		p++;
> +		if (opt->opt_option.has_arg > 0) {
> +			*p = ':';
> +			p++;
> +		}
> +		if (opt->opt_option.has_arg > 1) {
> +			*p = ':';
> +			p++;
> +		}
> +	}
> +
> +	/*
> +	 * Fill last entry of options with zeros.
> +	 */
> +
> +	memset(&lopts[i], 0, sizeof(struct option));
> +out:
> +	if (!rc) {
> +		*optstring = str;
> +		*longopts = lopts;
> +	} else {
> +		if (str)
> +			free(str);
> +		if (lopts)
> +			free(lopts);
> +	}
> +
> +	return rc;
> +}
> +
> +static struct o2info_option *find_option_by_val(int val)
> +{
> +	int i;
> +	struct o2info_option *opt = NULL;
> +
> +	for (i = 0; options[i]; i++) {
> +		if (options[i]->opt_option.val == val) {
> +			opt = options[i];
> +			break;
> +		}
> +	}
> +
> +	return opt;
> +}
> +
> +static errcode_t o2info_append_task(struct o2info_operation *o2p)
> +{
> +	errcode_t err;
> +	struct o2info_op_task *task;
> +
> +	err = ocfs2_malloc0(sizeof(struct o2info_op_task), &task);
> +	if (!err) {
> +		task->o2p_task = o2p;
> +		list_add_tail(&task->o2p_list, &o2info_op_task_list);
> +		o2info_op_task_count++;
> +	} else
> +		ocfs2_free(&task);
> +
> +	return err;
> +}
> +
> +static void o2info_free_op_task_list(void)
> +{
> +	struct o2info_op_task *task;
> +	struct list_head *pos, *next;
> +
> +	if (list_empty(&o2info_op_task_list))
> +		return;
> +
> +	list_for_each_safe(pos, next, &o2info_op_task_list) {
> +		task = list_entry(pos, struct o2info_op_task, o2p_list);
> +		list_del(pos);
> +		ocfs2_free(&task);
> +	}
> +}
> +
> +extern int optind, opterr, optopt;
> +extern char *optarg;
> +static errcode_t parse_options(int argc, char *argv[], char **device_or_file)
> +{
> +	int c, lopt_idx = 0;
> +	errcode_t err;
> +	struct option *long_options = NULL;
> +	char error[PATH_MAX];
> +	char *optstring = NULL;
> +	struct o2info_option *opt;
> +
> +	err = build_options(&optstring, &long_options);
> +	if (err)
> +		goto out;
> +
> +	opterr = 0;
> +	error[0] = '\0';
> +	while ((c = getopt_long(argc, argv, optstring,
> +				long_options, &lopt_idx)) != EOF) {
> +		opt = NULL;
> +		switch (c) {
> +		case '?':
> +			if (optopt)
> +				errorf("Invalid option: '-%c'\n", optopt);
> +			else
> +				errorf("Invalid option: '%s'\n",
> +				       argv[optind - 1]);
> +			print_usage(1);
> +			break;
> +
> +		case ':':
> +			if (optopt < CHAR_MAX)
> +				errorf("Option '-%c' requires an argument\n",
> +				       optopt);
> +			else
> +				errorf("Option '%s' requires an argument\n",
> +				       argv[optind - 1]);
> +			print_usage(1);
> +			break;
> +
> +		default:
> +			opt = find_option_by_val(c);
> +			if (!opt) {
> +				errorf("Shouldn't have gotten here: "
> +				       "option '-%c'\n", c);
> +				print_usage(1);
> +			}
> +
> +			if (optarg)
> +				opt->opt_private = (void *)optarg;
> +
> +			break;
> +		}
> +
> +		if (opt->opt_set) {
> +			errorf("Option '-%c' specified more than once\n",
> +			       c);
> +			print_usage(1);
> +		}
> +
> +		opt->opt_set = 1;
> +		/* Handlers for simple options such as showing version
> +		 * and printing the usage.
> +		 */
> +		if (opt->opt_handler) {
> +			if (opt->opt_handler(opt, optarg))
> +				print_usage(1);
> +		}
> +
> +		/* Real operation will be added to a list to run later.
> +		 */
> +		if (opt->opt_op) {
> +			opt->opt_op->to_private = opt->opt_private;
> +			err = o2info_append_task(opt->opt_op);
> +			if (err)
> +				goto out;
> +		}
> +	}
> +
> +	if (optind == 1)
> +		print_usage(1);
> +
> +	if (optind >= argc) {
> +		errorf("No device or file specified\n");
> +		print_usage(1);
> +	}
> +
> +	*device_or_file = strdup(argv[optind]);
> +	if (!*device_or_file) {
> +		errorf("No memory to for allocation\n");
> +		goto out;
> +	}
> +
> +	optind++;
> +
> +	if (optind < argc) {
> +		errorf("Too many arguments\n");
> +		print_usage(1);
> +	}
> +
> +out:
> +	if (optstring)
> +		ocfs2_free(&optstring);
> +
> +	if (long_options)
> +		ocfs2_free(&long_options);
> +
> +	return err;
> +}
> +
> +static errcode_t o2info_run_task(struct o2info_method *om)
> +{
> +	struct list_head *p, *n;
> +	struct o2info_op_task *task;
> +
> +	list_for_each_safe(p, n, &o2info_op_task_list) {
> +		task = list_entry(p, struct o2info_op_task, o2p_list);
> +		task->o2p_task->to_run(task->o2p_task, om,
> +				       task->o2p_task->to_private);
> +	}
> +	return 0;
> +}
> +
> +static void handle_signal(int caught_sig)
> +{
> +	int exitp = 0, abortp = 0;
> +	static int segv_already;
> +
> +	switch (caught_sig) {
> +	case SIGQUIT:
> +		abortp = 1;
> +		/* FALL THROUGH */
> +
> +	case SIGTERM:
> +	case SIGINT:
> +	case SIGHUP:
> +		errorf("Caught signal %d, exiting\n", caught_sig);
> +		exitp = 1;
> +		break;
> +
> +	case SIGSEGV:
> +		errorf("Segmentation fault, exiting\n");
> +		exitp = 1;
> +		if (segv_already) {
> +			errorf("Segmentation fault loop detected\n");
> +			abortp = 1;
> +		} else
> +			segv_already = 1;
> +		break;
> +
> +	default:
> +		errorf("Caught signal %d, ignoring\n", caught_sig);
> +		break;
> +	}
> +
> +	if (!exitp)
> +		return;
> +
> +	if (abortp)
> +		abort();
> +
> +	exit(1);
> +}
> +
> +static int setup_signals(void)
> +{
> +	int rc = 0;
> +	struct sigaction act;
> +
> +	act.sa_sigaction = NULL;
> +	sigemptyset(&act.sa_mask);
> +	act.sa_handler = handle_signal;
> +#ifdef SA_INTERRUPT
> +	act.sa_flags = SA_INTERRUPT;
> +#endif
> +	rc += sigaction(SIGTERM, &act, NULL);
> +	rc += sigaction(SIGINT, &act, NULL);
> +	rc += sigaction(SIGHUP, &act, NULL);
> +	rc += sigaction(SIGQUIT, &act, NULL);
> +	rc += sigaction(SIGSEGV, &act, NULL);
> +	act.sa_handler = SIG_IGN;
> +	rc += sigaction(SIGPIPE, &act, NULL);  /* Get EPIPE instead */
> +
> +	return rc;
> +}
> +
> +static void o2info_init(const char *argv0)
> +{
> +	initialize_ocfs_error_table();
> +
> +	tools_setup_argv0(argv0);
> +
> +	setbuf(stdout, NULL);
> +	setbuf(stderr, NULL);
> +
> +	if (setup_signals()) {
> +		errorf("Unable to setup signal handling \n");
> +		exit(1);
> +	}
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int rc = 0;
> +
> +	char *device_or_file = NULL;
> +	static struct o2info_method om;
> +
> +	o2info_init(argv[0]);
> +	parse_options(argc, argv, &device_or_file);
> +
> +	rc = is_device(device_or_file);
> +	if (rc < 0)
> +		goto out;
> +	else
> +		if (rc)
> +			om.method |= USE_LIBOCFS2;
> +		else
> +			om.method |= USE_IOCTL;
> +
> +	rc = o2info_open(device_or_file, &om, 0);
> +	if (rc)
> +		goto out;
> +
> +	rc = o2info_run_task(&om);
> +	if (rc)
> +		goto out;
> +
> +	o2info_free_op_task_list();
> +
> +	rc = o2info_close(&om);
> +out:
> +	if (device_or_file)
> +		ocfs2_free(&device_or_file);
> +
> +	return rc;
> +}
>   




More information about the Ocfs2-tools-devel mailing list