aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-03-26 13:20:04 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-03-26 13:20:04 +0000
commit922db9aa31d3d21cbfa631ee88b7159f34319cc2 (patch)
tree5e4a6cc92e42ff7694ffc8b6a91434640e953726
parent2b50df8606f8d891abf38bc48950434c1d7009e6 (diff)
downloadbusybox-w32-922db9aa31d3d21cbfa631ee88b7159f34319cc2.tar.gz
busybox-w32-922db9aa31d3d21cbfa631ee88b7159f34319cc2.tar.bz2
busybox-w32-922db9aa31d3d21cbfa631ee88b7159f34319cc2.zip
libbb: rework NOMMU helper API so that it makes more sense
and easier to use. Doesn't compile - need two more commits. git-svn-id: svn://busybox.net/trunk/busybox@18241 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--include/libbb.h86
-rw-r--r--libbb/vfork_daemon_rexec.c134
-rw-r--r--libbb/xfuncs.c78
3 files changed, 191 insertions, 107 deletions
diff --git a/include/libbb.h b/include/libbb.h
index aba9316d1..ff7d3bf1a 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -263,17 +263,9 @@ char *xrealloc_getcwd_or_warn(char *cwd);
263char *xmalloc_readlink_or_warn(const char *path); 263char *xmalloc_readlink_or_warn(const char *path);
264char *xmalloc_realpath(const char *path); 264char *xmalloc_realpath(const char *path);
265extern void xstat(const char *filename, struct stat *buf); 265extern void xstat(const char *filename, struct stat *buf);
266extern pid_t spawn(char **argv);
267extern pid_t xspawn(char **argv);
268extern int wait4pid(int pid); 266extern int wait4pid(int pid);
269extern void xsetgid(gid_t gid); 267extern void xsetgid(gid_t gid);
270extern void xsetuid(uid_t uid); 268extern void xsetuid(uid_t uid);
271extern void xdaemon(int nochdir, int noclose);
272/* More clever/thorough xdaemon */
273extern void bb_sanitize_stdio_maybe_daemonize(int daemonize);
274extern void bb_sanitize_stdio(void);
275/* NB: be careful: dont open syslog/network sockets before bb_daemonize */
276extern void bb_daemonize(void);
277extern void xchdir(const char *path); 269extern void xchdir(const char *path);
278extern void xsetenv(const char *key, const char *value); 270extern void xsetenv(const char *key, const char *value);
279extern int xopen(const char *pathname, int flags); 271extern int xopen(const char *pathname, int flags);
@@ -460,6 +452,62 @@ void clear_username_cache(void);
460enum { USERNAME_MAX_SIZE = 16 - sizeof(int) }; 452enum { USERNAME_MAX_SIZE = 16 - sizeof(int) };
461 453
462 454
455int execable_file(const char *name);
456char *find_execable(const char *filename);
457int exists_execable(const char *filename);
458
459#if ENABLE_FEATURE_EXEC_PREFER_APPLETS
460int bb_execvp(const char *file, char *const argv[]);
461#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
462#define BB_EXECLP(prog,cmd,...) \
463 execlp((find_applet_by_name(prog)) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
464 cmd, __VA_ARGS__)
465#else
466#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
467#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
468#endif
469
470/* NOMMU friendy fork+exec */
471pid_t spawn(char **argv);
472pid_t xspawn(char **argv);
473/* Helpers for daemonization.
474 * bb_daemonize(flags) = daemonize, does not compile on NOMMU
475 * bb_daemonize_or_rexec(flags, argv) = daemonizes on MMU (and ignores argv),
476 * rexec's itself on NOMMU with argv passed as command line.
477 * Thus bb_daemonize_or_rexec may cause your <applet>_main() to be re-executed
478 * from the start. (It will detect it and not reexec again second time).
479 * You have to audit carefully that you don't do something twice as a result
480 * (opening files/sockets, parsing config files etc...)!
481 *
482 * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty
483 * (will do setsid()).
484 *
485 * Helper for network daemons in foreground mode:
486 * bb_sanitize_stdio() = make sure that fd 0,1,2 are opened by opening them
487 * to /dev/null if they are not.
488 */
489enum {
490 DAEMON_CHDIR_ROOT = 1,
491 DAEMON_DEVNULL_STDIO = /* 2 */ 0, /* no users so far */
492 DAEMON_CLOSE_EXTRA_FDS = 4,
493 DAEMON_ONLY_SANITIZE = 8, /* internal use */
494};
495#ifndef BB_NOMMU
496#define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
497#define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
498#else
499extern smallint re_execed;
500pid_t BUG_fork_is_unavailable_on_nommu(void);
501pid_t BUG_daemon_is_unavailable_on_nommu(void);
502pid_t BUG_bb_daemonize_is_unavailable_on_nommu(void);
503#define fork() BUG_fork_is_unavailable_on_nommu()
504#define daemon(a,b) BUG_daemon_is_unavailable_on_nommu()
505#define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu()
506#endif
507void bb_daemonize_or_rexec(int flags, char **argv);
508void bb_sanitize_stdio(void);
509
510
463enum { BB_GETOPT_ERROR = 0x80000000 }; 511enum { BB_GETOPT_ERROR = 0x80000000 };
464extern const char *opt_complementary; 512extern const char *opt_complementary;
465#if ENABLE_GETOPT_LONG 513#if ENABLE_GETOPT_LONG
@@ -569,20 +617,6 @@ char *concat_path_file(const char *path, const char *filename);
569char *concat_subpath_file(const char *path, const char *filename); 617char *concat_subpath_file(const char *path, const char *filename);
570char *last_char_is(const char *s, int c); 618char *last_char_is(const char *s, int c);
571 619
572int execable_file(const char *name);
573char *find_execable(const char *filename);
574int exists_execable(const char *filename);
575
576#if ENABLE_FEATURE_EXEC_PREFER_APPLETS
577int bb_execvp(const char *file, char *const argv[]);
578#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
579#define BB_EXECLP(prog,cmd,...) \
580 execlp((find_applet_by_name(prog)) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
581 cmd, __VA_ARGS__)
582#else
583#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
584#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
585#endif
586 620
587USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out); 621USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out);
588int inflate(int in, int out); 622int inflate(int in, int out);
@@ -617,12 +651,8 @@ extern int index_in_str_array(const char * const string_array[], const char *key
617extern int index_in_substr_array(const char * const string_array[], const char *key); 651extern int index_in_substr_array(const char * const string_array[], const char *key);
618extern void print_login_issue(const char *issue_file, const char *tty); 652extern void print_login_issue(const char *issue_file, const char *tty);
619extern void print_login_prompt(void); 653extern void print_login_prompt(void);
620#ifdef BB_NOMMU 654
621extern pid_t BUG_fork_is_unavailable_on_nommu(void); 655
622#define fork() BUG_fork_is_unavailable_on_nommu()
623extern void vfork_daemon_rexec(int nochdir, int noclose, char **argv);
624extern smallint re_execed;
625#endif
626extern int get_terminal_width_height(const int fd, int *width, int *height); 656extern int get_terminal_width_height(const int fd, int *width, int *height);
627 657
628char *is_in_ino_dev_hashtable(const struct stat *statbuf); 658char *is_in_ino_dev_hashtable(const struct stat *statbuf);
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 3185f2d39..c59b0b6fd 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -18,11 +18,68 @@
18#include <paths.h> 18#include <paths.h>
19#include "libbb.h" 19#include "libbb.h"
20 20
21#ifdef BB_NOMMU 21/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
22 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
23pid_t spawn(char **argv)
24{
25 /* Compiler should not optimize stores here */
26 volatile int failed;
27 pid_t pid;
28
29 // Be nice to nommu machines.
30 failed = 0;
31 pid = vfork();
32 if (pid < 0) /* error */
33 return pid;
34 if (!pid) { /* child */
35 /* Don't use BB_EXECVP tricks here! */
36 execvp(argv[0], argv);
37
38 /* We are (maybe) sharing a stack with blocked parent,
39 * let parent know we failed and then exit to unblock parent
40 * (but don't run atexit() stuff, which would screw up parent.)
41 */
42 failed = errno;
43 _exit(0);
44 }
45 /* parent */
46 /* Unfortunately, this is not reliable: vfork()
47 * can be equivalent to fork() according to standards */
48 if (failed) {
49 errno = failed;
50 return -1;
51 }
52 return pid;
53}
54
55/* Die with an error message if we can't spawn a child process. */
56pid_t xspawn(char **argv)
57{
58 pid_t pid = spawn(argv);
59 if (pid < 0) bb_perror_msg_and_die("%s", *argv);
60 return pid;
61}
62
63
64
65#if 0 //ndef BB_NOMMU
66// Die with an error message if we can't daemonize.
67void xdaemon(int nochdir, int noclose)
68{
69 if (daemon(nochdir, noclose))
70 bb_perror_msg_and_die("daemon");
71}
72#endif
73
74#if 0 // def BB_NOMMU
22void vfork_daemon_rexec(int nochdir, int noclose, char **argv) 75void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
23{ 76{
24 int fd; 77 int fd;
25 78
79 /* Maybe we are already re-execed and come here again? */
80 if (re_execed)
81 return;
82
26 setsid(); 83 setsid();
27 84
28 if (!nochdir) 85 if (!nochdir)
@@ -56,3 +113,78 @@ void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
56 } 113 }
57} 114}
58#endif /* BB_NOMMU */ 115#endif /* BB_NOMMU */
116
117#ifdef BB_NOMMU
118static void daemon_or_rexec(char **argv)
119{
120 pid_t pid;
121 /* Maybe we are already re-execed and come here again? */
122 if (re_execed)
123 return;
124
125 pid = vfork();
126 if (pid < 0) /* wtf? */
127 bb_perror_msg_and_die("vfork");
128 if (pid) /* parent */
129 exit(0);
130 /* child - re-exec ourself */
131 /* high-order bit of first char in argv[0] is a hidden
132 * "we have (alrealy) re-execed, don't do it again" flag */
133 argv[0][0] |= 0x80;
134 execv(CONFIG_BUSYBOX_EXEC_PATH, argv);
135 bb_perror_msg_and_die("exec %s", CONFIG_BUSYBOX_EXEC_PATH);
136}
137#else
138static void daemon_or_rexec(void)
139{
140 pid_t pid;
141 pid = fork();
142 if (pid < 0) /* wtf? */
143 bb_perror_msg_and_die("fork");
144 if (pid) /* parent */
145 exit(0);
146 /* child */
147}
148#define daemon_or_rexec(argv) daemon_or_rexec()
149#endif
150
151
152/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
153 * char **argv "vanishes" */
154void bb_daemonize_or_rexec(int flags, char **argv)
155{
156 int fd;
157
158 fd = xopen(bb_dev_null, O_RDWR);
159
160 if (flags & DAEMON_CHDIR_ROOT)
161 xchdir("/");
162
163 if (flags & DAEMON_DEVNULL_STDIO) {
164 close(0);
165 close(1);
166 close(2);
167 }
168
169 while ((unsigned)fd < 2)
170 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
171
172 if (!(flags & DAEMON_ONLY_SANITIZE)) {
173 daemon_or_rexec(argv);
174 /* if daemonizing, make sure we detach from stdio */
175 setsid();
176 dup2(fd, 0);
177 dup2(fd, 1);
178 dup2(fd, 2);
179 }
180 if (fd > 2)
181 close(fd--);
182 if (flags & DAEMON_CLOSE_EXTRA_FDS)
183 while (fd > 2)
184 close(fd--); /* close everything after fd#2 */
185}
186
187void bb_sanitize_stdio(void)
188{
189 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
190}
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 1dcdbc065..14bd62a15 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -187,43 +187,6 @@ void xfflush_stdout(void)
187 } 187 }
188} 188}
189 189
190// This does a fork/exec in one call, using vfork(). Return PID of new child,
191// -1 for failure. Runs argv[0], searching path if that has no / in it.
192pid_t spawn(char **argv)
193{
194 /* Why static? */
195 static int failed;
196 pid_t pid;
197
198 // Be nice to nommu machines.
199 failed = 0;
200 pid = vfork();
201 if (pid < 0) return pid;
202 if (!pid) {
203 BB_EXECVP(argv[0], argv);
204
205 // We're sharing a stack with blocked parent, let parent know we failed
206 // and then exit to unblock parent (but don't run atexit() stuff, which
207 // would screw up parent.)
208
209 failed = errno;
210 _exit(0);
211 }
212 if (failed) {
213 errno = failed;
214 return -1;
215 }
216 return pid;
217}
218
219// Die with an error message if we can't spawn a child process.
220pid_t xspawn(char **argv)
221{
222 pid_t pid = spawn(argv);
223 if (pid < 0) bb_perror_msg_and_die("%s", *argv);
224 return pid;
225}
226
227// Wait for the specified child PID to exit, returning child's error return. 190// Wait for the specified child PID to exit, returning child's error return.
228int wait4pid(int pid) 191int wait4pid(int pid)
229{ 192{
@@ -510,47 +473,6 @@ DIR *xopendir(const char *path)
510 return dp; 473 return dp;
511} 474}
512 475
513#ifndef BB_NOMMU
514// Die with an error message if we can't daemonize.
515void xdaemon(int nochdir, int noclose)
516{
517 if (daemon(nochdir, noclose))
518 bb_perror_msg_and_die("daemon");
519}
520#endif
521
522void bb_sanitize_stdio_maybe_daemonize(int daemonize)
523{
524 int fd;
525 /* Mega-paranoid */
526 fd = xopen(bb_dev_null, O_RDWR);
527 while ((unsigned)fd < 2)
528 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
529 if (daemonize) {
530 pid_t pid = fork();
531 if (pid < 0) /* wtf? */
532 bb_perror_msg_and_die("fork");
533 if (pid) /* parent */
534 exit(0);
535 /* child */
536 /* if daemonizing, make sure we detach from stdio */
537 setsid();
538 dup2(fd, 0);
539 dup2(fd, 1);
540 dup2(fd, 2);
541 }
542 while (fd > 2)
543 close(fd--); /* close everything after fd#2 */
544}
545void bb_sanitize_stdio(void)
546{
547 bb_sanitize_stdio_maybe_daemonize(0);
548}
549void bb_daemonize(void)
550{
551 bb_sanitize_stdio_maybe_daemonize(1);
552}
553
554// Die with an error message if we can't open a new socket. 476// Die with an error message if we can't open a new socket.
555int xsocket(int domain, int type, int protocol) 477int xsocket(int domain, int type, int protocol)
556{ 478{