1
2
3
4
5
6#include "toys.h"
7
8
9
10#undef NEWTOY
11#undef OLDTOY
12#define NEWTOY(name, opts, flags) {#name, name##_main, OPTSTR_##name, flags},
13#define OLDTOY(name, oldname, flags) \
14 {#name, oldname##_main, OPTSTR_##oldname, flags},
15
16struct toy_list toy_list[] = {
17#include "generated/newtoys.h"
18};
19
20
21
22struct toy_context toys;
23union global_union this;
24char *toybox_version = TOYBOX_VERSION, toybuf[4096], libbuf[4096];
25
26struct toy_list *toy_find(char *name)
27{
28 int top, bottom, middle;
29
30 if (!CFG_TOYBOX || strchr(name, '/')) return 0;
31
32
33 if (!toys.which && strstart(&name, toy_list->name)) return toy_list;
34 bottom = 1;
35
36
37 top = ARRAY_LEN(toy_list)-1;
38 for (;;) {
39 int result;
40
41 middle = (top+bottom)/2;
42 if (middle<bottom || middle>top) return 0;
43 result = strcmp(name,toy_list[middle].name);
44 if (!result) return toy_list+middle;
45 if (result<0) top = --middle;
46 else bottom = ++middle;
47 }
48}
49
50
51
52
53
54
55#undef NEWTOY
56#undef OLDTOY
57#define NEWTOY(name, opts, flags) opts ||
58#define OLDTOY(name, oldname, flags) OPTSTR_##oldname ||
59static const int NEED_OPTIONS =
60#include "generated/newtoys.h"
610;
62
63
64
65#undef NEWTOY
66#undef OLDTOY
67#define NEWTOY(name,opt,flags) HELP_##name "\0"
68#if CFG_TOYBOX
69#define OLDTOY(name,oldname,flags) "\xff" #oldname "\0"
70#else
71#define OLDTOY(name, oldname, flags) HELP_##oldname "\0"
72#endif
73
74#include "generated/help.h"
75static char *help_data =
76#include "generated/newtoys.h"
77;
78
79void show_help(FILE *out, int full)
80{
81 int i = toys.which-toy_list;
82 char *s, *ss;
83
84 if (!(full&2))
85 fprintf(out, "Toybox %s"USE_TOYBOX(" multicall binary")"%s\n\n",
86 toybox_version, (CFG_TOYBOX && i) ? " (see toybox --help)"
87 : " (see https://landley.net/toybox)");
88
89 if (CFG_TOYBOX_HELP) {
90 for (;;) {
91 s = help_data;
92 while (i--) s += strlen(s) + 1;
93
94 if (*s != 255) break;
95 i = toy_find(++s)-toy_list;
96 if ((full&4) && toy_list[i].flags) {
97 fprintf(out, "See <a href=#%s>%s</a>\n", s, s);
98
99 return;
100 }
101 }
102
103 if (full) fprintf(out, "%s\n", s);
104 else {
105 strstart(&s, "usage: ");
106 for (ss = s; *ss && *ss!='\n'; ss++);
107 fprintf(out, "%.*s\n", (int)(ss-s), s);
108 }
109 }
110}
111
112static void unknown(char *name)
113{
114 toys.exitval = 127;
115 toys.which = toy_list;
116 help_exit("Unknown command %s", name);
117}
118
119
120void check_help(char **arg)
121{
122 if (!CFG_TOYBOX_HELP_DASHDASH || !*arg) return;
123 if (!CFG_TOYBOX || toys.which != toy_list)
124 if (toys.which->flags&TOYFLAG_NOHELP) return;
125
126 if (!strcmp(*arg, "--help")) {
127 if (CFG_TOYBOX && toys.which == toy_list && arg[1])
128 if (!(toys.which = toy_find(arg[1]))) unknown(arg[1]);
129 show_help(stdout, 1);
130 xexit();
131 }
132
133 if (!strcmp(*arg, "--version")) {
134 xprintf("toybox %s\n", toybox_version);
135 xexit();
136 }
137}
138
139
140void toy_singleinit(struct toy_list *which, char *argv[])
141{
142 toys.which = which;
143 toys.argv = argv;
144 toys.toycount = ARRAY_LEN(toy_list);
145
146 if (NEED_OPTIONS && which->options) get_optflags();
147 else {
148 check_help(toys.optargs = argv+1);
149 for (toys.optc = 0; toys.optargs[toys.optc]; toys.optc++);
150 }
151
152 if (!(CFG_TOYBOX && which == toy_list) && !(which->flags & TOYFLAG_NOFORK)) {
153 toys.old_umask = umask(0);
154 if (!(which->flags & TOYFLAG_UMASK)) umask(toys.old_umask);
155
156
157
158
159 setlocale(LC_CTYPE, "");
160 if (strcmp("UTF-8", nl_langinfo(CODESET)))
161 uselocale(newlocale(LC_CTYPE_MASK, "en_US.UTF-8", NULL));
162
163 setvbuf(stdout, 0, (which->flags & TOYFLAG_LINEBUF) ? _IOLBF : _IONBF, 0);
164 }
165}
166
167
168void toy_init(struct toy_list *which, char *argv[])
169{
170 void *oldwhich = toys.which;
171
172
173 if (CFG_TOYBOX_SUID) {
174 if (!toys.which) toys.which = toy_list;
175
176 uid_t uid = getuid(), euid = geteuid();
177
178 if (!(which->flags & TOYFLAG_STAYROOT)) {
179 if (uid != euid) {
180 if (setuid(uid)) perror_exit("setuid %d->%d", euid, uid);
181 euid = uid;
182 toys.wasroot++;
183 }
184 } else if (CFG_TOYBOX_DEBUG && uid && which != toy_list)
185 error_msg("Not installed suid root");
186
187 if ((which->flags & TOYFLAG_NEEDROOT) && euid) {
188 toys.which = which;
189 check_help(argv+1);
190 help_exit("Not root");
191 }
192 }
193
194
195
196 if (argv<toys.optargs || argv>toys.optargs+toys.optc) free(toys.optargs);
197 memset(&toys, 0, offsetof(struct toy_context, rebound));
198 if (oldwhich) memset(&this, 0, sizeof(this));
199
200
201 toy_singleinit(which, argv);
202}
203
204
205
206static void toy_exec_which(struct toy_list *which, char *argv[])
207{
208
209 if (!which || (which->flags&TOYFLAG_NOFORK)) return;
210
211
212
213
214
215
216
217 if (!CFG_TOYBOX_NORECURSE && toys.stacktop)
218 if (labs((long)toys.stacktop-(long)&which)>6000) return;
219
220
221 if (toys.which && (which->flags&TOYFLAG_ROOTONLY) && toys.wasroot) return;
222
223
224 toy_init(which, argv);
225 if (toys.which) toys.which->toy_main();
226 xexit();
227}
228
229
230void toy_exec(char *argv[])
231{
232 toy_exec_which(toy_find(*argv), argv);
233}
234
235
236
237void toybox_main(void)
238{
239 char *toy_paths[] = {"usr/", "bin/", "sbin/", 0}, *s = toys.argv[1];
240 int i, len = 0;
241 unsigned width = 80;
242
243
244
245
246 while (s) {
247 char *ss = basename(s);
248 struct toy_list *tl = toy_find(ss);
249
250 if (tl==toy_list && s!=toys.argv[1]) unknown(ss);
251 toy_exec_which(tl, toys.argv+1);
252 s = (0<readlink(s, libbuf, sizeof(libbuf))) ? libbuf : 0;
253 }
254
255
256 toys.which = toy_list;
257
258 if (toys.argv[1] && strcmp(toys.argv[1], "--long")) unknown(toys.argv[1]);
259
260
261 terminal_size(&width, 0);
262 for (i = 1; i<ARRAY_LEN(toy_list); i++) {
263 int fl = toy_list[i].flags;
264 if (fl & TOYMASK_LOCATION) {
265 if (toys.argv[1]) {
266 int j;
267 for (j = 0; toy_paths[j]; j++)
268 if (fl & (1<<j)) len += printf("%s", toy_paths[j]);
269 }
270 len += printf("%s",toy_list[i].name);
271 if (++len > width-15) len = 0;
272 xputc(len ? ' ' : '\n');
273 }
274 }
275 xputc('\n');
276}
277
278int main(int argc, char *argv[])
279{
280
281 if (!*argv) return 127;
282
283
284
285 if (!CFG_TOYBOX_FORK && (0x80 & **argv)) **argv &= 0x7f;
286 else {
287 int stack_start;
288
289 toys.stacktop = &stack_start;
290 }
291
292
293 if (CFG_TOYBOX_ON_ANDROID) signal(SIGPIPE, SIG_DFL);
294
295 if (CFG_TOYBOX) {
296
297 toys.argv = argv-1;
298 toybox_main();
299 } else {
300
301 toy_singleinit(toy_list, argv);
302 toy_list->toy_main();
303 }
304
305 xexit();
306}
307