~wb-munzinger/+junk/ocfs2-tools

« back to all changes in this revision

Viewing changes to tunefs.ocfs2/ocfs2ne.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2009-07-06 07:26:30 UTC
  • mfrom: (1.1.7 upstream) (0.1.5 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090706072630-59335sl51k3rvu74
Tags: 1.4.2-1
* New upstream release (Closes: #535471).
* Drop patch for limits.h, included 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
 * ocfs2ne.c
 
5
 *
 
6
 * ocfs2 tune utility.
 
7
 *
 
8
 * Copyright (C) 2004, 2008 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 _GNU_SOURCE /* for getopt_long and O_DIRECT */
 
21
#include <stdio.h>
 
22
#include <string.h>
 
23
#include <inttypes.h>
 
24
#include <getopt.h>
 
25
#include <assert.h>
 
26
#include <errno.h>
 
27
 
 
28
#include "ocfs2/ocfs2.h"
 
29
 
 
30
#include "libocfs2ne.h"
 
31
 
 
32
 
 
33
/*
 
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'.
 
39
 *
 
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().
 
43
 *
 
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.
 
49
 */
 
50
struct tunefs_option {
 
51
        struct option   opt_option;             /* For getopt_long().  If
 
52
                                                   there is no short
 
53
                                                   option, set .val to
 
54
                                                   CHAR_MAX.  A unique
 
55
                                                   value will be inserted
 
56
                                                   by the code. */
 
57
        struct tunefs_operation *opt_op;        /* Operation associated
 
58
                                                   with this option.  This
 
59
                                                   needs to be set if the
 
60
                                                   option has no
 
61
                                                   ->opt_handle() or is
 
62
                                                   using
 
63
                                                   generic_handle_arg().
 
64
                                                   If set, opt_op will
 
65
                                                   be added to the run_list
 
66
                                                   when this option is
 
67
                                                   seen. */
 
68
        char            *opt_help;      /* Help string */
 
69
        int             opt_set;        /* Was this option seen */
 
70
        int             (*opt_handle)(struct tunefs_option *opt, char *arg);
 
71
        void            *opt_private;
 
72
};
 
73
 
 
74
/*
 
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.
 
77
 */
 
78
struct tunefs_journal_option {
 
79
        char                    *jo_name;
 
80
        char                    *jo_help;
 
81
        struct tunefs_operation *jo_op;
 
82
};
 
83
 
 
84
/* Things to run */
 
85
struct tunefs_run {
 
86
        struct list_head        tr_list;
 
87
        struct tunefs_operation *tr_op;
 
88
};
 
89
 
 
90
 
 
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;
 
101
 
 
102
/* List of operations we're going to run */
 
103
static LIST_HEAD(tunefs_run_list);
 
104
 
 
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;
 
109
 
 
110
static struct tunefs_journal_option set_journal_size_option = {
 
111
        .jo_name        = "size",
 
112
        .jo_help        = "size=<journal-size>",
 
113
        .jo_op          = &set_journal_size_op,
 
114
};
 
115
 
 
116
/* The list of all supported journal options */
 
117
static struct tunefs_journal_option *tunefs_journal_options[] = {
 
118
        &set_journal_size_option,
 
119
        NULL,
 
120
};
 
121
 
 
122
 
 
123
/*
 
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().
 
127
 *
 
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.
 
131
 *
 
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!
 
134
 */
 
135
static errcode_t tunefs_append_operation(struct tunefs_operation *op)
 
136
{
 
137
        errcode_t err;
 
138
        struct tunefs_run *run;
 
139
 
 
140
        err = ocfs2_malloc0(sizeof(struct tunefs_run), &run);
 
141
        if (!err) {
 
142
                run->tr_op = op;
 
143
                list_add_tail(&run->tr_list, &tunefs_run_list);
 
144
                tunefs_op_count++;
 
145
        }
 
146
 
 
147
        return err;
 
148
}
 
149
 
 
150
static errcode_t tunefs_prepend_operation(struct tunefs_operation *op)
 
151
{
 
152
        errcode_t err;
 
153
        struct tunefs_run *run;
 
154
 
 
155
        err = ocfs2_malloc0(sizeof(struct tunefs_run), &run);
 
156
        if (!err) {
 
157
                run->tr_op = op;
 
158
                list_add(&run->tr_list, &tunefs_run_list);
 
159
                tunefs_op_count++;
 
160
        }
 
161
 
 
162
        return err;
 
163
}
 
164
 
 
165
 
 
166
static void print_usage(int rc);
 
167
static int handle_help(struct tunefs_option *opt, char *arg)
 
168
{
 
169
        print_usage(0);
 
170
        return 1;
 
171
}
 
172
 
 
173
static int handle_version(struct tunefs_option *opt, char *arg)
 
174
{
 
175
        tools_version();
 
176
        exit(0);
 
177
        return 1;
 
178
}
 
179
 
 
180
static int handle_verbosity(struct tunefs_option *opt, char *arg)
 
181
{
 
182
        int rc = 0;
 
183
 
 
184
        switch (opt->opt_option.val)
 
185
        {
 
186
                case 'v':
 
187
                        tools_verbose();
 
188
                        break;
 
189
 
 
190
                case 'q':
 
191
                        tools_quiet();
 
192
                        break;
 
193
 
 
194
                default:
 
195
                        errorf("Invalid option to handle_verbosity: %c\n",
 
196
                               opt->opt_option.val);
 
197
                        rc = 1;
 
198
                        break;
 
199
        }
 
200
 
 
201
        /* More than one -v or -q is valid */
 
202
        opt->opt_set = 0;
 
203
        return rc;
 
204
}
 
205
 
 
206
static int handle_interactive(struct tunefs_option *opt, char *arg)
 
207
{
 
208
        tools_interactive();
 
209
        return 0;
 
210
}
 
211
 
 
212
static int handle_progress(struct tunefs_option *opt, char *arg)
 
213
{
 
214
        tools_progress_enable();
 
215
        return 0;
 
216
}
 
217
 
 
218
static int handle_answer(struct tunefs_option *opt, char *arg)
 
219
{
 
220
        int rc = 0;
 
221
 
 
222
        switch (opt->opt_option.val)
 
223
        {
 
224
                case 'y':
 
225
                        tools_interactive_yes();
 
226
                        break;
 
227
 
 
228
                case 'n':
 
229
                        tools_interactive_no();
 
230
                        break;
 
231
 
 
232
                default:
 
233
                        errorf("Invalid option to handle_answer: %c\n",
 
234
                               opt->opt_option.val);
 
235
                        rc = 1;
 
236
                        break;
 
237
        }
 
238
 
 
239
        return rc;
 
240
}
 
241
 
 
242
/*
 
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
 
245
 * tunefs_operation.
 
246
 */
 
247
static int generic_handle_arg(struct tunefs_option *opt, char *arg)
 
248
{
 
249
        struct tunefs_operation *op = opt->opt_op;
 
250
 
 
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);
 
255
                return 1;
 
256
        }
 
257
 
 
258
        return op->to_parse_option(op, arg);
 
259
}
 
260
 
 
261
/*
 
262
 * Store a copy of the argument on opt_private.
 
263
 *
 
264
 * For example, the multiple options setting fs_features want to save off
 
265
 * their feature string.  They use this function directly or indirectly.
 
266
 */
 
267
static int strdup_handle_arg(struct tunefs_option *opt, char *arg)
 
268
{
 
269
        char *ptr = NULL;
 
270
 
 
271
        if (arg) {
 
272
                ptr = strdup(arg);
 
273
                if (!ptr) {
 
274
                        errorf("Unable to allocate memory while processing "
 
275
                               "options\n");
 
276
                        return 1;
 
277
                }
 
278
        }
 
279
 
 
280
        opt->opt_private = ptr;
 
281
        return 0;
 
282
}
 
283
 
 
284
static int mount_type_handle_arg(struct tunefs_option *opt, char *arg)
 
285
{
 
286
        int rc = 0;
 
287
 
 
288
        if (!arg) {
 
289
                errorf("No mount type specified\n");
 
290
                rc = 1;
 
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");
 
295
        else {
 
296
                errorf("Invalid mount type: \"%s\"\n", arg);
 
297
                rc = 1;
 
298
        }
 
299
 
 
300
        return rc;
 
301
}
 
302
 
 
303
static int backup_super_handle_arg(struct tunefs_option *opt, char *arg)
 
304
{
 
305
        return strdup_handle_arg(opt, "backup-super");
 
306
}
 
307
 
 
308
static struct tunefs_journal_option *find_journal_option(char *name)
 
309
{
 
310
        int i;
 
311
        struct tunefs_journal_option *jopt;
 
312
 
 
313
        for (i = 0; tunefs_journal_options[i]; i++) {
 
314
                jopt = tunefs_journal_options[i];
 
315
                if (!strcmp(name, jopt->jo_name))
 
316
                        return jopt;
 
317
        }
 
318
 
 
319
        return NULL;
 
320
}
 
321
 
 
322
/* derived from e2fsprogs */
 
323
static int handle_journal_arg(struct tunefs_option *opt, char *arg)
 
324
{
 
325
        errcode_t err;
 
326
        int i, rc = 0;
 
327
        char *options, *token, *next, *p, *val;
 
328
        int journal_usage = 0;
 
329
        struct tunefs_journal_option *jopt;
 
330
 
 
331
        if (arg) {
 
332
                options = strdup(arg);
 
333
                if (!options) {
 
334
                        tcom_err(TUNEFS_ET_NO_MEMORY,
 
335
                                 "while processing journal options");
 
336
                        return 1;
 
337
                }
 
338
        } else
 
339
                options = NULL;
 
340
 
 
341
        for (token = options; token && *token; token = next) {
 
342
                p = strchr(token, ',');
 
343
                next = NULL;
 
344
 
 
345
                if (p) {
 
346
                        *p = '\0';
 
347
                        next = p + 1;
 
348
                }
 
349
 
 
350
                val = strchr(token, '=');
 
351
 
 
352
                if (val) {
 
353
                        *val = '\0';
 
354
                        val++;
 
355
                }
 
356
 
 
357
                jopt = find_journal_option(token);
 
358
                if (!jopt) {
 
359
                        errorf("Unknown journal option: \"%s\"\n", token);
 
360
                        journal_usage++;
 
361
                        continue;
 
362
                }
 
363
 
 
364
                if (jopt->jo_op->to_parse_option) {
 
365
                        if (jopt->jo_op->to_parse_option(jopt->jo_op, val)) {
 
366
                                journal_usage++;
 
367
                                continue;
 
368
                        }
 
369
                } else if (val) {
 
370
                        errorf("Journal option \"%s\" does not accept "
 
371
                               "arguments\n",
 
372
                               token);
 
373
                        journal_usage++;
 
374
                        continue;
 
375
                }
 
376
 
 
377
                err = tunefs_append_operation(jopt->jo_op);
 
378
                if (err) {
 
379
                        tcom_err(err, "while processing journal options");
 
380
                        rc = 1;
 
381
                        break;
 
382
                }
 
383
        }
 
384
 
 
385
        if (journal_usage) {
 
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);
 
390
                rc = 1;
 
391
        }
 
392
 
 
393
        free(options);
 
394
        return rc;
 
395
}
 
396
 
 
397
static struct tunefs_option help_option = {
 
398
        .opt_option     = {
 
399
                .name   = "help",
 
400
                .val    = 'h',
 
401
        },
 
402
        .opt_handle     = handle_help,
 
403
};
 
404
 
 
405
static struct tunefs_option version_option = {
 
406
        .opt_option     = {
 
407
                .name   = "version",
 
408
                .val    = 'V',
 
409
        },
 
410
        .opt_handle     = handle_version,
 
411
};
 
412
 
 
413
static struct tunefs_option verbose_option = {
 
414
        .opt_option     = {
 
415
                .name   = "verbose",
 
416
                .val    = 'v',
 
417
        },
 
418
        .opt_help       =
 
419
                "-v|--verbose (increases verbosity; more than one permitted)",
 
420
        .opt_handle     = handle_verbosity,
 
421
};
 
422
 
 
423
static struct tunefs_option quiet_option = {
 
424
        .opt_option     = {
 
425
                .name   = "quiet",
 
426
                .val    = 'q',
 
427
        },
 
428
        .opt_help       =
 
429
                "-q|--quiet (decreases verbosity; more than one permitted)",
 
430
        .opt_handle     = handle_verbosity,
 
431
};
 
432
 
 
433
static struct tunefs_option interactive_option = {
 
434
        .opt_option     = {
 
435
                .name   = "interactive",
 
436
                .val    = 'i',
 
437
        },
 
438
        .opt_help       = "-i|--interactive",
 
439
        .opt_handle     = handle_interactive,
 
440
};
 
441
 
 
442
static struct tunefs_option progress_option = {
 
443
        .opt_option     = {
 
444
                .name   = "progress",
 
445
                .val    = 'p',
 
446
        },
 
447
        .opt_help       = "-p|--progress",
 
448
        .opt_handle     = handle_progress,
 
449
};
 
450
 
 
451
static struct tunefs_option yes_option = {
 
452
        .opt_option     = {
 
453
                .name   = "yes",
 
454
                .val    = 'y',
 
455
        },
 
456
        .opt_help       = "-y|--yes",
 
457
        .opt_handle     = handle_answer,
 
458
};
 
459
 
 
460
static struct tunefs_option no_option = {
 
461
        .opt_option     = {
 
462
                .name   = "no",
 
463
                .val    = 'n',
 
464
        },
 
465
        .opt_help       = "-n|--no",
 
466
        .opt_handle     = handle_answer,
 
467
};
 
468
 
 
469
static struct tunefs_option query_option = {
 
470
        .opt_option     = {
 
471
                .name           = "query",
 
472
                .val            = 'Q',
 
473
                .has_arg        = 1,
 
474
        },
 
475
        .opt_help       = "-Q|--query <query-format>",
 
476
        .opt_handle     = &generic_handle_arg,
 
477
        .opt_op         = &query_op,
 
478
};
 
479
 
 
480
static struct tunefs_option list_sparse_option = {
 
481
        .opt_option     = {
 
482
                .name   = "list-sparse",
 
483
                .val    = CHAR_MAX,
 
484
        },
 
485
        .opt_help       = "   --list-sparse",
 
486
        .opt_op         = &list_sparse_op,
 
487
};
 
488
 
 
489
static struct tunefs_option reset_uuid_option = {
 
490
        .opt_option     = {
 
491
                .name   = "uuid-reset",
 
492
                .val    = 'U',
 
493
        },
 
494
        .opt_help       = "-U|--uuid-reset",
 
495
        .opt_op         = &reset_uuid_op,
 
496
};
 
497
 
 
498
static struct tunefs_option update_cluster_stack_option = {
 
499
        .opt_option     = {
 
500
                .name   = "update-cluster-stack",
 
501
                .val    = CHAR_MAX,
 
502
        },
 
503
        .opt_help       = "   --update-cluster-stack",
 
504
        .opt_op         = &update_cluster_stack_op,
 
505
};
 
506
 
 
507
static struct tunefs_option cloned_volume_option = {
 
508
        .opt_option     = {
 
509
                .name           = "cloned-volume",
 
510
                .val            = CHAR_MAX,
 
511
                .has_arg        = 2,
 
512
        },
 
513
        .opt_help       = "   --cloned-volume[=new-label]",
 
514
        .opt_op         = &cloned_volume_op,
 
515
};
 
516
 
 
517
static struct tunefs_option set_slot_count_option = {
 
518
        .opt_option     = {
 
519
                .name           = "node-slots",
 
520
                .val            = 'N',
 
521
                .has_arg        = 1,
 
522
        },
 
523
        .opt_help       = "-N|--node-slots <number-of-node-slots>",
 
524
        .opt_handle     = generic_handle_arg,
 
525
        .opt_op         = &set_slot_count_op,
 
526
};
 
527
 
 
528
static struct tunefs_option set_label_option = {
 
529
        .opt_option     = {
 
530
                .name           = "label",
 
531
                .val            = 'L',
 
532
                .has_arg        = 1,
 
533
        },
 
534
        .opt_help       = "-L|--label <label>",
 
535
        .opt_handle     = generic_handle_arg,
 
536
        .opt_op         = &set_label_op,
 
537
};
 
538
 
 
539
static struct tunefs_option mount_type_option = {
 
540
        .opt_option     = {
 
541
                .name           = "mount",
 
542
                .val            = 'M',
 
543
                .has_arg        = 1,
 
544
        },
 
545
        .opt_handle     = mount_type_handle_arg,
 
546
};
 
547
 
 
548
static struct tunefs_option backup_super_option = {
 
549
        .opt_option     = {
 
550
                .name   = "backup-super",
 
551
                .val    = CHAR_MAX,
 
552
        },
 
553
        .opt_handle     = backup_super_handle_arg,
 
554
};
 
555
 
 
556
static struct tunefs_option features_option = {
 
557
        .opt_option     = {
 
558
                .name           = "fs-features",
 
559
                .val            = CHAR_MAX,
 
560
                .has_arg        = 1,
 
561
        },
 
562
        .opt_help       = "   --fs-features [no]sparse,...",
 
563
        .opt_handle     = strdup_handle_arg,
 
564
};
 
565
 
 
566
static struct tunefs_option resize_volume_option = {
 
567
        .opt_option     = {
 
568
                .name           = "volume-size",
 
569
                .val            = 'S',
 
570
                .has_arg        = 2,
 
571
        },
 
572
        .opt_help       = "-S|--volume-size",
 
573
        .opt_handle     = strdup_handle_arg,
 
574
};
 
575
 
 
576
static struct tunefs_option journal_option = {
 
577
        .opt_option     = {
 
578
                .name           = "journal-options",
 
579
                .val            = 'J',
 
580
                .has_arg        = 1,
 
581
        },
 
582
        .opt_help       = "-J|--journal-options <options>",
 
583
        .opt_handle     = handle_journal_arg,
 
584
};
 
585
 
 
586
/* The order here creates the order in print_usage() */
 
587
static struct tunefs_option *options[] = {
 
588
        &help_option,
 
589
        &version_option,
 
590
        &interactive_option,
 
591
        &progress_option,
 
592
        &verbose_option,
 
593
        &quiet_option,
 
594
        &set_label_option,
 
595
        &set_slot_count_option,
 
596
        &resize_volume_option,
 
597
        &reset_uuid_option,
 
598
        &journal_option,
 
599
        &query_option,
 
600
        &list_sparse_option,
 
601
        &mount_type_option,
 
602
        &backup_super_option,
 
603
        &features_option,
 
604
        &update_cluster_stack_option,
 
605
        &cloned_volume_option,
 
606
        &yes_option,
 
607
        &no_option,
 
608
        NULL,
 
609
};
 
610
 
 
611
/*
 
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().
 
617
 */
 
618
static struct tunefs_option *feature_options[] = {
 
619
        &mount_type_option,
 
620
        &backup_super_option,
 
621
        &features_option,
 
622
        NULL,
 
623
};
 
624
 
 
625
static struct tunefs_option *find_option_by_val(int val)
 
626
{
 
627
        int i;
 
628
        struct tunefs_option *opt = NULL;
 
629
 
 
630
        for (i = 0; options[i]; i++) {
 
631
                if (options[i]->opt_option.val == val) {
 
632
                        opt = options[i];
 
633
                        break;
 
634
                }
 
635
        }
 
636
 
 
637
        return opt;
 
638
}
 
639
 
 
640
static void print_usage(int rc)
 
641
{
 
642
        int i;
 
643
        enum tools_verbosity_level level = VL_ERR;
 
644
 
 
645
        if (!rc)
 
646
                level = VL_OUT;
 
647
 
 
648
        verbosef(level, "Usage: %s [options] <device> [new-size]\n",
 
649
                 tools_progname());
 
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);
 
656
        }
 
657
        verbosef(level,
 
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");
 
660
        exit(rc);
 
661
}
 
662
 
 
663
static errcode_t parse_feature_strings(void)
 
664
{
 
665
        int i, rc;
 
666
        char *tmp, *features = NULL;
 
667
        struct tunefs_option *opt;
 
668
        size_t len, new_features_len, features_len = 0;
 
669
 
 
670
        for (i = 0; feature_options[i]; i++) {
 
671
                opt = feature_options[i];
 
672
                if (!opt->opt_set)
 
673
                        continue;
 
674
                if (!opt->opt_private)
 
675
                        continue;
 
676
 
 
677
                len = strlen(opt->opt_private);
 
678
                new_features_len = features_len + len;
 
679
                if (features_len)
 
680
                        new_features_len++;  /* A comma to separate */
 
681
                tmp = realloc(features, new_features_len + 1);
 
682
                if (!tmp) {
 
683
                        errorf("Unable to allocate memory while processing "
 
684
                               "options\n");
 
685
                        return 1;
 
686
                }
 
687
                features = tmp;
 
688
                tmp = features + features_len;
 
689
                if (features_len) {
 
690
                        *tmp = ',';
 
691
                        tmp++;
 
692
                }
 
693
                strcpy(tmp, opt->opt_private);
 
694
                features_len = new_features_len;
 
695
        }
 
696
 
 
697
        if (!features)
 
698
                return 0;
 
699
 
 
700
        verbosef(VL_DEBUG, "Full feature string is \"%s\"\n", features);
 
701
        rc = features_op.to_parse_option(&features_op, features);
 
702
        free(features);
 
703
        if (rc)
 
704
                print_usage(1);
 
705
 
 
706
        return tunefs_append_operation(&features_op);
 
707
}
 
708
 
 
709
/*
 
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.
 
712
 *
 
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.
 
715
 */
 
716
static errcode_t parse_resize(const char *arg)
 
717
{
 
718
        char operation_arg[NAME_MAX];  /* Should be big enough :-) */
 
719
 
 
720
        if (!resize_volume_option.opt_set) {
 
721
                if (arg) {
 
722
                        errorf("Too many arguments\n");
 
723
                        print_usage(1);
 
724
                }
 
725
 
 
726
                return 0;  /* no resize options */
 
727
        }
 
728
 
 
729
        if (!arg)
 
730
                goto parse_option;
 
731
 
 
732
        /*
 
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.
 
736
         *
 
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.
 
740
         */
 
741
        if (snprintf(operation_arg, NAME_MAX, "%s:%s",
 
742
                     resize_volume_option.opt_private ?
 
743
                     (char *)resize_volume_option.opt_private : "blocks",
 
744
                     arg) >= NAME_MAX) {
 
745
                errorf("Argument to option '--%s' is too long: %s\n",
 
746
                       resize_volume_option.opt_option.name, arg);
 
747
                print_usage(1);
 
748
        }
 
749
 
 
750
parse_option:
 
751
        if (resize_volume_op.to_parse_option(&resize_volume_op,
 
752
                                             arg ? operation_arg : NULL))
 
753
                print_usage(1);
 
754
 
 
755
        /*
 
756
         * We _prepend_ resize, because we want any other operations to
 
757
         * have all the space they need.
 
758
         */
 
759
        return tunefs_prepend_operation(&resize_volume_op);
 
760
}
 
761
 
 
762
static int build_options(char **optstring, struct option **longopts)
 
763
{
 
764
        errcode_t err;
 
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;
 
771
 
 
772
        unprintable_counter = 1;        /* Start unique at CHAR_MAX + 1*/
 
773
        optstring_len = 1;              /* For the leading ':' */
 
774
        for (i = 0; options[i]; i++) {
 
775
                opt = options[i];
 
776
 
 
777
                /*
 
778
                 * Any option with a val of CHAR_MAX wants an unique but
 
779
                 * unreadable ->val.  Only readable characters go into
 
780
                 * optstring.
 
781
                 */
 
782
                if (opt->opt_option.val == CHAR_MAX) {
 
783
                        opt->opt_option.val =
 
784
                                CHAR_MAX + unprintable_counter;
 
785
                        unprintable_counter++;
 
786
                        continue;
 
787
                }
 
788
 
 
789
                /*
 
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.
 
795
                 */
 
796
                optstring_len += 1 + opt->opt_option.has_arg;
 
797
        }
 
798
        num_opts = i;
 
799
 
 
800
        err = ocfs2_malloc0(sizeof(char) * (optstring_len + 1), &str);
 
801
        if (!err)
 
802
                err = ocfs2_malloc(sizeof(struct option) * (num_opts + 1),
 
803
                                   &lopts);
 
804
        if (err) {
 
805
                rc = -ENOMEM;
 
806
                goto out;
 
807
        }
 
808
 
 
809
        p = str;
 
810
        *p = ':';
 
811
        p++;
 
812
        for (i = 0; options[i]; i++) {
 
813
                assert(p < (str + optstring_len + 1));
 
814
                opt = options[i];
 
815
 
 
816
                memcpy(&lopts[i], &opt->opt_option, sizeof(struct option));
 
817
 
 
818
                if (opt->opt_option.val >= CHAR_MAX)
 
819
                        continue;
 
820
 
 
821
                *p = opt->opt_option.val;
 
822
                p++;
 
823
                if (opt->opt_option.has_arg > 0) {
 
824
                        *p = ':';
 
825
                        p++;
 
826
                }
 
827
                if (opt->opt_option.has_arg > 1) {
 
828
                        *p = ':';
 
829
                        p++;
 
830
                }
 
831
        }
 
832
 
 
833
out:
 
834
        if (!rc) {
 
835
                *optstring = str;
 
836
                *longopts = lopts;
 
837
        } else {
 
838
                if (str)
 
839
                        free(str);
 
840
                if (lopts)
 
841
                        free(lopts);
 
842
        }
 
843
 
 
844
        return rc;
 
845
}
 
846
 
 
847
 
 
848
extern int optind, opterr, optopt;
 
849
extern char *optarg;
 
850
static errcode_t parse_options(int argc, char *argv[], char **device)
 
851
{
 
852
        int c;
 
853
        errcode_t err;
 
854
        struct option *long_options = NULL;
 
855
        char error[PATH_MAX];
 
856
        char *optstring = NULL;
 
857
        struct tunefs_option *opt;
 
858
 
 
859
        err = build_options(&optstring, &long_options);
 
860
        if (err)
 
861
                goto out;
 
862
 
 
863
        opterr = 0;
 
864
        error[0] = '\0';
 
865
        while ((c = getopt_long(argc, argv, optstring,
 
866
                                long_options, NULL)) != EOF) {
 
867
                opt = NULL;
 
868
                switch (c) {
 
869
                        case '?':
 
870
                                if (optopt)
 
871
                                        errorf("Invalid option: '-%c'\n",
 
872
                                               optopt);
 
873
                                else
 
874
                                        errorf("Invalid option: '%s'\n",
 
875
                                               argv[optind - 1]);
 
876
                                print_usage(1);
 
877
                                break;
 
878
 
 
879
                        case ':':
 
880
                                if (optopt < CHAR_MAX)
 
881
                                        errorf("Option '-%c' requires "
 
882
                                               "an argument\n",
 
883
                                               optopt);
 
884
                                else
 
885
                                        errorf("Option '%s' requires "
 
886
                                               "an argument\n",
 
887
                                               argv[optind - 1]);
 
888
                                print_usage(1);
 
889
                                break;
 
890
 
 
891
                        default:
 
892
                                opt = find_option_by_val(c);
 
893
                                if (!opt) {
 
894
                                        errorf("Shouldn't have gotten "
 
895
                                               "here: option '-%c'\n",
 
896
                                               c);
 
897
                                        print_usage(1);
 
898
                                }
 
899
                                break;
 
900
                }
 
901
 
 
902
                if (opt->opt_set) {
 
903
                        errorf("Option '-%c' specified more than once\n",
 
904
                               c);
 
905
                        print_usage(1);
 
906
                }
 
907
 
 
908
                opt->opt_set = 1;
 
909
                if (opt->opt_handle) {
 
910
                        if (opt->opt_handle(opt, optarg))
 
911
                                print_usage(1);
 
912
                }
 
913
                if (opt->opt_op) {
 
914
                        err = tunefs_append_operation(opt->opt_op);
 
915
                }
 
916
        }
 
917
 
 
918
        err = parse_feature_strings();
 
919
        if (err)
 
920
                goto out;
 
921
 
 
922
        if (optind >= argc) {
 
923
                errorf("No device specified\n");
 
924
                print_usage(1);
 
925
        }
 
926
 
 
927
        *device = strdup(argv[optind]);
 
928
        if (!*device) {
 
929
                err = TUNEFS_ET_NO_MEMORY;
 
930
                goto out;
 
931
        }
 
932
        optind++;
 
933
 
 
934
        /* parse_resize() will check if we expected a size */
 
935
        if (optind < argc) {
 
936
                err = parse_resize(argv[optind]);
 
937
                optind++;
 
938
        } else
 
939
                err = parse_resize(NULL);
 
940
        if (err)
 
941
                goto out;
 
942
 
 
943
        if (optind < argc) {
 
944
                errorf("Too many arguments\n");
 
945
                print_usage(1);
 
946
        }
 
947
 
 
948
out:
 
949
        return err;
 
950
}
 
951
 
 
952
 
 
953
/*
 
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.
 
957
 */
 
958
static int run_operation_filter(ocfs2_filesys *fs, int filter)
 
959
{
 
960
        errcode_t err = 0;
 
961
        struct list_head *pos, *n;
 
962
        struct tunefs_run *run;
 
963
        struct tunefs_operation *op;
 
964
 
 
965
        list_for_each_safe(pos, n, &tunefs_run_list) {
 
966
                run = list_entry(pos, struct tunefs_run, tr_list);
 
967
                op = run->tr_op;
 
968
 
 
969
                if (filter && !(op->to_open_flags & filter))
 
970
                        continue;
 
971
 
 
972
                list_del(&run->tr_list);
 
973
                ocfs2_free(&run);
 
974
 
 
975
                err = tunefs_op_run(fs, op);
 
976
                if (err) {
 
977
                        if (err != TUNEFS_ET_OPERATION_FAILED) {
 
978
                                tcom_err(err,
 
979
                                         "while trying to perform "
 
980
                                         "operation \"%s\"",
 
981
                                         op->to_name);
 
982
                        }
 
983
                        break;
 
984
                }
 
985
                tools_progress_step(tunefs_op_progress, 1);
 
986
        }
 
987
 
 
988
        return err;
 
989
}
 
990
 
 
991
static int run_operations(const char *device)
 
992
{
 
993
        int rc;
 
994
        errcode_t tmp, err = 0;
 
995
        struct list_head *p;
 
996
        struct tunefs_run *run;
 
997
        ocfs2_filesys *fs;
 
998
        int open_flags;
 
999
 
 
1000
 
 
1001
        /*
 
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.
 
1007
         *
 
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
 
1012
         * other operations.
 
1013
         *
 
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.
 
1018
         *
 
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
 
1022
         * tunefs_run_list.
 
1023
         */
 
1024
        while (!err && !list_empty(&tunefs_run_list)) {
 
1025
                rc = 0;
 
1026
                open_flags = 0;
 
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;
 
1030
                }
 
1031
 
 
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);
 
1039
                else if (!err)
 
1040
                        rc = run_operation_filter(fs, 0);
 
1041
                else {
 
1042
                        tcom_err(err, "while opening device \"%s\"",
 
1043
                                 device);
 
1044
                        break;
 
1045
                }
 
1046
 
 
1047
                err = 0;
 
1048
                if (rc)
 
1049
                        err = TUNEFS_ET_OPERATION_FAILED;
 
1050
 
 
1051
                tmp = tunefs_close(fs);
 
1052
                if (tmp)
 
1053
                        tcom_err(tmp, "while closing device \"%s\"",
 
1054
                                 device);
 
1055
                if (!err)
 
1056
                        err = tmp;
 
1057
        }
 
1058
 
 
1059
        return err;
 
1060
}
 
1061
 
 
1062
int main(int argc, char *argv[])
 
1063
{
 
1064
        int rc = 1;
 
1065
        errcode_t err;
 
1066
        char *device;
 
1067
 
 
1068
        tunefs_init(argv[0]);
 
1069
 
 
1070
        err = parse_options(argc, argv, &device);
 
1071
        if (err) {
 
1072
                tcom_err(err, "while parsing options");
 
1073
                goto out;
 
1074
        }
 
1075
 
 
1076
        tunefs_op_progress = tools_progress_start("tunefs.ocfs2",
 
1077
                                                  "tunefs",
 
1078
                                                  tunefs_op_count);
 
1079
        if (!tunefs_op_progress) {
 
1080
                tcom_err(TUNEFS_ET_NO_MEMORY,
 
1081
                         "while initializing the progress display");
 
1082
                goto out;
 
1083
        }
 
1084
 
 
1085
        rc = run_operations(device);
 
1086
 
 
1087
        tools_progress_stop(tunefs_op_progress);
 
1088
 
 
1089
out:
 
1090
        return rc;
 
1091
}