aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2005-09-04 11:10:37 +0000
committerRob Landley <rob@landley.net>2005-09-04 11:10:37 +0000
commitb766c394569cce356fceb63d83da79581c0997b9 (patch)
treea1c4cd18cede88c2e18a6e22f0b59924d5838682
parent9754b91c16288fd0f4d6301fd6d01aa8b3c3b1d9 (diff)
downloadbusybox-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.c52
-rw-r--r--applets/busybox.c129
-rwxr-xr-xtestsuite/busybox.tests123
-rwxr-xr-xtestsuite/runtest4
-rwxr-xr-xtestsuite/testing.sh4
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
93extern void 93extern void bb_show_usage (void)
94bb_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
115static int 114static int applet_name_compare (const void *x, const void *y)
116applet_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
124extern const size_t NUM_APPLETS; 122extern const size_t NUM_APPLETS;
125 123
126struct BB_applet * 124struct BB_applet *find_applet_by_name (const char *name)
127find_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
133void 130void run_applet_by_name (const char *name, int argc, char **argv)
134run_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
12int been_there_done_that = 0; /* Also used in applets.c */
13const char *bb_applet_name; 12const 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() */
33typedef int (*__link_f)(const char *, const char *); 32typedef 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 */
41static 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 */
47static void install_links(const char *busybox, int use_symbolic_links) 35static 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
99int busybox_main(int argc, char **argv) 76int 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
7if [ ${#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
12HELPDUMP=`$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
17ln -s `which "$COMMAND"` busybox-suffix
18ln -s `which "$COMMAND"` unknown
19
20for i in busybox busybox-suffix
21do
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
41done
42
43COMMAND="./unknown"
44testing "busybox as unknown name" "2>&1" "unknown: applet not found\n" "" ""
45
46rm -f busybox-suffix unknown
47
48exit
49
50General 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
53Tests:
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
77data="42 1 3 woot
7842 1 010 zoology
79egg 1 2 papyrus
807 3 42 soup
81999 3 0 algebra
82"
83
84# Sorting with keys
85
86testing "sort one key" "-k4,4 input" \
87"999 3 0 algebra
88egg 1 2 papyrus
897 3 42 soup
9042 1 3 woot
9142 1 010 zoology
92" "$data" ""
93
94testing "sort key range with numeric option" "-k2,3n input" \
95"42 1 010 zoology
9642 1 3 woot
97egg 1 2 papyrus
987 3 42 soup
99999 3 0 algebra
100" "$data" ""
101
102# Busybox is definitely doing this one wrong just now...
103
104testing "sort key range with numeric option and global reverse" \
105"-k2,3n -r input" \
106"egg 1 2 papyrus
10742 1 3 woot
10842 1 010 zoology
109999 3 0 algebra
1107 3 42 soup
111" "$data" ""
112
113#
114
115testing "sort key range with multiple options" "-k2,3rn input" \
116"7 3 42 soup
117999 3 0 algebra
11842 1 010 zoology
11942 1 3 woot
120egg 1 2 papyrus
121" "$data" ""
122
123exit $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