diff mbox

[v2,1/2] btrfs-progs: Fix wrong optind re-initialization to allow mixed option and non-option

Message ID 20180620003839.10629-1-wqu@suse.com (mailing list archive)
State New, archived
Headers show

Commit Message

Qu Wenruo June 20, 2018, 12:38 a.m. UTC
In function handle_global_options(), we reset @optind to 1.
However according to man page of getopt(3) NOTES section, if we need to
rescan options later, @optind should be reset to 0 to initialize the
internal variables correctly.

This explains the reason why in cmd_check(), getopt_long() doesn't
handle the following command correctly:
"btrfs check /dev/data/btrfs --check-data-csum"

While mkfs.btrfs handles mixed non-option and option correctly:
"mkfs.btrfs -f /dev/data/disk1 --data raid1 /dev/data/disk2"

Cc: Paul Jones <paul@pauljones.id.au>
Cc: Hugo Mills <hugo@carfax.org.uk>
Fixes: 010ceab56e06 ("btrfs-progs: rework option parser to use getopt for global options")
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
changelog:
v2:
  Instead of resetting @optind at handle_global_options(), reset @optind
  before each later getopt() call. Since there are cases uses @optind and
  expects it to be starting from 1.
---
 cmds-balance.c            | 2 ++
 cmds-device.c             | 3 +++
 cmds-fi-du.c              | 1 +
 cmds-fi-usage.c           | 1 +
 cmds-filesystem.c         | 2 ++
 cmds-inspect-dump-tree.c  | 1 +
 cmds-inspect-tree-stats.c | 1 +
 cmds-inspect.c            | 3 +++
 cmds-qgroup.c             | 3 +++
 cmds-quota.c              | 1 +
 cmds-receive.c            | 1 +
 cmds-replace.c            | 3 +++
 cmds-rescue.c             | 2 ++
 cmds-restore.c            | 1 +
 cmds-send.c               | 1 +
 cmds-subvolume.c          | 6 ++++++
 16 files changed, 32 insertions(+)

Comments

David Sterba July 2, 2018, 10:12 p.m. UTC | #1
On Wed, Jun 20, 2018 at 08:38:38AM +0800, Qu Wenruo wrote:
> In function handle_global_options(), we reset @optind to 1.
> However according to man page of getopt(3) NOTES section, if we need to
> rescan options later, @optind should be reset to 0 to initialize the
> internal variables correctly.
> 
> This explains the reason why in cmd_check(), getopt_long() doesn't
> handle the following command correctly:
> "btrfs check /dev/data/btrfs --check-data-csum"
> 
> While mkfs.btrfs handles mixed non-option and option correctly:
> "mkfs.btrfs -f /dev/data/disk1 --data raid1 /dev/data/disk2"
> 
> Cc: Paul Jones <paul@pauljones.id.au>
> Cc: Hugo Mills <hugo@carfax.org.uk>
> Fixes: 010ceab56e06 ("btrfs-progs: rework option parser to use getopt for global options")
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> changelog:
> v2:
>   Instead of resetting @optind at handle_global_options(), reset @optind
>   before each later getopt() call. Since there are cases uses @optind and
>   expects it to be starting from 1.

So it's not possible to set it once before the callbacks are called in
btrfs.c:main() due to the exceptions that need it to be set to 1. Ok,
can you please send a separate patch that makes the optind = 1 explicit?
Even it might be redundant in the context, it's a way to document the
expected behaviour of getopt and also we would not have to think if the
optind setting is missing or not before the getopts. Thanks.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Sterba July 2, 2018, 10:24 p.m. UTC | #2
On Wed, Jun 20, 2018 at 08:38:38AM +0800, Qu Wenruo wrote:
> In function handle_global_options(), we reset @optind to 1.
> However according to man page of getopt(3) NOTES section, if we need to
> rescan options later, @optind should be reset to 0 to initialize the
> internal variables correctly.
> 
> This explains the reason why in cmd_check(), getopt_long() doesn't
> handle the following command correctly:
> "btrfs check /dev/data/btrfs --check-data-csum"
> 
> While mkfs.btrfs handles mixed non-option and option correctly:
> "mkfs.btrfs -f /dev/data/disk1 --data raid1 /dev/data/disk2"
> 
> Cc: Paul Jones <paul@pauljones.id.au>
> Cc: Hugo Mills <hugo@carfax.org.uk>
> Fixes: 010ceab56e06 ("btrfs-progs: rework option parser to use getopt for global options")
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> changelog:
> v2:
>   Instead of resetting @optind at handle_global_options(), reset @optind
>   before each later getopt() call. Since there are cases uses @optind and
>   expects it to be starting from 1.

1 and 2 applied, thanks.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Qu Wenruo July 3, 2018, 1 a.m. UTC | #3
On 2018年07月03日 06:12, David Sterba wrote:
> On Wed, Jun 20, 2018 at 08:38:38AM +0800, Qu Wenruo wrote:
>> In function handle_global_options(), we reset @optind to 1.
>> However according to man page of getopt(3) NOTES section, if we need to
>> rescan options later, @optind should be reset to 0 to initialize the
>> internal variables correctly.
>>
>> This explains the reason why in cmd_check(), getopt_long() doesn't
>> handle the following command correctly:
>> "btrfs check /dev/data/btrfs --check-data-csum"
>>
>> While mkfs.btrfs handles mixed non-option and option correctly:
>> "mkfs.btrfs -f /dev/data/disk1 --data raid1 /dev/data/disk2"
>>
>> Cc: Paul Jones <paul@pauljones.id.au>
>> Cc: Hugo Mills <hugo@carfax.org.uk>
>> Fixes: 010ceab56e06 ("btrfs-progs: rework option parser to use getopt for global options")
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>> changelog:
>> v2:
>>   Instead of resetting @optind at handle_global_options(), reset @optind
>>   before each later getopt() call. Since there are cases uses @optind and
>>   expects it to be starting from 1.
> 
> So it's not possible to set it once before the callbacks are called in
> btrfs.c:main() due to the exceptions that need it to be set to 1. Ok,
> can you please send a separate patch that makes the optind = 1 explicit?

It's already done in handle_global_options(), so every subcommand is
getting @optind set to 1 already.

Thanks,
Qu

> Even it might be redundant in the context, it's a way to document the
> expected behaviour of getopt and also we would not have to think if the
> optind setting is missing or not before the getopts. Thanks.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
diff mbox

Patch

diff --git a/cmds-balance.c b/cmds-balance.c
index 0c91bdf13ada..6cc26c358f95 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -528,6 +528,7 @@  static int cmd_balance_start(int argc, char **argv)
 
 	memset(&args, 0, sizeof(args));
 
+	optind = 0;
 	while (1) {
 		enum { GETOPT_VAL_FULL_BALANCE = 256,
 			GETOPT_VAL_BACKGROUND = 257 };
@@ -831,6 +832,7 @@  static int cmd_balance_status(int argc, char **argv)
 	int verbose = 0;
 	int ret;
 
+	optind = 0;
 	while (1) {
 		int opt;
 		static const struct option longopts[] = {
diff --git a/cmds-device.c b/cmds-device.c
index 86459d1b9564..cd689b5017c8 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -57,6 +57,7 @@  static int cmd_device_add(int argc, char **argv)
 	int force = 0;
 	int last_dev;
 
+	optind = 0;
 	while (1) {
 		int c;
 		static const struct option long_options[] = {
@@ -267,6 +268,7 @@  static int cmd_device_scan(int argc, char **argv)
 	int all = 0;
 	int ret = 0;
 
+	optind = 0;
 	while (1) {
 		int c;
 		static const struct option long_options[] = {
@@ -403,6 +405,7 @@  static int cmd_device_stats(int argc, char **argv)
 	__u64 flags = 0;
 	DIR *dirstream = NULL;
 
+	optind = 0;
 	while (1) {
 		int c;
 		static const struct option long_options[] = {
diff --git a/cmds-fi-du.c b/cmds-fi-du.c
index 7e6bb7f6a570..4e639f6dc231 100644
--- a/cmds-fi-du.c
+++ b/cmds-fi-du.c
@@ -565,6 +565,7 @@  int cmd_filesystem_du(int argc, char **argv)
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
 
+	optind = 0;
 	while (1) {
 		static const struct option long_options[] = {
 			{ "summarize", no_argument, NULL, 's'},
diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c
index de7ad668ba2d..cbb3cd191b3d 100644
--- a/cmds-fi-usage.c
+++ b/cmds-fi-usage.c
@@ -975,6 +975,7 @@  int cmd_filesystem_usage(int argc, char **argv)
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
 
+	optind = 0;
 	while (1) {
 		int c;
 
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 30a50bf55e38..06c8311bdfe3 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -685,6 +685,7 @@  static int cmd_filesystem_show(int argc, char **argv)
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
 
+	optind = 0;
 	while (1) {
 		int c;
 		static const struct option long_options[] = {
@@ -924,6 +925,7 @@  static int cmd_filesystem_defrag(int argc, char **argv)
 	defrag_global_errors = 0;
 	defrag_global_verbose = 0;
 	defrag_global_errors = 0;
+	optind = 0;
 	while(1) {
 		int c = getopt(argc, argv, "vrc::fs:l:t:");
 		if (c < 0)
diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c
index 92a2a45b267e..c8acd55a0c3a 100644
--- a/cmds-inspect-dump-tree.c
+++ b/cmds-inspect-dump-tree.c
@@ -235,6 +235,7 @@  int cmd_inspect_dump_tree(int argc, char **argv)
 	 * tree blocks as possible.
 	 */
 	open_ctree_flags = OPEN_CTREE_PARTIAL | OPEN_CTREE_NO_BLOCK_GROUPS;
+	optind = 0;
 	while (1) {
 		int c;
 		enum { GETOPT_VAL_FOLLOW = 256 };
diff --git a/cmds-inspect-tree-stats.c b/cmds-inspect-tree-stats.c
index eced0db9f840..dfa34c52ff5f 100644
--- a/cmds-inspect-tree-stats.c
+++ b/cmds-inspect-tree-stats.c
@@ -434,6 +434,7 @@  int cmd_inspect_tree_stats(int argc, char **argv)
 	int opt;
 	int ret = 0;
 
+	optind = 0;
 	while ((opt = getopt(argc, argv, "vb")) != -1) {
 		switch (opt) {
 		case 'v':
diff --git a/cmds-inspect.c b/cmds-inspect.c
index afd7fe48df5c..2fc50c1a2d90 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -94,6 +94,7 @@  static int cmd_inspect_inode_resolve(int argc, char **argv)
 	int ret;
 	DIR *dirstream = NULL;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "v");
 		if (c < 0)
@@ -148,6 +149,7 @@  static int cmd_inspect_logical_resolve(int argc, char **argv)
 	char *path_ptr;
 	DIR *dirstream = NULL;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "Pvs:");
 		if (c < 0)
@@ -591,6 +593,7 @@  static int cmd_inspect_min_dev_size(int argc, char **argv)
 	DIR *dirstream = NULL;
 	u64 devid = 1;
 
+	optind = 0;
 	while (1) {
 		int c;
 		enum { GETOPT_VAL_DEVID = 256 };
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 93206900693d..b928edc7c408 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -46,6 +46,7 @@  static int _cmd_qgroup_assign(int assign, int argc, char **argv,
 	DIR *dirstream = NULL;
 
 	if (assign) {
+		optind = 0;
 		while (1) {
 			enum { GETOPT_VAL_RESCAN = 256, GETOPT_VAL_NO_RESCAN };
 			static const struct option long_options[] = {
@@ -310,6 +311,7 @@  static int cmd_qgroup_show(int argc, char **argv)
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
 
+	optind = 0;
 	while (1) {
 		int c;
 		enum {
@@ -429,6 +431,7 @@  static int cmd_qgroup_limit(int argc, char **argv)
 	DIR *dirstream = NULL;
 	enum btrfs_util_error err;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "ce");
 		if (c < 0)
diff --git a/cmds-quota.c b/cmds-quota.c
index 745889d12523..c9ea9c0f36ec 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -119,6 +119,7 @@  static int cmd_quota_rescan(int argc, char **argv)
 	DIR *dirstream = NULL;
 	int wait_for_completion = 0;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "sw");
 		if (c < 0)
diff --git a/cmds-receive.c b/cmds-receive.c
index 68123a31cc5c..34d51ef3f301 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -1267,6 +1267,7 @@  int cmd_receive(int argc, char **argv)
 	realmnt[0] = 0;
 	fromfile[0] = 0;
 
+	optind = 0;
 	while (1) {
 		int c;
 		enum { GETOPT_VAL_DUMP = 257 };
diff --git a/cmds-replace.c b/cmds-replace.c
index 032a44fcda3c..1fa802845f0e 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -134,6 +134,7 @@  static int cmd_replace_start(int argc, char **argv)
 	u64 srcdev_size;
 	u64 dstdev_size;
 
+	optind = 0;
 	while ((c = getopt(argc, argv, "Brf")) != -1) {
 		switch (c) {
 		case 'B':
@@ -333,6 +334,7 @@  static int cmd_replace_status(int argc, char **argv)
 	int ret;
 	DIR *dirstream = NULL;
 
+	optind = 0;
 	while ((c = getopt(argc, argv, "1")) != -1) {
 		switch (c) {
 		case '1':
@@ -501,6 +503,7 @@  static int cmd_replace_cancel(int argc, char **argv)
 	char *path;
 	DIR *dirstream = NULL;
 
+	optind = 0;
 	while ((c = getopt(argc, argv, "")) != -1) {
 		switch (c) {
 		case '?':
diff --git a/cmds-rescue.c b/cmds-rescue.c
index c40088ad374e..0a1df5b8088b 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -52,6 +52,7 @@  static int cmd_rescue_chunk_recover(int argc, char *argv[])
 	int yes = 0;
 	int verbose = 0;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "yvh");
 		if (c < 0)
@@ -119,6 +120,7 @@  static int cmd_rescue_super_recover(int argc, char **argv)
 	int yes = 0;
 	char *dname;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "vy");
 		if (c < 0)
diff --git a/cmds-restore.c b/cmds-restore.c
index f228acab8276..f124e0f8ef15 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -1440,6 +1440,7 @@  int cmd_restore(int argc, char **argv)
 	regex_t match_reg, *mreg = NULL;
 	char reg_err[256];
 
+	optind = 0;
 	while (1) {
 		int opt;
 		enum { GETOPT_VAL_PATH_REGEX = 256 };
diff --git a/cmds-send.c b/cmds-send.c
index c5ecdaa11999..16b9f8d2bf0b 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -508,6 +508,7 @@  int cmd_send(int argc, char **argv)
 	send.dump_fd = fileno(stdout);
 	outname[0] = 0;
 
+	optind = 0;
 	while (1) {
 		enum { GETOPT_VAL_SEND_NO_DATA = 256 };
 		static const struct option long_options[] = {
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 45363a5ab3f8..e7a884af1f5d 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -102,6 +102,7 @@  static int cmd_subvol_create(int argc, char **argv)
 	struct btrfs_qgroup_inherit *inherit = NULL;
 	DIR	*dirstream = NULL;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "c:i:");
 		if (c < 0)
@@ -248,6 +249,7 @@  static int cmd_subvol_delete(int argc, char **argv)
 	enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
 	enum btrfs_util_error err;
 
+	optind = 0;
 	while (1) {
 		int c;
 		static const struct option long_options[] = {
@@ -466,6 +468,7 @@  static int cmd_subvol_list(int argc, char **argv)
 	filter_set = btrfs_list_alloc_filter_set();
 	comparer_set = btrfs_list_alloc_comparer_set();
 
+	optind = 0;
 	while(1) {
 		int c;
 		static const struct option long_options[] = {
@@ -636,6 +639,7 @@  static int cmd_subvol_snapshot(int argc, char **argv)
 	DIR *dirstream1 = NULL, *dirstream2 = NULL;
 
 	memset(&args, 0, sizeof(args));
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "c:i:r");
 		if (c < 0)
@@ -933,6 +937,7 @@  static int cmd_subvol_show(int argc, char **argv)
 	char *subvol_path = NULL;
 	enum btrfs_util_error err;
 
+	optind = 0;
 	while (1) {
 		int c;
 		static const struct option long_options[] = {
@@ -1132,6 +1137,7 @@  static int cmd_subvol_sync(int argc, char **argv)
 	int sleep_interval = 1;
 	enum btrfs_util_error err;
 
+	optind = 0;
 	while (1) {
 		int c = getopt(argc, argv, "s:");