btrfs-progs: add support for dry-run options

Some commands could be run in a dry-run mode, i.e. not doing any
write/change actions, only printing the steps and ignoring errors.

There are two possibilities where to put the option:

- as a global one: btrfs --dry-run subvolume delete /path
- local option:    btrfs subvolume delete --dry-run /path

As we have several global options already, let's put it there, dry-run
should not be very common so the slight inconvenience of writing the
option out of order of command arguments should be acceptable.

Issue: #629
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2023-10-24 14:35:06 +02:00
parent 2c747dd83f
commit 39c63831a0
5 changed files with 29 additions and 3 deletions

14
btrfs.c
View File

@ -44,6 +44,7 @@ static const char * const btrfs_cmd_group_usage[] = {
" -v|--verbose increase verbosity of the subcommand\n" " -v|--verbose increase verbosity of the subcommand\n"
" -q|--quiet print only errors\n" " -q|--quiet print only errors\n"
" --log <level> set log level (default, info, verbose, debug, quiet)\n" " --log <level> set log level (default, info, verbose, debug, quiet)\n"
" --dry-run if supported, do not do any active/changing actions\n"
"\n" "\n"
"Options for the main command only:\n" "Options for the main command only:\n"
" --help print condensed help for all subcommands\n" " --help print condensed help for all subcommands\n"
@ -119,7 +120,7 @@ parse_command_token(const char *arg, const struct cmd_group *grp)
return cmd; return cmd;
} }
static void check_output_format(const struct cmd_struct *cmd) static void check_command_flags(const struct cmd_struct *cmd)
{ {
if (cmd->next) if (cmd->next)
return; return;
@ -129,6 +130,11 @@ static void check_output_format(const struct cmd_struct *cmd)
output_format_name(bconf.output_format)); output_format_name(bconf.output_format));
exit(1); exit(1);
} }
if (bconf.dry_run && !(cmd->flags & CMD_DRY_RUN)) {
error("--dry-run option not supported for %s\n", cmd->token);
exit(1);
}
} }
static void handle_help_options_next_level(const struct cmd_struct *cmd, static void handle_help_options_next_level(const struct cmd_struct *cmd,
@ -165,7 +171,7 @@ int handle_command_group(const struct cmd_struct *cmd, int argc,
subcmd = parse_command_token(argv[0], cmd->next); subcmd = parse_command_token(argv[0], cmd->next);
handle_help_options_next_level(subcmd, argc, argv); handle_help_options_next_level(subcmd, argc, argv);
check_output_format(subcmd); check_command_flags(subcmd);
fixup_argv0(argv, subcmd->token); fixup_argv0(argv, subcmd->token);
return cmd_execute(subcmd, argc, argv); return cmd_execute(subcmd, argc, argv);
@ -288,6 +294,7 @@ static int handle_global_options(int argc, char **argv)
{ "quiet", no_argument, NULL, 'q' }, { "quiet", no_argument, NULL, 'q' },
{ "log", required_argument, NULL, OPT_LOG }, { "log", required_argument, NULL, OPT_LOG },
{ "param", required_argument, NULL, GETOPT_VAL_PARAM }, { "param", required_argument, NULL, GETOPT_VAL_PARAM },
{ "dry-run", no_argument, NULL, GETOPT_VAL_DRY_RUN },
{ NULL, 0, NULL, 0} { NULL, 0, NULL, 0}
}; };
int shift; int shift;
@ -316,6 +323,9 @@ static int handle_global_options(int argc, char **argv)
case GETOPT_VAL_PARAM: case GETOPT_VAL_PARAM:
bconf_save_param(optarg); bconf_save_param(optarg);
break; break;
case GETOPT_VAL_DRY_RUN:
bconf_set_dry_run();
break;
case 'v': case 'v':
bconf_be_verbose(); bconf_be_verbose();
break; break;

View File

@ -22,6 +22,7 @@ enum {
CMD_ALIAS = (1 << 1), /* alias of next command in cmd_group */ CMD_ALIAS = (1 << 1), /* alias of next command in cmd_group */
CMD_FORMAT_TEXT = (1 << 2), /* output as plain text */ CMD_FORMAT_TEXT = (1 << 2), /* output as plain text */
CMD_FORMAT_JSON = (1 << 3), /* output in json */ CMD_FORMAT_JSON = (1 << 3), /* output in json */
CMD_DRY_RUN = (1 << 4), /* Accepts global --dry-run option. */
}; };
#define CMD_FORMAT_MASK (CMD_FORMAT_TEXT | CMD_FORMAT_JSON) #define CMD_FORMAT_MASK (CMD_FORMAT_TEXT | CMD_FORMAT_JSON)

View File

@ -37,6 +37,7 @@ struct cmd_group;
#define GETOPT_VAL_HELP 520 #define GETOPT_VAL_HELP 520
#define GETOPT_VAL_PARAM 521 #define GETOPT_VAL_PARAM 521
#define GETOPT_VAL_DRY_RUN 522
#define ARGV0_BUF_SIZE PATH_MAX #define ARGV0_BUF_SIZE PATH_MAX
@ -83,7 +84,7 @@ struct cmd_group;
"Global options:" "Global options:"
#define HELPINFO_INSERT_FORMAT "--format TYPE" #define HELPINFO_INSERT_FORMAT "--format TYPE"
#define HELPINFO_INSERT_DRY_RUN OPTLINE("--dry-run", "do not do any active/changing actions")
#define HELPINFO_INSERT_VERBOSE OPTLINE("-v|--verbose", "increase output verbosity") #define HELPINFO_INSERT_VERBOSE OPTLINE("-v|--verbose", "increase output verbosity")
#define HELPINFO_INSERT_QUIET OPTLINE("-q|--quiet", "print only errors") #define HELPINFO_INSERT_QUIET OPTLINE("-q|--quiet", "print only errors")

View File

@ -1000,6 +1000,16 @@ void bconf_save_param(const char *str)
} }
} }
void bconf_set_dry_run(void)
{
pr_verbose(LOG_INFO, "Dry-run requested\n");
bconf.dry_run = 1;
}
bool bconf_is_dry_run(void)
{
return bconf.dry_run == 1;
}
/* Returns total size of main memory in bytes, -1UL if error. */ /* Returns total size of main memory in bytes, -1UL if error. */
unsigned long total_memory(void) unsigned long total_memory(void)

View File

@ -87,6 +87,8 @@ struct btrfs_config {
* > 0: verbose level * > 0: verbose level
*/ */
int verbose; int verbose;
/* Command line request to skip any modification actions. */
int dry_run;
struct list_head params; struct list_head params;
}; };
extern struct btrfs_config bconf; extern struct btrfs_config bconf;
@ -102,6 +104,8 @@ void bconf_be_verbose(void);
void bconf_be_quiet(void); void bconf_be_quiet(void);
void bconf_add_param(const char *key, const char *value); void bconf_add_param(const char *key, const char *value);
void bconf_save_param(const char *str); void bconf_save_param(const char *str);
void bconf_set_dry_run(void);
bool bconf_is_dry_run(void);
const char *bconf_param_value(const char *key); const char *bconf_param_value(const char *key);
/* Pseudo random number generator wrappers */ /* Pseudo random number generator wrappers */