212d46742c7ce4311447f7554e093d02f3040206
[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
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                 error_msg("%s: %s\n", proc, strerror(errno));
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                         error_msg("%s: %s\n", command, strerror(errno));
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         *argv = (char*)applet_name;
130
131 #ifdef BB_SH
132         /* Add in a special case hack -- whenever **argv == '-'
133          * (i.e. '-su' or '-sh') always invoke the shell */
134         if (**argv == '-' && *(*argv+1)!= '-') {
135                 exit(((*(shell_main)) (argc, argv)));
136         }
137 #endif
138
139         /* Do a binary search to find the applet entry given the name. */
140         search_applet.name = applet_name;
141         applet = bsearch(&search_applet, applets, NUM_APPLETS,
142                         sizeof(struct BB_applet), applet_name_compare);
143         if (applet != NULL) {
144                 if (applet->usage && argv[1] && strcmp(argv[1], "--help") == 0)
145                         usage(applet->usage); 
146                 exit((*(applet->main)) (argc, argv));
147         }
148
149         return(busybox_main(argc, argv));
150 }
151
152
153 int busybox_main(int argc, char **argv)
154 {
155         int col = 0;
156
157         argc--;
158         argv++;
159
160         if (been_there_done_that == 1 || argc < 1) {
161                 const struct BB_applet *a = applets;
162
163                 fprintf(stderr, "%s\n\n"
164                                 "Usage: busybox [function] [arguments]...\n"
165                                 "   or: [function] [arguments]...\n\n"
166                                 "\tBusyBox is a multi-call binary that combines many common Unix\n"
167                                 "\tutilities into a single executable.  Most people will create a\n"
168                                 "\tlink to busybox for each function they wish to use, and BusyBox\n"
169                                 "\twill act like whatever it was invoked as.\n" 
170                                 "\nCurrently defined functions:\n", full_version);
171
172                 while (a->name != 0) {
173                         col +=
174                                 fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
175                                                 (a++)->name);
176                         if (col > 60 && a->name != 0) {
177                                 fprintf(stderr, ",\n");
178                                 col = 0;
179                         }
180                 }
181                 fprintf(stderr, "\n\n");
182                 exit(-1);
183         }
184         /* If we've already been here once, exit now */
185         been_there_done_that = 1;
186         return (main(argc, argv));
187 }
188
189 /*
190 Local Variables:
191 c-file-style: "linux"
192 c-basic-offset: 4
193 tab-width: 4
194 End:
195 */