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