c8c060be7ca7d696cb628c8d45a0acfc45e962fb
[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 #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;
154         int ps_index;
155         char *index, *index2;
156
157         argc--;
158
159         /* If we've already been here once, exit now */
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
185         /* Flag that we've been here already */
186         been_there_done_that = 1;
187         
188         /* We do not want the word "busybox" to show up in ps, so we move
189          * everything in argv around to fake ps into showing what we want it to
190          * show.  Since we are only shrinking the string, we don't need to move 
191          * __environ or any of that tedious stuff... */
192         ps_index = 0;
193         index=*argv;
194         index2=argv[argc];
195         index2+=strlen(argv[argc]);
196         while(ps_index < argc) { 
197                 argv[ps_index]=index;
198                 memmove(index, argv[ps_index+1], strlen(argv[ps_index+1])+1);
199                 index+=(strlen(index));
200                 *index='\0';
201                 index++;
202                 ps_index++;
203         }
204         while(index<=index2)
205                 *index++='\0';
206
207         return (main(argc, argv));
208 }
209
210 /*
211 Local Variables:
212 c-file-style: "linux"
213 c-basic-offset: 4
214 tab-width: 4
215 End:
216 */