chattr: fix option parsing to accept more cryptic option combos
function old new delta chattr_main 286 289 +3 packed_usage 31793 31761 -32 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		| @@ -20,9 +20,12 @@ | ||||
| //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o | ||||
|  | ||||
| //usage:#define chattr_trivial_usage | ||||
| //usage:       "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..." | ||||
| //usage:       "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..." | ||||
| //usage:#define chattr_full_usage "\n\n" | ||||
| //usage:       "Change ext2 file attributes\n" | ||||
| //usage:     "\n	-R	Recurse" | ||||
| //usage:     "\n	-v VER	Set version/generation number" | ||||
| //-V, -f accepted but ignored | ||||
| //usage:     "\nModifiers:" | ||||
| //usage:     "\n	-,+,=	Remove/add/set attributes" | ||||
| //usage:     "\nAttributes:" | ||||
| @@ -37,8 +40,6 @@ | ||||
| //usage:     "\n	S	Write synchronously" | ||||
| //usage:     "\n	t	Disable tail-merging of partial blocks with other files" | ||||
| //usage:     "\n	u	Allow file to be undeleted" | ||||
| //usage:     "\n	-R	Recurse" | ||||
| //usage:     "\n	-v VER	Set version/generation number" | ||||
|  | ||||
| #include "libbb.h" | ||||
| #include "e2fs_lib.h" | ||||
| @@ -52,7 +53,7 @@ struct globals { | ||||
| 	unsigned long version; | ||||
| 	unsigned long af; | ||||
| 	unsigned long rf; | ||||
| 	smallint flags; | ||||
| 	int flags; | ||||
| 	smallint recursive; | ||||
| }; | ||||
|  | ||||
| @@ -64,10 +65,11 @@ static unsigned long get_flag(char c) | ||||
| 	bb_show_usage(); | ||||
| } | ||||
|  | ||||
| static int decode_arg(const char *arg, struct globals *gp) | ||||
| static char** decode_arg(char **argv, struct globals *gp) | ||||
| { | ||||
| 	unsigned long *fl; | ||||
| 	char opt = *arg++; | ||||
| 	const char *arg = *argv; | ||||
| 	char opt = *arg; | ||||
|  | ||||
| 	fl = &gp->af; | ||||
| 	if (opt == '-') { | ||||
| @@ -75,15 +77,43 @@ static int decode_arg(const char *arg, struct globals *gp) | ||||
| 		fl = &gp->rf; | ||||
| 	} else if (opt == '+') { | ||||
| 		gp->flags |= OPT_ADD; | ||||
| 	} else if (opt == '=') { | ||||
| 	} else { /* if (opt == '=') */ | ||||
| 		gp->flags |= OPT_SET; | ||||
| 	} else | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while (*arg) | ||||
| 		*fl |= get_flag(*arg++); | ||||
| 	while (*++arg) { | ||||
| 		if (opt == '-') { | ||||
| //e2fsprogs-1.43.1 accepts: | ||||
| // "-RRR", "-RRRv VER" and even "-ARRRva VER" and "-vvv V1 V2 V3" | ||||
| // but not "-vVER". | ||||
| // IOW: options are parsed as part of "remove attrs" strings, | ||||
| // if "v" is seen, next argv[] is VER, even if more opts/attrs follow in this argv[]! | ||||
| 			if (*arg == 'R') { | ||||
| 				gp->recursive = 1; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (*arg == 'V') { | ||||
| 				/*"verbose and print program version" (nop for now) */; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (*arg == 'f') { | ||||
| 				/*"suppress most error messages" (nop) */; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (*arg == 'v') { | ||||
| 				if (!*++argv) | ||||
| 					bb_show_usage(); | ||||
| 				gp->version = xatoul(*argv); | ||||
| 				gp->flags |= OPT_SET_VER; | ||||
| 				continue; | ||||
| 			} | ||||
| //TODO: "-p PROJECT_NUM" ? | ||||
| 			/* not a known option, try as an attribute */ | ||||
| 		} | ||||
| 		*fl |= get_flag(*arg); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| 	return argv; | ||||
| } | ||||
|  | ||||
| static void change_attributes(const char *name, struct globals *gp); | ||||
| @@ -133,7 +163,7 @@ static void change_attributes(const char *name, struct globals *gp) | ||||
| 			fsflags &= ~gp->rf; | ||||
| 		/*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ | ||||
| 			fsflags |= gp->af; | ||||
| 		/* What is this? And why it's not done for SET case? */ | ||||
| // What is this? And why it's not done for SET case? | ||||
| 		if (!S_ISDIR(st.st_mode)) | ||||
| 			fsflags &= ~EXT2_DIRSYNC_FL; | ||||
| 	} | ||||
| @@ -149,36 +179,22 @@ int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||||
| int chattr_main(int argc UNUSED_PARAM, char **argv) | ||||
| { | ||||
| 	struct globals g; | ||||
| 	char *arg; | ||||
|  | ||||
| 	memset(&g, 0, sizeof(g)); | ||||
|  | ||||
| 	/* parse the args */ | ||||
| 	while ((arg = *++argv)) { | ||||
| 		/* take care of -R and -v <version> */ | ||||
| 		if (arg[0] == '-' | ||||
| 		 && (arg[1] == 'R' || arg[1] == 'v') | ||||
| 		 && !arg[2] | ||||
| 		) { | ||||
| 			if (arg[1] == 'R') { | ||||
| 				g.recursive = 1; | ||||
| 				continue; | ||||
| 			} | ||||
| 			/* arg[1] == 'v' */ | ||||
| 			if (!*++argv) | ||||
| 				bb_show_usage(); | ||||
| 			g.version = xatoul(*argv); | ||||
| 			g.flags |= OPT_SET_VER; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!decode_arg(arg, &g)) | ||||
| 	for (;;) { | ||||
| 		char *arg = *++argv; | ||||
| 		if (!arg) | ||||
| 			bb_show_usage(); | ||||
| 		if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=') | ||||
| 			break; | ||||
|  | ||||
| 		argv = decode_arg(argv, &g); | ||||
| 	} | ||||
| 	/* note: on loop exit, remaining argv[] is never empty */ | ||||
|  | ||||
| 	/* run sanity checks on all the arguments given us */ | ||||
| 	if (!*argv) | ||||
| 		bb_show_usage(); | ||||
| 	if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) | ||||
| 		bb_error_msg_and_die("= is incompatible with - and +"); | ||||
| 	if (g.rf & g.af) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user