[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