diff options
-rw-r--r-- | coreutils/cp.c | 30 | ||||
-rw-r--r-- | coreutils/install.c | 6 | ||||
-rw-r--r-- | coreutils/mv.c | 37 | ||||
-rw-r--r-- | libbb/getopt32.c | 11 |
4 files changed, 45 insertions, 39 deletions
diff --git a/coreutils/cp.c b/coreutils/cp.c index 884fbf70f..5b575819c 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c | |||
@@ -40,12 +40,16 @@ int cp_main(int argc, char **argv) | |||
40 | OPT_L = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3), | 40 | OPT_L = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3), |
41 | }; | 41 | }; |
42 | 42 | ||
43 | // Need at least two arguments | ||
43 | // Soft- and hardlinking don't mix | 44 | // Soft- and hardlinking don't mix |
44 | // -P and -d are the same (-P is POSIX, -d is GNU) | 45 | // -P and -d are the same (-P is POSIX, -d is GNU) |
45 | // -r and -R are the same | 46 | // -r and -R are the same |
46 | // -a = -pdR | 47 | // -a = -pdR |
47 | opt_complementary = "l--s:s--l:Pd:rR:apdR"; | 48 | opt_complementary = "-2:l--s:s--l:Pd:rR:apdR"; |
48 | flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHL"); | 49 | flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHL"); |
50 | argc -= optind; | ||
51 | argv += optind; | ||
52 | flags ^= FILEUTILS_DEREFERENCE; /* The sense of this flag was reversed. */ | ||
49 | /* Default behavior of cp is to dereference, so we don't have to do | 53 | /* Default behavior of cp is to dereference, so we don't have to do |
50 | * anything special when we are given -L. | 54 | * anything special when we are given -L. |
51 | * The behavior of -H is *almost* like -L, but not quite, so let's | 55 | * The behavior of -H is *almost* like -L, but not quite, so let's |
@@ -60,19 +64,12 @@ int cp_main(int argc, char **argv) | |||
60 | } | 64 | } |
61 | #endif | 65 | #endif |
62 | 66 | ||
63 | flags ^= FILEUTILS_DEREFERENCE; /* The sense of this flag was reversed. */ | ||
64 | |||
65 | if (optind + 2 > argc) { | ||
66 | bb_show_usage(); | ||
67 | } | ||
68 | |||
69 | last = argv[argc - 1]; | 67 | last = argv[argc - 1]; |
70 | argv += optind; | ||
71 | |||
72 | /* If there are only two arguments and... */ | 68 | /* If there are only two arguments and... */ |
73 | if (optind + 2 == argc) { | 69 | if (argc == 2) { |
74 | s_flags = cp_mv_stat2(*argv, &source_stat, | 70 | s_flags = cp_mv_stat2(*argv, &source_stat, |
75 | (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); | 71 | (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); |
72 | /* TODO: does coreutils cp exit? "cp BAD GOOD dir"... */ | ||
76 | if (s_flags < 0) | 73 | if (s_flags < 0) |
77 | return EXIT_FAILURE; | 74 | return EXIT_FAILURE; |
78 | d_flags = cp_mv_stat(last, &dest_stat); | 75 | d_flags = cp_mv_stat(last, &dest_stat); |
@@ -85,19 +82,24 @@ int cp_main(int argc, char **argv) | |||
85 | ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) | 82 | ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) |
86 | ) { | 83 | ) { |
87 | /* ...do a simple copy. */ | 84 | /* ...do a simple copy. */ |
88 | dest = xstrdup(last); | 85 | dest = last; |
89 | goto DO_COPY; /* Note: optind+2==argc implies argv[1]==last below. */ | 86 | goto DO_COPY; /* NB: argc==2 -> *++argv==last */ |
90 | } | 87 | } |
91 | } | 88 | } |
92 | 89 | ||
93 | do { | 90 | while (1) { |
94 | dest = concat_path_file(last, bb_get_last_path_component(*argv)); | 91 | dest = concat_path_file(last, bb_get_last_path_component(*argv)); |
95 | DO_COPY: | 92 | DO_COPY: |
96 | if (copy_file(*argv, dest, flags) < 0) { | 93 | if (copy_file(*argv, dest, flags) < 0) { |
97 | status = 1; | 94 | status = 1; |
98 | } | 95 | } |
96 | if (*++argv == last) { | ||
97 | /* possibly leaking dest... */ | ||
98 | break; | ||
99 | } | ||
99 | free((void*)dest); | 100 | free((void*)dest); |
100 | } while (*++argv != last); | 101 | } |
101 | 102 | ||
103 | /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */ | ||
102 | return status; | 104 | return status; |
103 | } | 105 | } |
diff --git a/coreutils/install.c b/coreutils/install.c index cf62a0022..d087306d6 100644 --- a/coreutils/install.c +++ b/coreutils/install.c | |||
@@ -123,10 +123,12 @@ int install_main(int argc, char **argv) | |||
123 | copy_flags |= FILEUTILS_PRESERVE_STATUS; | 123 | copy_flags |= FILEUTILS_PRESERVE_STATUS; |
124 | } | 124 | } |
125 | mode = 0666; | 125 | mode = 0666; |
126 | if (flags & OPT_MODE) bb_parse_mode(mode_str, &mode); | 126 | if (flags & OPT_MODE) |
127 | bb_parse_mode(mode_str, &mode); | ||
127 | uid = (flags & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); | 128 | uid = (flags & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); |
128 | gid = (flags & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); | 129 | gid = (flags & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); |
129 | if (flags & (OPT_OWNER|OPT_GROUP)) umask(0); | 130 | if (flags & (OPT_OWNER|OPT_GROUP)) |
131 | umask(0); | ||
130 | 132 | ||
131 | /* Create directories | 133 | /* Create directories |
132 | * don't use bb_make_directory() as it can't change uid or gid | 134 | * don't use bb_make_directory() as it can't change uid or gid |
diff --git a/coreutils/mv.c b/coreutils/mv.c index 553bb6ecb..1d2977060 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c | |||
@@ -47,16 +47,15 @@ int mv_main(int argc, char **argv) | |||
47 | #if ENABLE_FEATURE_MV_LONG_OPTIONS | 47 | #if ENABLE_FEATURE_MV_LONG_OPTIONS |
48 | applet_long_options = mv_longopts; | 48 | applet_long_options = mv_longopts; |
49 | #endif | 49 | #endif |
50 | opt_complementary = "f-i:i-f"; | 50 | // Need at least two arguments |
51 | // -f unsets -i, -i unsets -f | ||
52 | opt_complementary = "-2:f-i:i-f"; | ||
51 | flags = getopt32(argv, "fi"); | 53 | flags = getopt32(argv, "fi"); |
52 | if (optind + 2 > argc) { | 54 | argc -= optind; |
53 | bb_show_usage(); | ||
54 | } | ||
55 | |||
56 | last = argv[argc - 1]; | ||
57 | argv += optind; | 55 | argv += optind; |
56 | last = argv[argc - 1]; | ||
58 | 57 | ||
59 | if (optind + 2 == argc) { | 58 | if (argc == 2) { |
60 | dest_exists = cp_mv_stat(last, &dest_stat); | 59 | dest_exists = cp_mv_stat(last, &dest_stat); |
61 | if (dest_exists < 0) { | 60 | if (dest_exists < 0) { |
62 | return 1; | 61 | return 1; |
@@ -75,11 +74,11 @@ int mv_main(int argc, char **argv) | |||
75 | goto RET_1; | 74 | goto RET_1; |
76 | } | 75 | } |
77 | 76 | ||
78 | DO_MOVE: | 77 | DO_MOVE: |
79 | 78 | if (dest_exists && !(flags & OPT_FILEUTILS_FORCE) | |
80 | if (dest_exists && !(flags & OPT_FILEUTILS_FORCE) && | 79 | && ((access(dest, W_OK) < 0 && isatty(0)) |
81 | ((access(dest, W_OK) < 0 && isatty(0)) || | 80 | || (flags & OPT_FILEUTILS_INTERACTIVE)) |
82 | (flags & OPT_FILEUTILS_INTERACTIVE))) { | 81 | ) { |
83 | if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { | 82 | if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { |
84 | goto RET_1; /* Ouch! fprintf failed! */ | 83 | goto RET_1; /* Ouch! fprintf failed! */ |
85 | } | 84 | } |
@@ -91,8 +90,9 @@ DO_MOVE: | |||
91 | struct stat source_stat; | 90 | struct stat source_stat; |
92 | int source_exists; | 91 | int source_exists; |
93 | 92 | ||
94 | if (errno != EXDEV || | 93 | if (errno != EXDEV |
95 | (source_exists = cp_mv_stat(*argv, &source_stat)) < 1) { | 94 | || (source_exists = cp_mv_stat(*argv, &source_stat)) < 1 |
95 | ) { | ||
96 | bb_perror_msg("cannot rename '%s'", *argv); | 96 | bb_perror_msg("cannot rename '%s'", *argv); |
97 | } else { | 97 | } else { |
98 | if (dest_exists) { | 98 | if (dest_exists) { |
@@ -116,15 +116,16 @@ DO_MOVE: | |||
116 | #if ENABLE_SELINUX | 116 | #if ENABLE_SELINUX |
117 | copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; | 117 | copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; |
118 | #endif | 118 | #endif |
119 | if ((copy_file(*argv, dest, copy_flag) >= 0) && | 119 | if ((copy_file(*argv, dest, copy_flag) >= 0) |
120 | (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)) { | 120 | && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0) |
121 | ) { | ||
121 | goto RET_0; | 122 | goto RET_0; |
122 | } | 123 | } |
123 | } | 124 | } |
124 | RET_1: | 125 | RET_1: |
125 | status = 1; | 126 | status = 1; |
126 | } | 127 | } |
127 | RET_0: | 128 | RET_0: |
128 | if (dest != last) { | 129 | if (dest != last) { |
129 | free((void *) dest); | 130 | free((void *) dest); |
130 | } | 131 | } |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 3033bf11e..bcb7ea6a0 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
@@ -178,7 +178,7 @@ Special characters: | |||
178 | This is typically used to implement "print verbose usage message | 178 | This is typically used to implement "print verbose usage message |
179 | and exit" option. | 179 | and exit" option. |
180 | 180 | ||
181 | "-" A dash between two options causes the second of the two | 181 | "a-b" A dash between two options causes the second of the two |
182 | to be unset (and ignored) if it is given on the command line. | 182 | to be unset (and ignored) if it is given on the command line. |
183 | 183 | ||
184 | [FIXME: what if they are the same? like "x-x"? Is it ever useful?] | 184 | [FIXME: what if they are the same? like "x-x"? Is it ever useful?] |
@@ -204,7 +204,7 @@ Special characters: | |||
204 | if (opt & 4) | 204 | if (opt & 4) |
205 | printf("Detected odd -x usage\n"); | 205 | printf("Detected odd -x usage\n"); |
206 | 206 | ||
207 | "--" A double dash between two options, or between an option and a group | 207 | "a--b" A double dash between two options, or between an option and a group |
208 | of options, means that they are mutually exclusive. Unlike | 208 | of options, means that they are mutually exclusive. Unlike |
209 | the "-" case above, an error will be forced if the options | 209 | the "-" case above, an error will be forced if the options |
210 | are used together. | 210 | are used together. |
@@ -220,7 +220,7 @@ Special characters: | |||
220 | "x--x" Variation of the above, it means that -x option should occur | 220 | "x--x" Variation of the above, it means that -x option should occur |
221 | at most once. | 221 | at most once. |
222 | 222 | ||
223 | "::" A double colon after a char in opt_complementary means that the | 223 | "a::" A double colon after a char in opt_complementary means that the |
224 | option can occur multiple times. Each occurrence will be saved as | 224 | option can occur multiple times. Each occurrence will be saved as |
225 | a llist_t element instead of char*. | 225 | a llist_t element instead of char*. |
226 | 226 | ||
@@ -240,7 +240,7 @@ Special characters: | |||
240 | root:x:0:0:root:/root:/bin/bash | 240 | root:x:0:0:root:/root:/bin/bash |
241 | user:x:500:500::/home/user:/bin/bash | 241 | user:x:500:500::/home/user:/bin/bash |
242 | 242 | ||
243 | "?" An "?" between an option and a group of options means that | 243 | "a?b" A "?" between an option and a group of options means that |
244 | at least one of them is required to occur if the first option | 244 | at least one of them is required to occur if the first option |
245 | occurs in preceding command line arguments. | 245 | occurs in preceding command line arguments. |
246 | 246 | ||
@@ -259,7 +259,7 @@ Special characters: | |||
259 | For example from "start-stop-daemon" applet: | 259 | For example from "start-stop-daemon" applet: |
260 | 260 | ||
261 | // Don't allow -KS -SK, but -S or -K is required | 261 | // Don't allow -KS -SK, but -S or -K is required |
262 | opt_complementary = "K:S:?K--S:S--K"; | 262 | opt_complementary = "K:S:K--S:S--K"; |
263 | flags = getopt32(argv, "KS...); | 263 | flags = getopt32(argv, "KS...); |
264 | 264 | ||
265 | 265 | ||
@@ -268,6 +268,7 @@ Special characters: | |||
268 | max 3 args; count uses of '-2'; min 2 args; if there is | 268 | max 3 args; count uses of '-2'; min 2 args; if there is |
269 | a '-2' option then unset '-3', '-X' and '-a'; if there is | 269 | a '-2' option then unset '-3', '-X' and '-a'; if there is |
270 | a '-2' and after it a '-x' then error out. | 270 | a '-2' and after it a '-x' then error out. |
271 | But it's far too obfuscated. Use ':' to separate groups. | ||
271 | */ | 272 | */ |
272 | 273 | ||
273 | /* Code here assumes that 'unsigned' is at least 32 bits wide */ | 274 | /* Code here assumes that 'unsigned' is at least 32 bits wide */ |