1
/* -*- mode: c; c-basic-offset: 8; -*-
2
* vim: noexpandtab sw=8 ts=8 sts=0:
8
* Copyright (C) 2004, 2008 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 _GNU_SOURCE /* for getopt_long and O_DIRECT */
28
#include "ocfs2/ocfs2.h"
30
#include "libocfs2ne.h"
34
* Why do we have a list of option structures will callbacks instead of
35
* a simple switch() statement? Because the ocfs2ne option set has grown
36
* over time, and there are a few operations that can be triggered by
37
* more than one option. For example, -M {cluster|local} is really just
38
* clearing or setting the fs feature 'local'.
40
* For most argument-free operations, they'll just specify their name and
41
* val. Options with arguments will mostly use generic_handle_arg() as
42
* their ->opt_handle().
44
* If you are adding a new feature flag, do not add an option here. It
45
* should be handled by --fs-features. Just write a tunefs_feature in
46
* ocfs2ne_feature_<name>.c and add it to the list ocfs2ne_features.c.
47
* If you are adding an operation, make its option something that stands on
48
* its own and can use generic_handle_arg() if it needs an argument.
50
struct tunefs_option {
51
struct option opt_option; /* For getopt_long(). If
55
value will be inserted
57
struct tunefs_operation *opt_op; /* Operation associated
58
with this option. This
59
needs to be set if the
65
be added to the run_list
68
char *opt_help; /* Help string */
69
int opt_set; /* Was this option seen */
70
int (*opt_handle)(struct tunefs_option *opt, char *arg);
75
* ocfs2ne lumps all journal options as name[=value] arguments underneath
76
* '-J'. They end up being tunefs_operations, and we link them up here.
78
struct tunefs_journal_option {
81
struct tunefs_operation *jo_op;
86
struct list_head tr_list;
87
struct tunefs_operation *tr_op;
91
extern struct tunefs_operation list_sparse_op;
92
extern struct tunefs_operation query_op;
93
extern struct tunefs_operation reset_uuid_op;
94
extern struct tunefs_operation features_op;
95
extern struct tunefs_operation resize_volume_op;
96
extern struct tunefs_operation set_journal_size_op;
97
extern struct tunefs_operation set_label_op;
98
extern struct tunefs_operation set_slot_count_op;
99
extern struct tunefs_operation update_cluster_stack_op;
100
extern struct tunefs_operation cloned_volume_op;
102
/* List of operations we're going to run */
103
static LIST_HEAD(tunefs_run_list);
105
/* Number of operations we're going to run */
106
static int tunefs_op_count;
107
/* Progress display for tunefs operations */
108
static struct tools_progress *tunefs_op_progress;
110
static struct tunefs_journal_option set_journal_size_option = {
112
.jo_help = "size=<journal-size>",
113
.jo_op = &set_journal_size_op,
116
/* The list of all supported journal options */
117
static struct tunefs_journal_option *tunefs_journal_options[] = {
118
&set_journal_size_option,
124
* Operations are intended to run in the order we see them in the
125
* command-line arguments. As each option is seen, the operation is
126
* added with tunefs_append_operation().
128
* There are two exceptions. First, special-cased options (pretty much
129
* the feature) will end up at the end because we can't process them
130
* until we've seen all command-line arguments.
132
* Second, resize is the only user of tunefs_prepend_operation(). We want
133
* to grow the filesystem *before* we do anything that might require space!
135
static errcode_t tunefs_append_operation(struct tunefs_operation *op)
138
struct tunefs_run *run;
140
err = ocfs2_malloc0(sizeof(struct tunefs_run), &run);
143
list_add_tail(&run->tr_list, &tunefs_run_list);
150
static errcode_t tunefs_prepend_operation(struct tunefs_operation *op)
153
struct tunefs_run *run;
155
err = ocfs2_malloc0(sizeof(struct tunefs_run), &run);
158
list_add(&run->tr_list, &tunefs_run_list);
166
static void print_usage(int rc);
167
static int handle_help(struct tunefs_option *opt, char *arg)
173
static int handle_version(struct tunefs_option *opt, char *arg)
180
static int handle_verbosity(struct tunefs_option *opt, char *arg)
184
switch (opt->opt_option.val)
195
errorf("Invalid option to handle_verbosity: %c\n",
196
opt->opt_option.val);
201
/* More than one -v or -q is valid */
206
static int handle_interactive(struct tunefs_option *opt, char *arg)
212
static int handle_progress(struct tunefs_option *opt, char *arg)
214
tools_progress_enable();
218
static int handle_answer(struct tunefs_option *opt, char *arg)
222
switch (opt->opt_option.val)
225
tools_interactive_yes();
229
tools_interactive_no();
233
errorf("Invalid option to handle_answer: %c\n",
234
opt->opt_option.val);
243
* Plain operations just want to have their ->to_parse_option() called.
244
* Their tunefs_option can use this function if they set opt_op to the
247
static int generic_handle_arg(struct tunefs_option *opt, char *arg)
249
struct tunefs_operation *op = opt->opt_op;
251
if (!op->to_parse_option) {
252
errorf("Option \"%s\" claims it has an argument, but "
253
"operation \"%s\" isn't expecting one\n",
254
opt->opt_option.name, op->to_name);
258
return op->to_parse_option(op, arg);
262
* Store a copy of the argument on opt_private.
264
* For example, the multiple options setting fs_features want to save off
265
* their feature string. They use this function directly or indirectly.
267
static int strdup_handle_arg(struct tunefs_option *opt, char *arg)
274
errorf("Unable to allocate memory while processing "
280
opt->opt_private = ptr;
284
static int mount_type_handle_arg(struct tunefs_option *opt, char *arg)
289
errorf("No mount type specified\n");
291
} else if (!strcmp(arg, "local"))
292
rc = strdup_handle_arg(opt, "local");
293
else if (!strcmp(arg, "cluster"))
294
rc = strdup_handle_arg(opt, "nolocal");
296
errorf("Invalid mount type: \"%s\"\n", arg);
303
static int backup_super_handle_arg(struct tunefs_option *opt, char *arg)
305
return strdup_handle_arg(opt, "backup-super");
308
static struct tunefs_journal_option *find_journal_option(char *name)
311
struct tunefs_journal_option *jopt;
313
for (i = 0; tunefs_journal_options[i]; i++) {
314
jopt = tunefs_journal_options[i];
315
if (!strcmp(name, jopt->jo_name))
322
/* derived from e2fsprogs */
323
static int handle_journal_arg(struct tunefs_option *opt, char *arg)
327
char *options, *token, *next, *p, *val;
328
int journal_usage = 0;
329
struct tunefs_journal_option *jopt;
332
options = strdup(arg);
334
tcom_err(TUNEFS_ET_NO_MEMORY,
335
"while processing journal options");
341
for (token = options; token && *token; token = next) {
342
p = strchr(token, ',');
350
val = strchr(token, '=');
357
jopt = find_journal_option(token);
359
errorf("Unknown journal option: \"%s\"\n", token);
364
if (jopt->jo_op->to_parse_option) {
365
if (jopt->jo_op->to_parse_option(jopt->jo_op, val)) {
370
errorf("Journal option \"%s\" does not accept "
377
err = tunefs_append_operation(jopt->jo_op);
379
tcom_err(err, "while processing journal options");
386
verbosef(VL_ERR, "Valid journal options are:\n");
387
for (i = 0; tunefs_journal_options[i]; i++)
388
verbosef(VL_ERR, "\t%s\n",
389
tunefs_journal_options[i]->jo_help);
397
static struct tunefs_option help_option = {
402
.opt_handle = handle_help,
405
static struct tunefs_option version_option = {
410
.opt_handle = handle_version,
413
static struct tunefs_option verbose_option = {
419
"-v|--verbose (increases verbosity; more than one permitted)",
420
.opt_handle = handle_verbosity,
423
static struct tunefs_option quiet_option = {
429
"-q|--quiet (decreases verbosity; more than one permitted)",
430
.opt_handle = handle_verbosity,
433
static struct tunefs_option interactive_option = {
435
.name = "interactive",
438
.opt_help = "-i|--interactive",
439
.opt_handle = handle_interactive,
442
static struct tunefs_option progress_option = {
447
.opt_help = "-p|--progress",
448
.opt_handle = handle_progress,
451
static struct tunefs_option yes_option = {
456
.opt_help = "-y|--yes",
457
.opt_handle = handle_answer,
460
static struct tunefs_option no_option = {
465
.opt_help = "-n|--no",
466
.opt_handle = handle_answer,
469
static struct tunefs_option query_option = {
475
.opt_help = "-Q|--query <query-format>",
476
.opt_handle = &generic_handle_arg,
480
static struct tunefs_option list_sparse_option = {
482
.name = "list-sparse",
485
.opt_help = " --list-sparse",
486
.opt_op = &list_sparse_op,
489
static struct tunefs_option reset_uuid_option = {
491
.name = "uuid-reset",
494
.opt_help = "-U|--uuid-reset",
495
.opt_op = &reset_uuid_op,
498
static struct tunefs_option update_cluster_stack_option = {
500
.name = "update-cluster-stack",
503
.opt_help = " --update-cluster-stack",
504
.opt_op = &update_cluster_stack_op,
507
static struct tunefs_option cloned_volume_option = {
509
.name = "cloned-volume",
513
.opt_help = " --cloned-volume[=new-label]",
514
.opt_op = &cloned_volume_op,
517
static struct tunefs_option set_slot_count_option = {
519
.name = "node-slots",
523
.opt_help = "-N|--node-slots <number-of-node-slots>",
524
.opt_handle = generic_handle_arg,
525
.opt_op = &set_slot_count_op,
528
static struct tunefs_option set_label_option = {
534
.opt_help = "-L|--label <label>",
535
.opt_handle = generic_handle_arg,
536
.opt_op = &set_label_op,
539
static struct tunefs_option mount_type_option = {
545
.opt_handle = mount_type_handle_arg,
548
static struct tunefs_option backup_super_option = {
550
.name = "backup-super",
553
.opt_handle = backup_super_handle_arg,
556
static struct tunefs_option features_option = {
558
.name = "fs-features",
562
.opt_help = " --fs-features [no]sparse,...",
563
.opt_handle = strdup_handle_arg,
566
static struct tunefs_option resize_volume_option = {
568
.name = "volume-size",
572
.opt_help = "-S|--volume-size",
573
.opt_handle = strdup_handle_arg,
576
static struct tunefs_option journal_option = {
578
.name = "journal-options",
582
.opt_help = "-J|--journal-options <options>",
583
.opt_handle = handle_journal_arg,
586
/* The order here creates the order in print_usage() */
587
static struct tunefs_option *options[] = {
595
&set_slot_count_option,
596
&resize_volume_option,
602
&backup_super_option,
604
&update_cluster_stack_option,
605
&cloned_volume_option,
612
* The options listed here all end up setting or clearing filesystem
613
* features. These options must also live in the master options array.
614
* When the are processed in parse_options(), they should attach the
615
* relevant feature string to opt_private. The feature strings will be
616
* processed at the end of parse_options().
618
static struct tunefs_option *feature_options[] = {
620
&backup_super_option,
625
static struct tunefs_option *find_option_by_val(int val)
628
struct tunefs_option *opt = NULL;
630
for (i = 0; options[i]; i++) {
631
if (options[i]->opt_option.val == val) {
640
static void print_usage(int rc)
643
enum tools_verbosity_level level = VL_ERR;
648
verbosef(level, "Usage: %s [options] <device> [new-size]\n",
650
verbosef(level, " %s -h|--help\n", tools_progname());
651
verbosef(level, " %s -V|--version\n", tools_progname());
652
verbosef(level, "[options] can be any mix of:\n");
653
for (i = 0; options[i]; i++) {
654
if (options[i]->opt_help)
655
verbosef(level, "\t%s\n", options[i]->opt_help);
658
"[new-size] is only valid with the '-S' option\n"
659
"All sizes can be specified with K/M/G/T/P suffixes\n");
663
static errcode_t parse_feature_strings(void)
666
char *tmp, *features = NULL;
667
struct tunefs_option *opt;
668
size_t len, new_features_len, features_len = 0;
670
for (i = 0; feature_options[i]; i++) {
671
opt = feature_options[i];
674
if (!opt->opt_private)
677
len = strlen(opt->opt_private);
678
new_features_len = features_len + len;
680
new_features_len++; /* A comma to separate */
681
tmp = realloc(features, new_features_len + 1);
683
errorf("Unable to allocate memory while processing "
688
tmp = features + features_len;
693
strcpy(tmp, opt->opt_private);
694
features_len = new_features_len;
700
verbosef(VL_DEBUG, "Full feature string is \"%s\"\n", features);
701
rc = features_op.to_parse_option(&features_op, features);
706
return tunefs_append_operation(&features_op);
710
* We do resize_volume checks in this special-case function because the
711
* new size is separated from the option flag due to historical reasons.
713
* If resize_volume_option.opt_set, we may or may not have arg. A NULL
714
* arg is means "fill up the LUN". If !opt_set, arg must be NULL.
716
static errcode_t parse_resize(const char *arg)
718
char operation_arg[NAME_MAX]; /* Should be big enough :-) */
720
if (!resize_volume_option.opt_set) {
722
errorf("Too many arguments\n");
726
return 0; /* no resize options */
733
* We've stored any argument to -S on opt_private. If there
734
* was no argument to -S, our new size is in blocks due to
735
* historical reasons.
737
* We don't have an open filesystem at this point, so we
738
* can't convert clusters<->blocks<->bytes. So let's just tell
739
* the resize operation what unit we're talking.
741
if (snprintf(operation_arg, NAME_MAX, "%s:%s",
742
resize_volume_option.opt_private ?
743
(char *)resize_volume_option.opt_private : "blocks",
745
errorf("Argument to option '--%s' is too long: %s\n",
746
resize_volume_option.opt_option.name, arg);
751
if (resize_volume_op.to_parse_option(&resize_volume_op,
752
arg ? operation_arg : NULL))
756
* We _prepend_ resize, because we want any other operations to
757
* have all the space they need.
759
return tunefs_prepend_operation(&resize_volume_op);
762
static int build_options(char **optstring, struct option **longopts)
765
int i, num_opts, rc = 0;
766
int unprintable_counter;
767
size_t optstring_len;
768
char *p, *str = NULL;
769
struct option *lopts = NULL;
770
struct tunefs_option *opt;
772
unprintable_counter = 1; /* Start unique at CHAR_MAX + 1*/
773
optstring_len = 1; /* For the leading ':' */
774
for (i = 0; options[i]; i++) {
778
* Any option with a val of CHAR_MAX wants an unique but
779
* unreadable ->val. Only readable characters go into
782
if (opt->opt_option.val == CHAR_MAX) {
783
opt->opt_option.val =
784
CHAR_MAX + unprintable_counter;
785
unprintable_counter++;
790
* A given option has a single character in optstring.
791
* If it takes a mandatory argument, has_arg==1 and you add
792
* a ":" to optstring. If it takes an optional argument,
793
* has_arg==2 and you add "::" to optstring. Thus,
794
* 1 + has_arg is the total space needed in opstring.
796
optstring_len += 1 + opt->opt_option.has_arg;
800
err = ocfs2_malloc0(sizeof(char) * (optstring_len + 1), &str);
802
err = ocfs2_malloc(sizeof(struct option) * (num_opts + 1),
812
for (i = 0; options[i]; i++) {
813
assert(p < (str + optstring_len + 1));
816
memcpy(&lopts[i], &opt->opt_option, sizeof(struct option));
818
if (opt->opt_option.val >= CHAR_MAX)
821
*p = opt->opt_option.val;
823
if (opt->opt_option.has_arg > 0) {
827
if (opt->opt_option.has_arg > 1) {
848
extern int optind, opterr, optopt;
850
static errcode_t parse_options(int argc, char *argv[], char **device)
854
struct option *long_options = NULL;
855
char error[PATH_MAX];
856
char *optstring = NULL;
857
struct tunefs_option *opt;
859
err = build_options(&optstring, &long_options);
865
while ((c = getopt_long(argc, argv, optstring,
866
long_options, NULL)) != EOF) {
871
errorf("Invalid option: '-%c'\n",
874
errorf("Invalid option: '%s'\n",
880
if (optopt < CHAR_MAX)
881
errorf("Option '-%c' requires "
885
errorf("Option '%s' requires "
892
opt = find_option_by_val(c);
894
errorf("Shouldn't have gotten "
895
"here: option '-%c'\n",
903
errorf("Option '-%c' specified more than once\n",
909
if (opt->opt_handle) {
910
if (opt->opt_handle(opt, optarg))
914
err = tunefs_append_operation(opt->opt_op);
918
err = parse_feature_strings();
922
if (optind >= argc) {
923
errorf("No device specified\n");
927
*device = strdup(argv[optind]);
929
err = TUNEFS_ET_NO_MEMORY;
934
/* parse_resize() will check if we expected a size */
936
err = parse_resize(argv[optind]);
939
err = parse_resize(NULL);
944
errorf("Too many arguments\n");
954
* This goes through tunefs_run_list and runs each operation in turn.
955
* Once an operation has completed, it is removed from the list. If filter
956
* is non-zero, only operations that match filter are run this pass.
958
static int run_operation_filter(ocfs2_filesys *fs, int filter)
961
struct list_head *pos, *n;
962
struct tunefs_run *run;
963
struct tunefs_operation *op;
965
list_for_each_safe(pos, n, &tunefs_run_list) {
966
run = list_entry(pos, struct tunefs_run, tr_list);
969
if (filter && !(op->to_open_flags & filter))
972
list_del(&run->tr_list);
975
err = tunefs_op_run(fs, op);
977
if (err != TUNEFS_ET_OPERATION_FAILED) {
979
"while trying to perform "
985
tools_progress_step(tunefs_op_progress, 1);
991
static int run_operations(const char *device)
994
errcode_t tmp, err = 0;
996
struct tunefs_run *run;
1002
* We have a specific order here. If we open the filesystem and
1003
* get TUNEFS_ET_CLUSTER_SKIPPED, we know that cloned_volume is
1004
* involved. We want to run that first and change our volume's
1005
* UUID+label, then close and reopen the filesystem. We should be
1006
* able to continue with any other operations.
1008
* Next, if we open the filesystem and * get
1009
* TUNEFS_ET_INVALID_STACK_NAME, we know that update_cluster_stack
1010
* is involved. We want to run that, and again close and reopen
1011
* the filesystem. This should allow us to continue with any
1014
* Next, if we get TUNEFS_ET_PERFORM_ONLINE, we have at least
1015
* one operation capable of working online. We want to run through
1016
* the online capable ops before failing anything that cannot be
1017
* done online. Basically, do as much as we can.
1019
* Last, anything else is run. This is the normal state if we have
1020
* a correctly configured cluster and have locked down the
1021
* filesystem. It runs in the order we added things to
1024
while (!err && !list_empty(&tunefs_run_list)) {
1027
list_for_each(p, &tunefs_run_list) {
1028
run = list_entry(p, struct tunefs_run, tr_list);
1029
open_flags |= run->tr_op->to_open_flags;
1032
err = tunefs_open(device, open_flags, &fs);
1033
if (err == TUNEFS_ET_CLUSTER_SKIPPED)
1034
rc = run_operation_filter(fs, TUNEFS_FLAG_SKIPCLUSTER);
1035
else if (err == TUNEFS_ET_INVALID_STACK_NAME)
1036
rc = run_operation_filter(fs, TUNEFS_FLAG_NOCLUSTER);
1037
else if (err == TUNEFS_ET_PERFORM_ONLINE)
1038
rc = run_operation_filter(fs, TUNEFS_FLAG_ONLINE);
1040
rc = run_operation_filter(fs, 0);
1042
tcom_err(err, "while opening device \"%s\"",
1049
err = TUNEFS_ET_OPERATION_FAILED;
1051
tmp = tunefs_close(fs);
1053
tcom_err(tmp, "while closing device \"%s\"",
1062
int main(int argc, char *argv[])
1068
tunefs_init(argv[0]);
1070
err = parse_options(argc, argv, &device);
1072
tcom_err(err, "while parsing options");
1076
tunefs_op_progress = tools_progress_start("tunefs.ocfs2",
1079
if (!tunefs_op_progress) {
1080
tcom_err(TUNEFS_ET_NO_MEMORY,
1081
"while initializing the progress display");
1085
rc = run_operations(device);
1087
tools_progress_stop(tunefs_op_progress);