libbb: rework NOMMU helper API so that it makes more sense
and easier to use. Doesn't compile - need two more commits.
This commit is contained in:
parent
f62c6fa1ca
commit
bb7fcb4229
@ -263,17 +263,9 @@ char *xrealloc_getcwd_or_warn(char *cwd);
|
||||
char *xmalloc_readlink_or_warn(const char *path);
|
||||
char *xmalloc_realpath(const char *path);
|
||||
extern void xstat(const char *filename, struct stat *buf);
|
||||
extern pid_t spawn(char **argv);
|
||||
extern pid_t xspawn(char **argv);
|
||||
extern int wait4pid(int pid);
|
||||
extern void xsetgid(gid_t gid);
|
||||
extern void xsetuid(uid_t uid);
|
||||
extern void xdaemon(int nochdir, int noclose);
|
||||
/* More clever/thorough xdaemon */
|
||||
extern void bb_sanitize_stdio_maybe_daemonize(int daemonize);
|
||||
extern void bb_sanitize_stdio(void);
|
||||
/* NB: be careful: dont open syslog/network sockets before bb_daemonize */
|
||||
extern void bb_daemonize(void);
|
||||
extern void xchdir(const char *path);
|
||||
extern void xsetenv(const char *key, const char *value);
|
||||
extern int xopen(const char *pathname, int flags);
|
||||
@ -460,6 +452,62 @@ void clear_username_cache(void);
|
||||
enum { USERNAME_MAX_SIZE = 16 - sizeof(int) };
|
||||
|
||||
|
||||
int execable_file(const char *name);
|
||||
char *find_execable(const char *filename);
|
||||
int exists_execable(const char *filename);
|
||||
|
||||
#if ENABLE_FEATURE_EXEC_PREFER_APPLETS
|
||||
int bb_execvp(const char *file, char *const argv[]);
|
||||
#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
|
||||
#define BB_EXECLP(prog,cmd,...) \
|
||||
execlp((find_applet_by_name(prog)) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
|
||||
cmd, __VA_ARGS__)
|
||||
#else
|
||||
#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
|
||||
#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* NOMMU friendy fork+exec */
|
||||
pid_t spawn(char **argv);
|
||||
pid_t xspawn(char **argv);
|
||||
/* Helpers for daemonization.
|
||||
* bb_daemonize(flags) = daemonize, does not compile on NOMMU
|
||||
* bb_daemonize_or_rexec(flags, argv) = daemonizes on MMU (and ignores argv),
|
||||
* rexec's itself on NOMMU with argv passed as command line.
|
||||
* Thus bb_daemonize_or_rexec may cause your <applet>_main() to be re-executed
|
||||
* from the start. (It will detect it and not reexec again second time).
|
||||
* You have to audit carefully that you don't do something twice as a result
|
||||
* (opening files/sockets, parsing config files etc...)!
|
||||
*
|
||||
* Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty
|
||||
* (will do setsid()).
|
||||
*
|
||||
* Helper for network daemons in foreground mode:
|
||||
* bb_sanitize_stdio() = make sure that fd 0,1,2 are opened by opening them
|
||||
* to /dev/null if they are not.
|
||||
*/
|
||||
enum {
|
||||
DAEMON_CHDIR_ROOT = 1,
|
||||
DAEMON_DEVNULL_STDIO = /* 2 */ 0, /* no users so far */
|
||||
DAEMON_CLOSE_EXTRA_FDS = 4,
|
||||
DAEMON_ONLY_SANITIZE = 8, /* internal use */
|
||||
};
|
||||
#ifndef BB_NOMMU
|
||||
#define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
|
||||
#define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
|
||||
#else
|
||||
extern smallint re_execed;
|
||||
pid_t BUG_fork_is_unavailable_on_nommu(void);
|
||||
pid_t BUG_daemon_is_unavailable_on_nommu(void);
|
||||
pid_t BUG_bb_daemonize_is_unavailable_on_nommu(void);
|
||||
#define fork() BUG_fork_is_unavailable_on_nommu()
|
||||
#define daemon(a,b) BUG_daemon_is_unavailable_on_nommu()
|
||||
#define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu()
|
||||
#endif
|
||||
void bb_daemonize_or_rexec(int flags, char **argv);
|
||||
void bb_sanitize_stdio(void);
|
||||
|
||||
|
||||
enum { BB_GETOPT_ERROR = 0x80000000 };
|
||||
extern const char *opt_complementary;
|
||||
#if ENABLE_GETOPT_LONG
|
||||
@ -569,20 +617,6 @@ char *concat_path_file(const char *path, const char *filename);
|
||||
char *concat_subpath_file(const char *path, const char *filename);
|
||||
char *last_char_is(const char *s, int c);
|
||||
|
||||
int execable_file(const char *name);
|
||||
char *find_execable(const char *filename);
|
||||
int exists_execable(const char *filename);
|
||||
|
||||
#if ENABLE_FEATURE_EXEC_PREFER_APPLETS
|
||||
int bb_execvp(const char *file, char *const argv[]);
|
||||
#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
|
||||
#define BB_EXECLP(prog,cmd,...) \
|
||||
execlp((find_applet_by_name(prog)) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
|
||||
cmd, __VA_ARGS__)
|
||||
#else
|
||||
#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
|
||||
#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out);
|
||||
int inflate(int in, int out);
|
||||
@ -617,12 +651,8 @@ extern int index_in_str_array(const char * const string_array[], const char *key
|
||||
extern int index_in_substr_array(const char * const string_array[], const char *key);
|
||||
extern void print_login_issue(const char *issue_file, const char *tty);
|
||||
extern void print_login_prompt(void);
|
||||
#ifdef BB_NOMMU
|
||||
extern pid_t BUG_fork_is_unavailable_on_nommu(void);
|
||||
#define fork() BUG_fork_is_unavailable_on_nommu()
|
||||
extern void vfork_daemon_rexec(int nochdir, int noclose, char **argv);
|
||||
extern smallint re_execed;
|
||||
#endif
|
||||
|
||||
|
||||
extern int get_terminal_width_height(const int fd, int *width, int *height);
|
||||
|
||||
char *is_in_ino_dev_hashtable(const struct stat *statbuf);
|
||||
|
@ -18,11 +18,68 @@
|
||||
#include <paths.h>
|
||||
#include "libbb.h"
|
||||
|
||||
#ifdef BB_NOMMU
|
||||
/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
|
||||
* -1 for failure. Runs argv[0], searching path if that has no / in it. */
|
||||
pid_t spawn(char **argv)
|
||||
{
|
||||
/* Compiler should not optimize stores here */
|
||||
volatile int failed;
|
||||
pid_t pid;
|
||||
|
||||
// Be nice to nommu machines.
|
||||
failed = 0;
|
||||
pid = vfork();
|
||||
if (pid < 0) /* error */
|
||||
return pid;
|
||||
if (!pid) { /* child */
|
||||
/* Don't use BB_EXECVP tricks here! */
|
||||
execvp(argv[0], argv);
|
||||
|
||||
/* We are (maybe) sharing a stack with blocked parent,
|
||||
* let parent know we failed and then exit to unblock parent
|
||||
* (but don't run atexit() stuff, which would screw up parent.)
|
||||
*/
|
||||
failed = errno;
|
||||
_exit(0);
|
||||
}
|
||||
/* parent */
|
||||
/* Unfortunately, this is not reliable: vfork()
|
||||
* can be equivalent to fork() according to standards */
|
||||
if (failed) {
|
||||
errno = failed;
|
||||
return -1;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Die with an error message if we can't spawn a child process. */
|
||||
pid_t xspawn(char **argv)
|
||||
{
|
||||
pid_t pid = spawn(argv);
|
||||
if (pid < 0) bb_perror_msg_and_die("%s", *argv);
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0 //ndef BB_NOMMU
|
||||
// Die with an error message if we can't daemonize.
|
||||
void xdaemon(int nochdir, int noclose)
|
||||
{
|
||||
if (daemon(nochdir, noclose))
|
||||
bb_perror_msg_and_die("daemon");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // def BB_NOMMU
|
||||
void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Maybe we are already re-execed and come here again? */
|
||||
if (re_execed)
|
||||
return;
|
||||
|
||||
setsid();
|
||||
|
||||
if (!nochdir)
|
||||
@ -56,3 +113,78 @@ void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
|
||||
}
|
||||
}
|
||||
#endif /* BB_NOMMU */
|
||||
|
||||
#ifdef BB_NOMMU
|
||||
static void daemon_or_rexec(char **argv)
|
||||
{
|
||||
pid_t pid;
|
||||
/* Maybe we are already re-execed and come here again? */
|
||||
if (re_execed)
|
||||
return;
|
||||
|
||||
pid = vfork();
|
||||
if (pid < 0) /* wtf? */
|
||||
bb_perror_msg_and_die("vfork");
|
||||
if (pid) /* parent */
|
||||
exit(0);
|
||||
/* child - re-exec ourself */
|
||||
/* high-order bit of first char in argv[0] is a hidden
|
||||
* "we have (alrealy) re-execed, don't do it again" flag */
|
||||
argv[0][0] |= 0x80;
|
||||
execv(CONFIG_BUSYBOX_EXEC_PATH, argv);
|
||||
bb_perror_msg_and_die("exec %s", CONFIG_BUSYBOX_EXEC_PATH);
|
||||
}
|
||||
#else
|
||||
static void daemon_or_rexec(void)
|
||||
{
|
||||
pid_t pid;
|
||||
pid = fork();
|
||||
if (pid < 0) /* wtf? */
|
||||
bb_perror_msg_and_die("fork");
|
||||
if (pid) /* parent */
|
||||
exit(0);
|
||||
/* child */
|
||||
}
|
||||
#define daemon_or_rexec(argv) daemon_or_rexec()
|
||||
#endif
|
||||
|
||||
|
||||
/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
|
||||
* char **argv "vanishes" */
|
||||
void bb_daemonize_or_rexec(int flags, char **argv)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = xopen(bb_dev_null, O_RDWR);
|
||||
|
||||
if (flags & DAEMON_CHDIR_ROOT)
|
||||
xchdir("/");
|
||||
|
||||
if (flags & DAEMON_DEVNULL_STDIO) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
|
||||
while ((unsigned)fd < 2)
|
||||
fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
|
||||
|
||||
if (!(flags & DAEMON_ONLY_SANITIZE)) {
|
||||
daemon_or_rexec(argv);
|
||||
/* if daemonizing, make sure we detach from stdio */
|
||||
setsid();
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
if (fd > 2)
|
||||
close(fd--);
|
||||
if (flags & DAEMON_CLOSE_EXTRA_FDS)
|
||||
while (fd > 2)
|
||||
close(fd--); /* close everything after fd#2 */
|
||||
}
|
||||
|
||||
void bb_sanitize_stdio(void)
|
||||
{
|
||||
bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
|
||||
}
|
||||
|
@ -187,43 +187,6 @@ void xfflush_stdout(void)
|
||||
}
|
||||
}
|
||||
|
||||
// This does a fork/exec in one call, using vfork(). Return PID of new child,
|
||||
// -1 for failure. Runs argv[0], searching path if that has no / in it.
|
||||
pid_t spawn(char **argv)
|
||||
{
|
||||
/* Why static? */
|
||||
static int failed;
|
||||
pid_t pid;
|
||||
|
||||
// Be nice to nommu machines.
|
||||
failed = 0;
|
||||
pid = vfork();
|
||||
if (pid < 0) return pid;
|
||||
if (!pid) {
|
||||
BB_EXECVP(argv[0], argv);
|
||||
|
||||
// We're sharing a stack with blocked parent, let parent know we failed
|
||||
// and then exit to unblock parent (but don't run atexit() stuff, which
|
||||
// would screw up parent.)
|
||||
|
||||
failed = errno;
|
||||
_exit(0);
|
||||
}
|
||||
if (failed) {
|
||||
errno = failed;
|
||||
return -1;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Die with an error message if we can't spawn a child process.
|
||||
pid_t xspawn(char **argv)
|
||||
{
|
||||
pid_t pid = spawn(argv);
|
||||
if (pid < 0) bb_perror_msg_and_die("%s", *argv);
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Wait for the specified child PID to exit, returning child's error return.
|
||||
int wait4pid(int pid)
|
||||
{
|
||||
@ -510,47 +473,6 @@ DIR *xopendir(const char *path)
|
||||
return dp;
|
||||
}
|
||||
|
||||
#ifndef BB_NOMMU
|
||||
// Die with an error message if we can't daemonize.
|
||||
void xdaemon(int nochdir, int noclose)
|
||||
{
|
||||
if (daemon(nochdir, noclose))
|
||||
bb_perror_msg_and_die("daemon");
|
||||
}
|
||||
#endif
|
||||
|
||||
void bb_sanitize_stdio_maybe_daemonize(int daemonize)
|
||||
{
|
||||
int fd;
|
||||
/* Mega-paranoid */
|
||||
fd = xopen(bb_dev_null, O_RDWR);
|
||||
while ((unsigned)fd < 2)
|
||||
fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
|
||||
if (daemonize) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) /* wtf? */
|
||||
bb_perror_msg_and_die("fork");
|
||||
if (pid) /* parent */
|
||||
exit(0);
|
||||
/* child */
|
||||
/* if daemonizing, make sure we detach from stdio */
|
||||
setsid();
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
while (fd > 2)
|
||||
close(fd--); /* close everything after fd#2 */
|
||||
}
|
||||
void bb_sanitize_stdio(void)
|
||||
{
|
||||
bb_sanitize_stdio_maybe_daemonize(0);
|
||||
}
|
||||
void bb_daemonize(void)
|
||||
{
|
||||
bb_sanitize_stdio_maybe_daemonize(1);
|
||||
}
|
||||
|
||||
// Die with an error message if we can't open a new socket.
|
||||
int xsocket(int domain, int type, int protocol)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user