0a3333d99a05d458c562794e9ffe0de185937817
[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 int main(int argc, char **argv)
85 {
86         struct BB_applet search_applet, *applet;
87         const char                              *s;
88         applet_name = "busybox";
89
90 #ifdef BB_FEATURE_INSTALLER     
91         /* 
92          * This style of argument parsing doesn't scale well 
93          * in the event that busybox starts wanting more --options.
94          * If someone has a cleaner approach, by all means implement it.
95          */
96         if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
97                 int use_symbolic_links = 0;
98                 int rc = 0;
99                 char *busybox;
100
101                 /* to use symlinks, or not to use symlinks... */
102                 if (argc > 2) {
103                         if ((strcmp(argv[2], "-s") == 0)) { 
104                                 use_symbolic_links = 1; 
105                         }
106                 }
107
108                 /* link */
109                 busybox = busybox_fullpath();
110                 if (busybox) {
111                         install_links(busybox, use_symbolic_links);
112                         free(busybox);
113                 } else {
114                         rc = 1;
115                 }
116                 return rc;
117         }
118 #endif /* BB_FEATURE_INSTALLER */
119
120         for (s = applet_name = argv[0]; *s != '\0';) {
121                 if (*s++ == '/')
122                         applet_name = s;
123         }
124
125         *argv = (char*)applet_name;
126
127 #ifdef BB_SH
128         /* Add in a special case hack -- whenever **argv == '-'
129          * (i.e. '-su' or '-sh') always invoke the shell */
130         if (**argv == '-' && *(*argv+1)!= '-') {
131                 exit(((*(shell_main)) (argc, argv)));
132         }
133 #endif
134
135         /* Do a binary search to find the applet entry given the name. */
136         search_applet.name = applet_name;
137         applet = bsearch(&search_applet, applets, NUM_APPLETS,
138                         sizeof(struct BB_applet), applet_name_compare);
139         if (applet != NULL) {
140                 if (applet->usage && argv[1] && strcmp(argv[1], "--help") == 0)
141                         usage(applet->usage); 
142                 exit((*(applet->main)) (argc, argv));
143         }
144
145         return(busybox_main(argc, argv));
146 }
147
148
149 int busybox_main(int argc, char **argv)
150 {
151         int col = 0;
152
153         argc--;
154         argv++;
155
156         if (been_there_done_that == 1 || argc < 1) {
157                 const struct BB_applet *a = applets;
158
159                 fprintf(stderr, "%s\n\n"
160                                 "Usage: busybox [function] [arguments]...\n"
161                                 "   or: [function] [arguments]...\n\n"
162                                 "\tBusyBox is a multi-call binary that combines many common Unix\n"
163                                 "\tutilities into a single executable.  Most people will create a\n"
164                                 "\tlink to busybox for each function they wish to use, and BusyBox\n"
165                                 "\twill act like whatever it was invoked as.\n" 
166                                 "\nCurrently defined functions:\n", full_version);
167
168                 while (a->name != 0) {
169                         col +=
170                                 fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
171                                                 (a++)->name);
172                         if (col > 60 && a->name != 0) {
173                                 fprintf(stderr, ",\n");
174                                 col = 0;
175                         }
176                 }
177                 fprintf(stderr, "\n\n");
178                 exit(-1);
179         }
180         /* If we've already been here once, exit now */
181         been_there_done_that = 1;
182         return (main(argc, argv));
183 }
184
185 /*
186 Local Variables:
187 c-file-style: "linux"
188 c-basic-offset: 4
189 tab-width: 4
190 End:
191 */