ab3762eb875d6565ade15630f80570cd9e265b29
[oweals/busybox.git] / applets / 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 #include <stdlib.h>
7
8 #undef APPLET
9 #undef APPLET_NOUSAGE
10 #undef PROTOTYPES
11 #include "applets.h"
12
13 #define bb_need_full_version
14 #define BB_DECLARE_EXTERN
15 #include "messages.c"
16
17 static int been_there_done_that = 0;
18
19
20 const char *applet_name;
21
22 #ifdef BB_FEATURE_INSTALLER
23 /* 
24  * directory table
25  *              this should be consistent w/ the enum, busybox.h::Location,
26  *              or else...
27  */
28 static char* install_dir[] = {
29         "/",
30         "/bin",
31         "/sbin",
32         "/usr/bin",
33         "/usr/sbin",
34 };
35
36 /* abstract link() */
37 typedef int (*__link_f)(const char *, const char *);
38
39 /* 
40  * Where in the filesystem is this busybox?
41  * [return]
42  *              malloc'd string w/ full pathname of busybox's location
43  *              NULL on failure
44  */
45 static char *busybox_fullpath()
46 {
47         pid_t pid;
48         char path[256];
49         char proc[256];
50         int len;
51
52         pid = getpid();
53         sprintf(proc, "/proc/%d/exe", pid);
54         len = readlink(proc, path, 256);
55         if (len != -1) {
56                 path[len] = 0;
57         } else {
58                 perror_msg("%s", proc);
59                 return NULL;
60         }
61         return strdup(path);
62 }
63
64 /* create (sym)links for each applet */
65 static void install_links(const char *busybox, int use_symbolic_links)
66 {
67         __link_f Link = link;
68
69         char command[256];
70         int i;
71         int rc;
72
73         if (use_symbolic_links) Link = symlink;
74
75         for (i = 0; applets[i].name != NULL; i++) {
76                 sprintf ( command, "%s/%s", 
77                                 install_dir[applets[i].location], 
78                                 applets[i].name);
79                 rc = Link(busybox, command);
80
81                 if (rc) {
82                         perror_msg("%s", command);
83                 }
84         }
85 }
86
87 #endif /* BB_FEATURE_INSTALLER */
88
89 int main(int argc, char **argv)
90 {
91         struct BB_applet search_applet, *applet;
92         const char                              *s;
93
94         for (s = applet_name = argv[0]; *s != '\0';) {
95                 if (*s++ == '/')
96                         applet_name = s;
97         }
98
99 #ifdef BB_SH
100         /* Add in a special case hack -- whenever **argv == '-'
101          * (i.e. '-su' or '-sh') always invoke the shell */
102         if (**argv == '-' && *(*argv+1)!= '-') {
103                 exit(((*(shell_main)) (argc, argv)));
104         }
105 #endif
106
107         /* Do a binary search to find the applet entry given the name. */
108         search_applet.name = applet_name;
109         applet = bsearch(&search_applet, applets, NUM_APPLETS,
110                         sizeof(struct BB_applet), applet_name_compare);
111         if (applet != NULL) {
112                 if (applet->usage && argv[1] && strcmp(argv[1], "--help") == 0)
113                         usage(applet->usage); 
114                 exit((*(applet->main)) (argc, argv));
115         }
116
117         error_msg_and_die("applet not found\n");
118 }
119
120
121 int busybox_main(int argc, char **argv)
122 {
123         int col = 0, len, i;
124
125 #ifdef BB_FEATURE_INSTALLER     
126         /* 
127          * This style of argument parsing doesn't scale well 
128          * in the event that busybox starts wanting more --options.
129          * If someone has a cleaner approach, by all means implement it.
130          */
131         if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
132                 int use_symbolic_links = 0;
133                 int rc = 0;
134                 char *busybox;
135
136                 /* to use symlinks, or not to use symlinks... */
137                 if (argc > 2) {
138                         if ((strcmp(argv[2], "-s") == 0)) { 
139                                 use_symbolic_links = 1; 
140                         }
141                 }
142
143                 /* link */
144                 busybox = busybox_fullpath();
145                 if (busybox) {
146                         install_links(busybox, use_symbolic_links);
147                         free(busybox);
148                 } else {
149                         rc = 1;
150                 }
151                 return rc;
152         }
153 #endif /* BB_FEATURE_INSTALLER */
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 */