Unverified Commit f9d14b54 by Christian Brauner Committed by Stéphane Graber

init: rework dumb init

parent 79d5bcf1
...@@ -298,7 +298,8 @@ endif ...@@ -298,7 +298,8 @@ endif
if HAVE_STATIC_LIBCAP if HAVE_STATIC_LIBCAP
sbin_PROGRAMS += init.lxc.static sbin_PROGRAMS += init.lxc.static
init_lxc_static_SOURCES = tools/lxc_init.c error.c log.c initutils.c caps.c init_lxc_static_SOURCES = tools/lxc_init.c error.c log.c initutils.c caps.c \
arguments.c
if !HAVE_GETLINE if !HAVE_GETLINE
if HAVE_FGETLN if HAVE_FGETLN
......
...@@ -64,33 +64,36 @@ static int execute_start(struct lxc_handler *handler, void* data) ...@@ -64,33 +64,36 @@ static int execute_start(struct lxc_handler *handler, void* data)
initpath = choose_init(NULL); initpath = choose_init(NULL);
if (!initpath) { if (!initpath) {
ERROR("Failed to find an lxc-init or init.lxc"); ERROR("Failed to find an init.lxc or init.lxc.static");
goto out2; goto out2;
} }
argv[i++] = initpath; 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) if (my_args->quiet)
argv[i++] = "--quiet"; argv[i++] = "--quiet";
if (!handler->conf->rootfs.path) { if (!handler->conf->rootfs.path) {
argv[i++] = "--name"; argv[i++] = "-P";
argv[i++] = (char *)handler->name;
argv[i++] = "--lxcpath";
argv[i++] = (char *)handler->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++] = "--"; argv[i++] = "--";
for (j = 0; j < argc; j++) for (j = 0; j < argc; j++)
argv[i++] = my_args->argv[j]; argv[i++] = my_args->argv[j];
argv[i++] = NULL; argv[i++] = NULL;
NOTICE("exec'ing '%s'", my_args->argv[0]); NOTICE("Exec'ing \"%s\"", my_args->argv[0]);
execvp(argv[0], argv); execvp(argv[0], argv);
SYSERROR("failed to exec %s", argv[0]); SYSERROR("Failed to exec %s", argv[0]);
free(initpath); free(initpath);
out2: out2:
free(argv); free(argv);
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <sys/prctl.h>
#include "initutils.h" #include "initutils.h"
#include "log.h" #include "log.h"
...@@ -296,3 +298,107 @@ FILE *fopen_cloexec(const char *path, const char *mode) ...@@ -296,3 +298,107 @@ FILE *fopen_cloexec(const char *path, const char *mode)
errno = saved_errno; errno = saved_errno;
return ret; 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,17 +25,16 @@ ...@@ -25,17 +25,16 @@
#define __LXC_INITUTILS_H #define __LXC_INITUTILS_H
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.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" #include "config.h"
...@@ -44,11 +43,37 @@ ...@@ -44,11 +43,37 @@
#define DEFAULT_ZFSROOT "lxc" #define DEFAULT_ZFSROOT "lxc"
#define DEFAULT_RBDPOOL "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 void lxc_setup_fs(void);
extern const char *lxc_global_config_value(const char *option_name); extern const char *lxc_global_config_value(const char *option_name);
/* open a file with O_CLOEXEC */ /* open a file with O_CLOEXEC */
extern void remove_trailing_slashes(char *p); extern void remove_trailing_slashes(char *p);
FILE *fopen_cloexec(const char *path, const char *mode); extern FILE *fopen_cloexec(const char *path, const char *mode);
extern int setproctitle(char *title);
#endif /* __LXC_INITUTILS_H */ #endif /* __LXC_INITUTILS_H */
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "confile_utils.h" #include "confile_utils.h"
#include "console.h" #include "console.h"
#include "criu.h" #include "criu.h"
#include "initutils.h"
#include "log.h" #include "log.h"
#include "lxc.h" #include "lxc.h"
#include "lxccontainer.h" #include "lxccontainer.h"
......
...@@ -22,35 +22,27 @@ ...@@ -22,35 +22,27 @@
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <getopt.h>
#include <libgen.h> #include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <getopt.h>
#include <lxc/lxccontainer.h> #include <lxc/lxccontainer.h>
#include "log.h" #include "arguments.h"
#include "error.h" #include "error.h"
#include "initutils.h" #include "initutils.h"
#include "log.h"
lxc_log_define(lxc_init, lxc); 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 sig_atomic_t was_interrupted = 0;
static void interrupt_handler(int sig) static void interrupt_handler(int sig)
...@@ -59,114 +51,124 @@ static void interrupt_handler(int sig) ...@@ -59,114 +51,124 @@ static void interrupt_handler(int sig)
was_interrupted = sig; was_interrupted = sig;
} }
static void usage(void) { static const struct option my_longopts[] = {
fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n" LXC_COMMON_OPTIONS
"Common options :\n" };
" -n, --name=NAME NAME of the container\n"
" -l, --logpriority=LEVEL Set log priority to LEVEL\n" static int my_parser(struct lxc_arguments *args, int c, char *arg)
" -q, --quiet Don't produce any output\n" {
" -P, --lxcpath=PATH Use specified container path\n" return 0;
" -?, --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 main(int argc, char *argv[])
{ {
int i, ret;
pid_t pid, sid; pid_t pid, sid;
int err;
char **aargv;
sigset_t mask, omask;
struct sigaction act; struct sigaction act;
int i, have_status = 0, shutdown = 0;
int opt;
char *lxcpath = NULL, *name = NULL, *logpriority = NULL;
struct lxc_log log; struct lxc_log log;
sigset_t mask, omask;
int have_status = 0, shutdown = 0;
while ((opt = getopt_long(argc, argv, "n:l:qP:", options, NULL)) != -1) { if (lxc_arguments_parse(&my_args, argc, argv))
switch(opt) { exit(EXIT_FAILURE);
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 = name; log.name = my_args.name;
log.file = name ? NULL : "none"; log.file = my_args.log_file;
log.level = logpriority; log.level = my_args.log_priority;
log.prefix = basename(argv[0]); log.prefix = my_args.progname;
log.quiet = quiet; log.quiet = my_args.quiet;
log.lxcpath = lxcpath; log.lxcpath = my_args.lxcpath[0];
err = lxc_log_init(&log); ret = lxc_log_init(&log);
if (err < 0) if (ret < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
lxc_log_options_no_override(); lxc_log_options_no_override();
if (!argv[optind]) { if (!my_args.argc) {
ERROR("Missing command to launch"); ERROR("Please specify a command to execute");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
aargv = &argv[optind]; /* Mask all the signals so we are safe to install a signal handler and
* to fork.
/*
* mask all the signals so we are safe to install a
* signal handler and to fork
*/ */
if (sigfillset(&mask) || ret = sigfillset(&mask);
sigdelset(&mask, SIGILL) || if (ret < 0)
sigdelset(&mask, SIGSEGV) ||
sigdelset(&mask, SIGBUS) ||
sigprocmask(SIG_SETMASK, &mask, &omask)) {
SYSERROR("Failed to set signal mask");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
if (sigfillset(&act.sa_mask) || ret = sigdelset(&mask, SIGILL);
sigdelset(&act.sa_mask, SIGILL) || if (ret < 0)
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); 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);
ret = sigdelset(&act.sa_mask, SIGBUS);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&act.sa_mask, SIGSTOP);
if (ret < 0)
exit(EXIT_FAILURE);
ret = sigdelset(&act.sa_mask, SIGKILL);
if (ret < 0)
exit(EXIT_FAILURE);
act.sa_flags = 0; act.sa_flags = 0;
act.sa_handler = interrupt_handler; act.sa_handler = interrupt_handler;
for (i = 1; i < NSIG; i++) { for (i = 1; i < NSIG; i++) {
/* Exclude some signals: ILL, SEGV and BUS are likely to /* Exclude some signals: ILL, SEGV and BUS are likely to reveal
* reveal a bug and we want a core. STOP and KILL cannot be * a bug and we want a core. STOP and KILL cannot be handled
* handled anyway: they're here for documentation. 32 and 33 * anyway: they're here for documentation. 32 and 33 are not
* are not defined. * defined.
*/ */
if (i == SIGILL || if (i == SIGILL || i == SIGSEGV || i == SIGBUS ||
i == SIGSEGV || i == SIGSTOP || i == SIGKILL || i == 32 || i == 33)
i == SIGBUS ||
i == SIGSTOP ||
i == SIGKILL ||
i == 32 || i == 33)
continue; continue;
if (sigaction(i, &act, NULL) && errno != EINVAL) { ret = sigaction(i, &act, NULL);
SYSERROR("Failed to sigaction"); if (ret < 0) {
if (errno == EINVAL)
continue;
SYSERROR("Failed to change signal action");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
...@@ -178,13 +180,19 @@ int main(int argc, char *argv[]) ...@@ -178,13 +180,19 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (!pid) { if (!pid) {
int ret;
/* restore default signal handlers */ /* restore default signal handlers */
for (i = 1; i < NSIG; i++) for (i = 1; i < NSIG; i++) {
signal(i, SIG_DFL); 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);
}
}
if (sigprocmask(SIG_SETMASK, &omask, NULL)) { ret = sigprocmask(SIG_SETMASK, &omask, NULL);
if (ret < 0) {
SYSERROR("Failed to set signal mask"); SYSERROR("Failed to set signal mask");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
...@@ -193,25 +201,31 @@ int main(int argc, char *argv[]) ...@@ -193,25 +201,31 @@ int main(int argc, char *argv[])
if (sid < 0) if (sid < 0)
DEBUG("Failed to make child session leader"); DEBUG("Failed to make child session leader");
NOTICE("About to exec '%s'", aargv[0]); NOTICE("Exec'ing \"%s\"", my_args.argv[0]);
ret = execvp(aargv[0], aargv); ret = execvp(my_args.argv[0], my_args.argv);
ERROR("Failed to exec: '%s' : %s", aargv[0], strerror(errno)); ERROR("%s - Failed to exec \"%s\"", strerror(errno), my_args.argv[0]);
exit(ret); exit(ret);
} }
/* let's process the signals now */ INFO("Attempting to set proc title to \"init\"");
if (sigdelset(&omask, SIGALRM) || setproctitle("init");
sigprocmask(SIG_SETMASK, &omask, NULL)) {
/* 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) {
SYSERROR("Failed to set signal mask"); SYSERROR("Failed to set signal mask");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* no need of other inherited fds but stderr */ /* No need of other inherited fds but stderr. */
close(fileno(stdin)); close(STDIN_FILENO);
close(fileno(stdout)); close(STDOUT_FILENO);
err = EXIT_SUCCESS;
for (;;) { for (;;) {
int status; int status;
pid_t waited_pid; pid_t waited_pid;
...@@ -223,47 +237,56 @@ int main(int argc, char *argv[]) ...@@ -223,47 +237,56 @@ int main(int argc, char *argv[])
case SIGTERM: case SIGTERM:
if (!shutdown) { if (!shutdown) {
shutdown = 1; shutdown = 1;
kill(-1, SIGTERM); ret = kill(-1, SIGTERM);
if (ret < 0)
DEBUG("%s - Failed to send SIGTERM to "
"all children", strerror(errno));
alarm(1); alarm(1);
} }
break; break;
case SIGALRM: case SIGALRM:
kill(-1, SIGKILL); ret = kill(-1, SIGKILL);
if (ret < 0)
DEBUG("%s - Failed to send SIGKILL to all "
"children", strerror(errno));
break; break;
default: default:
kill(pid, was_interrupted); ret = kill(pid, was_interrupted);
if (ret < 0)
DEBUG("%s - Failed to send signal \"%d\" to "
"%d", strerror(errno), was_interrupted, pid);
break; break;
} }
ret = EXIT_SUCCESS;
was_interrupted = 0; was_interrupted = 0;
waited_pid = wait(&status); waited_pid = wait(&status);
if (waited_pid < 0) { if (waited_pid < 0) {
if (errno == ECHILD) if (errno == ECHILD)
goto out; goto out;
if (errno == EINTR) if (errno == EINTR)
continue; continue;
ERROR("Failed to wait child : %s", ERROR("%s - Failed to wait on child %d",
strerror(errno)); strerror(errno), pid);
goto out; goto out;
} }
/* reset timer each time a process exited */ /* Reset timer each time a process exited. */
if (shutdown) if (shutdown)
alarm(1); alarm(1);
/* /* Keep the exit code of the started application (not wrapped
* keep the exit code of started application * pid) and continue to wait for the end of the orphan group.
* (not wrapped pid) and continue to wait for
* the end of the orphan group.
*/ */
if (waited_pid == pid && !have_status) { if (waited_pid == pid && !have_status) {
err = lxc_error_set_and_log(waited_pid, status); ret = lxc_error_set_and_log(waited_pid, status);
have_status = 1; have_status = 1;
} }
} }
out: out:
if (err < 0) if (ret < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
exit(err); exit(ret);
} }
...@@ -49,31 +49,6 @@ ...@@ -49,31 +49,6 @@
#include "namespace.h" #include "namespace.h"
#include "utils.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 #ifndef O_PATH
#define O_PATH 010000000 #define O_PATH 010000000
#endif #endif
...@@ -1371,110 +1346,6 @@ char *get_template_path(const char *t) ...@@ -1371,110 +1346,6 @@ 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'. * @path: a pathname where / replaced with '\0'.
* @offsetp: pointer to int showing which path segment was last seen. * @offsetp: pointer to int showing which path segment was last seen.
* Updated on return to reflect the next segment. * Updated on return to reflect the next segment.
......
...@@ -339,7 +339,6 @@ extern int print_to_file(const char *file, const char *content); ...@@ -339,7 +339,6 @@ extern int print_to_file(const char *file, const char *content);
extern bool switch_to_ns(pid_t pid, const char *ns); extern bool switch_to_ns(pid_t pid, const char *ns);
extern int is_dir(const char *path); extern int is_dir(const char *path);
extern char *get_template_path(const char *t); 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, extern int safe_mount(const char *src, const char *dest, const char *fstype,
unsigned long flags, const void *data, unsigned long flags, const void *data,
const char *rootfs); 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