Apply a patch from Evin Robertson -- new pivot_root applet.
[oweals/busybox.git] / busybox.c
1 /* vi: set sw=4 ts=4: */
2 #include "busybox.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <stdlib.h>
8
9 #undef APPLET
10 #undef APPLET_NOUSAGE
11 #undef PROTOTYPES
12 #include "applets.h"
13
14 #define bb_need_full_version
15 #define BB_DECLARE_EXTERN
16 #include "messages.c"
17
18 static int been_there_done_that = 0;
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                 perror_msg("%s", proc);
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) 
73                 Link = symlink;
74
75         for (i = 0; applets[i].name != NULL; i++) {
76                 sprintf ( command, "%s/%s", 
77                                 install_dir[applets[i].location], applets[i].name);
78                 rc = Link(busybox, command);
79
80                 if (rc) {
81                         perror_msg("%s", command);
82                 }
83         }
84 }
85
86 #endif /* BB_FEATURE_INSTALLER */
87
88 int main(int argc, char **argv)
89 {
90         struct BB_applet *applet;
91         const char *s;
92
93         for (s = applet_name = argv[0]; *s != '\0';) {
94                 if (*s++ == '/')
95                         applet_name = s;
96         }
97
98 #ifdef BB_SH
99         /* Add in a special case hack -- whenever **argv == '-'
100          * (i.e. '-su' or '-sh') always invoke the shell */
101         if (**argv == '-' && *(*argv+1)!= '-') {
102                 exit(((*(shell_main)) (argc, argv)));
103         }
104 #endif
105
106         /* Do a binary search to find the applet entry given the name. */
107         if ((applet = find_applet_by_name(applet_name)) != NULL) {
108                 if (applet->usage && argv[1] && strcmp(argv[1], "--help") == 0)
109                         usage(applet->usage);
110                 exit((*(applet->main)) (argc, argv));
111         }
112
113         error_msg_and_die("applet not found");
114 }
115
116
117 int busybox_main(int argc, char **argv)
118 {
119         int col = 0, len, i;
120
121 #ifdef BB_FEATURE_INSTALLER     
122         /* 
123          * This style of argument parsing doesn't scale well 
124          * in the event that busybox starts wanting more --options.
125          * If someone has a cleaner approach, by all means implement it.
126          */
127         if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
128                 int use_symbolic_links = 0;
129                 int rc = 0;
130                 char *busybox;
131
132                 /* to use symlinks, or not to use symlinks... */
133                 if (argc > 2) {
134                         if ((strcmp(argv[2], "-s") == 0)) { 
135                                 use_symbolic_links = 1; 
136                         }
137                 }
138
139                 /* link */
140                 busybox = busybox_fullpath();
141                 if (busybox) {
142                         install_links(busybox, use_symbolic_links);
143                         free(busybox);
144                 } else {
145                         rc = 1;
146                 }
147                 return rc;
148         }
149 #endif /* BB_FEATURE_INSTALLER */
150
151         argc--;
152
153         /* If we've already been here once, exit now */
154         if (been_there_done_that == 1 || argc < 1) {
155                 const struct BB_applet *a = applets;
156
157                 fprintf(stderr, "%s\n\n"
158                                 "Usage: busybox [function] [arguments]...\n"
159                                 "   or: [function] [arguments]...\n\n"
160                                 "\tBusyBox is a multi-call binary that combines many common Unix\n"
161                                 "\tutilities into a single executable.  Most people will create a\n"
162                                 "\tlink to busybox for each function they wish to use, and BusyBox\n"
163                                 "\twill act like whatever it was invoked as.\n" 
164                                 "\nCurrently defined functions:\n", full_version);
165
166                 while (a->name != 0) {
167                         col +=
168                                 fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
169                                                 (a++)->name);
170                         if (col > 60 && a->name != 0) {
171                                 fprintf(stderr, ",\n");
172                                 col = 0;
173                         }
174                 }
175                 fprintf(stderr, "\n\n");
176                 exit(-1);
177         }
178
179         /* Flag that we've been here already */
180         been_there_done_that = 1;
181         
182         /* Move the command line down a notch */
183         len = argv[argc] + strlen(argv[argc]) - argv[1];
184         memmove(argv[0], argv[1], len);
185         memset(argv[0] + len, 0, argv[1] - argv[0]);
186
187         /* Fix up the argv pointers */
188         len = argv[1] - argv[0];
189         memmove(argv, argv + 1, sizeof(char *) * (argc + 1));
190         for (i = 0; i < argc; i++)
191                 argv[i] -= len;
192
193         return (main(argc, argv));
194 }
195
196 /*
197 Local Variables:
198 c-file-style: "linux"
199 c-basic-offset: 4
200 tab-width: 4
201 End:
202 */