* Boston, MA 021110-1307, USA.
*/
-#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
+#include "volumes.h"
+#include "crc32c.h"
#include "commands.h"
-#include "version.h"
+#include "utils.h"
+#include "help.h"
-static const char btrfs_cmd_group_usage[] =
- "btrfs [--help] [--version] <group> [<group>...] <command> [<args>]";
+static const char * const btrfs_cmd_group_usage[] = {
+ "btrfs [--help] [--version] <group> [<group>...] <command> [<args>]",
+ NULL
+};
static const char btrfs_cmd_group_info[] =
"Use --help as an argument for information on a specific group or command.";
-char argv0_buf[ARGV0_BUF_SIZE] = "btrfs";
-
static inline const char *skip_prefix(const char *str, const char *prefix)
{
size_t len = strlen(prefix);
return strncmp(str, prefix, len) ? NULL : str + len;
}
-int prefixcmp(const char *str, const char *prefix)
-{
- for (; ; str++, prefix++)
- if (!*prefix)
- return 0;
- else if (*str != *prefix)
- return (unsigned char)*prefix - (unsigned char)*str;
-}
-
static int parse_one_token(const char *arg, const struct cmd_group *grp,
const struct cmd_struct **cmd_ret)
{
static const struct cmd_struct *
parse_command_token(const char *arg, const struct cmd_group *grp)
{
- const struct cmd_struct *cmd;
+ const struct cmd_struct *cmd = NULL;
switch(parse_one_token(arg, grp, &cmd)) {
case -1:
return cmd;
}
-void handle_help_options_next_level(const struct cmd_struct *cmd,
- int argc, char **argv)
+static void handle_help_options_next_level(const struct cmd_struct *cmd,
+ int argc, char **argv)
{
if (argc < 2)
return;
}
}
-static void fixup_argv0(char **argv, const char *token)
-{
- int len = strlen(argv0_buf);
-
- snprintf(argv0_buf + len, sizeof(argv0_buf) - len, " %s", token);
- argv[0] = argv0_buf;
-}
-
int handle_command_group(const struct cmd_group *grp, int argc,
char **argv)
return cmd->fn(argc, argv);
}
-int check_argc_exact(int nargs, int expected)
-{
- if (nargs < expected)
- fprintf(stderr, "%s: too few arguments\n", argv0_buf);
- if (nargs > expected)
- fprintf(stderr, "%s: too many arguments\n", argv0_buf);
-
- return nargs != expected;
-}
-
-int check_argc_min(int nargs, int expected)
-{
- if (nargs < expected) {
- fprintf(stderr, "%s: too few arguments\n", argv0_buf);
- return 1;
- }
-
- return 0;
-}
-
-int check_argc_max(int nargs, int expected)
-{
- if (nargs > expected) {
- fprintf(stderr, "%s: too many arguments\n", argv0_buf);
- return 1;
- }
-
- return 0;
-}
-
-const struct cmd_group btrfs_cmd_group;
+static const struct cmd_group btrfs_cmd_group;
static const char * const cmd_help_usage[] = {
"btrfs help [--full]",
- "Dislay help information",
+ "Display help information",
"",
"--full display detailed help on every command",
NULL
static int cmd_version(int argc, char **argv)
{
- printf("%s\n", BTRFS_BUILD_VERSION);
+ printf("%s\n", PACKAGE_STRING);
return 0;
}
-static int handle_options(int *argc, char ***argv)
+/*
+ * Parse global options, between binary name and first non-option argument
+ * after processing all valid options (including those with arguments).
+ *
+ * Returns index to argv where parsting stopped, optind is reset to 1
+ */
+static int handle_global_options(int argc, char **argv)
{
- char **orig_argv = *argv;
+ enum { OPT_HELP = 256, OPT_VERSION, OPT_FULL };
+ static const struct option long_options[] = {
+ { "help", no_argument, NULL, OPT_HELP },
+ { "version", no_argument, NULL, OPT_VERSION },
+ { "full", no_argument, NULL, OPT_FULL },
+ { NULL, 0, NULL, 0}
+ };
+ int shift;
+
+ if (argc == 0)
+ return 0;
- while (*argc > 0) {
- const char *arg = (*argv)[0];
- if (arg[0] != '-')
- break;
+ opterr = 0;
+ while (1) {
+ int c;
- if (!strcmp(arg, "--help")) {
- break;
- } else if (!strcmp(arg, "--version")) {
+ c = getopt_long(argc, argv, "+", long_options, NULL);
+ if (c < 0)
break;
- } else {
- fprintf(stderr, "Unknown option: %s\n", arg);
- fprintf(stderr, "usage: %s\n",
- btrfs_cmd_group.usagestr);
+
+ switch (c) {
+ case OPT_HELP: break;
+ case OPT_VERSION: break;
+ case OPT_FULL: break;
+ default:
+ fprintf(stderr, "Unknown global option: %s\n",
+ argv[optind - 1]);
exit(129);
}
+ }
+
+ shift = optind;
+ optind = 1;
- (*argv)++;
- (*argc)--;
+ return shift;
+}
+
+void handle_special_globals(int shift, int argc, char **argv)
+{
+ int has_help = 0;
+ int has_full = 0;
+ int i;
+
+ for (i = 0; i < shift; i++) {
+ if (strcmp(argv[i], "--help") == 0)
+ has_help = 1;
+ else if (strcmp(argv[i], "--full") == 0)
+ has_full = 1;
}
- return (*argv) - orig_argv;
+ if (has_help) {
+ if (has_full)
+ usage_command_group(&btrfs_cmd_group, 1, 0);
+ else
+ cmd_help(argc, argv);
+ exit(0);
+ }
+
+ for (i = 0; i < shift; i++)
+ if (strcmp(argv[i], "--version") == 0) {
+ cmd_version(argc, argv);
+ exit(0);
+ }
}
-const struct cmd_group btrfs_cmd_group = {
+static const struct cmd_group btrfs_cmd_group = {
btrfs_cmd_group_usage, btrfs_cmd_group_info, {
{ "subvolume", cmd_subvolume, NULL, &subvolume_cmd_group, 0 },
{ "filesystem", cmd_filesystem, NULL, &filesystem_cmd_group, 0 },
{ "balance", cmd_balance, NULL, &balance_cmd_group, 0 },
{ "device", cmd_device, NULL, &device_cmd_group, 0 },
{ "scrub", cmd_scrub, NULL, &scrub_cmd_group, 0 },
+ { "check", cmd_check, cmd_check_usage, NULL, 0 },
+ { "rescue", cmd_rescue, NULL, &rescue_cmd_group, 0 },
+ { "restore", cmd_restore, cmd_restore_usage, NULL, 0 },
{ "inspect-internal", cmd_inspect, NULL, &inspect_cmd_group, 0 },
+ { "property", cmd_property, NULL, &property_cmd_group, 0 },
+ { "send", cmd_send, cmd_send_usage, NULL, 0 },
+ { "receive", cmd_receive, cmd_receive_usage, NULL, 0 },
+ { "quota", cmd_quota, NULL, "a_cmd_group, 0 },
+ { "qgroup", cmd_qgroup, NULL, &qgroup_cmd_group, 0 },
+ { "replace", cmd_replace, NULL, &replace_cmd_group, 0 },
{ "help", cmd_help, cmd_help_usage, NULL, 0 },
{ "version", cmd_version, cmd_version_usage, NULL, 0 },
- { 0, 0, 0, 0, 0 }
+ NULL_CMD_STRUCT
},
};
int main(int argc, char **argv)
{
const struct cmd_struct *cmd;
+ const char *bname;
+ int ret;
- argc--;
- argv++;
- handle_options(&argc, &argv);
- if (argc > 0) {
- if (!prefixcmp(argv[0], "--"))
- argv[0] += 2;
+ btrfs_config_init();
+
+ if ((bname = strrchr(argv[0], '/')) != NULL)
+ bname++;
+ else
+ bname = argv[0];
+
+ if (!strcmp(bname, "btrfsck")) {
+ argv[0] = "check";
} else {
- usage_command_group(&btrfs_cmd_group, 0, 0);
- exit(1);
+ int shift;
+
+ shift = handle_global_options(argc, argv);
+ handle_special_globals(shift, argc, argv);
+ while (shift-- > 0) {
+ argc--;
+ argv++;
+ }
+ if (argc == 0) {
+ usage_command_group_short(&btrfs_cmd_group);
+ exit(1);
+ }
}
cmd = parse_command_token(argv[0], &btrfs_cmd_group);
handle_help_options_next_level(cmd, argc, argv);
+ crc32c_optimization_init();
+
fixup_argv0(argv, cmd->token);
- exit(cmd->fn(argc, argv));
+
+ ret = cmd->fn(argc, argv);
+
+ btrfs_close_all_devices();
+
+ exit(ret);
}