source: MondoRescue/branches/stable/mindi-busybox/libbb/getopt32.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

  • Property svn:eol-style set to native
File size: 16.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * universal getopt32 implementation for busybox
4 *
5 * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <getopt.h>
11#include "libbb.h"
12
13/* Documentation
14
15uint32_t
16getopt32(char **argv, const char *applet_opts, ...)
17
18 The command line options must be declared in const char
19 *applet_opts as a string of chars, for example:
20
21 flags = getopt32(argv, "rnug");
22
23 If one of the given options is found, a flag value is added to
24 the return value (an unsigned long).
25
26 The flag value is determined by the position of the char in
27 applet_opts string. For example, in the above case:
28
29 flags = getopt32(argv, "rnug");
30
31 "r" will add 1 (bit 0)
32 "n" will add 2 (bit 1)
33 "u will add 4 (bit 2)
34 "g" will add 8 (bit 3)
35
36 and so on. You can also look at the return value as a bit
37 field and each option sets one bit.
38
39 On exit, global variable optind is set so that if you
40 will do argc -= optind; argv += optind; then
41 argc will be equal to number of remaining non-option
42 arguments, first one would be in argv[0], next in argv[1] and so on
43 (options and their parameters will be moved into argv[]
44 positions prior to argv[optind]).
45
46 ":" If one of the options requires an argument, then add a ":"
47 after the char in applet_opts and provide a pointer to store
48 the argument. For example:
49
50 char *pointer_to_arg_for_a;
51 char *pointer_to_arg_for_b;
52 char *pointer_to_arg_for_c;
53 char *pointer_to_arg_for_d;
54
55 flags = getopt32(argv, "a:b:c:d:",
56 &pointer_to_arg_for_a, &pointer_to_arg_for_b,
57 &pointer_to_arg_for_c, &pointer_to_arg_for_d);
58
59 The type of the pointer (char* or llist_t*) may be controlled
60 by the "::" special separator that is set in the external string
61 opt_complementary (see below for more info).
62
63 "::" If option can have an *optional* argument, then add a "::"
64 after its char in applet_opts and provide a pointer to store
65 the argument. Note that optional arguments _must_
66 immediately follow the option: -oparam, not -o param.
67
68 "+" If the first character in the applet_opts string is a plus,
69 then option processing will stop as soon as a non-option is
70 encountered in the argv array. Useful for applets like env
71 which should not process arguments to subprograms:
72 env -i ls -d /
73 Here we want env to process just the '-i', not the '-d'.
74
75const char *applet_long_options
76
77 This struct allows you to define long options:
78
79 static const char applet_longopts[] ALIGN1 =
80 //"name\0" has_arg val
81 "verbose\0" No_argument "v"
82 ;
83 applet_long_options = applet_longopts;
84
85 The last member of struct option (val) typically is set to
86 matching short option from applet_opts. If there is no matching
87 char in applet_opts, then:
88 - return bit have next position after short options
89 - if has_arg is not "No_argument", use ptr for arg also
90 - opt_complementary affects it too
91
92 Note: a good applet will make long options configurable via the
93 config process and not a required feature. The current standard
94 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
95
96const char *opt_complementary
97
98 ":" The colon (":") is used to separate groups of two or more chars
99 and/or groups of chars and special characters (stating some
100 conditions to be checked).
101
102 "abc" If groups of two or more chars are specified, the first char
103 is the main option and the other chars are secondary options.
104 Their flags will be turned on if the main option is found even
105 if they are not specifed on the command line. For example:
106
107 opt_complementary = "abc";
108 flags = getopt32(argv, "abcd")
109
110 If getopt() finds "-a" on the command line, then
111 getopt32's return value will be as if "-a -b -c" were
112 found.
113
114 "ww" Adjacent double options have a counter associated which indicates
115 the number of occurences of the option.
116 For example the ps applet needs:
117 if w is given once, GNU ps sets the width to 132,
118 if w is given more than once, it is "unlimited"
119
120 int w_counter = 0;
121 opt_complementary = "ww";
122 getopt32(argv, "w", &w_counter);
123 if (w_counter)
124 width = (w_counter == 1) ? 132 : INT_MAX;
125 else
126 get_terminal_width(...&width...);
127
128 w_counter is a pointer to an integer. It has to be passed to
129 getopt32() after all other option argument sinks.
130
131 For example: accept multiple -v to indicate the level of verbosity
132 and for each -b optarg, add optarg to my_b. Finally, if b is given,
133 turn off c and vice versa:
134
135 llist_t *my_b = NULL;
136 int verbose_level = 0;
137 opt_complementary = "vv:b::b-c:c-b";
138 f = getopt32(argv, "vb:c", &my_b, &verbose_level);
139 if (f & 2) // -c after -b unsets -b flag
140 while (my_b) { dosomething_with(my_b->data); my_b = my_b->link; }
141 if (my_b) // but llist is stored if -b is specified
142 free_llist(my_b);
143 if (verbose_level) printf("verbose level is %d\n", verbose_level);
144
145Special characters:
146
147 "-" A dash as the first char in a opt_complementary group forces
148 all arguments to be treated as options, even if they have
149 no leading dashes. Next char in this case can't be a digit (0-9),
150 use ':' or end of line. For example:
151
152 opt_complementary = "-:w-x:x-w";
153 getopt32(argv, "wx");
154
155 Allows any arguments to be given without a dash (./program w x)
156 as well as with a dash (./program -x).
157
158 "--" A double dash at the beginning of opt_complementary means the
159 argv[1] string should always be treated as options, even if it isn't
160 prefixed with a "-". This is useful for special syntax in applets
161 such as "ar" and "tar":
162 tar xvf foo.tar
163
164 "-N" A dash as the first char in a opt_complementary group followed
165 by a single digit (0-9) means that at least N non-option
166 arguments must be present on the command line
167
168 "=N" An equal sign as the first char in a opt_complementary group followed
169 by a single digit (0-9) means that exactly N non-option
170 arguments must be present on the command line
171
172 "?N" A "?" as the first char in a opt_complementary group followed
173 by a single digit (0-9) means that at most N arguments must be present
174 on the command line.
175
176 "V-" An option with dash before colon or end-of-line results in
177 bb_show_usage being called if this option is encountered.
178 This is typically used to implement "print verbose usage message
179 and exit" option.
180
181 "-" 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.
183
184 [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
185
186 For example:
187 The du applet has the options "-s" and "-d depth". If
188 getopt32 finds -s, then -d is unset or if it finds -d
189 then -s is unset. (Note: busybox implements the GNU
190 "--max-depth" option as "-d".) To obtain this behavior, you
191 set opt_complementary = "s-d:d-s". Only one flag value is
192 added to getopt32's return value depending on the
193 position of the options on the command line. If one of the
194 two options requires an argument pointer (":" in applet_opts
195 as in "d:") optarg is set accordingly.
196
197 char *smax_print_depth;
198
199 opt_complementary = "s-d:d-s:x-x";
200 opt = getopt32(argv, "sd:x", &smax_print_depth);
201
202 if (opt & 2)
203 max_print_depth = atoi(smax_print_depth);
204 if (opt & 4)
205 printf("Detected odd -x usage\n");
206
207 "--" A double dash between two options, or between an option and a group
208 of options, means that they are mutually exclusive. Unlike
209 the "-" case above, an error will be forced if the options
210 are used together.
211
212 For example:
213 The cut applet must have only one type of list specified, so
214 -b, -c and -f are mutually exclusive and should raise an error
215 if specified together. In this case you must set
216 opt_complementary = "b--cf:c--bf:f--bc". If two of the
217 mutually exclusive options are found, getopt32 will call
218 bb_show_usage() and die.
219
220 "x--x" Variation of the above, it means that -x option should occur
221 at most once.
222
223 "::" A double colon after a char in opt_complementary means that the
224 option can occur multiple times. Each occurrence will be saved as
225 a llist_t element instead of char*.
226
227 For example:
228 The grep applet can have one or more "-e pattern" arguments.
229 In this case you should use getopt32() as follows:
230
231 llist_t *patterns = NULL;
232
233 (this pointer must be initializated to NULL if the list is empty
234 as required by llist_add_to_end(llist_t **old_head, char *new_item).)
235
236 opt_complementary = "e::";
237
238 getopt32(argv, "e:", &patterns);
239 $ grep -e user -e root /etc/passwd
240 root:x:0:0:root:/root:/bin/bash
241 user:x:500:500::/home/user:/bin/bash
242
243 "?" An "?" between an option and a group of options means that
244 at least one of them is required to occur if the first option
245 occurs in preceding command line arguments.
246
247 For example from "id" applet:
248
249 // Don't allow -n -r -rn -ug -rug -nug -rnug
250 opt_complementary = "r?ug:n?ug:?u--g:g--u";
251 flags = getopt32(argv, "rnug");
252
253 This example allowed only:
254 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
255
256 "X" A opt_complementary group with just a single letter means
257 that this option is required. If more than one such group exists,
258 at least one option is required to occur (not all of them).
259 For example from "start-stop-daemon" applet:
260
261 // Don't allow -KS -SK, but -S or -K is required
262 opt_complementary = "K:S:?K--S:S--K";
263 flags = getopt32(argv, "KS...);
264
265
266 Don't forget to use ':'. For example, "?322-22-23X-x-a"
267 is interpreted as "?3:22:-2:2-2:2-3Xa:2--x" -
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
270 a '-2' and after it a '-x' then error out.
271*/
272
273/* Code here assumes that 'unsigned' is at least 32 bits wide */
274
275const char *opt_complementary;
276
277typedef struct {
278 int opt;
279 int list_flg;
280 unsigned switch_on;
281 unsigned switch_off;
282 unsigned incongruously;
283 unsigned requires;
284 void **optarg; /* char **optarg or llist_t **optarg */
285 int *counter;
286} t_complementary;
287
288/* You can set applet_long_options for parse called long options */
289#if ENABLE_GETOPT_LONG
290static const struct option bb_null_long_options[1] = {
291 { 0, 0, 0, 0 }
292};
293const char *applet_long_options;
294#endif
295
296uint32_t option_mask32;
297
298uint32_t
299getopt32(char **argv, const char *applet_opts, ...)
300{
301 int argc;
302 unsigned flags = 0;
303 unsigned requires = 0;
304 t_complementary complementary[33];
305 int c;
306 const unsigned char *s;
307 t_complementary *on_off;
308 va_list p;
309#if ENABLE_GETOPT_LONG
310 const struct option *l_o;
311 struct option *long_options = (struct option *) &bb_null_long_options;
312#endif
313 unsigned trigger;
314 char **pargv = NULL;
315 int min_arg = 0;
316 int max_arg = -1;
317
318#define SHOW_USAGE_IF_ERROR 1
319#define ALL_ARGV_IS_OPTS 2
320#define FIRST_ARGV_IS_OPT 4
321#define FREE_FIRST_ARGV_IS_OPT 8
322 int spec_flgs = 0;
323
324 argc = 0;
325 while (argv[argc])
326 argc++;
327
328 va_start(p, applet_opts);
329
330 c = 0;
331 on_off = complementary;
332 memset(on_off, 0, sizeof(complementary));
333
334 /* skip GNU extension */
335 s = (const unsigned char *)applet_opts;
336 if (*s == '+' || *s == '-')
337 s++;
338 while (*s) {
339 if (c >= 32) break;
340 on_off->opt = *s;
341 on_off->switch_on = (1 << c);
342 if (*++s == ':') {
343 on_off->optarg = va_arg(p, void **);
344 while (*++s == ':') /* skip */;
345 }
346 on_off++;
347 c++;
348 }
349
350#if ENABLE_GETOPT_LONG
351 if (applet_long_options) {
352 const char *optstr;
353 unsigned i, count;
354
355 count = 1;
356 optstr = applet_long_options;
357 while (optstr[0]) {
358 optstr += strlen(optstr) + 3; /* skip NUL, has_arg, val */
359 count++;
360 }
361 /* count == no. of longopts + 1 */
362 long_options = alloca(count * sizeof(*long_options));
363 memset(long_options, 0, count * sizeof(*long_options));
364 i = 0;
365 optstr = applet_long_options;
366 while (--count) {
367 long_options[i].name = optstr;
368 optstr += strlen(optstr) + 1;
369 long_options[i].has_arg = (unsigned char)(*optstr++);
370 /* long_options[i].flag = NULL; */
371 long_options[i].val = (unsigned char)(*optstr++);
372 i++;
373 }
374 for (l_o = long_options; l_o->name; l_o++) {
375 if (l_o->flag)
376 continue;
377 for (on_off = complementary; on_off->opt != 0; on_off++)
378 if (on_off->opt == l_o->val)
379 goto next_long;
380 if (c >= 32) break;
381 on_off->opt = l_o->val;
382 on_off->switch_on = (1 << c);
383 if (l_o->has_arg != no_argument)
384 on_off->optarg = va_arg(p, void **);
385 c++;
386 next_long: ;
387 }
388 }
389#endif /* ENABLE_GETOPT_LONG */
390 for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
391 t_complementary *pair;
392 unsigned *pair_switch;
393
394 if (*s == ':')
395 continue;
396 c = s[1];
397 if (*s == '?') {
398 if (c < '0' || c > '9') {
399 spec_flgs |= SHOW_USAGE_IF_ERROR;
400 } else {
401 max_arg = c - '0';
402 s++;
403 }
404 continue;
405 }
406 if (*s == '-') {
407 if (c < '0' || c > '9') {
408 if (c == '-') {
409 spec_flgs |= FIRST_ARGV_IS_OPT;
410 s++;
411 } else
412 spec_flgs |= ALL_ARGV_IS_OPTS;
413 } else {
414 min_arg = c - '0';
415 s++;
416 }
417 continue;
418 }
419 if (*s == '=') {
420 min_arg = max_arg = c - '0';
421 s++;
422 continue;
423 }
424 for (on_off = complementary; on_off->opt; on_off++)
425 if (on_off->opt == *s)
426 break;
427 if (c == ':' && s[2] == ':') {
428 on_off->list_flg++;
429 continue;
430 }
431 if (c == ':' || c == '\0') {
432 requires |= on_off->switch_on;
433 continue;
434 }
435 if (c == '-' && (s[2] == ':' || s[2] == '\0')) {
436 flags |= on_off->switch_on;
437 on_off->incongruously |= on_off->switch_on;
438 s++;
439 continue;
440 }
441 if (c == *s) {
442 on_off->counter = va_arg(p, int *);
443 s++;
444 }
445 pair = on_off;
446 pair_switch = &(pair->switch_on);
447 for (s++; *s && *s != ':'; s++) {
448 if (*s == '?') {
449 pair_switch = &(pair->requires);
450 } else if (*s == '-') {
451 if (pair_switch == &(pair->switch_off))
452 pair_switch = &(pair->incongruously);
453 else
454 pair_switch = &(pair->switch_off);
455 } else {
456 for (on_off = complementary; on_off->opt; on_off++)
457 if (on_off->opt == *s) {
458 *pair_switch |= on_off->switch_on;
459 break;
460 }
461 }
462 }
463 s--;
464 }
465 va_end(p);
466
467 if (spec_flgs & FIRST_ARGV_IS_OPT) {
468 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
469 argv[1] = xasprintf("-%s", argv[1]);
470 if (ENABLE_FEATURE_CLEAN_UP)
471 spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
472 }
473 }
474
475 /* In case getopt32 was already called, reinit some state */
476 optind = 1;
477 /* optarg = NULL; opterr = 0; optopt = 0; ?? */
478
479 /* Note: just "getopt() <= 0" will not work good for
480 * "fake" short options, like this one:
481 * wget $'-\203' "Test: test" http://kernel.org/
482 * (supposed to act as --header, but doesn't) */
483#if ENABLE_GETOPT_LONG
484 while ((c = getopt_long(argc, argv, applet_opts,
485 long_options, NULL)) != -1) {
486#else
487 while ((c = getopt(argc, argv, applet_opts)) != -1) {
488#endif
489 c &= 0xff; /* fight libc's sign extends */
490 loop_arg_is_opt:
491 for (on_off = complementary; on_off->opt != c; on_off++) {
492 /* c==0 if long opt have non NULL flag */
493 if (on_off->opt == 0 && c != 0)
494 bb_show_usage();
495 }
496 if (flags & on_off->incongruously)
497 bb_show_usage();
498 trigger = on_off->switch_on & on_off->switch_off;
499 flags &= ~(on_off->switch_off ^ trigger);
500 flags |= on_off->switch_on ^ trigger;
501 flags ^= trigger;
502 if (on_off->counter)
503 (*(on_off->counter))++;
504 if (on_off->list_flg) {
505 llist_add_to_end((llist_t **)(on_off->optarg), optarg);
506 } else if (on_off->optarg) {
507 *(char **)(on_off->optarg) = optarg;
508 }
509 if (pargv != NULL)
510 break;
511 }
512
513 if (spec_flgs & ALL_ARGV_IS_OPTS) {
514 /* process argv is option, for example "ps" applet */
515 if (pargv == NULL)
516 pargv = argv + optind;
517 while (*pargv) {
518 c = **pargv;
519 if (c == '\0') {
520 pargv++;
521 } else {
522 (*pargv)++;
523 goto loop_arg_is_opt;
524 }
525 }
526 }
527
528#if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP
529 if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)
530 free(argv[1]);
531#endif
532 /* check depending requires for given options */
533 for (on_off = complementary; on_off->opt; on_off++) {
534 if (on_off->requires && (flags & on_off->switch_on) &&
535 (flags & on_off->requires) == 0)
536 bb_show_usage();
537 }
538 if (requires && (flags & requires) == 0)
539 bb_show_usage();
540 argc -= optind;
541 if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
542 bb_show_usage();
543
544 option_mask32 = flags;
545 return flags;
546}
Note: See TracBrowser for help on using the repository browser.