diff options
author | Rob Landley <rob@landley.net> | 2005-09-04 11:10:37 +0000 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2005-09-04 11:10:37 +0000 |
commit | b766c394569cce356fceb63d83da79581c0997b9 (patch) | |
tree | a1c4cd18cede88c2e18a6e22f0b59924d5838682 | |
parent | 9754b91c16288fd0f4d6301fd6d01aa8b3c3b1d9 (diff) | |
download | busybox-w32-b766c394569cce356fceb63d83da79581c0997b9.tar.gz busybox-w32-b766c394569cce356fceb63d83da79581c0997b9.tar.bz2 busybox-w32-b766c394569cce356fceb63d83da79581c0997b9.zip |
General cleanup of command line parsing to allow "busybox" to work as a prefix.
(I.E. any argv[0] that starts with "busybox" winds up in busybox_main().)
Added testing/busybox.tests which tests the following permutations:
./busybox
./busybox-suffix
./busybox cat
./busybox-suffix cat
./busybox --help
./busybox-suffix --help
./busybox --help cat
./busybox-suffix --help cat
./busybox --help unknown
./busybox-suffix --help unknown
./unknown
Also repair the test suite so ./runtest calls the ".tests" scripts properly.
Note: you can now go "busybox busybox busbox ls -l" and it'll take it. The
new code is pretty generic. I can block that if anybody can come up with a
good reason to...
-rw-r--r-- | applets/applets.c | 52 | ||||
-rw-r--r-- | applets/busybox.c | 129 | ||||
-rwxr-xr-x | testsuite/busybox.tests | 123 | ||||
-rwxr-xr-x | testsuite/runtest | 4 | ||||
-rwxr-xr-x | testsuite/testing.sh | 4 |
5 files changed, 185 insertions, 127 deletions
diff --git a/applets/applets.c b/applets/applets.c index ce9ecbbc5..21b0c3dbc 100644 --- a/applets/applets.c +++ b/applets/applets.c | |||
@@ -90,8 +90,7 @@ static int suid_cfg_readable; | |||
90 | 90 | ||
91 | 91 | ||
92 | 92 | ||
93 | extern void | 93 | extern void bb_show_usage (void) |
94 | bb_show_usage (void) | ||
95 | { | 94 | { |
96 | const char *format_string; | 95 | const char *format_string; |
97 | const char *usage_string = usage_messages; | 96 | const char *usage_string = usage_messages; |
@@ -112,8 +111,7 @@ bb_show_usage (void) | |||
112 | exit (EXIT_FAILURE); | 111 | exit (EXIT_FAILURE); |
113 | } | 112 | } |
114 | 113 | ||
115 | static int | 114 | static int applet_name_compare (const void *x, const void *y) |
116 | applet_name_compare (const void *x, const void *y) | ||
117 | { | 115 | { |
118 | const char *name = x; | 116 | const char *name = x; |
119 | const struct BB_applet *applet = y; | 117 | const struct BB_applet *applet = y; |
@@ -123,47 +121,25 @@ applet_name_compare (const void *x, const void *y) | |||
123 | 121 | ||
124 | extern const size_t NUM_APPLETS; | 122 | extern const size_t NUM_APPLETS; |
125 | 123 | ||
126 | struct BB_applet * | 124 | struct BB_applet *find_applet_by_name (const char *name) |
127 | find_applet_by_name (const char *name) | ||
128 | { | 125 | { |
129 | return bsearch (name, applets, NUM_APPLETS, sizeof (struct BB_applet), | 126 | return bsearch (name, applets, NUM_APPLETS, sizeof (struct BB_applet), |
130 | applet_name_compare); | 127 | applet_name_compare); |
131 | } | 128 | } |
132 | 129 | ||
133 | void | 130 | void run_applet_by_name (const char *name, int argc, char **argv) |
134 | run_applet_by_name (const char *name, int argc, char **argv) | ||
135 | { | 131 | { |
136 | static int recurse_level = 0; | 132 | if(ENABLE_FEATURE_SUID_CONFIG) parse_config_file (); |
137 | extern int been_there_done_that; /* From busybox.c */ | 133 | |
138 | 134 | if(!strncmp(name, "busybox", 7)) busybox_main(argc, argv); | |
139 | #ifdef CONFIG_FEATURE_SUID_CONFIG | 135 | /* Do a binary search to find the applet entry given the name. */ |
140 | if (recurse_level == 0) | 136 | applet_using = find_applet_by_name(name); |
141 | parse_config_file (); | 137 | if(applet_using) { |
142 | #endif | 138 | bb_applet_name = applet_using->name; |
143 | 139 | if(argc==2 && !strcmp(argv[1], "--help")) bb_show_usage (); | |
144 | recurse_level++; | 140 | if(ENABLE_FEATURE_SUID) check_suid (applet_using); |
145 | /* Do a binary search to find the applet entry given the name. */ | 141 | exit ((*(applet_using->main)) (argc, argv)); |
146 | if ((applet_using = find_applet_by_name (name)) != NULL) { | ||
147 | bb_applet_name = applet_using->name; | ||
148 | if (argv[1] && strcmp (argv[1], "--help") == 0) { | ||
149 | if (strcmp (applet_using->name, "busybox") == 0) { | ||
150 | if (argv[2]) | ||
151 | applet_using = find_applet_by_name (argv[2]); | ||
152 | else | ||
153 | applet_using = NULL; | ||
154 | } | ||
155 | if (applet_using) | ||
156 | bb_show_usage (); | ||
157 | been_there_done_that = 1; | ||
158 | busybox_main (0, NULL); | ||
159 | } | 142 | } |
160 | #ifdef CONFIG_FEATURE_SUID | ||
161 | check_suid (applet_using); | ||
162 | #endif | ||
163 | |||
164 | exit ((*(applet_using->main)) (argc, argv)); | ||
165 | } | ||
166 | recurse_level--; | ||
167 | } | 143 | } |
168 | 144 | ||
169 | 145 | ||
diff --git a/applets/busybox.c b/applets/busybox.c index ee74b4c18..420c9c0e5 100644 --- a/applets/busybox.c +++ b/applets/busybox.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <locale.h> | 9 | #include <locale.h> |
10 | #endif | 10 | #endif |
11 | 11 | ||
12 | int been_there_done_that = 0; /* Also used in applets.c */ | ||
13 | const char *bb_applet_name; | 12 | const char *bb_applet_name; |
14 | 13 | ||
15 | #ifdef CONFIG_FEATURE_INSTALLER | 14 | #ifdef CONFIG_FEATURE_INSTALLER |
@@ -32,17 +31,6 @@ static const char* const install_dir[] = { | |||
32 | /* abstract link() */ | 31 | /* abstract link() */ |
33 | typedef int (*__link_f)(const char *, const char *); | 32 | typedef int (*__link_f)(const char *, const char *); |
34 | 33 | ||
35 | /* | ||
36 | * Where in the filesystem is this busybox? | ||
37 | * [return] | ||
38 | * malloc'd string w/ full pathname of busybox's location | ||
39 | * NULL on failure | ||
40 | */ | ||
41 | static inline char *busybox_fullpath(void) | ||
42 | { | ||
43 | return xreadlink("/proc/self/exe"); | ||
44 | } | ||
45 | |||
46 | /* create (sym)links for each applet */ | 34 | /* create (sym)links for each applet */ |
47 | static void install_links(const char *busybox, int use_symbolic_links) | 35 | static void install_links(const char *busybox, int use_symbolic_links) |
48 | { | 36 | { |
@@ -72,41 +60,27 @@ int main(int argc, char **argv) | |||
72 | { | 60 | { |
73 | const char *s; | 61 | const char *s; |
74 | 62 | ||
75 | bb_applet_name = argv[0]; | 63 | bb_applet_name=argv[0]; |
76 | 64 | if (*bb_applet_name == '-') bb_applet_name++; | |
77 | if (bb_applet_name[0] == '-') | 65 | for (s = bb_applet_name; *s ;) |
78 | bb_applet_name++; | 66 | if (*(s++) == '/') bb_applet_name = s; |
79 | 67 | ||
80 | for (s = bb_applet_name; *s != '\0';) { | 68 | /* Set locale for everybody except `init' */ |
81 | if (*s++ == '/') | 69 | if(ENABLE_LOCALE_SUPPORT && (!ENABLE_INIT || getpid()==1)) |
82 | bb_applet_name = s; | ||
83 | } | ||
84 | |||
85 | #ifdef CONFIG_LOCALE_SUPPORT | ||
86 | #ifdef CONFIG_INIT | ||
87 | if(getpid()!=1) /* Do not set locale for `init' */ | ||
88 | #endif | ||
89 | { | ||
90 | setlocale(LC_ALL, ""); | 70 | setlocale(LC_ALL, ""); |
91 | } | ||
92 | #endif | ||
93 | 71 | ||
94 | run_applet_by_name(bb_applet_name, argc, argv); | 72 | run_applet_by_name(bb_applet_name, argc, argv); |
95 | bb_error_msg_and_die("applet not found"); | 73 | bb_error_msg_and_die("applet not found"); |
96 | } | 74 | } |
97 | 75 | ||
98 | |||
99 | int busybox_main(int argc, char **argv) | 76 | int busybox_main(int argc, char **argv) |
100 | { | 77 | { |
101 | int col = 0, len, i; | ||
102 | |||
103 | #ifdef CONFIG_FEATURE_INSTALLER | ||
104 | /* | 78 | /* |
105 | * This style of argument parsing doesn't scale well | 79 | * This style of argument parsing doesn't scale well |
106 | * in the event that busybox starts wanting more --options. | 80 | * in the event that busybox starts wanting more --options. |
107 | * If someone has a cleaner approach, by all means implement it. | 81 | * If someone has a cleaner approach, by all means implement it. |
108 | */ | 82 | */ |
109 | if (argc > 1 && (strcmp(argv[1], "--install") == 0)) { | 83 | if (ENABLE_FEATURE_INSTALLER && argc > 1 && !strcmp(argv[1], "--install")) { |
110 | int use_symbolic_links = 0; | 84 | int use_symbolic_links = 0; |
111 | int rc = 0; | 85 | int rc = 0; |
112 | char *busybox; | 86 | char *busybox; |
@@ -119,7 +93,7 @@ int busybox_main(int argc, char **argv) | |||
119 | } | 93 | } |
120 | 94 | ||
121 | /* link */ | 95 | /* link */ |
122 | busybox = busybox_fullpath(); | 96 | busybox = xreadlink("/proc/self/exe"); |
123 | if (busybox) { | 97 | if (busybox) { |
124 | install_links(busybox, use_symbolic_links); | 98 | install_links(busybox, use_symbolic_links); |
125 | free(busybox); | 99 | free(busybox); |
@@ -128,60 +102,45 @@ int busybox_main(int argc, char **argv) | |||
128 | } | 102 | } |
129 | return rc; | 103 | return rc; |
130 | } | 104 | } |
131 | #endif /* CONFIG_FEATURE_INSTALLER */ | ||
132 | |||
133 | argc--; | ||
134 | |||
135 | /* If we've already been here once, exit now */ | ||
136 | if (been_there_done_that == 1 || argc < 1) { | ||
137 | const struct BB_applet *a = applets; | ||
138 | int output_width = 60; | ||
139 | |||
140 | #ifdef CONFIG_FEATURE_AUTOWIDTH | ||
141 | /* Obtain the terminal width. */ | ||
142 | get_terminal_width_height(0, &output_width, NULL); | ||
143 | /* leading tab and room to wrap */ | ||
144 | output_width -= 20; | ||
145 | #endif | ||
146 | 105 | ||
147 | printf("%s\n\n" | 106 | /* Deal with --help. (Also print help when called with no arguments) */ |
148 | "Usage: busybox [function] [arguments]...\n" | 107 | |
149 | " or: [function] [arguments]...\n\n" | 108 | if (argc==1 || !strcmp(argv[1],"--help") ) { |
150 | "\tBusyBox is a multi-call binary that combines many common Unix\n" | 109 | if (argc>2) run_applet_by_name(bb_applet_name=argv[2], argc, argv); |
151 | "\tutilities into a single executable. Most people will create a\n" | 110 | else { |
152 | "\tlink to busybox for each function they wish to use and BusyBox\n" | 111 | const struct BB_applet *a; |
153 | "\twill act like whatever it was invoked as!\n" | 112 | int col, output_width; |
154 | "\nCurrently defined functions:\n", bb_msg_full_version); | 113 | |
155 | 114 | if (ENABLE_FEATURE_AUTOWIDTH) { | |
156 | while (a->name != 0) { | 115 | /* Obtain the terminal width. */ |
157 | col += | 116 | get_terminal_width_height(0, &output_width, NULL); |
158 | printf("%s%s", ((col == 0) ? "\t" : ", "), | 117 | /* leading tab and room to wrap */ |
159 | (a++)->name); | 118 | output_width -= 20; |
160 | if (col > output_width && a->name != 0) { | 119 | } else output_width = 60; |
161 | printf(",\n"); | 120 | |
162 | col = 0; | 121 | printf("%s\n\n" |
122 | "Usage: busybox [function] [arguments]...\n" | ||
123 | " or: [function] [arguments]...\n\n" | ||
124 | "\tBusyBox is a multi-call binary that combines many common Unix\n" | ||
125 | "\tutilities into a single executable. Most people will create a\n" | ||
126 | "\tlink to busybox for each function they wish to use and BusyBox\n" | ||
127 | "\twill act like whatever it was invoked as!\n" | ||
128 | "\nCurrently defined functions:\n", bb_msg_full_version); | ||
129 | |||
130 | col=0; | ||
131 | for(a = applets; a->name;) { | ||
132 | col += printf("%s%s", (col ? ", " : "\t"), (a++)->name); | ||
133 | if (col > output_width && a->name) { | ||
134 | printf(",\n"); | ||
135 | col = 0; | ||
136 | } | ||
163 | } | 137 | } |
138 | printf("\n\n"); | ||
139 | exit(0); | ||
164 | } | 140 | } |
165 | printf("\n\n"); | 141 | } else run_applet_by_name(bb_applet_name=argv[1], argc-1, argv+1); |
166 | exit(0); | 142 | |
167 | } | 143 | bb_error_msg_and_die("applet not found"); |
168 | |||
169 | /* Flag that we've been here already */ | ||
170 | been_there_done_that = 1; | ||
171 | |||
172 | /* Move the command line down a notch */ | ||
173 | /* Preserve pointers so setproctitle() works consistently */ | ||
174 | len = argv[argc] + strlen(argv[argc]) - argv[1]; | ||
175 | memmove(argv[0], argv[1], len); | ||
176 | memset(argv[0] + len, 0, argv[1] - argv[0]); | ||
177 | |||
178 | /* Fix up the argv pointers */ | ||
179 | len = argv[1] - argv[0]; | ||
180 | memmove(argv, argv + 1, sizeof(char *) * (argc + 1)); | ||
181 | for (i = 0; i < argc; i++) | ||
182 | argv[i] -= len; | ||
183 | |||
184 | return (main(argc, argv)); | ||
185 | } | 144 | } |
186 | 145 | ||
187 | /* | 146 | /* |
diff --git a/testsuite/busybox.tests b/testsuite/busybox.tests new file mode 100755 index 000000000..f26f01b0c --- /dev/null +++ b/testsuite/busybox.tests | |||
@@ -0,0 +1,123 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # Tests for busybox applet itself. | ||
4 | # Copyright 2005 by Rob Landley <rob@landley.net> | ||
5 | # Licensed under GPL v2, see file LICENSE for details. | ||
6 | |||
7 | if [ ${#COMMAND} -eq 0 ]; then COMMAND=busybox; fi | ||
8 | . testing.sh | ||
9 | |||
10 | # We'll assume "cat" is built in, because we need some other command to test. | ||
11 | |||
12 | HELPDUMP=`$COMMAND` | ||
13 | |||
14 | # The gratuitous "\n"s are due to a shell idiosyncrasy: environment variables | ||
15 | # seem to strip trailing whitespace, which makes cmp and diff unhappy. | ||
16 | |||
17 | ln -s `which "$COMMAND"` busybox-suffix | ||
18 | ln -s `which "$COMMAND"` unknown | ||
19 | |||
20 | for i in busybox busybox-suffix | ||
21 | do | ||
22 | # The gratuitous "\n"s are due to a shell idiosyncrasy: | ||
23 | # environment variables seem to strip trailing whitespace. | ||
24 | |||
25 | testing "$i" "" "$HELPDUMP\n\n" "" "" | ||
26 | |||
27 | testing "$i cat" "cat" "moo" "" "moo" | ||
28 | |||
29 | testing "$i unknown" "unknown 2>&1" \ | ||
30 | "unknown: applet not found\n" "" "" | ||
31 | |||
32 | testing "$i --help" "--help 2>&1" "$HELPDUMP\n\n" "" "" | ||
33 | |||
34 | testing "$i --help cat" "--help cat 2>&1 | grep prints" \ | ||
35 | "Concatenates FILE(s) and prints them to stdout.\n" "" "" | ||
36 | |||
37 | testing "$i --help unknown" "--help unknown 2>&1" \ | ||
38 | "unknown: applet not found\n" "" "" | ||
39 | |||
40 | COMMAND=./busybox-suffix | ||
41 | done | ||
42 | |||
43 | COMMAND="./unknown" | ||
44 | testing "busybox as unknown name" "2>&1" "unknown: applet not found\n" "" "" | ||
45 | |||
46 | rm -f busybox-suffix unknown | ||
47 | |||
48 | exit | ||
49 | |||
50 | General cleanup of command line parsing to allow "busybox" to work as a prefix. | ||
51 | (I.E. any argv[0] that starts with "busybox" winds up in busybox_main().) | ||
52 | |||
53 | Tests: | ||
54 | ./busybox | ||
55 | ./busybox-walrus | ||
56 | ./busybox ls | ||
57 | ./busybox-walrus ls | ||
58 | ./busybox --help | ||
59 | ./busybox-walrus --help | ||
60 | ./busybox --help ls | ||
61 | ./busybox-walrus --help ls | ||
62 | ./busybox --help walrus | ||
63 | ./busybox-walrus --help walrus | ||
64 | |||
65 | |||
66 | |||
67 | |||
68 | |||
69 | |||
70 | |||
71 | |||
72 | |||
73 | # These tests require the full option set. | ||
74 | |||
75 | # Longish chunk of data re-used by the next few tests | ||
76 | |||
77 | data="42 1 3 woot | ||
78 | 42 1 010 zoology | ||
79 | egg 1 2 papyrus | ||
80 | 7 3 42 soup | ||
81 | 999 3 0 algebra | ||
82 | " | ||
83 | |||
84 | # Sorting with keys | ||
85 | |||
86 | testing "sort one key" "-k4,4 input" \ | ||
87 | "999 3 0 algebra | ||
88 | egg 1 2 papyrus | ||
89 | 7 3 42 soup | ||
90 | 42 1 3 woot | ||
91 | 42 1 010 zoology | ||
92 | " "$data" "" | ||
93 | |||
94 | testing "sort key range with numeric option" "-k2,3n input" \ | ||
95 | "42 1 010 zoology | ||
96 | 42 1 3 woot | ||
97 | egg 1 2 papyrus | ||
98 | 7 3 42 soup | ||
99 | 999 3 0 algebra | ||
100 | " "$data" "" | ||
101 | |||
102 | # Busybox is definitely doing this one wrong just now... | ||
103 | |||
104 | testing "sort key range with numeric option and global reverse" \ | ||
105 | "-k2,3n -r input" \ | ||
106 | "egg 1 2 papyrus | ||
107 | 42 1 3 woot | ||
108 | 42 1 010 zoology | ||
109 | 999 3 0 algebra | ||
110 | 7 3 42 soup | ||
111 | " "$data" "" | ||
112 | |||
113 | # | ||
114 | |||
115 | testing "sort key range with multiple options" "-k2,3rn input" \ | ||
116 | "7 3 42 soup | ||
117 | 999 3 0 algebra | ||
118 | 42 1 010 zoology | ||
119 | 42 1 3 woot | ||
120 | egg 1 2 papyrus | ||
121 | " "$data" "" | ||
122 | |||
123 | exit $FAILCOUNT | ||
diff --git a/testsuite/runtest b/testsuite/runtest index 91b794317..6a0dc9d3e 100755 --- a/testsuite/runtest +++ b/testsuite/runtest | |||
@@ -97,8 +97,8 @@ for applet in $applets; do | |||
97 | status=1 | 97 | status=1 |
98 | fi | 98 | fi |
99 | fi | 99 | fi |
100 | 100 | applet=`echo "$applet" | sed -n 's/\.tests$//p'` | |
101 | if [ -f "$applet".tests ] | 101 | if [ ${#applet} != 0 ] |
102 | then | 102 | then |
103 | rm -f links/"$applet" | 103 | rm -f links/"$applet" |
104 | ln -s ../../busybox links/"$applet" | 104 | ln -s ../../busybox links/"$applet" |
diff --git a/testsuite/testing.sh b/testsuite/testing.sh index d516f722a..0925d090d 100755 --- a/testsuite/testing.sh +++ b/testsuite/testing.sh | |||
@@ -48,13 +48,13 @@ function testing() | |||
48 | if [ $? -ne 0 ] | 48 | if [ $? -ne 0 ] |
49 | then | 49 | then |
50 | FAILCOUNT=$[$FAILCOUNT+1] | 50 | FAILCOUNT=$[$FAILCOUNT+1] |
51 | echo FAIL:"$1" | 51 | echo "FAIL: $1" |
52 | if [ $verbose ] | 52 | if [ $verbose ] |
53 | then | 53 | then |
54 | diff -u expected actual | 54 | diff -u expected actual |
55 | fi | 55 | fi |
56 | else | 56 | else |
57 | echo PASS:"$1" | 57 | echo "PASS: $1" |
58 | fi | 58 | fi |
59 | rm -f input expected actual | 59 | rm -f input expected actual |
60 | 60 | ||