Fixed tiny typo.
[oweals/busybox.git] / busybox.c
1 /* vi: set sw=4 ts=4: */
2 #include "busybox.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <errno.h>
6
7 #undef APPLET
8 #undef APPLET_NOUSAGE
9 #undef PROTOTYPES
10 #include "applets.h"
11
12 #define bb_need_full_version
13 #define BB_DECLARE_EXTERN
14 #include "messages.c"
15
16 static int been_there_done_that = 0;
17
18
19 const char *applet_name;
20
21 #ifdef BB_FEATURE_INSTALLER
22 /* 
23  * directory table
24  *              this should be consistent w/ the enum, busybox.h::Location,
25  *              or else...
26  */
27 static char* install_dir[] = {
28         "/",
29         "/bin",
30         "/sbin",
31         "/usr/bin",
32         "/usr/sbin",
33 };
34
35 /* abstract link() */
36 typedef int (*__link_f)(const char *, const char *);
37
38 /* 
39  * Where in the filesystem is this busybox?
40  * [return]
41  *              malloc'd string w/ full pathname of busybox's location
42  *              NULL on failure
43  */
44 static char *busybox_fullpath()
45 {
46         pid_t pid;
47         char path[256];
48         char proc[256];
49         int len;
50
51         pid = getpid();
52         sprintf(proc, "/proc/%d/exe", pid);
53         len = readlink(proc, path, 256);
54         if (len != -1) {
55                 path[len] = 0;
56         } else {
57                 perror_msg("%s", proc);
58                 return NULL;
59         }
60         return strdup(path);
61 }
62
63 /* create (sym)links for each applet */
64 static void install_links(const char *busybox, int use_symbolic_links)
65 {
66         __link_f Link = link;
67
68         char command[256];
69         int i;
70         int rc;
71
72         if (use_symbolic_links) Link = symlink;
73
74         for (i = 0; applets[i].name != NULL; i++) {
75                 sprintf ( command, "%s/%s", 
76                                 install_dir[applets[i].location], 
77                                 applets[i].name);
78                 rc = Link(busybox, command);
79
80                 if (rc) {
81                         perror_msg("%s", command);
82                 }
83         }
84 }
85
86 #endif /* BB_FEATURE_INSTALLER */
87
88 int main(int argc, char **argv)
89 {
90         struct BB_applet search_applet, *applet;
91         const char                              *s;
92         applet_name = "busybox";
93
94 #ifdef BB_FEATURE_INSTALLER     
95         /* 
96          * This style of argument parsing doesn't scale well 
97          * in the event that busybox starts wanting more --options.
98          * If someone has a cleaner approach, by all means implement it.
99          */
100         if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
101                 int use_symbolic_links = 0;
102                 int rc = 0;
103                 char *busybox;
104
105                 /* to use symlinks, or not to use symlinks... */
106                 if (argc > 2) {
107                         if ((strcmp(argv[2], "-s") == 0)) { 
108                                 use_symbolic_links = 1; 
109                         }
110                 }
111
112                 /* link */
113                 busybox = busybox_fullpath();
114                 if (busybox) {
115                         install_links(busybox, use_symbolic_links);
116                         free(busybox);
117                 } else {
118                         rc = 1;
119                 }
120                 return rc;
121         }
122 #endif /* BB_FEATURE_INSTALLER */
123
124         for (s = applet_name = argv[0]; *s != '\0';) {
125                 if (*s++ == '/')
126                         applet_name = s;
127         }
128
129 #ifdef BB_SH
130         /* Add in a special case hack -- whenever **argv == '-'
131          * (i.e. '-su' or '-sh') always invoke the shell */
132         if (**argv == '-' && *(*argv+1)!= '-') {
133                 exit(((*(shell_main)) (argc, argv)));
134         }
135 #endif
136
137         /* Do a binary search to find the applet entry given the name. */
138         search_applet.name = applet_name;
139         applet = bsearch(&search_applet, applets, NUM_APPLETS,
140                         sizeof(struct BB_applet), applet_name_compare);
141         if (applet != NULL) {
142                 if (applet->usage && argv[1] && strcmp(argv[1], "--help") == 0)
143                         usage(applet->usage); 
144                 exit((*(applet->main)) (argc, argv));
145         }
146
147         return(busybox_main(argc, argv));
148 }
149
150
151 int busybox_main(int argc, char **argv)
152 {
153         int col = 0, len, i;
154
155         argc--;
156
157         /* If we've already been here once, exit now */
158         if (been_there_done_that == 1 || argc < 1) {
159                 const struct BB_applet *a = applets;
160
161                 fprintf(stderr, "%s\n\n"
162                                 "Usage: busybox [function] [arguments]...\n"
163                                 "   or: [function] [arguments]...\n\n"
164                                 "\tBusyBox is a multi-call binary that combines many common Unix\n"
165                                 "\tutilities into a single executable.  Most people will create a\n"
166                                 "\tlink to busybox for each function they wish to use, and BusyBox\n"
167                                 "\twill act like whatever it was invoked as.\n" 
168                                 "\nCurrently defined functions:\n", full_version);
169
170                 while (a->name != 0) {
171                         col +=
172                                 fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
173                                                 (a++)->name);
174                         if (col > 60 && a->name != 0) {
175                                 fprintf(stderr, ",\n");
176                                 col = 0;
177                         }
178                 }
179                 fprintf(stderr, "\n\n");
180                 exit(-1);
181         }
182
183         /* Flag that we've been here already */
184         been_there_done_that = 1;
185         
186         /* Move the command line down a notch */
187         len = argv[argc] + strlen(argv[argc]) - argv[1];
188         memmove(argv[0], argv[1], len);
189         memset(argv[0] + len, 0, argv[1] - argv[0]);
190
191         /* Fix up the argv pointers */
192         len = argv[1] - argv[0];
193         memmove(argv, argv+1, sizeof(char *) * (argc + 1));
194         for (i = 0; i < argc; i++)
195                 argv[i] -= len;
196
197         return (main(argc, argv));
198 }
199
200 /*
201 Local Variables:
202 c-file-style: "linux"
203 c-basic-offset: 4
204 tab-width: 4
205 End:
206 */