~wb-munzinger/+junk/ocfs2-tools

« back to all changes in this revision

Viewing changes to o2info/o2info.c

  • Committer: David Weber
  • Date: 2012-01-30 08:42:00 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: wb@munzinger.de-20120130084200-c8cy478mu9fk7tkf
Import upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 8; -*-
 
2
 * vim: noexpandtab sw=8 ts=8 sts=0:
 
3
 *
 
4
 * o2info.c
 
5
 *
 
6
 * Ocfs2 utility to gather and report fs information
 
7
 *
 
8
 * Copyright (C) 2010 Oracle.  All rights reserved.
 
9
 *
 
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.
 
13
 *
 
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.
 
18
 */
 
19
 
 
20
#define _XOPEN_SOURCE 600
 
21
#define _LARGEFILE64_SOURCE
 
22
#define _GNU_SOURCE /* Because libc really doesn't want us using O_DIRECT? */
 
23
 
 
24
#include <unistd.h>
 
25
#include <errno.h>
 
26
#include <signal.h>
 
27
#include <getopt.h>
 
28
#include <assert.h>
 
29
 
 
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"
 
34
 
 
35
#include "utils.h"
 
36
 
 
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;
 
44
 
 
45
static LIST_HEAD(o2info_op_task_list);
 
46
static int o2info_op_task_count;
 
47
int cluster_coherent;
 
48
 
 
49
void print_usage(int rc);
 
50
static int help_handler(struct o2info_option *opt, char *arg)
 
51
{
 
52
        print_usage(0);
 
53
        exit(0);
 
54
}
 
55
 
 
56
static int version_handler(struct o2info_option *opt, char *arg)
 
57
{
 
58
        tools_version();
 
59
        exit(0);
 
60
}
 
61
 
 
62
static int coherency_handler(struct o2info_option *opt, char *arg)
 
63
{
 
64
        cluster_coherent = 1;
 
65
 
 
66
        return 0;
 
67
}
 
68
 
 
69
static struct o2info_option help_option = {
 
70
        .opt_option     = {
 
71
                .name           = "help",
 
72
                .val            = 'h',
 
73
                .has_arg        = 0,
 
74
                .flag           = NULL,
 
75
        },
 
76
        .opt_help       = NULL,
 
77
        .opt_handler    = help_handler,
 
78
        .opt_op         = NULL,
 
79
        .opt_private = NULL,
 
80
};
 
81
 
 
82
static struct o2info_option version_option = {
 
83
        .opt_option     = {
 
84
                .name           = "version",
 
85
                .val            = 'V',
 
86
                .has_arg        = 0,
 
87
                .flag           = NULL,
 
88
        },
 
89
        .opt_help       = NULL,
 
90
        .opt_handler    = version_handler,
 
91
        .opt_op         = NULL,
 
92
        .opt_private = NULL,
 
93
};
 
94
 
 
95
static struct o2info_option coherency_option = {
 
96
        .opt_option     = {
 
97
                .name           = "cluster-coherent",
 
98
                .val            = 'C',
 
99
                .has_arg        = 0,
 
100
                .flag           = NULL,
 
101
        },
 
102
        .opt_help       =
 
103
                "-C|--cluster-coherent",
 
104
        .opt_handler    = coherency_handler,
 
105
        .opt_op         = NULL,
 
106
        .opt_private = NULL,
 
107
};
 
108
 
 
109
static struct o2info_option fs_features_option = {
 
110
        .opt_option     = {
 
111
                .name           = "fs-features",
 
112
                .val            = CHAR_MAX,
 
113
                .has_arg        = 0,
 
114
                .flag           = NULL,
 
115
        },
 
116
        .opt_help       = "   --fs-features",
 
117
        .opt_handler    = NULL,
 
118
        .opt_op         = &fs_features_op,
 
119
        .opt_private    = NULL,
 
120
};
 
121
 
 
122
static struct o2info_option volinfo_option = {
 
123
        .opt_option     = {
 
124
                .name           = "volinfo",
 
125
                .val            = CHAR_MAX,
 
126
                .has_arg        = 0,
 
127
                .flag           = NULL,
 
128
        },
 
129
        .opt_help       = "   --volinfo",
 
130
        .opt_handler    = NULL,
 
131
        .opt_op         = &volinfo_op,
 
132
        .opt_private    = NULL,
 
133
};
 
134
 
 
135
static struct o2info_option mkfs_option = {
 
136
        .opt_option     = {
 
137
                .name           = "mkfs",
 
138
                .val            = CHAR_MAX,
 
139
                .has_arg        = 0,
 
140
                .flag           = NULL,
 
141
        },
 
142
        .opt_help       = "   --mkfs",
 
143
        .opt_handler    = NULL,
 
144
        .opt_op         = &mkfs_op,
 
145
        .opt_private    = NULL,
 
146
};
 
147
 
 
148
static struct o2info_option freeinode_option = {
 
149
        .opt_option     = {
 
150
                .name           = "freeinode",
 
151
                .val            = CHAR_MAX,
 
152
                .has_arg        = 0,
 
153
                .flag           = NULL,
 
154
        },
 
155
        .opt_help       = "   --freeinode",
 
156
        .opt_handler    = NULL,
 
157
        .opt_op         = &freeinode_op,
 
158
        .opt_private    = NULL,
 
159
};
 
160
 
 
161
static struct o2info_option freefrag_option = {
 
162
        .opt_option     = {
 
163
                .name           = "freefrag",
 
164
                .val            = CHAR_MAX,
 
165
                .has_arg        = 1,
 
166
                .flag           = NULL,
 
167
        },
 
168
        .opt_help       = "   --freefrag <chunksize in KB>",
 
169
        .opt_handler    = NULL,
 
170
        .opt_op         = &freefrag_op,
 
171
        .opt_private    = NULL,
 
172
};
 
173
 
 
174
static struct o2info_option space_usage_option = {
 
175
        .opt_option     = {
 
176
                .name           = "space-usage",
 
177
                .val            = CHAR_MAX,
 
178
                .has_arg        = 0,
 
179
                .flag           = NULL,
 
180
        },
 
181
        .opt_help       = "   --space-usage",
 
182
        .opt_handler    = NULL,
 
183
        .opt_op         = &space_usage_op,
 
184
        .opt_private    = NULL,
 
185
};
 
186
 
 
187
static struct o2info_option filestat_option = {
 
188
        .opt_option     = {
 
189
                .name           = "filestat",
 
190
                .val            = CHAR_MAX,
 
191
                .has_arg        = 0,
 
192
                .flag           = NULL,
 
193
        },
 
194
        .opt_help       = "   --filestat",
 
195
        .opt_handler    = NULL,
 
196
        .opt_op         = &filestat_op,
 
197
        .opt_private    = NULL,
 
198
};
 
199
 
 
200
static struct o2info_option *options[] = {
 
201
        &help_option,
 
202
        &version_option,
 
203
        &coherency_option,
 
204
        &fs_features_option,
 
205
        &volinfo_option,
 
206
        &mkfs_option,
 
207
        &freeinode_option,
 
208
        &freefrag_option,
 
209
        &space_usage_option,
 
210
        &filestat_option,
 
211
        NULL,
 
212
};
 
213
 
 
214
void print_usage(int rc)
 
215
{
 
216
        int i;
 
217
        enum tools_verbosity_level level = VL_ERR;
 
218
 
 
219
        if (!rc)
 
220
                level = VL_OUT;
 
221
 
 
222
        verbosef(level, "Usage: %s [options] <device or file>\n",
 
223
                 tools_progname());
 
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");
 
227
 
 
228
        for (i = 0; options[i]; i++) {
 
229
                if (options[i]->opt_help)
 
230
                        verbosef(level, "\t%s\n", options[i]->opt_help);
 
231
        }
 
232
 
 
233
        exit(rc);
 
234
}
 
235
 
 
236
static int build_options(char **optstring, struct option **longopts)
 
237
{
 
238
        errcode_t err;
 
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;
 
245
 
 
246
        unprintable_counter = 1;        /* Start unique at CHAR_MAX + 1*/
 
247
        optstring_len = 1;              /* For the leading ':' */
 
248
        for (i = 0; options[i]; i++) {
 
249
                opt = options[i];
 
250
 
 
251
                /*
 
252
                 * Any option with a val of CHAR_MAX wants an unique but
 
253
                 * unreadable ->val.  Only readable characters go into
 
254
                 * optstring.
 
255
                 */
 
256
                if (opt->opt_option.val == CHAR_MAX) {
 
257
                        opt->opt_option.val =
 
258
                                CHAR_MAX + unprintable_counter;
 
259
                        unprintable_counter++;
 
260
                        continue;
 
261
                }
 
262
 
 
263
                /*
 
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.
 
269
                 */
 
270
                optstring_len += 1 + opt->opt_option.has_arg;
 
271
        }
 
272
 
 
273
        num_opts = i;
 
274
 
 
275
        err = ocfs2_malloc0(sizeof(char) * (optstring_len + 1), &str);
 
276
        if (!err)
 
277
                err = ocfs2_malloc(sizeof(struct option) * (num_opts + 1),
 
278
                                   &lopts);
 
279
        if (err) {
 
280
                rc = -ENOMEM;
 
281
                goto out;
 
282
        }
 
283
 
 
284
        p = str;
 
285
        *p++ = ':';
 
286
        for (i = 0; options[i]; i++) {
 
287
                assert(p < (str + optstring_len + 1));
 
288
                opt = options[i];
 
289
 
 
290
                memcpy(&lopts[i], &opt->opt_option, sizeof(struct option));
 
291
 
 
292
                if (opt->opt_option.val >= CHAR_MAX)
 
293
                        continue;
 
294
 
 
295
                *p = opt->opt_option.val;
 
296
                p++;
 
297
                if (opt->opt_option.has_arg > 0) {
 
298
                        *p = ':';
 
299
                        p++;
 
300
                }
 
301
                if (opt->opt_option.has_arg > 1) {
 
302
                        *p = ':';
 
303
                        p++;
 
304
                }
 
305
        }
 
306
 
 
307
        /*
 
308
         * Fill last entry of options with zeros.
 
309
         */
 
310
        memset(&lopts[i], 0, sizeof(struct option));
 
311
 
 
312
out:
 
313
        if (!rc) {
 
314
                *optstring = str;
 
315
                *longopts = lopts;
 
316
        } else {
 
317
                if (str)
 
318
                        free(str);
 
319
                if (lopts)
 
320
                        free(lopts);
 
321
        }
 
322
 
 
323
        return rc;
 
324
}
 
325
 
 
326
static struct o2info_option *find_option_by_val(int val)
 
327
{
 
328
        int i;
 
329
        struct o2info_option *opt = NULL;
 
330
 
 
331
        for (i = 0; options[i]; i++) {
 
332
                if (options[i]->opt_option.val == val) {
 
333
                        opt = options[i];
 
334
                        break;
 
335
                }
 
336
        }
 
337
 
 
338
        return opt;
 
339
}
 
340
 
 
341
static errcode_t o2info_append_task(struct o2info_operation *o2p)
 
342
{
 
343
        errcode_t err;
 
344
        struct o2info_op_task *task;
 
345
 
 
346
        err = ocfs2_malloc0(sizeof(struct o2info_op_task), &task);
 
347
        if (!err) {
 
348
                task->o2p_task = o2p;
 
349
                list_add_tail(&task->o2p_list, &o2info_op_task_list);
 
350
                o2info_op_task_count++;
 
351
        } else
 
352
                ocfs2_free(&task);
 
353
 
 
354
        return err;
 
355
}
 
356
 
 
357
static void o2info_free_op_task_list(void)
 
358
{
 
359
        struct o2info_op_task *task;
 
360
        struct list_head *pos, *next;
 
361
 
 
362
        if (list_empty(&o2info_op_task_list))
 
363
                return;
 
364
 
 
365
        list_for_each_safe(pos, next, &o2info_op_task_list) {
 
366
                task = list_entry(pos, struct o2info_op_task, o2p_list);
 
367
                list_del(pos);
 
368
                ocfs2_free(&task);
 
369
        }
 
370
}
 
371
 
 
372
extern int optind, opterr, optopt;
 
373
extern char *optarg;
 
374
static errcode_t parse_options(int argc, char *argv[], char **device_or_file)
 
375
{
 
376
        int c, lopt_idx = 0;
 
377
        errcode_t err;
 
378
        struct option *long_options = NULL;
 
379
        char error[PATH_MAX];
 
380
        char *optstring = NULL;
 
381
        struct o2info_option *opt;
 
382
 
 
383
        err = build_options(&optstring, &long_options);
 
384
        if (err)
 
385
                goto out;
 
386
 
 
387
        opterr = 0;
 
388
        error[0] = '\0';
 
389
        while ((c = getopt_long(argc, argv, optstring,
 
390
                                long_options, &lopt_idx)) != EOF) {
 
391
                opt = NULL;
 
392
                switch (c) {
 
393
                case '?':
 
394
                        if (optopt)
 
395
                                errorf("Invalid option: '-%c'\n", optopt);
 
396
                        else
 
397
                                errorf("Invalid option: '%s'\n",
 
398
                                       argv[optind - 1]);
 
399
                        print_usage(1);
 
400
                        break;
 
401
 
 
402
                case ':':
 
403
                        if (optopt < CHAR_MAX)
 
404
                                errorf("Option '-%c' requires an argument\n",
 
405
                                       optopt);
 
406
                        else
 
407
                                errorf("Option '%s' requires an argument\n",
 
408
                                       argv[optind - 1]);
 
409
                        print_usage(1);
 
410
                        break;
 
411
 
 
412
                default:
 
413
                        opt = find_option_by_val(c);
 
414
                        if (!opt) {
 
415
                                errorf("Shouldn't have gotten here: "
 
416
                                       "option '-%c'\n", c);
 
417
                                print_usage(1);
 
418
                        }
 
419
 
 
420
                        if (optarg)
 
421
                                opt->opt_private = (void *)optarg;
 
422
 
 
423
                        break;
 
424
                }
 
425
 
 
426
                if (opt->opt_set) {
 
427
                        errorf("Option '-%c' specified more than once\n",
 
428
                               c);
 
429
                        print_usage(1);
 
430
                }
 
431
 
 
432
                opt->opt_set = 1;
 
433
                /*
 
434
                 * Handlers for simple options such as showing version,
 
435
                 * printing the usage, or specify the coherency etc.
 
436
                 */
 
437
                if (opt->opt_handler) {
 
438
                        if (opt->opt_handler(opt, optarg))
 
439
                                print_usage(1);
 
440
                }
 
441
 
 
442
                /*
 
443
                 * Real operation will be added to a list to run later.
 
444
                 */
 
445
                if (opt->opt_op) {
 
446
                        opt->opt_op->to_private = opt->opt_private;
 
447
                        err = o2info_append_task(opt->opt_op);
 
448
                        if (err)
 
449
                                goto out;
 
450
                }
 
451
        }
 
452
 
 
453
        if (optind == 1)
 
454
                print_usage(1);
 
455
 
 
456
        if (optind >= argc) {
 
457
                errorf("No device or file specified\n");
 
458
                print_usage(1);
 
459
        }
 
460
 
 
461
        *device_or_file = strdup(argv[optind]);
 
462
        if (!*device_or_file) {
 
463
                errorf("No memory for allocation\n");
 
464
                goto out;
 
465
        }
 
466
 
 
467
        optind++;
 
468
 
 
469
        if (optind < argc) {
 
470
                errorf("Too many arguments\n");
 
471
                print_usage(1);
 
472
        }
 
473
 
 
474
out:
 
475
        if (optstring)
 
476
                ocfs2_free(&optstring);
 
477
 
 
478
        if (long_options)
 
479
                ocfs2_free(&long_options);
 
480
 
 
481
        return err;
 
482
}
 
483
 
 
484
static errcode_t o2info_run_task(struct o2info_method *om)
 
485
{
 
486
        struct list_head *p, *n;
 
487
        struct o2info_op_task *task;
 
488
 
 
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);
 
493
        }
 
494
 
 
495
        return 0;
 
496
}
 
497
 
 
498
static void handle_signal(int caught_sig)
 
499
{
 
500
        int exitp = 0, abortp = 0;
 
501
        static int segv_already;
 
502
 
 
503
        switch (caught_sig) {
 
504
        case SIGQUIT:
 
505
                abortp = 1;
 
506
                /* FALL THROUGH */
 
507
 
 
508
        case SIGTERM:
 
509
        case SIGINT:
 
510
        case SIGHUP:
 
511
                errorf("Caught signal %d, exiting\n", caught_sig);
 
512
                exitp = 1;
 
513
                break;
 
514
 
 
515
        case SIGSEGV:
 
516
                errorf("Segmentation fault, exiting\n");
 
517
                exitp = 1;
 
518
                if (segv_already) {
 
519
                        errorf("Segmentation fault loop detected\n");
 
520
                        abortp = 1;
 
521
                } else
 
522
                        segv_already = 1;
 
523
                break;
 
524
 
 
525
        default:
 
526
                errorf("Caught signal %d, ignoring\n", caught_sig);
 
527
                break;
 
528
        }
 
529
 
 
530
        if (!exitp)
 
531
                return;
 
532
 
 
533
        if (abortp)
 
534
                abort();
 
535
 
 
536
        exit(1);
 
537
}
 
538
 
 
539
static int setup_signals(void)
 
540
{
 
541
        int rc = 0;
 
542
        struct sigaction act;
 
543
 
 
544
        act.sa_sigaction = NULL;
 
545
        sigemptyset(&act.sa_mask);
 
546
        act.sa_handler = handle_signal;
 
547
#ifdef SA_INTERRUPT
 
548
        act.sa_flags = SA_INTERRUPT;
 
549
#endif
 
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 */
 
557
 
 
558
        return rc;
 
559
}
 
560
 
 
561
static void o2info_init(const char *argv0)
 
562
{
 
563
        initialize_ocfs_error_table();
 
564
 
 
565
        tools_setup_argv0(argv0);
 
566
 
 
567
        setbuf(stdout, NULL);
 
568
        setbuf(stderr, NULL);
 
569
 
 
570
        if (setup_signals()) {
 
571
                errorf("Unable to setup signal handling \n");
 
572
                exit(1);
 
573
        }
 
574
 
 
575
        cluster_coherent = 0;
 
576
}
 
577
 
 
578
int main(int argc, char *argv[])
 
579
{
 
580
        int rc = 0;
 
581
 
 
582
        char *device_or_file = NULL;
 
583
        static struct o2info_method om;
 
584
 
 
585
        o2info_init(argv[0]);
 
586
        parse_options(argc, argv, &device_or_file);
 
587
 
 
588
        rc = o2info_method(device_or_file);
 
589
        if (rc < 0)
 
590
                goto out;
 
591
        else
 
592
                om.om_method = rc;
 
593
 
 
594
        strncpy(om.om_path, device_or_file, PATH_MAX);
 
595
 
 
596
        rc = o2info_open(&om, 0);
 
597
        if (rc)
 
598
                goto out;
 
599
 
 
600
        rc = o2info_run_task(&om);
 
601
        if (rc)
 
602
                goto out;
 
603
 
 
604
        o2info_free_op_task_list();
 
605
 
 
606
        rc = o2info_close(&om);
 
607
out:
 
608
        if (device_or_file)
 
609
                ocfs2_free(&device_or_file);
 
610
 
 
611
        return rc;
 
612
}