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_readlink_or_warn(const char *path);
|
||||||
char *xmalloc_realpath(const char *path);
|
char *xmalloc_realpath(const char *path);
|
||||||
extern void xstat(const char *filename, struct stat *buf);
|
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 int wait4pid(int pid);
|
||||||
extern void xsetgid(gid_t gid);
|
extern void xsetgid(gid_t gid);
|
||||||
extern void xsetuid(uid_t uid);
|
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 xchdir(const char *path);
|
||||||
extern void xsetenv(const char *key, const char *value);
|
extern void xsetenv(const char *key, const char *value);
|
||||||
extern int xopen(const char *pathname, int flags);
|
extern int xopen(const char *pathname, int flags);
|
||||||
@ -460,6 +452,62 @@ void clear_username_cache(void);
|
|||||||
enum { USERNAME_MAX_SIZE = 16 - sizeof(int) };
|
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 };
|
enum { BB_GETOPT_ERROR = 0x80000000 };
|
||||||
extern const char *opt_complementary;
|
extern const char *opt_complementary;
|
||||||
#if ENABLE_GETOPT_LONG
|
#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 *concat_subpath_file(const char *path, const char *filename);
|
||||||
char *last_char_is(const char *s, int c);
|
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);
|
USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out);
|
||||||
int inflate(int in, int 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 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_issue(const char *issue_file, const char *tty);
|
||||||
extern void print_login_prompt(void);
|
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);
|
extern int get_terminal_width_height(const int fd, int *width, int *height);
|
||||||
|
|
||||||
char *is_in_ino_dev_hashtable(const struct stat *statbuf);
|
char *is_in_ino_dev_hashtable(const struct stat *statbuf);
|
||||||
|
@ -18,11 +18,68 @@
|
|||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include "libbb.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)
|
void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
/* Maybe we are already re-execed and come here again? */
|
||||||
|
if (re_execed)
|
||||||
|
return;
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if (!nochdir)
|
if (!nochdir)
|
||||||
@ -56,3 +113,78 @@ void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* BB_NOMMU */
|
#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.
|
// Wait for the specified child PID to exit, returning child's error return.
|
||||||
int wait4pid(int pid)
|
int wait4pid(int pid)
|
||||||
{
|
{
|
||||||
@ -510,47 +473,6 @@ DIR *xopendir(const char *path)
|
|||||||
return dp;
|
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.
|
// Die with an error message if we can't open a new socket.
|
||||||
int xsocket(int domain, int type, int protocol)
|
int xsocket(int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user