Revert "init: rework dumb init"

Seems a bit invasive for a bugfix release. This reverts commit f9d14b54. Signed-off-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent 49eb81b1
......@@ -298,8 +298,7 @@ endif
if HAVE_STATIC_LIBCAP
sbin_PROGRAMS += init.lxc.static
init_lxc_static_SOURCES = tools/lxc_init.c error.c log.c initutils.c caps.c \
arguments.c
init_lxc_static_SOURCES = tools/lxc_init.c error.c log.c initutils.c caps.c
if !HAVE_GETLINE
if HAVE_FGETLN
......
......@@ -64,36 +64,33 @@ static int execute_start(struct lxc_handler *handler, void* data)
initpath = choose_init(NULL);
if (!initpath) {
ERROR("Failed to find an init.lxc or init.lxc.static");
ERROR("Failed to find an lxc-init or init.lxc");
goto out2;
}
argv[i++] = initpath;
argv[i++] = "-n";
argv[i++] = (char *)handler->name;
if (lxc_log_has_valid_level()) {
argv[i++] = "-l";
argv[i++] = (char *)lxc_log_priority_to_string(lxc_log_get_level());
}
if (my_args->quiet)
argv[i++] = "--quiet";
if (!handler->conf->rootfs.path) {
argv[i++] = "-P";
argv[i++] = "--name";
argv[i++] = (char *)handler->name;
argv[i++] = "--lxcpath";
argv[i++] = (char *)handler->lxcpath;
}
if (lxc_log_has_valid_level()) {
argv[i++] = "--logpriority";
argv[i++] = (char *)
lxc_log_priority_to_string(lxc_log_get_level());
}
}
argv[i++] = "--";
for (j = 0; j < argc; j++)
argv[i++] = my_args->argv[j];
argv[i++] = NULL;
NOTICE("Exec'ing \"%s\"", my_args->argv[0]);
NOTICE("exec'ing '%s'", my_args->argv[0]);
execvp(argv[0], argv);
SYSERROR("Failed to exec %s", argv[0]);
SYSERROR("failed to exec %s", argv[0]);
free(initpath);
out2:
free(argv);
......
......@@ -21,8 +21,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/prctl.h>
#include "initutils.h"
#include "log.h"
......@@ -298,107 +296,3 @@ FILE *fopen_cloexec(const char *path, const char *mode)
errno = saved_errno;
return ret;
}
/*
* Sets the process title to the specified title. Note that this may fail if
* the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
*/
int setproctitle(char *title)
{
static char *proctitle = NULL;
char buf[2048], *tmp;
FILE *f;
int i, len, ret = 0;
/* We don't really need to know all of this stuff, but unfortunately
* PR_SET_MM_MAP requires us to set it all at once, so we have to
* figure it out anyway.
*/
unsigned long start_data, end_data, start_brk, start_code, end_code,
start_stack, arg_start, arg_end, env_start, env_end,
brk_val;
struct prctl_mm_map prctl_map;
f = fopen_cloexec("/proc/self/stat", "r");
if (!f) {
return -1;
}
tmp = fgets(buf, sizeof(buf), f);
fclose(f);
if (!tmp) {
return -1;
}
/* Skip the first 25 fields, column 26-28 are start_code, end_code,
* and start_stack */
tmp = strchr(buf, ' ');
for (i = 0; i < 24; i++) {
if (!tmp)
return -1;
tmp = strchr(tmp+1, ' ');
}
if (!tmp)
return -1;
i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
if (i != 3)
return -1;
/* Skip the next 19 fields, column 45-51 are start_data to arg_end */
for (i = 0; i < 19; i++) {
if (!tmp)
return -1;
tmp = strchr(tmp+1, ' ');
}
if (!tmp)
return -1;
i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
&start_data,
&end_data,
&start_brk,
&env_start,
&env_end);
if (i != 5)
return -1;
/* Include the null byte here, because in the calculations below we
* want to have room for it. */
len = strlen(title) + 1;
proctitle = realloc(proctitle, len);
if (!proctitle)
return -1;
arg_start = (unsigned long) proctitle;
arg_end = arg_start + len;
brk_val = syscall(__NR_brk, 0);
prctl_map = (struct prctl_mm_map) {
.start_code = start_code,
.end_code = end_code,
.start_stack = start_stack,
.start_data = start_data,
.end_data = end_data,
.start_brk = start_brk,
.brk = brk_val,
.arg_start = arg_start,
.arg_end = arg_end,
.env_start = env_start,
.env_end = env_end,
.auxv = NULL,
.auxv_size = 0,
.exe_fd = -1,
};
ret = prctl(PR_SET_MM, PR_SET_MM_MAP, (long) &prctl_map, sizeof(prctl_map), 0);
if (ret == 0)
strcpy((char*)arg_start, title);
else
INFO("setting cmdline failed - %s", strerror(errno));
return ret;
}
......@@ -25,16 +25,17 @@
#define __LXC_INITUTILS_H
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include "config.h"
......@@ -43,37 +44,11 @@
#define DEFAULT_ZFSROOT "lxc"
#define DEFAULT_RBDPOOL "lxc"
#ifndef PR_SET_MM
#define PR_SET_MM 35
#endif
#ifndef PR_SET_MM_MAP
#define PR_SET_MM_MAP 14
struct prctl_mm_map {
uint64_t start_code;
uint64_t end_code;
uint64_t start_data;
uint64_t end_data;
uint64_t start_brk;
uint64_t brk;
uint64_t start_stack;
uint64_t arg_start;
uint64_t arg_end;
uint64_t env_start;
uint64_t env_end;
uint64_t *auxv;
uint32_t auxv_size;
uint32_t exe_fd;
};
#endif
extern void lxc_setup_fs(void);
extern const char *lxc_global_config_value(const char *option_name);
/* open a file with O_CLOEXEC */
extern void remove_trailing_slashes(char *p);
extern FILE *fopen_cloexec(const char *path, const char *mode);
extern int setproctitle(char *title);
FILE *fopen_cloexec(const char *path, const char *mode);
#endif /* __LXC_INITUTILS_H */
......@@ -50,7 +50,6 @@
#include "confile_utils.h"
#include "console.h"
#include "criu.h"
#include "initutils.h"
#include "log.h"
#include "lxc.h"
#include "lxccontainer.h"
......
......@@ -22,27 +22,35 @@
*/
#define _GNU_SOURCE
#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <getopt.h>
#include <lxc/lxccontainer.h>
#include "arguments.h"
#include "log.h"
#include "error.h"
#include "initutils.h"
#include "log.h"
lxc_log_define(lxc_init, lxc);
static int quiet;
static const struct option options[] = {
{ "name", required_argument, NULL, 'n' },
{ "logpriority", required_argument, NULL, 'l' },
{ "quiet", no_argument, NULL, 'q' },
{ "lxcpath", required_argument, NULL, 'P' },
{ 0, 0, 0, 0 },
};
static sig_atomic_t was_interrupted = 0;
static void interrupt_handler(int sig)
......@@ -51,124 +59,114 @@ static void interrupt_handler(int sig)
was_interrupted = sig;
}
static const struct option my_longopts[] = {
LXC_COMMON_OPTIONS
};
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
return 0;
static void usage(void) {
fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n"
"Common options :\n"
" -n, --name=NAME NAME of the container\n"
" -l, --logpriority=LEVEL Set log priority to LEVEL\n"
" -q, --quiet Don't produce any output\n"
" -P, --lxcpath=PATH Use specified container path\n"
" -?, --help Give this help list\n"
"\n"
"Mandatory or optional arguments to long options are also mandatory or optional\n"
"for any corresponding short options.\n"
"\n"
"NOTE: lxc-init is intended for use by lxc internally\n"
" and does not need to be run by hand\n\n");
}
static struct lxc_arguments my_args = {
.progname = "lxc-init",
.help = "\
--name=NAME -- COMMAND\n\
\n\
lxc-init start a COMMAND as PID 2 inside a container\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
",
.options = my_longopts,
.parser = my_parser,
};
int main(int argc, char *argv[])
{
int i, ret;
pid_t pid, sid;
int err;
char **aargv;
sigset_t mask, omask;
struct sigaction act;
int i, have_status = 0, shutdown = 0;
int opt;
char *lxcpath = NULL, *name = NULL, *logpriority = NULL;
struct lxc_log log;
sigset_t mask, omask;
int have_status = 0, shutdown = 0;
if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE);
while ((opt = getopt_long(argc, argv, "n:l:qP:", options, NULL)) != -1) {
switch(opt) {
case 'n':
name = optarg;
break;
case 'l':
logpriority = optarg;
break;
case 'q':
quiet = 1;
break;
case 'P':
lxcpath = optarg;
break;
default: /* '?' */
usage();
exit(EXIT_FAILURE);
}
}
log.name = my_args.name;
log.file = my_args.log_file;
log.level = my_args.log_priority;
log.prefix = my_args.progname;
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
log.name = name;
log.file = name ? NULL : "none";
log.level = logpriority;
log.prefix = basename(argv[0]);
log.quiet = quiet;
log.lxcpath = lxcpath;
ret = lxc_log_init(&log);
if (ret < 0)
err = lxc_log_init(&log);
if (err < 0)
exit(EXIT_FAILURE);
lxc_log_options_no_override();
if (!my_args.argc) {
ERROR("Please specify a command to execute");
if (!argv[optind]) {
ERROR("Missing command to launch");
exit(EXIT_FAILURE);
}
/* Mask all the signals so we are safe to install a signal handler and
* to fork.
*/
ret = sigfillset(&mask);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&mask, SIGILL);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&mask, SIGSEGV);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&mask, SIGBUS);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigprocmask(SIG_SETMASK, &mask, &omask);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigfillset(&act.sa_mask);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&act.sa_mask, SIGILL);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&act.sa_mask, SIGSEGV);
if (ret < 0)
exit(EXIT_FAILURE);
aargv = &argv[optind];
ret = sigdelset(&act.sa_mask, SIGBUS);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&act.sa_mask, SIGSTOP);
if (ret < 0)
/*
* mask all the signals so we are safe to install a
* signal handler and to fork
*/
if (sigfillset(&mask) ||
sigdelset(&mask, SIGILL) ||
sigdelset(&mask, SIGSEGV) ||
sigdelset(&mask, SIGBUS) ||
sigprocmask(SIG_SETMASK, &mask, &omask)) {
SYSERROR("Failed to set signal mask");
exit(EXIT_FAILURE);
}
ret = sigdelset(&act.sa_mask, SIGKILL);
if (ret < 0)
if (sigfillset(&act.sa_mask) ||
sigdelset(&act.sa_mask, SIGILL) ||
sigdelset(&act.sa_mask, SIGSEGV) ||
sigdelset(&act.sa_mask, SIGBUS) ||
sigdelset(&act.sa_mask, SIGSTOP) ||
sigdelset(&act.sa_mask, SIGKILL)) {
ERROR("Failed to set signal");
exit(EXIT_FAILURE);
}
act.sa_flags = 0;
act.sa_handler = interrupt_handler;
for (i = 1; i < NSIG; i++) {
/* Exclude some signals: ILL, SEGV and BUS are likely to reveal
* a bug and we want a core. STOP and KILL cannot be handled
* anyway: they're here for documentation. 32 and 33 are not
* defined.
/* Exclude some signals: ILL, SEGV and BUS are likely to
* reveal a bug and we want a core. STOP and KILL cannot be
* handled anyway: they're here for documentation. 32 and 33
* are not defined.
*/
if (i == SIGILL || i == SIGSEGV || i == SIGBUS ||
i == SIGSTOP || i == SIGKILL || i == 32 || i == 33)
if (i == SIGILL ||
i == SIGSEGV ||
i == SIGBUS ||
i == SIGSTOP ||
i == SIGKILL ||
i == 32 || i == 33)
continue;
ret = sigaction(i, &act, NULL);
if (ret < 0) {
if (errno == EINVAL)
continue;
SYSERROR("Failed to change signal action");
if (sigaction(i, &act, NULL) && errno != EINVAL) {
SYSERROR("Failed to sigaction");
exit(EXIT_FAILURE);
}
}
......@@ -180,19 +178,13 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
if (!pid) {
int ret;
/* restore default signal handlers */
for (i = 1; i < NSIG; i++) {
sighandler_t sigerr;
sigerr = signal(i, SIG_DFL);
if (sigerr == SIG_ERR) {
DEBUG("%s - Failed to reset to default action "
"for signal \"%d\": %d", strerror(errno),
i, pid);
}
}
for (i = 1; i < NSIG; i++)
signal(i, SIG_DFL);
ret = sigprocmask(SIG_SETMASK, &omask, NULL);
if (ret < 0) {
if (sigprocmask(SIG_SETMASK, &omask, NULL)) {
SYSERROR("Failed to set signal mask");
exit(EXIT_FAILURE);
}
......@@ -201,31 +193,25 @@ int main(int argc, char *argv[])
if (sid < 0)
DEBUG("Failed to make child session leader");
NOTICE("Exec'ing \"%s\"", my_args.argv[0]);
NOTICE("About to exec '%s'", aargv[0]);
ret = execvp(my_args.argv[0], my_args.argv);
ERROR("%s - Failed to exec \"%s\"", strerror(errno), my_args.argv[0]);
ret = execvp(aargv[0], aargv);
ERROR("Failed to exec: '%s' : %s", aargv[0], strerror(errno));
exit(ret);
}
INFO("Attempting to set proc title to \"init\"");
setproctitle("init");
/* Let's process the signals now. */
ret = sigdelset(&omask, SIGALRM);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigprocmask(SIG_SETMASK, &omask, NULL);
if (ret < 0) {
/* let's process the signals now */
if (sigdelset(&omask, SIGALRM) ||
sigprocmask(SIG_SETMASK, &omask, NULL)) {
SYSERROR("Failed to set signal mask");
exit(EXIT_FAILURE);
}
/* No need of other inherited fds but stderr. */
close(STDIN_FILENO);
close(STDOUT_FILENO);
/* no need of other inherited fds but stderr */
close(fileno(stdin));
close(fileno(stdout));
err = EXIT_SUCCESS;
for (;;) {
int status;
pid_t waited_pid;
......@@ -237,56 +223,47 @@ int main(int argc, char *argv[])
case SIGTERM:
if (!shutdown) {
shutdown = 1;
ret = kill(-1, SIGTERM);
if (ret < 0)
DEBUG("%s - Failed to send SIGTERM to "
"all children", strerror(errno));
kill(-1, SIGTERM);
alarm(1);
}
break;
case SIGALRM:
ret = kill(-1, SIGKILL);
if (ret < 0)
DEBUG("%s - Failed to send SIGKILL to all "
"children", strerror(errno));
kill(-1, SIGKILL);
break;
default:
ret = kill(pid, was_interrupted);
if (ret < 0)
DEBUG("%s - Failed to send signal \"%d\" to "
"%d", strerror(errno), was_interrupted, pid);
kill(pid, was_interrupted);
break;
}
ret = EXIT_SUCCESS;
was_interrupted = 0;
waited_pid = wait(&status);
if (waited_pid < 0) {
if (errno == ECHILD)
goto out;
if (errno == EINTR)
continue;
ERROR("%s - Failed to wait on child %d",
strerror(errno), pid);
ERROR("Failed to wait child : %s",
strerror(errno));
goto out;
}
/* Reset timer each time a process exited. */
/* reset timer each time a process exited */
if (shutdown)
alarm(1);
/* Keep the exit code of the started application (not wrapped
* pid) and continue to wait for the end of the orphan group.
/*
* keep the exit code of started application
* (not wrapped pid) and continue to wait for
* the end of the orphan group.
*/
if (waited_pid == pid && !have_status) {
ret = lxc_error_set_and_log(waited_pid, status);
err = lxc_error_set_and_log(waited_pid, status);
have_status = 1;
}
}
out:
if (ret < 0)
if (err < 0)
exit(EXIT_FAILURE);
exit(ret);
exit(err);
}
......@@ -49,6 +49,31 @@
#include "namespace.h"
#include "utils.h"
#ifndef PR_SET_MM
#define PR_SET_MM 35
#endif
#ifndef PR_SET_MM_MAP
#define PR_SET_MM_MAP 14
struct prctl_mm_map {
uint64_t start_code;
uint64_t end_code;
uint64_t start_data;
uint64_t end_data;
uint64_t start_brk;
uint64_t brk;
uint64_t start_stack;
uint64_t arg_start;
uint64_t arg_end;
uint64_t env_start;
uint64_t env_end;
uint64_t *auxv;
uint32_t auxv_size;
uint32_t exe_fd;
};
#endif
#ifndef O_PATH
#define O_PATH 010000000
#endif
......@@ -1346,6 +1371,110 @@ char *get_template_path(const char *t)
}
/*
* Sets the process title to the specified title. Note that this may fail if
* the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
*/
int setproctitle(char *title)
{
static char *proctitle = NULL;
char buf[2048], *tmp;
FILE *f;
int i, len, ret = 0;
/* We don't really need to know all of this stuff, but unfortunately
* PR_SET_MM_MAP requires us to set it all at once, so we have to
* figure it out anyway.
*/
unsigned long start_data, end_data, start_brk, start_code, end_code,
start_stack, arg_start, arg_end, env_start, env_end,
brk_val;
struct prctl_mm_map prctl_map;
f = fopen_cloexec("/proc/self/stat", "r");
if (!f) {
return -1;
}
tmp = fgets(buf, sizeof(buf), f);
fclose(f);
if (!tmp) {
return -1;
}
/* Skip the first 25 fields, column 26-28 are start_code, end_code,
* and start_stack */
tmp = strchr(buf, ' ');
for (i = 0; i < 24; i++) {
if (!tmp)
return -1;
tmp = strchr(tmp+1, ' ');
}
if (!tmp)
return -1;
i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
if (i != 3)
return -1;
/* Skip the next 19 fields, column 45-51 are start_data to arg_end */
for (i = 0; i < 19; i++) {
if (!tmp)
return -1;
tmp = strchr(tmp+1, ' ');
}
if (!tmp)
return -1;
i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
&start_data,
&end_data,
&start_brk,
&env_start,
&env_end);
if (i != 5)
return -1;
/* Include the null byte here, because in the calculations below we
* want to have room for it. */
len = strlen(title) + 1;
proctitle = realloc(proctitle, len);
if (!proctitle)
return -1;
arg_start = (unsigned long) proctitle;
arg_end = arg_start + len;
brk_val = syscall(__NR_brk, 0);
prctl_map = (struct prctl_mm_map) {
.start_code = start_code,
.end_code = end_code,
.start_stack = start_stack,
.start_data = start_data,
.end_data = end_data,
.start_brk = start_brk,
.brk = brk_val,
.arg_start = arg_start,
.arg_end = arg_end,
.env_start = env_start,
.env_end = env_end,
.auxv = NULL,
.auxv_size = 0,
.exe_fd = -1,
};
ret = prctl(PR_SET_MM, PR_SET_MM_MAP, (long) &prctl_map, sizeof(prctl_map), 0);
if (ret == 0)
strcpy((char*)arg_start, title);
else
INFO("setting cmdline failed - %s", strerror(errno));
return ret;
}
/*
* @path: a pathname where / replaced with '\0'.
* @offsetp: pointer to int showing which path segment was last seen.
* Updated on return to reflect the next segment.
......
......@@ -339,6 +339,7 @@ extern int print_to_file(const char *file, const char *content);
extern bool switch_to_ns(pid_t pid, const char *ns);
extern int is_dir(const char *path);
extern char *get_template_path(const char *t);
extern int setproctitle(char *title);
extern int safe_mount(const char *src, const char *dest, const char *fstype,
unsigned long flags, const void *data,
const char *rootfs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment