aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-05 20:33:48 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-05 20:33:48 +0200
commitd3147cd5c38d9f232a9e279562129157e871d1ee (patch)
treeec99377ed27da2f8510a966b4e94425fa38b3bec
parentcaf26b36f3c11f6b5c8f8ab2bf829d14e4e6980e (diff)
downloadbusybox-w32-d3147cd5c38d9f232a9e279562129157e871d1ee.tar.gz
busybox-w32-d3147cd5c38d9f232a9e279562129157e871d1ee.tar.bz2
busybox-w32-d3147cd5c38d9f232a9e279562129157e871d1ee.zip
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>
-rw-r--r--e2fsprogs/chattr.c86
1 files changed, 51 insertions, 35 deletions
diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c
index 72327d728..bb870a990 100644
--- a/e2fsprogs/chattr.c
+++ b/e2fsprogs/chattr.c
@@ -20,9 +20,12 @@
20//kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o 20//kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
21 21
22//usage:#define chattr_trivial_usage 22//usage:#define chattr_trivial_usage
23//usage: "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..." 23//usage: "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..."
24//usage:#define chattr_full_usage "\n\n" 24//usage:#define chattr_full_usage "\n\n"
25//usage: "Change ext2 file attributes\n" 25//usage: "Change ext2 file attributes\n"
26//usage: "\n -R Recurse"
27//usage: "\n -v VER Set version/generation number"
28//-V, -f accepted but ignored
26//usage: "\nModifiers:" 29//usage: "\nModifiers:"
27//usage: "\n -,+,= Remove/add/set attributes" 30//usage: "\n -,+,= Remove/add/set attributes"
28//usage: "\nAttributes:" 31//usage: "\nAttributes:"
@@ -37,8 +40,6 @@
37//usage: "\n S Write synchronously" 40//usage: "\n S Write synchronously"
38//usage: "\n t Disable tail-merging of partial blocks with other files" 41//usage: "\n t Disable tail-merging of partial blocks with other files"
39//usage: "\n u Allow file to be undeleted" 42//usage: "\n u Allow file to be undeleted"
40//usage: "\n -R Recurse"
41//usage: "\n -v VER Set version/generation number"
42 43
43#include "libbb.h" 44#include "libbb.h"
44#include "e2fs_lib.h" 45#include "e2fs_lib.h"
@@ -52,7 +53,7 @@ struct globals {
52 unsigned long version; 53 unsigned long version;
53 unsigned long af; 54 unsigned long af;
54 unsigned long rf; 55 unsigned long rf;
55 smallint flags; 56 int flags;
56 smallint recursive; 57 smallint recursive;
57}; 58};
58 59
@@ -64,10 +65,11 @@ static unsigned long get_flag(char c)
64 bb_show_usage(); 65 bb_show_usage();
65} 66}
66 67
67static int decode_arg(const char *arg, struct globals *gp) 68static char** decode_arg(char **argv, struct globals *gp)
68{ 69{
69 unsigned long *fl; 70 unsigned long *fl;
70 char opt = *arg++; 71 const char *arg = *argv;
72 char opt = *arg;
71 73
72 fl = &gp->af; 74 fl = &gp->af;
73 if (opt == '-') { 75 if (opt == '-') {
@@ -75,15 +77,43 @@ static int decode_arg(const char *arg, struct globals *gp)
75 fl = &gp->rf; 77 fl = &gp->rf;
76 } else if (opt == '+') { 78 } else if (opt == '+') {
77 gp->flags |= OPT_ADD; 79 gp->flags |= OPT_ADD;
78 } else if (opt == '=') { 80 } else { /* if (opt == '=') */
79 gp->flags |= OPT_SET; 81 gp->flags |= OPT_SET;
80 } else 82 }
81 return 0;
82 83
83 while (*arg) 84 while (*++arg) {
84 *fl |= get_flag(*arg++); 85 if (opt == '-') {
86//e2fsprogs-1.43.1 accepts:
87// "-RRR", "-RRRv VER" and even "-ARRRva VER" and "-vvv V1 V2 V3"
88// but not "-vVER".
89// IOW: options are parsed as part of "remove attrs" strings,
90// if "v" is seen, next argv[] is VER, even if more opts/attrs follow in this argv[]!
91 if (*arg == 'R') {
92 gp->recursive = 1;
93 continue;
94 }
95 if (*arg == 'V') {
96 /*"verbose and print program version" (nop for now) */;
97 continue;
98 }
99 if (*arg == 'f') {
100 /*"suppress most error messages" (nop) */;
101 continue;
102 }
103 if (*arg == 'v') {
104 if (!*++argv)
105 bb_show_usage();
106 gp->version = xatoul(*argv);
107 gp->flags |= OPT_SET_VER;
108 continue;
109 }
110//TODO: "-p PROJECT_NUM" ?
111 /* not a known option, try as an attribute */
112 }
113 *fl |= get_flag(*arg);
114 }
85 115
86 return 1; 116 return argv;
87} 117}
88 118
89static void change_attributes(const char *name, struct globals *gp); 119static void change_attributes(const char *name, struct globals *gp);
@@ -133,7 +163,7 @@ static void change_attributes(const char *name, struct globals *gp)
133 fsflags &= ~gp->rf; 163 fsflags &= ~gp->rf;
134 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ 164 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
135 fsflags |= gp->af; 165 fsflags |= gp->af;
136 /* What is this? And why it's not done for SET case? */ 166// What is this? And why it's not done for SET case?
137 if (!S_ISDIR(st.st_mode)) 167 if (!S_ISDIR(st.st_mode))
138 fsflags &= ~EXT2_DIRSYNC_FL; 168 fsflags &= ~EXT2_DIRSYNC_FL;
139 } 169 }
@@ -149,36 +179,22 @@ int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
149int chattr_main(int argc UNUSED_PARAM, char **argv) 179int chattr_main(int argc UNUSED_PARAM, char **argv)
150{ 180{
151 struct globals g; 181 struct globals g;
152 char *arg;
153 182
154 memset(&g, 0, sizeof(g)); 183 memset(&g, 0, sizeof(g));
155 184
156 /* parse the args */ 185 /* parse the args */
157 while ((arg = *++argv)) { 186 for (;;) {
158 /* take care of -R and -v <version> */ 187 char *arg = *++argv;
159 if (arg[0] == '-' 188 if (!arg)
160 && (arg[1] == 'R' || arg[1] == 'v') 189 bb_show_usage();
161 && !arg[2] 190 if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=')
162 ) {
163 if (arg[1] == 'R') {
164 g.recursive = 1;
165 continue;
166 }
167 /* arg[1] == 'v' */
168 if (!*++argv)
169 bb_show_usage();
170 g.version = xatoul(*argv);
171 g.flags |= OPT_SET_VER;
172 continue;
173 }
174
175 if (!decode_arg(arg, &g))
176 break; 191 break;
192
193 argv = decode_arg(argv, &g);
177 } 194 }
195 /* note: on loop exit, remaining argv[] is never empty */
178 196
179 /* run sanity checks on all the arguments given us */ 197 /* run sanity checks on all the arguments given us */
180 if (!*argv)
181 bb_show_usage();
182 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) 198 if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM)))
183 bb_error_msg_and_die("= is incompatible with - and +"); 199 bb_error_msg_and_die("= is incompatible with - and +");
184 if (g.rf & g.af) 200 if (g.rf & g.af)