1
/* -*- mode: c; c-basic-offset: 8; -*-
2
* vim: noexpandtab sw=8 ts=8 sts=0:
6
* Ocfs2 utility to gather and report fs information
8
* Copyright (C) 2010 Oracle. All rights reserved.
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public
12
* License version 2 as published by the Free Software Foundation.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* General Public License for more details.
20
#define _XOPEN_SOURCE 600
21
#define _LARGEFILE64_SOURCE
22
#define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */
30
#include "ocfs2/ocfs2.h"
31
#include "ocfs2-kernel/ocfs2_ioctl.h"
32
#include "ocfs2-kernel/kernel-list.h"
33
#include "tools-internal/verbose.h"
37
extern struct o2info_operation fs_features_op;
38
extern struct o2info_operation volinfo_op;
39
extern struct o2info_operation mkfs_op;
40
extern struct o2info_operation freeinode_op;
41
extern struct o2info_operation freefrag_op;
42
extern struct o2info_operation space_usage_op;
43
extern struct o2info_operation filestat_op;
45
static LIST_HEAD(o2info_op_task_list);
46
static int o2info_op_task_count;
49
void print_usage(int rc);
50
static int help_handler(struct o2info_option *opt, char *arg)
56
static int version_handler(struct o2info_option *opt, char *arg)
62
static int coherency_handler(struct o2info_option *opt, char *arg)
69
static struct o2info_option help_option = {
77
.opt_handler = help_handler,
82
static struct o2info_option version_option = {
90
.opt_handler = version_handler,
95
static struct o2info_option coherency_option = {
97
.name = "cluster-coherent",
103
"-C|--cluster-coherent",
104
.opt_handler = coherency_handler,
109
static struct o2info_option fs_features_option = {
111
.name = "fs-features",
116
.opt_help = " --fs-features",
118
.opt_op = &fs_features_op,
122
static struct o2info_option volinfo_option = {
129
.opt_help = " --volinfo",
131
.opt_op = &volinfo_op,
135
static struct o2info_option mkfs_option = {
142
.opt_help = " --mkfs",
148
static struct o2info_option freeinode_option = {
155
.opt_help = " --freeinode",
157
.opt_op = &freeinode_op,
161
static struct o2info_option freefrag_option = {
168
.opt_help = " --freefrag <chunksize in KB>",
170
.opt_op = &freefrag_op,
174
static struct o2info_option space_usage_option = {
176
.name = "space-usage",
181
.opt_help = " --space-usage",
183
.opt_op = &space_usage_op,
187
static struct o2info_option filestat_option = {
194
.opt_help = " --filestat",
196
.opt_op = &filestat_op,
200
static struct o2info_option *options[] = {
214
void print_usage(int rc)
217
enum tools_verbosity_level level = VL_ERR;
222
verbosef(level, "Usage: %s [options] <device or file>\n",
224
verbosef(level, " %s -h|--help\n", tools_progname());
225
verbosef(level, " %s -V|--version\n", tools_progname());
226
verbosef(level, "[options] can be followings:\n");
228
for (i = 0; options[i]; i++) {
229
if (options[i]->opt_help)
230
verbosef(level, "\t%s\n", options[i]->opt_help);
236
static int build_options(char **optstring, struct option **longopts)
239
int i, num_opts, rc = 0;
240
int unprintable_counter;
241
size_t optstring_len;
242
char *p, *str = NULL;
243
struct option *lopts = NULL;
244
struct o2info_option *opt;
246
unprintable_counter = 1; /* Start unique at CHAR_MAX + 1*/
247
optstring_len = 1; /* For the leading ':' */
248
for (i = 0; options[i]; i++) {
252
* Any option with a val of CHAR_MAX wants an unique but
253
* unreadable ->val. Only readable characters go into
256
if (opt->opt_option.val == CHAR_MAX) {
257
opt->opt_option.val =
258
CHAR_MAX + unprintable_counter;
259
unprintable_counter++;
264
* A given option has a single character in optstring.
265
* If it takes a mandatory argument, has_arg==1 and you add
266
* a ":" to optstring. If it takes an optional argument,
267
* has_arg==2 and you add "::" to optstring. Thus,
268
* 1 + has_arg is the total space needed in opstring.
270
optstring_len += 1 + opt->opt_option.has_arg;
275
err = ocfs2_malloc0(sizeof(char) * (optstring_len + 1), &str);
277
err = ocfs2_malloc(sizeof(struct option) * (num_opts + 1),
286
for (i = 0; options[i]; i++) {
287
assert(p < (str + optstring_len + 1));
290
memcpy(&lopts[i], &opt->opt_option, sizeof(struct option));
292
if (opt->opt_option.val >= CHAR_MAX)
295
*p = opt->opt_option.val;
297
if (opt->opt_option.has_arg > 0) {
301
if (opt->opt_option.has_arg > 1) {
308
* Fill last entry of options with zeros.
310
memset(&lopts[i], 0, sizeof(struct option));
326
static struct o2info_option *find_option_by_val(int val)
329
struct o2info_option *opt = NULL;
331
for (i = 0; options[i]; i++) {
332
if (options[i]->opt_option.val == val) {
341
static errcode_t o2info_append_task(struct o2info_operation *o2p)
344
struct o2info_op_task *task;
346
err = ocfs2_malloc0(sizeof(struct o2info_op_task), &task);
348
task->o2p_task = o2p;
349
list_add_tail(&task->o2p_list, &o2info_op_task_list);
350
o2info_op_task_count++;
357
static void o2info_free_op_task_list(void)
359
struct o2info_op_task *task;
360
struct list_head *pos, *next;
362
if (list_empty(&o2info_op_task_list))
365
list_for_each_safe(pos, next, &o2info_op_task_list) {
366
task = list_entry(pos, struct o2info_op_task, o2p_list);
372
extern int optind, opterr, optopt;
374
static errcode_t parse_options(int argc, char *argv[], char **device_or_file)
378
struct option *long_options = NULL;
379
char error[PATH_MAX];
380
char *optstring = NULL;
381
struct o2info_option *opt;
383
err = build_options(&optstring, &long_options);
389
while ((c = getopt_long(argc, argv, optstring,
390
long_options, &lopt_idx)) != EOF) {
395
errorf("Invalid option: '-%c'\n", optopt);
397
errorf("Invalid option: '%s'\n",
403
if (optopt < CHAR_MAX)
404
errorf("Option '-%c' requires an argument\n",
407
errorf("Option '%s' requires an argument\n",
413
opt = find_option_by_val(c);
415
errorf("Shouldn't have gotten here: "
416
"option '-%c'\n", c);
421
opt->opt_private = (void *)optarg;
427
errorf("Option '-%c' specified more than once\n",
434
* Handlers for simple options such as showing version,
435
* printing the usage, or specify the coherency etc.
437
if (opt->opt_handler) {
438
if (opt->opt_handler(opt, optarg))
443
* Real operation will be added to a list to run later.
446
opt->opt_op->to_private = opt->opt_private;
447
err = o2info_append_task(opt->opt_op);
456
if (optind >= argc) {
457
errorf("No device or file specified\n");
461
*device_or_file = strdup(argv[optind]);
462
if (!*device_or_file) {
463
errorf("No memory for allocation\n");
470
errorf("Too many arguments\n");
476
ocfs2_free(&optstring);
479
ocfs2_free(&long_options);
484
static errcode_t o2info_run_task(struct o2info_method *om)
486
struct list_head *p, *n;
487
struct o2info_op_task *task;
489
list_for_each_safe(p, n, &o2info_op_task_list) {
490
task = list_entry(p, struct o2info_op_task, o2p_list);
491
task->o2p_task->to_run(task->o2p_task, om,
492
task->o2p_task->to_private);
498
static void handle_signal(int caught_sig)
500
int exitp = 0, abortp = 0;
501
static int segv_already;
503
switch (caught_sig) {
511
errorf("Caught signal %d, exiting\n", caught_sig);
516
errorf("Segmentation fault, exiting\n");
519
errorf("Segmentation fault loop detected\n");
526
errorf("Caught signal %d, ignoring\n", caught_sig);
539
static int setup_signals(void)
542
struct sigaction act;
544
act.sa_sigaction = NULL;
545
sigemptyset(&act.sa_mask);
546
act.sa_handler = handle_signal;
548
act.sa_flags = SA_INTERRUPT;
550
rc += sigaction(SIGTERM, &act, NULL);
551
rc += sigaction(SIGINT, &act, NULL);
552
rc += sigaction(SIGHUP, &act, NULL);
553
rc += sigaction(SIGQUIT, &act, NULL);
554
rc += sigaction(SIGSEGV, &act, NULL);
555
act.sa_handler = SIG_IGN;
556
rc += sigaction(SIGPIPE, &act, NULL); /* Get EPIPE instead */
561
static void o2info_init(const char *argv0)
563
initialize_ocfs_error_table();
565
tools_setup_argv0(argv0);
567
setbuf(stdout, NULL);
568
setbuf(stderr, NULL);
570
if (setup_signals()) {
571
errorf("Unable to setup signal handling \n");
575
cluster_coherent = 0;
578
int main(int argc, char *argv[])
582
char *device_or_file = NULL;
583
static struct o2info_method om;
585
o2info_init(argv[0]);
586
parse_options(argc, argv, &device_or_file);
588
rc = o2info_method(device_or_file);
594
strncpy(om.om_path, device_or_file, PATH_MAX);
596
rc = o2info_open(&om, 0);
600
rc = o2info_run_task(&om);
604
o2info_free_op_task_list();
606
rc = o2info_close(&om);
609
ocfs2_free(&device_or_file);