From 9267beba7b74a6180cb43ea04e94ff2436664da2 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:13:09 +0100 Subject: [PATCH 01/34] tools: move lxc-attach to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 6 +- src/lxc/confile.c | 41 ----- src/lxc/confile.h | 2 - src/lxc/tools/arguments.c | 9 +- src/lxc/tools/lxc_attach.c | 12 +- src/lxc/tools/lxc_autostart.c | 1 - src/lxc/tools/tool_utils.c | 336 ++++++++++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 130 +++++++++++++ 8 files changed, 480 insertions(+), 57 deletions(-) create mode 100644 src/lxc/tools/tool_utils.c create mode 100644 src/lxc/tools/tool_utils.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 8f9a7ab297..185d2a4807 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -4,7 +4,6 @@ pkginclude_HEADERS = \ version.h noinst_HEADERS = \ - tools/arguments.h \ attach.h \ storage/storage.h \ storage/aufs.h \ @@ -18,6 +17,9 @@ noinst_HEADERS = \ storage/rsync.h \ storage/zfs.h \ storage/storage_utils.h \ + tools/arguments.h \ + tools/tool_utils.h \ + tools/tool_list.h \ cgroups/cgroup.h \ cgroups/cgroup_utils.h \ caps.h \ @@ -266,7 +268,7 @@ AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir) endif LDADD=liblxc.la @CAP_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@ -lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c +lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c tools/tool_utils.c lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c diff --git a/src/lxc/confile.c b/src/lxc/confile.c index fa4f84da9e..9950c7ea4c 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2409,47 +2409,6 @@ signed long lxc_config_parse_arch(const char *arch) return -1; } -int lxc_fill_elevated_privileges(char *flaglist, int *flags) -{ - char *token, *saveptr = NULL; - int i, aflag; - struct { - const char *token; - int flag; - } all_privs[] = { - { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP }, - { "CAP", LXC_ATTACH_DROP_CAPABILITIES }, - { "LSM", LXC_ATTACH_LSM_EXEC }, - { NULL, 0 } - }; - - if (!flaglist) { - /* For the sake of backward compatibility, drop all privileges - * if none is specified. - */ - for (i = 0; all_privs[i].token; i++) - *flags |= all_privs[i].flag; - - return 0; - } - - token = strtok_r(flaglist, "|", &saveptr); - while (token) { - aflag = -1; - for (i = 0; all_privs[i].token; i++) - if (!strcmp(all_privs[i].token, token)) - aflag = all_privs[i].flag; - if (aflag < 0) - return -1; - - *flags |= aflag; - - token = strtok_r(NULL, "|", &saveptr); - } - - return 0; -} - /* Write out a configuration file. */ void write_config(FILE *fout, struct lxc_conf *c) { diff --git a/src/lxc/confile.h b/src/lxc/confile.h index d502178604..6c69bc7a5f 100644 --- a/src/lxc/confile.h +++ b/src/lxc/confile.h @@ -92,8 +92,6 @@ extern int lxc_config_define_load(struct lxc_list *defines, /* needed for lxc-attach */ extern signed long lxc_config_parse_arch(const char *arch); -extern int lxc_fill_elevated_privileges(char *flaglist, int *flags); - extern int lxc_clear_config_item(struct lxc_conf *c, const char *key); extern void write_config(FILE *fout, struct lxc_conf *c); diff --git a/src/lxc/tools/arguments.c b/src/lxc/tools/arguments.c index 272340b65d..f98053feca 100644 --- a/src/lxc/tools/arguments.c +++ b/src/lxc/tools/arguments.c @@ -182,6 +182,13 @@ static int lxc_arguments_lxcpath_add(struct lxc_arguments *args, return 0; } +void remove_trailing_slashes(char *p) +{ + int l = strlen(p); + while (--l >= 0 && (p[l] == '/' || p[l] == '\n')) + p[l] = '\0'; +} + extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, char *const argv[]) { @@ -250,7 +257,7 @@ extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, /* If no lxcpaths were given, use default */ if (!args->lxcpath_cnt) { ret = lxc_arguments_lxcpath_add( - args, lxc_global_config_value("lxc.lxcpath")); + args, lxc_get_global_config_item("lxc.lxcpath")); if (ret < 0) return ret; } diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c index 926bf079ee..b2c405d3ad 100644 --- a/src/lxc/tools/lxc_attach.c +++ b/src/lxc/tools/lxc_attach.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -36,16 +37,8 @@ #include -#include "attach.h" #include "arguments.h" -#include "caps.h" -#include "conf.h" -#include "confile.h" -#include "console.h" -#include "log.h" -#include "list.h" -#include "mainloop.h" -#include "utils.h" +#include "tool_utils.h" static const struct option my_longopts[] = { {"elevated-privileges", optional_argument, 0, 'e'}, @@ -290,7 +283,6 @@ int main(int argc, char *argv[]) r = lxc_log_init(&log); if (r) exit(EXIT_FAILURE); - lxc_log_options_no_override(); if (geteuid()) { if (access(my_args.lxcpath[0], O_RDONLY) < 0) { diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c index 48727b9f12..a3d4a8a8a4 100644 --- a/src/lxc/tools/lxc_autostart.c +++ b/src/lxc/tools/lxc_autostart.c @@ -24,7 +24,6 @@ #include #include "arguments.h" -#include "list.h" #include "log.h" #include "utils.h" diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c new file mode 100644 index 0000000000..39b3881615 --- /dev/null +++ b/src/lxc/tools/tool_utils.c @@ -0,0 +1,336 @@ +/* liblxcapi + * + * Copyright © 2018 Christian Brauner . + * Copyright © 2018 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_SYS_PERSONALITY_H +#include +#endif + +#include + +#include "tool_utils.h" + +int lxc_fill_elevated_privileges(char *flaglist, int *flags) +{ + char *token, *saveptr = NULL; + int i, aflag; + struct { + const char *token; + int flag; + } all_privs[] = { + { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP }, + { "CAP", LXC_ATTACH_DROP_CAPABILITIES }, + { "LSM", LXC_ATTACH_LSM_EXEC }, + { NULL, 0 } + }; + + if (!flaglist) { + /* For the sake of backward compatibility, drop all privileges + * if none is specified. + */ + for (i = 0; all_privs[i].token; i++) + *flags |= all_privs[i].flag; + + return 0; + } + + token = strtok_r(flaglist, "|", &saveptr); + while (token) { + aflag = -1; + for (i = 0; all_privs[i].token; i++) + if (!strcmp(all_privs[i].token, token)) + aflag = all_privs[i].flag; + if (aflag < 0) + return -1; + + *flags |= aflag; + + token = strtok_r(NULL, "|", &saveptr); + } + + return 0; +} + +signed long lxc_config_parse_arch(const char *arch) +{ +#if HAVE_SYS_PERSONALITY_H + size_t i; + struct per_name { + char *name; + unsigned long per; + } pername[] = { + { "x86", PER_LINUX32 }, + { "linux32", PER_LINUX32 }, + { "i386", PER_LINUX32 }, + { "i486", PER_LINUX32 }, + { "i586", PER_LINUX32 }, + { "i686", PER_LINUX32 }, + { "athlon", PER_LINUX32 }, + { "mips", PER_LINUX32 }, + { "mipsel", PER_LINUX32 }, + { "ppc", PER_LINUX32 }, + { "arm", PER_LINUX32 }, + { "armv7l", PER_LINUX32 }, + { "armhf", PER_LINUX32 }, + { "armel", PER_LINUX32 }, + { "powerpc", PER_LINUX32 }, + { "linux64", PER_LINUX }, + { "x86_64", PER_LINUX }, + { "amd64", PER_LINUX }, + { "mips64", PER_LINUX }, + { "mips64el", PER_LINUX }, + { "ppc64", PER_LINUX }, + { "ppc64le", PER_LINUX }, + { "ppc64el", PER_LINUX }, + { "powerpc64", PER_LINUX }, + { "s390x", PER_LINUX }, + { "aarch64", PER_LINUX }, + { "arm64", PER_LINUX }, + }; + size_t len = sizeof(pername) / sizeof(pername[0]); + + for (i = 0; i < len; i++) { + if (!strcmp(pername[i].name, arch)) + return pername[i].per; + } +#endif + + return -1; +} + +enum { + LXC_NS_USER, + LXC_NS_MNT, + LXC_NS_PID, + LXC_NS_UTS, + LXC_NS_IPC, + LXC_NS_NET, + LXC_NS_CGROUP, + LXC_NS_MAX +}; + +const static struct ns_info { + const char *proc_name; + int clone_flag; +} ns_info[LXC_NS_MAX] = { + [LXC_NS_USER] = { "user", CLONE_NEWUSER }, + [LXC_NS_MNT] = { "mnt", CLONE_NEWNS }, + [LXC_NS_PID] = { "pid", CLONE_NEWPID }, + [LXC_NS_UTS] = { "uts", CLONE_NEWUTS }, + [LXC_NS_IPC] = { "ipc", CLONE_NEWIPC }, + [LXC_NS_NET] = { "net", CLONE_NEWNET }, + [LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP } +}; + +int lxc_namespace_2_cloneflag(const char *namespace) +{ + int i; + for (i = 0; i < LXC_NS_MAX; i++) + if (!strcasecmp(ns_info[i].proc_name, namespace)) + return ns_info[i].clone_flag; + + fprintf(stderr, "Invalid namespace name \"%s\"", namespace); + return -EINVAL; +} + +int lxc_fill_namespace_flags(char *flaglist, int *flags) +{ + char *token, *saveptr = NULL; + int aflag; + + if (!flaglist) { + fprintf(stderr, "At least one namespace is needed\n"); + return -1; + } + + token = strtok_r(flaglist, "|", &saveptr); + while (token) { + + aflag = lxc_namespace_2_cloneflag(token); + if (aflag < 0) + return -1; + + *flags |= aflag; + + token = strtok_r(NULL, "|", &saveptr); + } + + return 0; +} + +#if HAVE_LIBCAP + +#ifndef PR_CAPBSET_READ +#define PR_CAPBSET_READ 23 +#endif + +int lxc_caps_init(void) +{ + uid_t uid = getuid(); + gid_t gid = getgid(); + uid_t euid = geteuid(); + + if (!uid) + return 0; + + if (uid && !euid) { + if (prctl(PR_SET_KEEPCAPS, 1)) { + fprintf(stderr, "%s - Failed to set PR_SET_KEEPCAPS\n", strerror(errno)); + return -1; + } + + if (setresgid(gid, gid, gid)) { + fprintf(stderr, "%s - Failed to change gid to %d\n", strerror(errno), gid); + return -1; + } + + if (setresuid(uid, uid, uid)) { + fprintf(stderr, "%s - Failed to change uid to %d\n", strerror(errno), uid); + return -1; + } + + if (lxc_caps_up()) { + fprintf(stderr, "%s - Failed to restore capabilities\n", strerror(errno)); + return -1; + } + } + + return 0; +} + +int lxc_caps_up(void) +{ + cap_t caps; + cap_value_t cap; + int ret; + + /* when we are run as root, we don't want to play + * with the capabilities */ + if (!getuid()) + return 0; + + caps = cap_get_proc(); + if (!caps) { + fprintf(stderr, "%s - Failed to cap_get_proc\n", strerror(errno)); + return -1; + } + + for (cap = 0; cap <= CAP_LAST_CAP; cap++) { + cap_flag_value_t flag; + + ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag); + if (ret) { + if (errno == EINVAL) { + break; + } else { + fprintf(stderr, "%s- Failed to call cap_get_flag\n", strerror(errno)); + goto out; + } + } + + ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag); + if (ret) { + fprintf(stderr, "%s - Failed to call cap_set_flag", strerror(errno)); + goto out; + } + } + + ret = cap_set_proc(caps); + if (ret) { + fprintf(stderr, "%s - Failed to cap_set_proc", strerror(errno)); + goto out; + } + +out: + cap_free(caps); + return 0; +} + +#endif + +int lxc_wait_for_pid_status(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + return -1; + } + if (ret != pid) + goto again; + return status; +} + +int lxc_safe_int(const char *numstr, int *converted) +{ + char *err = NULL; + signed long int sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + if (sli > INT_MAX || sli < INT_MIN) + return -ERANGE; + + *converted = (int)sli; + return 0; +} + +int lxc_safe_long(const char *numstr, long int *converted) +{ + char *err = NULL; + signed long int sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + *converted = sli; + return 0; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h new file mode 100644 index 0000000000..9f0e6a01fd --- /dev/null +++ b/src/lxc/tools/tool_utils.h @@ -0,0 +1,130 @@ +/* liblxcapi + * + * Copyright © 2018 Christian Brauner . + * Copyright © 2018 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __LXC_UTILS_H +#define __LXC_UTILS_H + +/* Properly support loop devices on 32bit systems. */ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include + +#include + +#include "tool_list.h" + +#define TOOL_MAXPATHLEN 4096 + +#ifndef CLONE_PARENT_SETTID +#define CLONE_PARENT_SETTID 0x00100000 +#endif + +#ifndef CLONE_CHILD_CLEARTID +#define CLONE_CHILD_CLEARTID 0x00200000 +#endif + +#ifndef CLONE_CHILD_SETTID +#define CLONE_CHILD_SETTID 0x01000000 +#endif + +#ifndef CLONE_VFORK +#define CLONE_VFORK 0x00004000 +#endif + +#ifndef CLONE_THREAD +#define CLONE_THREAD 0x00010000 +#endif + +#ifndef CLONE_SETTLS +#define CLONE_SETTLS 0x00080000 +#endif + +#ifndef CLONE_VM +#define CLONE_VM 0x00000100 +#endif + +#ifndef CLONE_FILES +#define CLONE_FILES 0x00000400 +#endif + +#ifndef CLONE_FS +# define CLONE_FS 0x00000200 +#endif +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWCGROUP +# define CLONE_NEWCGROUP 0x02000000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif + +enum { + LXC_NS_USER, + LXC_NS_MNT, + LXC_NS_PID, + LXC_NS_UTS, + LXC_NS_IPC, + LXC_NS_NET, + LXC_NS_CGROUP, + LXC_NS_MAX +}; + +extern int lxc_fill_elevated_privileges(char *flaglist, int *flags); +extern signed long lxc_config_parse_arch(const char *arch); +extern int lxc_namespace_2_cloneflag(const char *namespace); +extern int lxc_fill_namespace_flags(char *flaglist, int *flags); + +#if HAVE_LIBCAP +#include + +extern int lxc_caps_up(void); +extern int lxc_caps_init(void); +#else +static inline int lxc_caps_up(void) { + return 0; +} + +static inline int lxc_caps_init(void) { + return 0; +} +#endif + +extern int lxc_wait_for_pid_status(pid_t pid); +extern int lxc_safe_int(const char *numstr, int *converted); +extern int lxc_safe_long(const char *numstr, long int *converted); + +#endif /* __LXC_UTILS_H */ From a6993015de23bd96bde3941e0f78ff921956f0b6 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:25:15 +0100 Subject: [PATCH 02/34] tools: lxc-autostart: non-functional changes Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_autostart.c | 180 +++++++++++++++------------------- 1 file changed, 80 insertions(+), 100 deletions(-) diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c index a3d4a8a8a4..b3823af2f0 100644 --- a/src/lxc/tools/lxc_autostart.c +++ b/src/lxc/tools/lxc_autostart.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include #include #include @@ -144,14 +146,13 @@ int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) { return 0; } -/* - * This is a variation of get_list below it. - * This version allows two additional features. - * If a list is passed to it, it adds to it. - * It allows for empty entries (i.e. "group1,,group2") generating - * and empty list entry. +/* This is a variation of get_list below it. This version allows two additional + * features. If a list is passed to it, it adds to it. It allows for empty + * entries (i.e. "group1,,group2") generating and empty list entry. */ -static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list) { +static struct lxc_list *accumulate_list(char *input, char *delimiter, + struct lxc_list *str_list) +{ char *workstr = NULL; char *workptr = NULL; char *next_ptr = NULL; @@ -159,45 +160,33 @@ static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc struct lxc_list *workstr_list; workstr = strdup(input); - if (!workstr) { + if (!workstr) return NULL; - } workstr_list = str_list; - if ( ! workstr_list ) { + if (!workstr_list) { workstr_list = malloc(sizeof(*workstr_list)); lxc_list_init(workstr_list); } for (workptr = workstr; workptr; workptr = next_ptr) { - /* - * We can't use strtok_r here because it collapses - * multiple delimiters into 1 making empty fields - * impossible... + /* We can't use strtok_r here because it collapses multiple + * delimiters into 1 making empty fields impossible... */ - /* token = strtok_r(workptr, delimiter, &sptr); */ - next_ptr = strchr( workptr, *delimiter ); - - if( next_ptr ) { + next_ptr = strchr(workptr, *delimiter); + if (next_ptr) *next_ptr++ = '\0'; - } - /* - * At this point, we'd like to check to see if this - * group is already contained in the list and ignore - * it if it is... This also helps us with any - * corner cases where a string begins or ends with a - * delimiter. + /* At this point, we'd like to check to see if this group is + * already contained in the list and ignore it if it is... This + * also helps us with any corner cases where a string begins or + * ends with a delimiter. */ - - if ( list_contains_entry( workptr, workstr_list ) ) { - if ( *workptr ) { - fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr ); - fflush(stderr); - } else { - fprintf(stderr, "Duplicate NULL group in list - ignoring\n" ); - fflush(stderr); - } + if (list_contains_entry(workptr, workstr_list)) { + if (*workptr) + fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr); + else + fprintf(stderr, "Duplicate NULL group in list - ignoring\n"); } else { worklist = malloc(sizeof(*worklist)); if (!worklist) @@ -218,7 +207,8 @@ static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc return workstr_list; } -static struct lxc_list *get_list(char *input, char *delimiter) { +static struct lxc_list *get_list(char *input, char *delimiter) +{ char *workstr = NULL; char *workptr = NULL; char *sptr = NULL; @@ -235,11 +225,10 @@ static struct lxc_list *get_list(char *input, char *delimiter) { return NULL; } - for (workptr = workstr;;workptr = NULL) { + for (workptr = workstr;; workptr = NULL) { token = strtok_r(workptr, delimiter, &sptr); - if (!token) { + if (!token) break; - } worklist = malloc(sizeof(*worklist)); if (!worklist) @@ -259,16 +248,17 @@ static struct lxc_list *get_list(char *input, char *delimiter) { return workstr_list; } -static struct lxc_list *get_config_list(struct lxc_container *c, char *key) { +static struct lxc_list *get_config_list(struct lxc_container *c, char *key) +{ int len = 0; - char* value = NULL; + char *value = NULL; struct lxc_list *config_list = NULL; len = c->get_config_item(c, key, NULL, 0); if (len < 0) return NULL; - value = (char*) malloc(sizeof(char)*len + 1); + value = (char *)malloc(sizeof(char) * len + 1); if (value == NULL) return NULL; @@ -288,16 +278,16 @@ static struct lxc_list *get_config_list(struct lxc_container *c, char *key) { return config_list; } -static int get_config_integer(struct lxc_container *c, char *key) { - int len = 0; - int ret = 0; - char* value = NULL; +static int get_config_integer(struct lxc_container *c, char *key) +{ + int len = 0, ret = 0; + char *value = NULL; len = c->get_config_item(c, key, NULL, 0); if (len < 0) return 0; - value = (char*) malloc(sizeof(char)*len + 1); + value = (char *)malloc(sizeof(char) * len + 1); if (value == NULL) return 0; @@ -314,7 +304,8 @@ static int get_config_integer(struct lxc_container *c, char *key) { return ret; } -static int cmporder(const void *p1, const void *p2) { +static int cmporder(const void *p1, const void *p2) +{ struct lxc_container *c1 = *(struct lxc_container **)p1; struct lxc_container *c2 = *(struct lxc_container **)p2; @@ -323,33 +314,33 @@ static int cmporder(const void *p1, const void *p2) { if (c1_order == c2_order) return strcmp(c1->name, c2->name); - else - return (c1_order - c2_order); + + return (c1_order - c2_order); } -static int toss_list( struct lxc_list *c_groups_list ) { +static int toss_list(struct lxc_list *c_groups_list) +{ struct lxc_list *it, *next; - if (c_groups_list) { - lxc_list_for_each_safe(it, c_groups_list, next) { - lxc_list_del(it); - free(it->elem); - free(it); - } - free(c_groups_list); + if (!c_groups_list) + return 1; + + lxc_list_for_each_safe(it, c_groups_list, next) { + lxc_list_del(it); + free(it->elem); + free(it); } + free(c_groups_list); return 1; } int main(int argc, char *argv[]) { - int count = 0; - int i = 0; - int ret = 0; + int count = 0, i = 0, ret = 0; + struct lxc_list *cmd_group; struct lxc_container **containers = NULL; struct lxc_list **c_groups_lists = NULL; - struct lxc_list *cmd_group; struct lxc_log log; if (lxc_arguments_parse(&my_args, argc, argv)) @@ -374,36 +365,29 @@ int main(int argc, char *argv[]) if (count < 0) exit(EXIT_FAILURE); - if (!my_args.all) { - /* Allocate an array for our container group lists */ + /* Allocate an array for our container group lists */ + if (!my_args.all) c_groups_lists = calloc( count, sizeof( struct lxc_list * ) ); - } qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder); - if (cmd_groups_list && my_args.all) { + if (cmd_groups_list && my_args.all) fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.\n"); - fflush(stderr); - } - if (!cmd_groups_list) { - /* - * We need a default cmd_groups_list even for the -a - * case in order to force a pass through the loop for - * the NULL group. This, someday, could be taken from - * a config file somewhere... - */ + /* We need a default cmd_groups_list even for the -a + * case in order to force a pass through the loop for + * the NULL group. This, someday, could be taken from + * a config file somewhere... + */ + if (!cmd_groups_list) cmd_groups_list = accumulate_list( "" , ",", NULL ); - } lxc_list_for_each(cmd_group, cmd_groups_list) { - - /* - * Prograpmmers Note: - * Because we may take several passes through the container list - * We'll switch on if the container pointer is NULL and if we process a - * container (run it or decide to ignore it) and call lxc_container_put - * then we'll NULL it out and not check it again. + /* Because we may take several passes through the container list + * We'll switch on if the container pointer is NULL and if we + * process a container (run it or decide to ignore it) and call + * lxc_container_put then we'll NULL it out and not check it + * again. */ for (i = 0; i < count; i++) { struct lxc_container *c = containers[i]; @@ -412,10 +396,9 @@ int main(int argc, char *argv[]) /* Skip - must have been already processed */ continue; - /* - * We haven't loaded the container groups yet so - * these next two checks don't need to free them - * if they fail. They'll fail on the first pass. + /* We haven't loaded the container groups yet so these + * next two checks don't need to free them if they fail. + * They'll fail on the first pass. */ if (!c->may_control(c)) { /* We're done with this container */ @@ -442,8 +425,10 @@ int main(int argc, char *argv[]) ret = list_contains_entry(cmd_group->elem, c_groups_lists[i]); if ( ret == 0 ) { - /* Not in the target group this pass */ - /* Leave in the list for subsequent passes */ + /* Not in the target group this pass so + * leave in the list for subsequent + * passes. + */ continue; } } @@ -467,8 +452,7 @@ int main(int argc, char *argv[]) } } } - } - else if (my_args.hardstop) { + } else if (my_args.hardstop) { /* Kill the container */ if (c->is_running(c)) { if (my_args.list) { @@ -482,8 +466,7 @@ int main(int argc, char *argv[]) } } } - } - else if (my_args.reboot) { + } else if (my_args.reboot) { /* Reboot the container */ if (c->is_running(c)) { if (my_args.list) { @@ -500,8 +483,7 @@ int main(int argc, char *argv[]) sleep(get_config_integer(c, "lxc.start.delay")); } } - } - else { + } else { /* Start the container */ if (!c->is_running(c)) { if (my_args.list) { @@ -525,9 +507,8 @@ int main(int argc, char *argv[]) * then we're done with this container... We can dump any * c_groups_list and the container itself. */ - if ( lxc_container_put(c) > 0 ) { + if ( lxc_container_put(c) > 0 ) containers[i] = NULL; - } if ( c_groups_lists ) { toss_list(c_groups_lists[i]); c_groups_lists[i] = NULL; @@ -538,12 +519,11 @@ int main(int argc, char *argv[]) /* clean up any lingering detritus */ for (i = 0; i < count; i++) { - if ( containers[i] ) { + if (containers[i]) lxc_container_put(containers[i]); - } - if ( c_groups_lists && c_groups_lists[i] ) { + + if (c_groups_lists && c_groups_lists[i]) toss_list(c_groups_lists[i]); - } } free(c_groups_lists); From a9ff89baa0fe7cc3880fc8db34b61cfa074d1d93 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:32:04 +0100 Subject: [PATCH 03/34] tools: move lxc-autostart to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_autostart.c | 6 +- src/lxc/tools/tool_list.h | 167 ++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 src/lxc/tools/tool_list.h diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c index b3823af2f0..41d2e4b576 100644 --- a/src/lxc/tools/lxc_autostart.c +++ b/src/lxc/tools/lxc_autostart.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE #include #include #include @@ -26,8 +27,8 @@ #include #include "arguments.h" -#include "log.h" -#include "utils.h" +#include "tool_list.h" +#include "tool_utils.h" static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list); @@ -355,7 +356,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); diff --git a/src/lxc/tools/tool_list.h b/src/lxc/tools/tool_list.h new file mode 100644 index 0000000000..9858081ab5 --- /dev/null +++ b/src/lxc/tools/tool_list.h @@ -0,0 +1,167 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LXC_LIST_H +#define __LXC_LIST_H + +#include + +struct lxc_list { + void *elem; + struct lxc_list *next; + struct lxc_list *prev; +}; + +#define lxc_init_list(l) \ + { \ + .next = l, .prev = l \ + } + +/* + * Iterate through an lxc list. An example for an idiom would be: + * + * struct lxc_list *iterator; + * lxc_list_for_each(iterator, list) { + * type *tmp; + * tmp = iterator->elem; + * } + */ +#define lxc_list_for_each(__iterator, __list) \ + for (__iterator = (__list)->next; __iterator != __list; \ + __iterator = __iterator->next) + +/* Iterate safely through an lxc list. An example for an appropriate use case + * would be: + * + * struct lxc_list *cur, *next; + * lxc_list_for_each_safe(cur, list, next) { + * type *tmp; + * tmp = cur->elem; + * } + */ +#define lxc_list_for_each_safe(__iterator, __list, __next) \ + for (__iterator = (__list)->next, __next = __iterator->next; \ + __iterator != __list; __iterator = __next, __next = __next->next) + +/* Initalize list. */ +static inline void lxc_list_init(struct lxc_list *list) +{ + list->elem = NULL; + list->next = list->prev = list; +} + +/* Add an element to a list. See lxc_list_add() and lxc_list_add_tail() for an + * idiom. + */ +static inline void lxc_list_add_elem(struct lxc_list *list, void *elem) +{ + list->elem = elem; +} + +/* Retrieve first element of list. */ +static inline void *lxc_list_first_elem(struct lxc_list *list) +{ + return list->next->elem; +} + +/* Retrieve last element of list. */ +static inline void *lxc_list_last_elem(struct lxc_list *list) +{ + return list->prev->elem; +} + +/* Determine if list is empty. */ +static inline int lxc_list_empty(struct lxc_list *list) +{ + return list == list->next; +} + +/* Workhorse to be called from lxc_list_add() and lxc_list_add_tail(). */ +static inline void __lxc_list_add(struct lxc_list *new, struct lxc_list *prev, + struct lxc_list *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/* Idiom to add an element to the beginning of an lxc list: + * + * struct lxc_list *tmp = malloc(sizeof(*tmp)); + * if (tmp == NULL) + * return 1; + * lxc_list_add_elem(tmp, elem); + * lxc_list_add(list, tmp); + */ +static inline void lxc_list_add(struct lxc_list *head, struct lxc_list *list) +{ + __lxc_list_add(list, head, head->next); +} + +/* Idiom to add an element to the end of an lxc list: + * + * struct lxc_list *tmp = malloc(sizeof(*tmp)); + * if (tmp == NULL) + * return 1; + * lxc_list_add_elem(tmp, elem); + * lxc_list_add_tail(list, tmp); + */ +static inline void lxc_list_add_tail(struct lxc_list *head, + struct lxc_list *list) +{ + __lxc_list_add(list, head->prev, head); +} + +/* Idiom to remove an element from a list: + * struct lxc_list *cur, *next; + * lxc_list_for_each_safe(cur, list, next) { + * lxc_list_del(cur); + * free(cur->elem); + * free(cur); + * } + */ +static inline void lxc_list_del(struct lxc_list *list) +{ + struct lxc_list *next, *prev; + + next = list->next; + prev = list->prev; + next->prev = prev; + prev->next = next; +} + +/* Return length of the list. */ +static inline size_t lxc_list_len(struct lxc_list *list) +{ + size_t i = 0; + struct lxc_list *iter; + + lxc_list_for_each(iter, list) { + i++; + } + + return i; +} + +#endif /* __LXC_LIST_H */ From 744b1eec11a3d25e2990ebe29400375a157ca7fc Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:36:12 +0100 Subject: [PATCH 04/34] tools: move lxc-cgroup to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/arguments.h | 1 + src/lxc/tools/lxc_cgroup.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index 15941bcc39..bd491a32bf 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -31,6 +31,7 @@ #include #include +#define TOOL_MAXPATHLEN 4096 struct lxc_arguments; typedef int (*lxc_arguments_parser_t)(struct lxc_arguments *, int, char *); diff --git a/src/lxc/tools/lxc_cgroup.c b/src/lxc/tools/lxc_cgroup.c index cfd14bd8f8..3624e80b7d 100644 --- a/src/lxc/tools/lxc_cgroup.c +++ b/src/lxc/tools/lxc_cgroup.c @@ -21,17 +21,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE #include #include #include +#include #include #include #include #include "arguments.h" -#include "log.h" -#include "lxc.h" static int my_checker(const struct lxc_arguments* args) { @@ -39,6 +39,7 @@ static int my_checker(const struct lxc_arguments* args) lxc_error(args, "missing state object"); return -1; } + return 0; } @@ -83,7 +84,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -130,8 +130,8 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } } else { - char buffer[MAXPATHLEN]; - int ret = c->get_cgroup_item(c, state_object, buffer, MAXPATHLEN); + char buffer[TOOL_MAXPATHLEN]; + int ret = c->get_cgroup_item(c, state_object, buffer, TOOL_MAXPATHLEN); if (ret < 0) { fprintf(stderr, "failed to retrieve value of '%s' for '%s:%s'\n", state_object, my_args.lxcpath[0], my_args.name); From 844d9eac45e18cc4bafdff71d9653fefe54539a1 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:46:30 +0100 Subject: [PATCH 05/34] cmd: move lxc-lxc_usernsexec Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 4 +++- src/lxc/{tools => cmd}/lxc_usernsexec.c | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename src/lxc/{tools => cmd}/lxc_usernsexec.c (100%) diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 185d2a4807..35268ac04c 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -290,11 +290,13 @@ lxc_unshare_SOURCES = tools/lxc_unshare.c tools/arguments.c lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c -lxc_usernsexec_SOURCES = tools/lxc_usernsexec.c tools/arguments.c lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c lxc_user_nic_SOURCES = lxc_user_nic.c namespace.c network.c tools/arguments.c lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c +# Binaries shipping with liblxc +lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c + if ENABLE_DEPRECATED lxc_clone_SOURCES = tools/lxc_clone.c tools/arguments.c endif diff --git a/src/lxc/tools/lxc_usernsexec.c b/src/lxc/cmd/lxc_usernsexec.c similarity index 100% rename from src/lxc/tools/lxc_usernsexec.c rename to src/lxc/cmd/lxc_usernsexec.c From 2a5ee335a61e78a05cc7ff29ffb34abc3f417ee9 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:48:07 +0100 Subject: [PATCH 06/34] cmd: move init.lxc{.static} Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 4 ++-- src/lxc/{ => cmd}/lxc_init.c | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/lxc/{ => cmd}/lxc_init.c (100%) diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 35268ac04c..fe656c6cd2 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -278,7 +278,6 @@ lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c -init_lxc_SOURCES = lxc_init.c lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c @@ -295,6 +294,7 @@ lxc_user_nic_SOURCES = lxc_user_nic.c namespace.c network.c tools/arguments.c lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c # Binaries shipping with liblxc +init_lxc_SOURCES = cmd/lxc_init.c lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c if ENABLE_DEPRECATED @@ -308,7 +308,7 @@ endif if HAVE_STATIC_LIBCAP sbin_PROGRAMS += init.lxc.static -init_lxc_static_SOURCES = lxc_init.c error.c log.c initutils.c caps.c parse.c namespace.c +init_lxc_static_SOURCES = cmd/lxc_init.c error.c log.c initutils.c caps.c parse.c namespace.c if !HAVE_GETLINE if HAVE_FGETLN diff --git a/src/lxc/lxc_init.c b/src/lxc/cmd/lxc_init.c similarity index 100% rename from src/lxc/lxc_init.c rename to src/lxc/cmd/lxc_init.c From 48b1dc4cdcbafb7eae37873ccb9b97ac0acad94b Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:49:55 +0100 Subject: [PATCH 07/34] cmd: move lxc-checkconfig Closes #2073. Signed-off-by: Christian Brauner --- configure.ac | 2 +- src/lxc/Makefile.am | 2 +- src/lxc/{tools => cmd}/lxc-checkconfig.in | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lxc/{tools => cmd}/lxc-checkconfig.in (100%) diff --git a/configure.ac b/configure.ac index 6713539b43..64f7e60bb6 100644 --- a/configure.ac +++ b/configure.ac @@ -934,7 +934,7 @@ AC_CONFIG_FILES([ src/Makefile src/lxc/Makefile src/lxc/lxc.functions - src/lxc/tools/lxc-checkconfig + src/lxc/cmd/lxc-checkconfig src/lxc/tools/lxc-start-ephemeral src/lxc/tools/lxc-update-config src/lxc/version.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index fe656c6cd2..92b50f85ff 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -216,7 +216,7 @@ liblxc_la_LIBADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS) liblxc_la_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS) endif -bin_SCRIPTS = tools/lxc-checkconfig \ +bin_SCRIPTS = cmd/lxc-checkconfig \ tools/lxc-update-config EXTRA_DIST = \ diff --git a/src/lxc/tools/lxc-checkconfig.in b/src/lxc/cmd/lxc-checkconfig.in similarity index 100% rename from src/lxc/tools/lxc-checkconfig.in rename to src/lxc/cmd/lxc-checkconfig.in From 1c7507cb443daa98b7813833f04294e2ab1f0788 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:53:10 +0100 Subject: [PATCH 08/34] cmd: move lxc-user-nic Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 2 +- src/lxc/{ => cmd}/lxc_user_nic.c | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/lxc/{ => cmd}/lxc_user_nic.c (100%) diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 92b50f85ff..6beb197cf5 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -290,11 +290,11 @@ lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c -lxc_user_nic_SOURCES = lxc_user_nic.c namespace.c network.c tools/arguments.c lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c # Binaries shipping with liblxc init_lxc_SOURCES = cmd/lxc_init.c +lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c if ENABLE_DEPRECATED diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/cmd/lxc_user_nic.c similarity index 100% rename from src/lxc/lxc_user_nic.c rename to src/lxc/cmd/lxc_user_nic.c From b80939349c241d75f0d3d3d61e19607362eb9881 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:54:30 +0100 Subject: [PATCH 09/34] cmd: move lxc-monitord Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 2 +- src/lxc/{ => cmd}/lxc_monitord.c | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/lxc/{ => cmd}/lxc_monitord.c (100%) diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 6beb197cf5..ae5a699b9e 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -290,10 +290,10 @@ lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c -lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c # Binaries shipping with liblxc init_lxc_SOURCES = cmd/lxc_init.c +lxc_monitord_SOURCES = cmd/lxc_monitord.c lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c diff --git a/src/lxc/lxc_monitord.c b/src/lxc/cmd/lxc_monitord.c similarity index 100% rename from src/lxc/lxc_monitord.c rename to src/lxc/cmd/lxc_monitord.c From 6a342cab3692cd46b77853a9019c53d02dd63dce Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 13:56:37 +0100 Subject: [PATCH 10/34] cmd: move lxc-update-config Closes #2073. Signed-off-by: Christian Brauner --- configure.ac | 2 +- src/lxc/Makefile.am | 2 +- src/lxc/{tools => cmd}/lxc-update-config.in | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lxc/{tools => cmd}/lxc-update-config.in (100%) diff --git a/configure.ac b/configure.ac index 64f7e60bb6..b56b35b1a2 100644 --- a/configure.ac +++ b/configure.ac @@ -935,8 +935,8 @@ AC_CONFIG_FILES([ src/lxc/Makefile src/lxc/lxc.functions src/lxc/cmd/lxc-checkconfig + src/lxc/cmd/lxc-update-config src/lxc/tools/lxc-start-ephemeral - src/lxc/tools/lxc-update-config src/lxc/version.h src/python-lxc/Makefile diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index ae5a699b9e..d7043e01b5 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -217,7 +217,7 @@ liblxc_la_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_ endif bin_SCRIPTS = cmd/lxc-checkconfig \ - tools/lxc-update-config + cmd/lxc-update-config EXTRA_DIST = \ tools/lxc-top.lua diff --git a/src/lxc/tools/lxc-update-config.in b/src/lxc/cmd/lxc-update-config.in similarity index 100% rename from src/lxc/tools/lxc-update-config.in rename to src/lxc/cmd/lxc-update-config.in From 78485176fd49b03b8374aa449e11f60a4866ae09 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:02:10 +0100 Subject: [PATCH 11/34] tools: move lxc-checkpoint to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_checkpoint.c | 12 ++++-------- src/lxc/tools/tool_utils.c | 18 ++++++++++++++++++ src/lxc/tools/tool_utils.h | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/lxc/tools/lxc_checkpoint.c b/src/lxc/tools/lxc_checkpoint.c index 8f93934b37..f3f9e74150 100644 --- a/src/lxc/tools/lxc_checkpoint.c +++ b/src/lxc/tools/lxc_checkpoint.c @@ -1,5 +1,4 @@ /* - * * Copyright © 2014 Tycho Andersen . * Copyright © 2014 Canonical Ltd. * @@ -17,19 +16,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include +#define _GNU_SOURCE #include +#include +#include #include #include #include #include -#include "log.h" -#include "config.h" -#include "lxc.h" #include "arguments.h" -#include "utils.h" +#include "tool_utils.h" static char *checkpoint_dir = NULL; static bool stop = false; @@ -253,8 +251,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); - /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 39b3881615..4b4dad0b44 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -276,6 +276,24 @@ int lxc_caps_up(void) #endif +int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + return -1; + } + if (ret != pid) + goto again; + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + return -1; + return 0; +} + int lxc_wait_for_pid_status(pid_t pid) { int status, ret; diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 9f0e6a01fd..f900f037c3 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -123,6 +123,7 @@ static inline int lxc_caps_init(void) { } #endif +extern int wait_for_pid(pid_t pid); extern int lxc_wait_for_pid_status(pid_t pid); extern int lxc_safe_int(const char *numstr, int *converted); extern int lxc_safe_long(const char *numstr, long int *converted); From 2f9928f6381b4b49f6b3a77366efabe0c24b3a3b Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:05:21 +0100 Subject: [PATCH 12/34] tools: move lxc-clone to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_clone.c | 124 +++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 47 deletions(-) diff --git a/src/lxc/tools/lxc_clone.c b/src/lxc/tools/lxc_clone.c index 3aed40739c..4dca80b7b5 100644 --- a/src/lxc/tools/lxc_clone.c +++ b/src/lxc/tools/lxc_clone.c @@ -17,25 +17,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include +#include +#include #include #include +#include #include +#include +#include #include -#include #include -#include -#include -#include #include -#include "log.h" -#include "config.h" -#include "lxc.h" -#include "conf.h" -#include "state.h" - /* we pass fssize in bytes */ static uint64_t get_fssize(char *s) { @@ -43,30 +37,33 @@ static uint64_t get_fssize(char *s) char *end; ret = strtoull(s, &end, 0); - if (end == s) - { - fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s); + if (end == s) { + fprintf(stderr, + "Invalid blockdev size '%s', using default size\n", s); return 0; } + while (isblank(*end)) end++; - if (*end == '\0') + if (*end == '\0') { ret *= 1024ULL * 1024ULL; /* MB by default */ - else if (*end == 'b' || *end == 'B') + } else if (*end == 'b' || *end == 'B') { ret *= 1ULL; - else if (*end == 'k' || *end == 'K') + } else if (*end == 'k' || *end == 'K') { ret *= 1024ULL; - else if (*end == 'm' || *end == 'M') + } else if (*end == 'm' || *end == 'M') { ret *= 1024ULL * 1024ULL; - else if (*end == 'g' || *end == 'G') + } else if (*end == 'g' || *end == 'G') { ret *= 1024ULL * 1024ULL * 1024ULL; - else if (*end == 't' || *end == 'T') + } else if (*end == 't' || *end == 'T') { ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL; - else - { - fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s); + } else { + fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " + "using default size\n", + *end, s); return 0; } + return ret; } @@ -124,42 +121,76 @@ int main(int argc, char *argv[]) if (argc < 3) usage(argv[0]); - while (1) { - c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index); + while (true) { + c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, + &option_index); if (c == -1) break; switch (c) { - case 's': snapshot = 1; break; - case 'B': bdevtype = optarg; break; - case 'L': newsize = get_fssize(optarg); break; - case 'o': orig = optarg; break; - case 'n': new = optarg; break; - case 'v': vgname = optarg; break; - case 'K': keepname = 1; break; - case 'M': keepmac = 1; break; - case 'p': lxcpath = optarg; break; - case 'P': newpath = optarg; break; - case 'R': rename = 1; break; - case 't': fstype = optarg; break; - case 'h': usage(argv[0]); - default: break; + case 's': + snapshot = 1; + break; + case 'B': + bdevtype = optarg; + break; + case 'L': + newsize = get_fssize(optarg); + break; + case 'o': + orig = optarg; + break; + case 'n': + new = optarg; + break; + case 'v': + vgname = optarg; + break; + case 'K': + keepname = 1; + break; + case 'M': + keepmac = 1; + break; + case 'p': + lxcpath = optarg; + break; + case 'P': + newpath = optarg; + break; + case 'R': + rename = 1; + break; + case 't': + fstype = optarg; + break; + case 'h': + usage(argv[0]); + default: + break; } } - if (optind < argc && !orig) + + if (optind < argc && !orig) orig = argv[optind++]; - if (optind < argc && !new) + + if (optind < argc && !new) new = argv[optind++]; + + /* arguments for the clone hook */ if (optind < argc) - /* arguments for the clone hook */ args = &argv[optind]; + if (!new || !orig) { printf("Error: you must provide orig and new names\n"); usage(argv[0]); } - if (snapshot) flags |= LXC_CLONE_SNAPSHOT; - if (keepname) flags |= LXC_CLONE_KEEPNAME; - if (keepmac) flags |= LXC_CLONE_KEEPMACADDR; + if (snapshot) + flags |= LXC_CLONE_SNAPSHOT; + if (keepname) + flags |= LXC_CLONE_KEEPNAME; + if (keepmac) + flags |= LXC_CLONE_KEEPMACADDR; /* vgname and fstype could be supported by sending them through the * bdevdata. However, they currently are not yet. I'm not convinced @@ -201,8 +232,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } } else { - c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize, - args); + c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize, args); if (c2 == NULL) { lxc_container_put(c1); fprintf(stderr, "clone failed\n"); From 2e38dc377d9390a03c6737f05404f827c9ca1bb8 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:08:43 +0100 Subject: [PATCH 13/34] cmd: move lxc-config to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lxc/tools/lxc_config.c b/src/lxc/tools/lxc_config.c index 86187bd57c..682257f3db 100644 --- a/src/lxc/tools/lxc_config.c +++ b/src/lxc/tools/lxc_config.c @@ -23,8 +23,6 @@ #include -#include "config.h" - struct lxc_config_items { char *name; }; From 8d313ae1dd66601b60f950b0ad4962098d695b53 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:11:21 +0100 Subject: [PATCH 14/34] cmd: move lxc-console to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_console.c | 8 +------- src/lxc/tools/tool_utils.c | 28 ++++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 1 + 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/lxc/tools/lxc_console.c b/src/lxc/tools/lxc_console.c index 876cbce58c..f847811cb0 100644 --- a/src/lxc/tools/lxc_console.c +++ b/src/lxc/tools/lxc_console.c @@ -39,12 +39,7 @@ #include #include "arguments.h" -#include "commands.h" -#include "error.h" -#include "log.h" -#include "lxc.h" -#include "mainloop.h" -#include "utils.h" +#include "tool_utils.h" static char etoc(const char *expr) { @@ -115,7 +110,6 @@ int main(int argc, char *argv[]) ret = lxc_log_init(&log); if (ret) return EXIT_FAILURE; - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 4b4dad0b44..00181ab650 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -17,7 +17,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _GNU_SOURCE #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ +#include #include #include #include @@ -310,6 +312,32 @@ int lxc_wait_for_pid_status(pid_t pid) return status; } +int lxc_safe_uint(const char *numstr, unsigned int *converted) +{ + char *err = NULL; + unsigned long int uli; + + while (isspace(*numstr)) + numstr++; + + if (*numstr == '-') + return -EINVAL; + + errno = 0; + uli = strtoul(numstr, &err, 0); + if (errno == ERANGE && uli == ULONG_MAX) + return -ERANGE; + + if (err == numstr || *err != '\0') + return -EINVAL; + + if (uli > UINT_MAX) + return -ERANGE; + + *converted = (unsigned int)uli; + return 0; +} + int lxc_safe_int(const char *numstr, int *converted) { char *err = NULL; diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index f900f037c3..b122e3ea16 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -125,6 +125,7 @@ static inline int lxc_caps_init(void) { extern int wait_for_pid(pid_t pid); extern int lxc_wait_for_pid_status(pid_t pid); +extern int lxc_safe_uint(const char *numstr, unsigned int *converted); extern int lxc_safe_int(const char *numstr, int *converted); extern int lxc_safe_long(const char *numstr, long int *converted); From 0cb3e3a6ddbe9de3817546870e6481ddd51694aa Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:27:23 +0100 Subject: [PATCH 15/34] tools: move lxc-copy to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/include/getsubopt.c | 89 +++++++++++++++++ src/lxc/tools/include/getsubopt.h | 4 + src/lxc/tools/lxc_copy.c | 62 +++++------- src/lxc/tools/tool_utils.c | 159 ++++++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 12 +++ 5 files changed, 288 insertions(+), 38 deletions(-) create mode 100644 src/lxc/tools/include/getsubopt.c create mode 100644 src/lxc/tools/include/getsubopt.h diff --git a/src/lxc/tools/include/getsubopt.c b/src/lxc/tools/include/getsubopt.c new file mode 100644 index 0000000000..b75497b1a4 --- /dev/null +++ b/src/lxc/tools/include/getsubopt.c @@ -0,0 +1,89 @@ +/* + * Android c-library does not have getsubopt, + * so code lifted from uClibc + * http://git.uclibc.org/uClibc/tree/libc/unistd/getsubopt.c + */ + +/* Parse comma separate list into words. + Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +#include +#include + +char *strchrnul(const char *s, int c) +{ + char *result; + + result = strchr( s, c ); + + if( !result ) + { + result = (char *)s + strlen( s ); + } + + return( result ); +} + +/* Parse comma separated suboption from *OPTIONP and match against + strings in TOKENS. If found return index and set *VALUEP to + optional value introduced by an equal sign. If the suboption is + not part of TOKENS return in *VALUEP beginning of unknown + suboption. On exit *OPTIONP is set to the beginning of the next + token or at the terminating NUL character. */ +int +getsubopt (char **optionp, char *const *tokens, char **valuep) +{ + char *endp, *vstart; + int cnt; + + if (**optionp == '\0') + return -1; + + /* Find end of next token. */ + endp = strchrnul (*optionp, ','); + + /* Find start of value. */ + vstart = memchr (*optionp, '=', endp - *optionp); + if (vstart == NULL) + vstart = endp; + + /* Try to match the characters between *OPTIONP and VSTART against + one of the TOKENS. */ + for (cnt = 0; tokens[cnt] != NULL; ++cnt) + if (strncmp (*optionp, tokens[cnt], vstart - *optionp) == 0 + && tokens[cnt][vstart - *optionp] == '\0') + { + /* We found the current option in TOKENS. */ + *valuep = vstart != endp ? vstart + 1 : NULL; + + if (*endp != '\0') + *endp++ = '\0'; + *optionp = endp; + + return cnt; + } + + /* The current suboption does not match any option. */ + *valuep = *optionp; + + if (*endp != '\0') + *endp++ = '\0'; + *optionp = endp; + + return -1; +} diff --git a/src/lxc/tools/include/getsubopt.h b/src/lxc/tools/include/getsubopt.h new file mode 100644 index 0000000000..e45cf66b01 --- /dev/null +++ b/src/lxc/tools/include/getsubopt.h @@ -0,0 +1,4 @@ +#ifndef _GETSUBOPT_H +#define _GETSUBOPT_H +int getsubopt (char **optionp, char *const *tokens, char **valuep); +#endif diff --git a/src/lxc/tools/lxc_copy.c b/src/lxc/tools/lxc_copy.c index 1718f84a74..ae8b810213 100644 --- a/src/lxc/tools/lxc_copy.c +++ b/src/lxc/tools/lxc_copy.c @@ -17,37 +17,29 @@ */ #define _GNU_SOURCE -#include "config.h" - -#include +#include +#include +#include #include #include -#include -#include +#include #include -#include +#include #include -#include -#include -#include -#include +#include #include -#include +#include +#include +#include +#include #include -#include "attach.h" -#include "log.h" -#include "confile.h" #include "arguments.h" -#include "lxc.h" -#include "conf.h" -#include "state.h" -#include "storage.h" -#include "utils.h" +#include "tool_utils.h" #ifndef HAVE_GETSUBOPT -#include <../include/getsubopt.h> +#include "include/getsubopt.h" #endif enum mnttype { @@ -186,7 +178,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(ret); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -273,17 +264,17 @@ static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg) { - char upperdir[MAXPATHLEN]; - char workdir[MAXPATHLEN]; + char upperdir[TOOL_MAXPATHLEN]; + char workdir[TOOL_MAXPATHLEN]; unsigned int i; int ret; struct mnts *m = NULL; for (i = 0, m = mnts; i < num; i++, m++) { if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) { - ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX", + ret = snprintf(upperdir, TOOL_MAXPATHLEN, "%s/%s/delta#XXXXXX", arg->newpath, arg->newname); - if (ret < 0 || ret >= MAXPATHLEN) + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return -1; if (!mkdtemp(upperdir)) return -1; @@ -293,9 +284,9 @@ static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_argu } if (m->mnt_type == LXC_MNT_OVL) { - ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX", + ret = snprintf(workdir, TOOL_MAXPATHLEN, "%s/%s/work#XXXXXX", arg->newpath, arg->newname); - if (ret < 0 || ret >= MAXPATHLEN) + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return -1; if (!mkdtemp(workdir)) return -1; @@ -400,19 +391,19 @@ static int do_clone(struct lxc_container *c, char *newname, char *newpath, static int do_clone_ephemeral(struct lxc_container *c, struct lxc_arguments *arg, char **args, int flags) { - char *bdev; char *premount; - char randname[MAXPATHLEN]; + char randname[TOOL_MAXPATHLEN]; unsigned int i; int ret = 0; bool bret = true, started = false; + char *tmp_buf = randname; struct lxc_container *clone; lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; attach_options.env_policy = LXC_ATTACH_CLEAR_ENV; if (!arg->newname) { - ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name); - if (ret < 0 || ret >= MAXPATHLEN) + ret = snprintf(randname, TOOL_MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return -1; if (!mkdtemp(randname)) return -1; @@ -429,12 +420,6 @@ static int do_clone_ephemeral(struct lxc_container *c, return -1; if (arg->tmpfs) { - bdev = c->lxc_conf->rootfs.bdev_type; - if (bdev && strcmp(bdev, "dir")) { - fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev); - goto destroy_and_put; - } - premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg); if (!premount) goto destroy_and_put; @@ -501,7 +486,8 @@ static int do_clone_ephemeral(struct lxc_container *c, destroy_and_put: if (started) clone->shutdown(clone, -1); - if (!started || clone->lxc_conf->ephemeral != 1) + ret = clone->get_config_item(clone, "lxc.ephemeral", tmp_buf, TOOL_MAXPATHLEN); + if (ret > 0 && strcmp(tmp_buf, "0")) clone->destroy(clone); free_mnts(); lxc_container_put(clone); diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 00181ab650..29adc67763 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -380,3 +381,161 @@ int lxc_safe_long(const char *numstr, long int *converted) *converted = sli; return 0; } + +void lxc_free_array(void **array, lxc_free_fn element_free_fn) +{ + void **p; + for (p = array; p && *p; p++) + element_free_fn(*p); + free((void*)array); +} + +int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t capacity_increment) +{ + size_t new_capacity; + void **new_array; + + /* first time around, catch some trivial mistakes of the user + * only initializing one of these */ + if (!*array || !*capacity) { + *array = NULL; + *capacity = 0; + } + + new_capacity = *capacity; + while (new_size + 1 > new_capacity) + new_capacity += capacity_increment; + if (new_capacity != *capacity) { + /* we have to reallocate */ + new_array = realloc(*array, new_capacity * sizeof(void *)); + if (!new_array) + return -1; + memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *)); + *array = new_array; + *capacity = new_capacity; + } + + /* array has sufficient elements */ + return 0; +} + +char **lxc_string_split(const char *string, char _sep) +{ + char *token, *str, *saveptr = NULL; + char sep[2] = {_sep, '\0'}; + char **tmp = NULL, **result = NULL; + size_t result_capacity = 0; + size_t result_count = 0; + int r, saved_errno; + + if (!string) + return calloc(1, sizeof(char *)); + + str = alloca(strlen(string) + 1); + strcpy(str, string); + for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) { + r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16); + if (r < 0) + goto error_out; + result[result_count] = strdup(token); + if (!result[result_count]) + goto error_out; + result_count++; + } + + /* if we allocated too much, reduce it */ + tmp = realloc(result, (result_count + 1) * sizeof(char *)); + if (!tmp) + goto error_out; + result = tmp; + /* Make sure we don't return uninitialized memory. */ + if (result_count == 0) + *result = NULL; + return result; +error_out: + saved_errno = errno; + lxc_free_array((void **)result, free); + errno = saved_errno; + return NULL; +} + +char **lxc_normalize_path(const char *path) +{ + char **components; + char **p; + size_t components_len = 0; + size_t pos = 0; + + components = lxc_string_split(path, '/'); + if (!components) + return NULL; + for (p = components; *p; p++) + components_len++; + + /* resolve '.' and '..' */ + for (pos = 0; pos < components_len; ) { + if (!strcmp(components[pos], ".") || (!strcmp(components[pos], "..") && pos == 0)) { + /* eat this element */ + free(components[pos]); + memmove(&components[pos], &components[pos+1], sizeof(char *) * (components_len - pos)); + components_len--; + } else if (!strcmp(components[pos], "..")) { + /* eat this and the previous element */ + free(components[pos - 1]); + free(components[pos]); + memmove(&components[pos-1], &components[pos+1], sizeof(char *) * (components_len - pos)); + components_len -= 2; + pos--; + } else { + pos++; + } + } + + return components; +} + +char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix) +{ + char *result; + char **p; + size_t sep_len = strlen(sep); + size_t result_len = use_as_prefix * sep_len; + + /* calculate new string length */ + for (p = (char **)parts; *p; p++) + result_len += (p > (char **)parts) * sep_len + strlen(*p); + + result = calloc(result_len + 1, 1); + if (!result) + return NULL; + + if (use_as_prefix) + strcpy(result, sep); + for (p = (char **)parts; *p; p++) { + if (p > (char **)parts) + strcat(result, sep); + strcat(result, *p); + } + + return result; +} + +int is_dir(const char *path) +{ + struct stat statbuf; + int ret = stat(path, &statbuf); + if (ret == 0 && S_ISDIR(statbuf.st_mode)) + return 1; + return 0; +} + +size_t lxc_array_len(void **array) +{ + void **p; + size_t result = 0; + + for (p = array; p && *p; p++) + result++; + + return result; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index b122e3ea16..2453e3d612 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -129,4 +129,16 @@ extern int lxc_safe_uint(const char *numstr, unsigned int *converted); extern int lxc_safe_int(const char *numstr, int *converted); extern int lxc_safe_long(const char *numstr, long int *converted); +typedef void (*lxc_free_fn)(void *); +extern void lxc_free_array(void **array, lxc_free_fn element_free_fn); +extern size_t lxc_array_len(void **array); +extern int lxc_grow_array(void ***array, size_t *capacity, size_t new_size, + size_t capacity_increment); +extern char **lxc_string_split(const char *string, char _sep); +extern char **lxc_normalize_path(const char *path); +extern char *lxc_string_join(const char *sep, const char **parts, + bool use_as_prefix); + +extern int is_dir(const char *path); + #endif /* __LXC_UTILS_H */ From e6294545d11d237d17aca02cdc0778d8b078cc05 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:33:06 +0100 Subject: [PATCH 16/34] tools: move lxc-create to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_create.c | 30 ++++++++++++++------ src/lxc/tools/tool_utils.c | 57 ++++++++++++++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 3 ++ 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/lxc/tools/lxc_create.c b/src/lxc/tools/lxc_create.c index f702c2ba7c..9a4640316f 100644 --- a/src/lxc/tools/lxc_create.c +++ b/src/lxc/tools/lxc_create.c @@ -22,16 +22,14 @@ #include #include #include +#include #include -#include #include +#include + #include "arguments.h" -#include "log.h" -#include "lxc.h" -#include "storage.h" -#include "storage_utils.h" -#include "utils.h" +#include "tool_utils.h" static uint64_t get_fssize(char *s) { @@ -203,6 +201,23 @@ static bool validate_bdev_args(struct lxc_arguments *a) return true; } +static bool is_valid_storage_type(const char *type) +{ + if (strcmp(type, "dir") == 0 || + strcmp(type, "btrfs") == 0 || + strcmp(type, "aufs") == 0 || + strcmp(type, "loop") == 0 || + strcmp(type, "lvm") == 0 || + strcmp(type, "nbd") == 0 || + strcmp(type, "overlay") == 0 || + strcmp(type, "overlayfs") == 0 || + strcmp(type, "rbd") == 0 || + strcmp(type, "zfs") == 0) + return true; + + return false; +} + int main(int argc, char *argv[]) { struct lxc_container *c; @@ -225,7 +240,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -286,7 +300,7 @@ int main(int argc, char *argv[]) if (my_args.configfile) c->load_config(c, my_args.configfile); else - c->load_config(c, lxc_global_config_value("lxc.default_config")); + c->load_config(c, lxc_get_global_config_item("lxc.default_config")); if (my_args.fstype) spec.fstype = my_args.fstype; diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 29adc67763..94f118e635 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -539,3 +539,60 @@ size_t lxc_array_len(void **array) return result; } + +/* + * Given the '-t' template option to lxc-create, figure out what to + * do. If the template is a full executable path, use that. If it + * is something like 'sshd', then return $templatepath/lxc-sshd. + * On success return the template, on error return NULL. + */ +char *get_template_path(const char *t) +{ + int ret, len; + char *tpath; + + if (t[0] == '/' && access(t, X_OK) == 0) { + tpath = strdup(t); + return tpath; + } + + len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1; + tpath = malloc(len); + if (!tpath) + return NULL; + ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t); + if (ret < 0 || ret >= len) { + free(tpath); + return NULL; + } + if (access(tpath, X_OK) < 0) { + fprintf(stderr, "Bad template: %s\n", t); + free(tpath); + return NULL; + } + + return tpath; +} + +int mkdir_p(const char *dir, mode_t mode) +{ + const char *tmp = dir; + const char *orig = dir; + char *makeme; + + do { + dir = tmp + strspn(tmp, "/"); + tmp = dir + strcspn(dir, "/"); + makeme = strndup(orig, dir - orig); + if (*makeme) { + if (mkdir(makeme, mode) && errno != EEXIST) { + fprintf(stderr, "Failed to create directory \"%s\"\n", makeme); + free(makeme); + return -1; + } + } + free(makeme); + } while(tmp != dir); + + return 0; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 2453e3d612..02b2eedd03 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -139,6 +139,9 @@ extern char **lxc_normalize_path(const char *path); extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix); +extern int mkdir_p(const char *dir, mode_t mode); extern int is_dir(const char *path); +extern char *get_template_path(const char *t); + #endif /* __LXC_UTILS_H */ From e3347eef56460e72b896c696ae9e5a81e5ecb0f2 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:39:21 +0100 Subject: [PATCH 17/34] tools: move lxc-destroy to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_destroy.c | 40 ++++++++++++++++++++----------------- src/lxc/tools/tool_utils.c | 7 +++++++ src/lxc/tools/tool_utils.h | 1 + 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/lxc/tools/lxc_destroy.c b/src/lxc/tools/lxc_destroy.c index 1c3f7dc501..48484a6be8 100644 --- a/src/lxc/tools/lxc_destroy.c +++ b/src/lxc/tools/lxc_destroy.c @@ -18,19 +18,18 @@ */ #define _GNU_SOURCE -#include "config.h" - +#include #include #include +#include #include +#include #include #include #include "arguments.h" -#include "log.h" -#include "lxc.h" -#include "utils.h" +#include "tool_utils.h" static int my_parser(struct lxc_arguments* args, int c, char* arg); static bool quiet; @@ -83,7 +82,7 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); + if (my_args.quiet) quiet = true; @@ -155,11 +154,11 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) static bool do_destroy(struct lxc_container *c) { bool bret = true; - char path[MAXPATHLEN]; + char path[TOOL_MAXPATHLEN]; /* First check whether the container has dependent clones or snapshots. */ - int ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name); - if (ret < 0 || ret >= MAXPATHLEN) + int ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return false; if (file_exists(path)) { @@ -168,8 +167,8 @@ static bool do_destroy(struct lxc_container *c) return false; } - ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name); - if (ret < 0 || ret >= MAXPATHLEN) + ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return false; if (rmdir(path) < 0 && errno != ENOENT) { @@ -189,8 +188,13 @@ static bool do_destroy(struct lxc_container *c) /* If the container was ephemeral we have already removed it when we * stopped it. */ - if (c->is_defined(c) && !c->lxc_conf->ephemeral) - bret = c->destroy(c); + if (c->is_defined(c)) { + char buf[256]; + ret = c->get_config_item(c, "lxc.ephemeral", buf, 256); + if (ret > 0 && strcmp(buf, "0") == 0) { + bret = c->destroy(c); + } + } if (!bret) { if (!quiet) @@ -206,7 +210,7 @@ static bool do_destroy_with_snapshots(struct lxc_container *c) struct lxc_container *c1; struct stat fbuf; bool bret = false; - char path[MAXPATHLEN]; + char path[TOOL_MAXPATHLEN]; char *buf = NULL; char *lxcpath = NULL; char *lxcname = NULL; @@ -216,8 +220,8 @@ static bool do_destroy_with_snapshots(struct lxc_container *c) int counter = 0; /* Destroy clones. */ - ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name); - if (ret < 0 || ret >= MAXPATHLEN) + ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return false; fd = open(path, O_RDONLY | O_CLOEXEC); @@ -268,8 +272,8 @@ static bool do_destroy_with_snapshots(struct lxc_container *c) } /* Destroy snapshots located in the containers snap/ folder. */ - ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name); - if (ret < 0 || ret >= MAXPATHLEN) + ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) return false; if (rmdir(path) < 0 && errno != ENOENT) diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 94f118e635..e50f50273d 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -596,3 +596,10 @@ int mkdir_p(const char *dir, mode_t mode) return 0; } + +bool file_exists(const char *f) +{ + struct stat statbuf; + + return stat(f, &statbuf) == 0; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 02b2eedd03..4c9b43a28e 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -140,6 +140,7 @@ extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix); extern int mkdir_p(const char *dir, mode_t mode); +extern bool file_exists(const char *f); extern int is_dir(const char *path); extern char *get_template_path(const char *t); From 23500ef53871020b673a062c8ce58f7c7b249a51 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 14:46:46 +0100 Subject: [PATCH 18/34] tools: move lxc-device to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/arguments.h | 1 - src/lxc/tools/include/ifaddrs.c | 599 ++++++++++++++++++++++++++++++++ src/lxc/tools/include/ifaddrs.h | 54 +++ src/lxc/tools/lxc_cgroup.c | 1 + src/lxc/tools/lxc_device.c | 16 +- src/lxc/tools/tool_utils.c | 27 ++ src/lxc/tools/tool_utils.h | 2 + 7 files changed, 690 insertions(+), 10 deletions(-) create mode 100644 src/lxc/tools/include/ifaddrs.c create mode 100644 src/lxc/tools/include/ifaddrs.h diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index bd491a32bf..15941bcc39 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -31,7 +31,6 @@ #include #include -#define TOOL_MAXPATHLEN 4096 struct lxc_arguments; typedef int (*lxc_arguments_parser_t)(struct lxc_arguments *, int, char *); diff --git a/src/lxc/tools/include/ifaddrs.c b/src/lxc/tools/include/ifaddrs.c new file mode 100644 index 0000000000..1f954dd7d3 --- /dev/null +++ b/src/lxc/tools/include/ifaddrs.c @@ -0,0 +1,599 @@ +/* +Copyright (c) 2013, Kenneth MacKay +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ifaddrs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(void) +{ + int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(l_socket < 0) + { + return -1; + } + + struct sockaddr_nl l_addr; + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) + { + close(l_socket); + return -1; + } + + return l_socket; +} + +static int netlink_send(int p_socket, int p_request) +{ + char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; + memset(l_buffer, 0, sizeof(l_buffer)); + struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer; + struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); + + l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); + l_hdr->nlmsg_type = p_request; + l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + l_hdr->nlmsg_pid = 0; + l_hdr->nlmsg_seq = p_socket; + l_msg->rtgen_family = AF_UNSPEC; + + struct sockaddr_nl l_addr; + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); +} + +static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) +{ + struct msghdr l_msg; + struct iovec l_iov = { p_buffer, p_len }; + struct sockaddr_nl l_addr; + + for(;;) + { + l_msg.msg_name = (void *)&l_addr; + l_msg.msg_namelen = sizeof(l_addr); + l_msg.msg_iov = &l_iov; + l_msg.msg_iovlen = 1; + l_msg.msg_control = NULL; + l_msg.msg_controllen = 0; + l_msg.msg_flags = 0; + int l_result = recvmsg(p_socket, &l_msg, 0); + + if(l_result < 0) + { + if(errno == EINTR) + { + continue; + } + return -2; + } + + if(l_msg.msg_flags & MSG_TRUNC) + { // buffer was too small + return -1; + } + return l_result; + } +} + +static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +{ + size_t l_size = 4096; + void *l_buffer = NULL; + + for(;;) + { + free(l_buffer); + l_buffer = malloc(l_size); + + int l_read = netlink_recv(p_socket, l_buffer, l_size); + *p_size = l_read; + if(l_read == -2) + { + free(l_buffer); + return NULL; + } + if(l_read >= 0) + { + pid_t l_pid = getpid(); + struct nlmsghdr *l_hdr; + for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + *p_done = 1; + break; + } + + if(l_hdr->nlmsg_type == NLMSG_ERROR) + { + free(l_buffer); + return NULL; + } + } + return l_buffer; + } + + l_size *= 2; + } +} + +static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) +{ + NetlinkList *l_item = malloc(sizeof(NetlinkList)); + l_item->m_next = NULL; + l_item->m_data = p_data; + l_item->m_size = p_size; + return l_item; +} + +static void freeResultList(NetlinkList *p_list) +{ + NetlinkList *l_cur; + while(p_list) + { + l_cur = p_list; + p_list = p_list->m_next; + free(l_cur->m_data); + free(l_cur); + } +} + +static NetlinkList *getResultList(int p_socket, int p_request) +{ + if(netlink_send(p_socket, p_request) < 0) + { + return NULL; + } + + NetlinkList *l_list = NULL; + NetlinkList *l_end = NULL; + int l_size; + int l_done = 0; + while(!l_done) + { + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + if(!l_hdr) + { // error + freeResultList(l_list); + return NULL; + } + + NetlinkList *l_item = newListItem(l_hdr, l_size); + if(!l_list) + { + l_list = l_item; + } + else + { + l_end->m_next = l_item; + } + l_end = l_item; + } + return l_list; +} + +static size_t maxSize(size_t a, size_t b) +{ + return (a > b ? a : b); +} + +static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) +{ + switch(p_family) + { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_PACKET: + return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); + default: + return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); + } +} + +static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) +{ + switch(p_family) + { + case AF_INET: + memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); + break; + case AF_PACKET: + memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); + ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; + break; + default: + memcpy(p_dest->sa_data, p_data, p_size); + break; + } + p_dest->sa_family = p_family; +} + +static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) +{ + if(!*p_resultList) + { + *p_resultList = p_entry; + } + else + { + struct ifaddrs *l_cur = *p_resultList; + while(l_cur->ifa_next) + { + l_cur = l_cur->ifa_next; + } + l_cur->ifa_next = p_entry; + } +} + +static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + size_t l_dataSize = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + struct rtattr *l_rta; + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); + break; + case IFLA_IFNAME: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + case IFLA_STATS: + l_dataSize += NLMSG_ALIGN(l_rtaSize); + break; + default: + break; + } + } + + struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize); + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = ""; + + char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + char *l_addr = l_name + l_nameSize; + char *l_data = l_addr + l_addrSize; + + l_entry->ifa_flags = l_info->ifi_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + { + size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); + makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; + ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; + if(l_rta->rta_type == IFLA_ADDRESS) + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFLA_IFNAME: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + case IFLA_STATS: + memcpy(l_data, l_rtaData, l_rtaDataSize); + l_entry->ifa_data = l_data; + break; + default: + break; + } + } + + addToEnd(p_resultList, l_entry); + p_links[l_info->ifi_index - 1] = l_entry; +} + +static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + + int l_addedNetmask = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + struct rtattr *l_rta; + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + if(l_info->ifa_family == AF_PACKET) + { + continue; + } + + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_LOCAL: + if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) + { // make room for netmask + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + l_addedNetmask = 1; + } + case IFA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + break; + case IFA_LABEL: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + default: + break; + } + } + + struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name; + + char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + char *l_addr = l_name + l_nameSize; + + l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_BROADCAST: + case IFA_LOCAL: + { + size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); + makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + if(l_info->ifa_family == AF_INET6) + { + if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) + { + ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; + } + } + + if(l_rta->rta_type == IFA_ADDRESS) + { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + } + else if(l_rta->rta_type == IFA_LOCAL) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = l_entry->ifa_addr; + } + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFA_LABEL: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + default: + break; + } + } + + if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) + { + unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); + unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); + char l_mask[16] = {0}; + unsigned i; + for(i=0; i<(l_prefix/8); ++i) + { + l_mask[i] = 0xff; + } + if (l_prefix % 8) { + l_mask[i] = 0xff << (8 - (l_prefix % 8)); + } + + makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); + l_entry->ifa_netmask = (struct sockaddr *)l_addr; + } + + addToEnd(p_resultList, l_entry); +} + +static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + interpretLink(l_hdr, p_links, p_resultList); + } + else if(l_hdr->nlmsg_type == RTM_NEWADDR) + { + interpretAddr(l_hdr, p_links, p_resultList); + } + } + } +} + +static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList) +{ + unsigned l_links = 0; + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + ++l_links; + } + } + } + + return l_links; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + if(!ifap) + { + return -1; + } + *ifap = NULL; + + int l_socket = netlink_socket(); + if(l_socket < 0) + { + return -1; + } + + NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults); + struct ifaddrs *l_links[l_numLinks]; + memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *)); + + interpret(l_socket, l_linkResults, l_links, ifap); + interpret(l_socket, l_addrResults, l_links, ifap); + + freeResultList(l_linkResults); + freeResultList(l_addrResults); + close(l_socket); + return 0; +} + +void freeifaddrs(struct ifaddrs *ifa) +{ + struct ifaddrs *l_cur; + while(ifa) + { + l_cur = ifa; + ifa = ifa->ifa_next; + free(l_cur); + } +} diff --git a/src/lxc/tools/include/ifaddrs.h b/src/lxc/tools/include/ifaddrs.h new file mode 100644 index 0000000000..9cd19fec12 --- /dev/null +++ b/src/lxc/tools/include/ifaddrs.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/src/lxc/tools/lxc_cgroup.c b/src/lxc/tools/lxc_cgroup.c index 3624e80b7d..231cc7b7c2 100644 --- a/src/lxc/tools/lxc_cgroup.c +++ b/src/lxc/tools/lxc_cgroup.c @@ -32,6 +32,7 @@ #include #include "arguments.h" +#include "tool_utils.h" static int my_checker(const struct lxc_arguments* args) { diff --git a/src/lxc/tools/lxc_device.c b/src/lxc/tools/lxc_device.c index f73e8c2cb7..501bc99a0d 100644 --- a/src/lxc/tools/lxc_device.c +++ b/src/lxc/tools/lxc_device.c @@ -18,25 +18,24 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#define _GNU_SOURCE +#include +#include #include +#include #include #include -#include -#include -#include #include -#include "utils.h" -#include "lxc.h" -#include "log.h" - #include "arguments.h" +#include "tool_utils.h" #if HAVE_IFADDRS_H #include #else -#include <../include/ifaddrs.h> +#include "include/ifaddrs.h" #endif static const struct option my_longopts[] = { @@ -123,7 +122,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) goto err; - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index e50f50273d..42be4d2496 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -21,7 +21,9 @@ #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ #include #include +#include #include +#include #include #include #include @@ -603,3 +605,28 @@ bool file_exists(const char *f) return stat(f, &statbuf) == 0; } + +bool switch_to_ns(pid_t pid, const char *ns) { + int fd, ret; + char nspath[TOOL_MAXPATHLEN]; + + /* Switch to new ns */ + ret = snprintf(nspath, TOOL_MAXPATHLEN, "/proc/%d/ns/%s", pid, ns); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) + return false; + + fd = open(nspath, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Failed to open %s\n", nspath); + return false; + } + + ret = setns(fd, 0); + if (ret) { + fprintf(stderr, "Failed to set process %d to %s of %d\n", pid, ns, fd); + close(fd); + return false; + } + close(fd); + return true; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 4c9b43a28e..e6d922f3ae 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -145,4 +145,6 @@ extern int is_dir(const char *path); extern char *get_template_path(const char *t); +extern bool switch_to_ns(pid_t pid, const char *ns); + #endif /* __LXC_UTILS_H */ From 791e7a73a9bca8dbde19afb49f172a901ce0dd43 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 15:31:03 +0100 Subject: [PATCH 19/34] tools: move lxc-execute to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 14 +-- src/lxc/tools/arguments.c | 7 +- src/lxc/tools/lxc_execute.c | 65 +++++++---- src/lxc/tools/tool_utils.c | 215 ++++++++++++++++++++++++++++++++++-- src/lxc/tools/tool_utils.h | 14 +++ 5 files changed, 275 insertions(+), 40 deletions(-) diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index d7043e01b5..7908f20cac 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -269,13 +269,13 @@ endif LDADD=liblxc.la @CAP_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@ lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c tools/tool_utils.c -lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c -lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c -lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c -lxc_console_SOURCES = tools/lxc_console.c tools/arguments.c -lxc_destroy_SOURCES = tools/lxc_destroy.c tools/arguments.c -lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c -lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c +lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c tools/tool_utils.c +lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c tools/tool_utils.c +lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c tools/tool_utils.c +lxc_console_SOURCES = tools/lxc_console.c tools/arguments.c tools/tool_utils.c +lxc_destroy_SOURCES = tools/lxc_destroy.c tools/arguments.c tools/tool_utils.c +lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c tools/tool_utils.c +lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c tools/tool_utils.c lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c diff --git a/src/lxc/tools/arguments.c b/src/lxc/tools/arguments.c index f98053feca..1be7eba58d 100644 --- a/src/lxc/tools/arguments.c +++ b/src/lxc/tools/arguments.c @@ -22,6 +22,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE #include #include #include @@ -32,10 +33,10 @@ #include #include +#include + #include "arguments.h" -#include "utils.h" -#include "version.h" -#include "namespace.h" +#include "tool_utils.h" static int build_shortopts(const struct option *a_options, char *a_shortopts, size_t a_size) diff --git a/src/lxc/tools/lxc_execute.c b/src/lxc/tools/lxc_execute.c index 3348d7c1c2..dd58aed706 100644 --- a/src/lxc/tools/lxc_execute.c +++ b/src/lxc/tools/lxc_execute.c @@ -20,6 +20,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + #define _GNU_SOURCE #include #include @@ -35,19 +36,15 @@ #include #include "arguments.h" -#include "caps.h" -#include "conf.h" -#include "config.h" -#include "confile.h" -#include "log.h" -#include "lxc.h" -#include "start.h" -#include "utils.h" +#include "tool_list.h" +#include "tool_utils.h" static struct lxc_list defines; static int my_parser(struct lxc_arguments* args, int c, char* arg) { + int ret; + switch (c) { case 'd': args->daemonize = 1; @@ -56,7 +53,9 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg) args->rcfile = arg; break; case 's': - return lxc_config_define_add(&defines, arg); + ret = lxc_config_define_add(&defines, arg); + if (ret < 0) + lxc_config_define_free(&defines); break; case 'u': if (lxc_safe_uint(arg, &args->uid) < 0) @@ -114,14 +113,17 @@ Options :\n\ .daemonize = 0, }; -static bool set_argv(struct lxc_conf *conf, struct lxc_arguments *args) +static bool set_argv(struct lxc_container *c, struct lxc_arguments *args) { + int ret; + char buf[TOOL_MAXPATHLEN]; char **components, **p; - if (!conf->execute_cmd) + ret = c->get_config_item(c, "lxc.execute.cmd", buf, TOOL_MAXPATHLEN); + if (ret < 0) return false; - components = lxc_string_split_quoted(conf->execute_cmd); + components = lxc_string_split_quoted(buf); if (!components) return false; @@ -156,7 +158,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -189,24 +190,50 @@ int main(int argc, char *argv[]) } if (my_args.argc == 0) { - if (!set_argv(c->lxc_conf, &my_args)) { + if (!set_argv(c, &my_args)) { fprintf(stderr, "missing command to execute!\n"); lxc_container_put(c); exit(EXIT_FAILURE); } } - ret = lxc_config_define_load(&defines, c->lxc_conf); + ret = lxc_config_define_load(&defines, c); if (ret) { lxc_container_put(c); exit(EXIT_FAILURE); } - if (my_args.uid) - c->lxc_conf->init_uid = my_args.uid; + if (my_args.uid) { + char buf[256]; + + ret = snprintf(buf, 256, "%d", my_args.uid); + if (ret < 0 || (size_t)ret >= 256) { + lxc_container_put(c); + exit(EXIT_FAILURE); + } + + ret = c->set_config_item(c, "lxc.init.uid", buf); + if (ret < 0) { + lxc_container_put(c); + exit(EXIT_FAILURE); + } + } + + if (my_args.gid) { + char buf[256]; - if (my_args.gid) - c->lxc_conf->init_gid = my_args.gid; + ret = snprintf(buf, 256, "%d", my_args.gid); + if (ret < 0 || (size_t)ret >= 256) { + lxc_container_put(c); + exit(EXIT_FAILURE); + } + + ret = c->set_config_item(c, "lxc.init.gid", buf); + if (ret < 0) { + lxc_container_put(c); + exit(EXIT_FAILURE); + } + } if (!lxc_setup_shared_ns(&my_args, c)) { lxc_container_put(c); diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 42be4d2496..b1557a18e5 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -131,17 +131,6 @@ signed long lxc_config_parse_arch(const char *arch) return -1; } -enum { - LXC_NS_USER, - LXC_NS_MNT, - LXC_NS_PID, - LXC_NS_UTS, - LXC_NS_IPC, - LXC_NS_NET, - LXC_NS_CGROUP, - LXC_NS_MAX -}; - const static struct ns_info { const char *proc_name; int clone_flag; @@ -630,3 +619,207 @@ bool switch_to_ns(pid_t pid, const char *ns) { close(fd); return true; } + +static bool complete_word(char ***result, char *start, char *end, size_t *cap, size_t *cnt) +{ + int r; + + r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16); + if (r < 0) + return false; + (*result)[*cnt] = strndup(start, end - start); + if (!(*result)[*cnt]) + return false; + (*cnt)++; + + return true; +} + +/* + * Given a a string 'one two "three four"', split into three words, + * one, two, and "three four" + */ +char **lxc_string_split_quoted(char *string) +{ + char *nextword = string, *p, state; + char **result = NULL; + size_t result_capacity = 0; + size_t result_count = 0; + + if (!string || !*string) + return calloc(1, sizeof(char *)); + + // TODO I'm *not* handling escaped quote + state = ' '; + for (p = string; *p; p++) { + switch(state) { + case ' ': + if (isspace(*p)) + continue; + else if (*p == '"' || *p == '\'') { + nextword = p; + state = *p; + continue; + } + nextword = p; + state = 'a'; + continue; + case 'a': + if (isspace(*p)) { + complete_word(&result, nextword, p, &result_capacity, &result_count); + state = ' '; + continue; + } + continue; + case '"': + case '\'': + if (*p == state) { + complete_word(&result, nextword+1, p, &result_capacity, &result_count); + state = ' '; + continue; + } + continue; + } + } + + if (state == 'a') + complete_word(&result, nextword, p, &result_capacity, &result_count); + + return realloc(result, (result_count + 1) * sizeof(char *)); +} + +int lxc_char_left_gc(const char *buffer, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + if (buffer[i] == ' ' || + buffer[i] == '\t') + continue; + return i; + } + return 0; +} + +int lxc_char_right_gc(const char *buffer, size_t len) +{ + int i; + for (i = len - 1; i >= 0; i--) { + if (buffer[i] == ' ' || + buffer[i] == '\t' || + buffer[i] == '\n' || + buffer[i] == '\0') + continue; + return i + 1; + } + return 0; +} + +struct new_config_item *parse_line(char *buffer) +{ + char *dot, *key, *line, *linep, *value; + int ret = 0; + char *dup = buffer; + struct new_config_item *new = NULL; + + linep = line = strdup(dup); + if (!line) + return NULL; + + line += lxc_char_left_gc(line, strlen(line)); + + /* martian option - don't add it to the config itself */ + if (strncmp(line, "lxc.", 4)) + goto on_error; + + ret = -1; + dot = strchr(line, '='); + if (!dot) { + fprintf(stderr, "Invalid configuration item: %s\n", line); + goto on_error; + } + + *dot = '\0'; + value = dot + 1; + + key = line; + key[lxc_char_right_gc(key, strlen(key))] = '\0'; + + value += lxc_char_left_gc(value, strlen(value)); + value[lxc_char_right_gc(value, strlen(value))] = '\0'; + + if (*value == '\'' || *value == '\"') { + size_t len; + + len = strlen(value); + if (len > 1 && value[len - 1] == *value) { + value[len - 1] = '\0'; + value++; + } + } + + ret = -1; + new = malloc(sizeof(struct new_config_item)); + if (!new) + goto on_error; + + new->key = strdup(key); + new->val = strdup(value); + if (!new->val || !new->key) + goto on_error; + ret = 0; + +on_error: + free(linep); + if (ret < 0 && new) { + free(new->key); + free(new->val); + free(new); + new = NULL; + } + + return new; +} + +int lxc_config_define_add(struct lxc_list *defines, char *arg) +{ + struct lxc_list *dent; + + dent = malloc(sizeof(struct lxc_list)); + if (!dent) + return -1; + + dent->elem = parse_line(arg); + if (!dent->elem) + return -1; + lxc_list_add_tail(defines, dent); + return 0; +} + +int lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c) +{ + struct lxc_list *it; + int ret = 0; + + lxc_list_for_each(it, defines) { + struct new_config_item *new_item = it->elem; + ret = c->set_config_item(c, new_item->key, new_item->val); + if (ret < 0) + break; + } + + lxc_config_define_free(defines); + return ret; +} + +void lxc_config_define_free(struct lxc_list *defines) +{ + struct lxc_list *it, *next; + + lxc_list_for_each_safe(it, defines, next) { + struct new_config_item *new_item = it->elem; + free(new_item->key); + free(new_item->val); + lxc_list_del(it); + free(it); + } +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index e6d922f3ae..5d1e8d3e3b 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -138,6 +138,7 @@ extern char **lxc_string_split(const char *string, char _sep); extern char **lxc_normalize_path(const char *path); extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix); +extern char **lxc_string_split_quoted(char *string); extern int mkdir_p(const char *dir, mode_t mode); extern bool file_exists(const char *f); @@ -147,4 +148,17 @@ extern char *get_template_path(const char *t); extern bool switch_to_ns(pid_t pid, const char *ns); +extern int lxc_config_define_add(struct lxc_list *defines, char *arg); +extern int lxc_config_define_load(struct lxc_list *defines, + struct lxc_container *c); +extern void lxc_config_define_free(struct lxc_list *defines); +extern int lxc_char_left_gc(const char *buffer, size_t len); +extern int lxc_char_right_gc(const char *buffer, size_t len); + +struct new_config_item { + char *key; + char *val; +}; +extern struct new_config_item *parse_line(char *buffer); + #endif /* __LXC_UTILS_H */ From 49ac7514cf8b1ae257418445bc6b2fe9568c7adf Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 15:32:07 +0100 Subject: [PATCH 20/34] tools: move lxc-freeze to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_freeze.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lxc/tools/lxc_freeze.c b/src/lxc/tools/lxc_freeze.c index aab2b6fe3b..09c21b30eb 100644 --- a/src/lxc/tools/lxc_freeze.c +++ b/src/lxc/tools/lxc_freeze.c @@ -20,17 +20,17 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#define _GNU_SOURCE +#include #include +#include +#include #include #include -#include -#include #include -#include "lxc.h" -#include "log.h" - #include "arguments.h" static const struct option my_longopts[] = { @@ -72,7 +72,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); From 8765242a3b3856d383fa63df3112262da1ac8d48 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 15:36:15 +0100 Subject: [PATCH 21/34] tools: move lxc-info to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_info.c | 20 +++++++++----------- src/lxc/tools/tool_utils.c | 27 +++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 1 + 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/lxc/tools/lxc_info.c b/src/lxc/tools/lxc_info.c index 3c7f6b3988..de8f574634 100644 --- a/src/lxc/tools/lxc_info.c +++ b/src/lxc/tools/lxc_info.c @@ -21,21 +21,20 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#define _GNU_SOURCE +#include +#include #include +#include #include +#include #include -#include -#include #include #include -#include "lxc.h" -#include "log.h" -#include "utils.h" -#include "commands.h" #include "arguments.h" +#include "tool_utils.h" static bool ips; static bool state; @@ -205,7 +204,7 @@ static void print_stats(struct lxc_container *c) char buf[4096]; ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf)); - if (ret > 0 && ret < sizeof(buf)) { + if (ret > 0 && (size_t)ret < sizeof(buf)) { str_chomp(buf); if (humanize) { float seconds = strtof(buf, NULL) / 1000000000.0; @@ -217,7 +216,7 @@ static void print_stats(struct lxc_container *c) } ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, sizeof(buf)); - if (ret > 0 && ret < sizeof(buf)) { + if (ret > 0 && (size_t)ret < sizeof(buf)) { char *ch; /* put ch on last "Total" line */ @@ -247,7 +246,7 @@ static void print_stats(struct lxc_container *c) for (i = 0; lxstat[i].name; i++) { ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf)); - if (ret > 0 && ret < sizeof(buf)) { + if (ret > 0 && (size_t)ret < sizeof(buf)) { str_chomp(buf); str_size_humanize(buf, sizeof(buf)); printf("%-15s %s\n", lxstat[i].name, buf); @@ -409,7 +408,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(ret); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index b1557a18e5..462a07a223 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -823,3 +823,30 @@ void lxc_config_define_free(struct lxc_list *defines) free(it); } } + +int lxc_read_from_file(const char *filename, void* buf, size_t count) +{ + int fd = -1, saved_errno; + ssize_t ret; + + fd = open(filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + if (!buf || !count) { + char buf2[100]; + size_t count2 = 0; + while ((ret = read(fd, buf2, 100)) > 0) + count2 += ret; + if (ret >= 0) + ret = count2; + } else { + memset(buf, 0, count); + ret = read(fd, buf, count); + } + + saved_errno = errno; + close(fd); + errno = saved_errno; + return ret; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 5d1e8d3e3b..2816376801 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -143,6 +143,7 @@ extern char **lxc_string_split_quoted(char *string); extern int mkdir_p(const char *dir, mode_t mode); extern bool file_exists(const char *f); extern int is_dir(const char *path); +extern int lxc_read_from_file(const char *filename, void* buf, size_t count); extern char *get_template_path(const char *t); From 4b7c0ef8b25d273e1e1b9359d6f7ff78c1cfd25a Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 15:47:32 +0100 Subject: [PATCH 22/34] tools: move lxc-ls to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 28 ++-- src/lxc/tools/lxc_ls.c | 13 +- src/lxc/tools/tool_utils.c | 281 +++++++++++++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 14 ++ 4 files changed, 313 insertions(+), 23 deletions(-) diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 7908f20cac..cb057774b5 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -276,20 +276,20 @@ lxc_console_SOURCES = tools/lxc_console.c tools/arguments.c tools/tool_utils.c lxc_destroy_SOURCES = tools/lxc_destroy.c tools/arguments.c tools/tool_utils.c lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c tools/tool_utils.c lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c tools/tool_utils.c -lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c -lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c -lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c -lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c -lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c -lxc_start_SOURCES = tools/lxc_start.c tools/arguments.c -lxc_stop_SOURCES = tools/lxc_stop.c tools/arguments.c -lxc_top_SOURCES = tools/lxc_top.c tools/arguments.c -lxc_unfreeze_SOURCES = tools/lxc_unfreeze.c tools/arguments.c -lxc_unshare_SOURCES = tools/lxc_unshare.c tools/arguments.c -lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c -lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c -lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c -lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c +lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c tools/tool_utils.c +lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c tools/tool_utils.c +lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c tools/tool_utils.c +lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c tools/tool_utils.c +lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c tools/tool_utils.c +lxc_start_SOURCES = tools/lxc_start.c tools/arguments.c tools/tool_utils.c +lxc_stop_SOURCES = tools/lxc_stop.c tools/arguments.c tools/tool_utils.c +lxc_top_SOURCES = tools/lxc_top.c tools/arguments.c tools/tool_utils.c +lxc_unfreeze_SOURCES = tools/lxc_unfreeze.c tools/arguments.c tools/tool_utils.c +lxc_unshare_SOURCES = tools/lxc_unshare.c tools/arguments.c tools/tool_utils.c +lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c tools/tool_utils.c +lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c tools/tool_utils.c +lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c tools/tool_utils.c +lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c tools/tool_utils.c # Binaries shipping with liblxc init_lxc_SOURCES = cmd/lxc_init.c diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c index 6f9719a868..1cec7d5d97 100644 --- a/src/lxc/tools/lxc_ls.c +++ b/src/lxc/tools/lxc_ls.c @@ -16,9 +16,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "config.h" - +#define _GNU_SOURCE #include +#include #include #include #include @@ -35,11 +35,7 @@ #include #include "arguments.h" -#include "conf.h" -#include "confile.h" -#include "log.h" -#include "lxc.h" -#include "utils.h" +#include "tool_utils.h" /* Per default we only allow five levels of recursion to protect the stack at * least a little bit. */ @@ -231,7 +227,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -1072,7 +1067,7 @@ static int ls_remove_lock(const char *path, const char *name, if (check < 0 || (size_t)check >= *len_lockpath) goto out; - lxc_rmdir_onedev(*lockpath, NULL); + (void)rm_r(*lockpath); ret = 0; out: diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 462a07a223..71b4996590 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -20,6 +20,7 @@ #define _GNU_SOURCE #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ #include +#include #include #include #include @@ -850,3 +851,283 @@ int lxc_read_from_file(const char *filename, void* buf, size_t count) errno = saved_errno; return ret; } + +char **lxc_string_split_and_trim(const char *string, char _sep) +{ + char *token, *str, *saveptr = NULL; + char sep[2] = { _sep, '\0' }; + char **result = NULL; + size_t result_capacity = 0; + size_t result_count = 0; + int r, saved_errno; + size_t i = 0; + + if (!string) + return calloc(1, sizeof(char *)); + + str = alloca(strlen(string)+1); + strcpy(str, string); + for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) { + while (token[0] == ' ' || token[0] == '\t') + token++; + i = strlen(token); + while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) { + token[i - 1] = '\0'; + i--; + } + r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16); + if (r < 0) + goto error_out; + result[result_count] = strdup(token); + if (!result[result_count]) + goto error_out; + result_count++; + } + + /* if we allocated too much, reduce it */ + return realloc(result, (result_count + 1) * sizeof(char *)); +error_out: + saved_errno = errno; + lxc_free_array((void **)result, free); + errno = saved_errno; + return NULL; +} + +char *lxc_append_paths(const char *first, const char *second) +{ + int ret; + size_t len; + char *result = NULL; + const char *pattern = "%s%s"; + + len = strlen(first) + strlen(second) + 1; + if (second[0] != '/') { + len += 1; + pattern = "%s/%s"; + } + + result = calloc(1, len); + if (!result) + return NULL; + + ret = snprintf(result, len, pattern, first, second); + if (ret < 0 || (size_t)ret >= len) { + free(result); + return NULL; + } + + return result; +} + +bool dir_exists(const char *path) +{ + struct stat sb; + int ret; + + ret = stat(path, &sb); + if (ret < 0) + /* Could be something other than eexist, just say "no". */ + return false; + return S_ISDIR(sb.st_mode); +} + +char *lxc_string_replace(const char *needle, const char *replacement, + const char *haystack) +{ + ssize_t len = -1, saved_len = -1; + char *result = NULL; + size_t replacement_len = strlen(replacement); + size_t needle_len = strlen(needle); + + /* should be executed exactly twice */ + while (len == -1 || result == NULL) { + char *p; + char *last_p; + ssize_t part_len; + + if (len != -1) { + result = calloc(1, len + 1); + if (!result) + return NULL; + saved_len = len; + } + + len = 0; + + for (last_p = (char *)haystack, p = strstr(last_p, needle); p; last_p = p, p = strstr(last_p, needle)) { + part_len = (ssize_t)(p - last_p); + if (result && part_len > 0) + memcpy(&result[len], last_p, part_len); + len += part_len; + if (result && replacement_len > 0) + memcpy(&result[len], replacement, replacement_len); + len += replacement_len; + p += needle_len; + } + part_len = strlen(last_p); + if (result && part_len > 0) + memcpy(&result[len], last_p, part_len); + len += part_len; + } + + /* make sure we did the same thing twice, + * once for calculating length, the other + * time for copying data */ + if (saved_len != len) { + free(result); + return NULL; + } + /* make sure we didn't overwrite any buffer, + * due to calloc the string should be 0-terminated */ + if (result[len] != '\0') { + free(result); + return NULL; + } + + return result; +} + +ssize_t lxc_write_nointr(int fd, const void* buf, size_t count) +{ + ssize_t ret; +again: + ret = write(fd, buf, count); + if (ret < 0 && errno == EINTR) + goto again; + return ret; +} + +char *get_rundir() +{ + char *rundir; + const char *homedir; + + if (geteuid() == 0) { + rundir = strdup(RUNTIME_PATH); + return rundir; + } + + rundir = getenv("XDG_RUNTIME_DIR"); + if (rundir) { + rundir = strdup(rundir); + return rundir; + } + + homedir = getenv("HOME"); + if (!homedir) + return NULL; + + rundir = malloc(sizeof(char) * (17 + strlen(homedir))); + sprintf(rundir, "%s/.cache/lxc/run/", homedir); + + return rundir; +} + +char *must_copy_string(const char *entry) +{ + char *ret; + + if (!entry) + return NULL; + do { + ret = strdup(entry); + } while (!ret); + + return ret; +} + + +void *must_realloc(void *orig, size_t sz) +{ + void *ret; + + do { + ret = realloc(orig, sz); + } while (!ret); + + return ret; +} + +char *must_make_path(const char *first, ...) +{ + va_list args; + char *cur, *dest; + size_t full_len = strlen(first); + + dest = must_copy_string(first); + + va_start(args, first); + while ((cur = va_arg(args, char *)) != NULL) { + full_len += strlen(cur); + if (cur[0] != '/') + full_len++; + dest = must_realloc(dest, full_len + 1); + if (cur[0] != '/') + strcat(dest, "/"); + strcat(dest, cur); + } + va_end(args); + + return dest; +} + +int rm_r(char *dirname) +{ + int ret; + struct dirent *direntp; + DIR *dir; + int r = 0; + + dir = opendir(dirname); + if (!dir) + return -1; + + while ((direntp = readdir(dir))) { + char *pathname; + struct stat mystat; + + if (!direntp) + break; + + if (!strcmp(direntp->d_name, ".") || + !strcmp(direntp->d_name, "..")) + continue; + + pathname = must_make_path(dirname, direntp->d_name, NULL); + + ret = lstat(pathname, &mystat); + if (ret < 0) { + r = -1; + goto next; + } + + if (!S_ISDIR(mystat.st_mode)) + goto next; + + ret = rm_r(pathname); + if (ret < 0) + r = -1; + next: + free(pathname); + } + + ret = rmdir(dirname); + if (ret < 0) + r = -1; + + ret = closedir(dir); + if (ret < 0) + r = -1; + + return r; +} + +ssize_t lxc_read_nointr(int fd, void* buf, size_t count) +{ + ssize_t ret; +again: + ret = read(fd, buf, count); + if (ret < 0 && errno == EINTR) + goto again; + return ret; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 2816376801..278402ab3a 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -139,9 +139,18 @@ extern char **lxc_normalize_path(const char *path); extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix); extern char **lxc_string_split_quoted(char *string); +extern char **lxc_string_split_and_trim(const char *string, char _sep); +extern char *lxc_append_paths(const char *first, const char *second); +extern char *lxc_string_replace(const char *needle, const char *replacement, + const char *haystack); +extern char *must_copy_string(const char *entry); +extern void *must_realloc(void *orig, size_t sz); +extern char *must_make_path(const char *first, ...); extern int mkdir_p(const char *dir, mode_t mode); +extern int rm_r(char *dirname); extern bool file_exists(const char *f); +extern bool dir_exists(const char *path); extern int is_dir(const char *path); extern int lxc_read_from_file(const char *filename, void* buf, size_t count); @@ -162,4 +171,9 @@ struct new_config_item { }; extern struct new_config_item *parse_line(char *buffer); +extern ssize_t lxc_read_nointr(int fd, void* buf, size_t count); +extern ssize_t lxc_write_nointr(int fd, const void* buf, size_t count); + +extern char *get_rundir(); + #endif /* __LXC_UTILS_H */ From 6a3ec2c51e29faeca69a378a39a84577bc416a8c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 16:01:10 +0100 Subject: [PATCH 23/34] tools: move lxc-snapshot to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_snapshot.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/lxc/tools/lxc_snapshot.c b/src/lxc/tools/lxc_snapshot.c index 0c0ea3ada5..7c8255c2c1 100644 --- a/src/lxc/tools/lxc_snapshot.c +++ b/src/lxc/tools/lxc_snapshot.c @@ -17,21 +17,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "confile.h" -#include +#define _GNU_SOURCE +#include +#include #include +#include +#include +#include #include -#include #include -#include #include -#include "lxc.h" -#include "log.h" #include "arguments.h" -#include "storage.h" -#include "utils.h" +#include "tool_utils.h" static int my_parser(struct lxc_arguments *args, int c, char *arg); @@ -97,7 +96,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); From 9810df078547d8a5da363ff1cfaf8a25b71b59fc Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 16:04:28 +0100 Subject: [PATCH 24/34] tools: move lxc-start to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_start.c | 93 +++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c index 5a422923ff..31a7cd6900 100644 --- a/src/lxc/tools/lxc_start.c +++ b/src/lxc/tools/lxc_start.c @@ -20,35 +20,30 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" -#include -#include -#include -#include -#include +#define _GNU_SOURCE #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include #include -#include -#include #include #include -#include -#include -#include +#include +#include #include -#include "log.h" -#include "caps.h" -#include "lxc.h" -#include "conf.h" -#include "cgroup.h" -#include "utils.h" -#include "confile.h" #include "arguments.h" +#include "tool_list.h" +#include "tool_utils.h" static struct lxc_list defines; @@ -82,21 +77,44 @@ static int ensure_path(char **confpath, const char *path) return err; } -static int my_parser(struct lxc_arguments* args, int c, char* arg) +static int my_parser(struct lxc_arguments *args, int c, char *arg) { switch (c) { - case 'c': args->console = arg; break; - case 'L': args->console_log = arg; break; - case 'd': args->daemonize = 1; break; - case 'F': args->daemonize = 0; break; - case 'f': args->rcfile = arg; break; - case 'C': args->close_all_fds = 1; break; - case 's': return lxc_config_define_add(&defines, arg); - case 'p': args->pidfile = arg; break; - case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break; - case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break; - case OPT_SHARE_UTS: args->share_ns[LXC_NS_UTS] = arg; break; - case OPT_SHARE_PID: args->share_ns[LXC_NS_PID] = arg; break; + case 'c': + args->console = arg; + break; + case 'L': + args->console_log = arg; + break; + case 'd': + args->daemonize = 1; + break; + case 'F': + args->daemonize = 0; + break; + case 'f': + args->rcfile = arg; + break; + case 'C': + args->close_all_fds = 1; + break; + case 's': + return lxc_config_define_add(&defines, arg); + case 'p': + args->pidfile = arg; + break; + case OPT_SHARE_NET: + args->share_ns[LXC_NS_NET] = arg; + break; + case OPT_SHARE_IPC: + args->share_ns[LXC_NS_IPC] = arg; + break; + case OPT_SHARE_UTS: + args->share_ns[LXC_NS_UTS] = arg; + break; + case OPT_SHARE_PID: + args->share_ns[LXC_NS_PID] = arg; + break; } return 0; } @@ -147,11 +165,10 @@ Options :\n\ int main(int argc, char *argv[]) { - struct lxc_conf *conf; - struct lxc_log log; const char *lxcpath; char *const *args; struct lxc_container *c; + struct lxc_log log; int err = EXIT_FAILURE; char *rcfile = NULL; char *const default_args[] = { @@ -181,7 +198,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(err); - lxc_log_options_no_override(); lxcpath = my_args.lxcpath[0]; if (access(lxcpath, O_RDONLY) < 0) { @@ -259,11 +275,12 @@ int main(int argc, char *argv[]) * We should use set_config_item() over &defines, which would handle * unset c->lxc_conf for us and let us not use lxc_config_define_load() */ - if (!c->lxc_conf) - c->lxc_conf = lxc_conf_init(); - conf = c->lxc_conf; + if (!c->lxc_conf) { + fprintf(stderr, "No container config specified\n"); + goto out; + } - if (lxc_config_define_load(&defines, conf)) + if (lxc_config_define_load(&defines, c)) goto out; if (!rcfile && !strcmp("/sbin/init", args[0])) { From 52d27da510808c3e347d9fb059e24087a941a4b5 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 16:17:46 +0100 Subject: [PATCH 25/34] tools: move lxc-stop to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_stop.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/lxc/tools/lxc_stop.c b/src/lxc/tools/lxc_stop.c index 9d2ba6ed14..f133c99770 100644 --- a/src/lxc/tools/lxc_stop.c +++ b/src/lxc/tools/lxc_stop.c @@ -20,18 +20,18 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + +#define _GNU_SOURCE #include -#include +#include +#include #include +#include #include -#include "lxc.h" -#include "log.h" #include "arguments.h" -#include "commands.h" -#include "utils.h" +#include "tool_utils.h" #define OPT_NO_LOCK OPT_USAGE + 1 #define OPT_NO_KILL OPT_USAGE + 2 @@ -113,7 +113,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(ret); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -155,13 +154,6 @@ int main(int argc, char *argv[]) exit(ret); } - /* shortcut - if locking is bogus, we should be able to kill - * containers at least */ - if (my_args.nolock) { - ret = lxc_cmd_stop(my_args.name, my_args.lxcpath[0]); - exit(ret); - } - c = lxc_container_new(my_args.name, my_args.lxcpath[0]); if (!c) { fprintf(stderr, "Error opening container\n"); From adc0914195a224d9575a2ae99a825d0e43317751 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 16:29:46 +0100 Subject: [PATCH 26/34] tools: move lxc-top to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_top.c | 172 ++++++++++++++++++++++++++++++++++------ 1 file changed, 146 insertions(+), 26 deletions(-) diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c index 5d5c08a252..868693866c 100644 --- a/src/lxc/tools/lxc_top.c +++ b/src/lxc/tools/lxc_top.c @@ -21,25 +21,26 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ #include #include #include #include +#include #include #include -#include +#include #include #include #include #include +#include + #include #include "arguments.h" -#include "log.h" -#include "lxc.h" -#include "mainloop.h" -#include "utils.h" +#include "tool_utils.h" #define USER_HZ 100 #define ESC "\033" @@ -181,24 +182,6 @@ static int stdin_tios_rows(void) return 25; } -static int stdin_handler(int fd, uint32_t events, void *data, - struct lxc_epoll_descr *descr) -{ - char *in_char = data; - - if (events & EPOLLIN) { - int rc; - - rc = read(fd, in_char, sizeof(*in_char)); - if (rc <= 0) - *in_char = '\0'; - } - - if (events & EPOLLHUP) - *in_char = 'q'; - return 1; -} - static void sig_handler(int sig) { exit(EXIT_SUCCESS); @@ -310,7 +293,7 @@ static void stat_get_blk_stats(struct lxc_container *c, const char *item, char **lines, **cols; len = c->get_cgroup_item(c, item, buf, sizeof(buf)); - if (len <= 0 || len >= sizeof(buf)) { + if (len <= 0 || (size_t)len >= sizeof(buf)) { fprintf(stderr, "unable to read cgroup item %s\n", item); return; } @@ -409,7 +392,7 @@ static void stats_print(const char *name, const struct stats *stats, size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str)); ret = snprintf(iosb_str, sizeof(iosb_str), "%s(%s/%s)", iosb_total_str, iosb_read_str, iosb_write_str); - if (ret < 0 || ret >= sizeof(iosb_str)) + if (ret < 0 || (size_t)ret >= sizeof(iosb_str)) printf("snprintf'd too many characters: %d\n", ret); printf("%-18.18s %12.2f %12.2f %12.2f %36s %10s", @@ -429,7 +412,7 @@ static void stats_print(const char *name, const struct stats *stats, printf(" %10s", kmem_used_str); } } else { - gettimeofday(&time_val, NULL); + (void)gettimeofday(&time_val, NULL); time_ms = (unsigned long long) (time_val.tv_sec) * 1000 + (unsigned long long) (time_val.tv_usec) / 1000; printf("%" PRIu64 ",%s,%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64, @@ -554,6 +537,143 @@ static void ct_realloc(int active_cnt) } } +#define LXC_MAINLOOP_CONTINUE 0 +#define LXC_MAINLOOP_CLOSE 1 + +struct lxc_epoll_descr { + int epfd; + struct lxc_list handlers; +}; + +typedef int (*lxc_mainloop_callback_t)(int fd, uint32_t event, void *data, + struct lxc_epoll_descr *descr); + +struct mainloop_handler { + lxc_mainloop_callback_t callback; + int fd; + void *data; +}; + +#define MAX_EVENTS 10 + +int lxc_mainloop(struct lxc_epoll_descr *descr, int timeout_ms) +{ + int i, nfds, ret; + struct mainloop_handler *handler; + struct epoll_event events[MAX_EVENTS]; + + for (;;) { + nfds = epoll_wait(descr->epfd, events, MAX_EVENTS, timeout_ms); + if (nfds < 0) { + if (errno == EINTR) + continue; + + return -1; + } + + for (i = 0; i < nfds; i++) { + handler = events[i].data.ptr; + + /* If the handler returns a positive value, exit the + * mainloop. + */ + ret = handler->callback(handler->fd, events[i].events, + handler->data, descr); + if (ret == LXC_MAINLOOP_CLOSE) + return 0; + } + + if (nfds == 0) + return 0; + + if (lxc_list_empty(&descr->handlers)) + return 0; + } +} + +int lxc_mainloop_open(struct lxc_epoll_descr *descr) +{ + /* hint value passed to epoll create */ + descr->epfd = epoll_create1(EPOLL_CLOEXEC); + if (descr->epfd < 0) + return -1; + + lxc_list_init(&descr->handlers); + return 0; +} + +int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd, + lxc_mainloop_callback_t callback, void *data) +{ + struct epoll_event ev; + struct mainloop_handler *handler; + struct lxc_list *item; + + handler = malloc(sizeof(*handler)); + if (!handler) + return -1; + + handler->callback = callback; + handler->fd = fd; + handler->data = data; + + ev.events = EPOLLIN; + ev.data.ptr = handler; + + if (epoll_ctl(descr->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) + goto out_free_handler; + + item = malloc(sizeof(*item)); + if (!item) + goto out_free_handler; + + item->elem = handler; + lxc_list_add(&descr->handlers, item); + return 0; + +out_free_handler: + free(handler); + return -1; +} + +int lxc_mainloop_close(struct lxc_epoll_descr *descr) +{ + struct lxc_list *iterator, *next; + + iterator = descr->handlers.next; + while (iterator != &descr->handlers) { + next = iterator->next; + + lxc_list_del(iterator); + free(iterator->elem); + free(iterator); + iterator = next; + } + + if (descr->epfd >= 0) + return close(descr->epfd); + + return 0; +} + +static int stdin_handler(int fd, uint32_t events, void *data, + struct lxc_epoll_descr *descr) +{ + char *in_char = data; + + if (events & EPOLLIN) { + int rc; + + rc = read(fd, in_char, sizeof(*in_char)); + if (rc <= 0) + *in_char = '\0'; + } + + if (events & EPOLLHUP) + *in_char = 'q'; + return 1; +} + int main(int argc, char *argv[]) { struct lxc_epoll_descr descr; From 81bba32eda50697d8d57b557bc378d1ea41d27bb Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 16:30:38 +0100 Subject: [PATCH 27/34] tools: move lxc-unfreeze to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_unfreeze.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lxc/tools/lxc_unfreeze.c b/src/lxc/tools/lxc_unfreeze.c index 5027d28e6c..f12b5d57ac 100644 --- a/src/lxc/tools/lxc_unfreeze.c +++ b/src/lxc/tools/lxc_unfreeze.c @@ -20,16 +20,18 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#define _GNU_SOURCE +#include #include +#include #include -#include #include #include -#include "lxc.h" -#include "log.h" #include "arguments.h" +#include "tool_utils.h" static const struct option my_longopts[] = { LXC_COMMON_OPTIONS @@ -71,7 +73,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); From b678c6d8a7eb71723cf3af1cdbdf7293adb4c197 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 16:36:12 +0100 Subject: [PATCH 28/34] tools: move lxc-wait to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_wait.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lxc/tools/lxc_wait.c b/src/lxc/tools/lxc_wait.c index 62b7c01b5e..6186bce059 100644 --- a/src/lxc/tools/lxc_wait.c +++ b/src/lxc/tools/lxc_wait.c @@ -20,6 +20,8 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#define _GNU_SOURCE #include #include #include @@ -30,9 +32,8 @@ #include -#include "lxc.h" -#include "log.h" #include "arguments.h" +#include "tool_utils.h" static int my_checker(const struct lxc_arguments* args) { @@ -98,7 +99,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(EXIT_FAILURE); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); From d567a9a7e9c660ab821b26e45de7c31dc368348f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Jan 2018 17:06:42 +0100 Subject: [PATCH 29/34] tools: move lxc-unshare to API symbols only Closes #2073. Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_unshare.c | 77 ++++++++++++++++++++++++++++--------- src/lxc/tools/tool_utils.c | 63 ++++++++++++++++++++++++++++++ src/lxc/tools/tool_utils.h | 24 ++++++++++++ 3 files changed, 146 insertions(+), 18 deletions(-) diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c index 9e062a0ca7..98143d6623 100644 --- a/src/lxc/tools/lxc_unshare.c +++ b/src/lxc/tools/lxc_unshare.c @@ -20,30 +20,27 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" -#include +#define _GNU_SOURCE #include +#include #include #include -#include #include +#include #include +#include #include #include +#include +#include #include #include #include #include -#include -#include "caps.h" -#include "cgroup.h" -#include "error.h" -#include "log.h" -#include "namespace.h" -#include "network.h" -#include "utils.h" +#include "arguments.h" +#include "tool_utils.h" struct my_iflist { @@ -67,7 +64,7 @@ static void usage(char *cmd) static bool lookup_user(const char *optarg, uid_t *uid) { - char name[MAXPATHLEN]; + char name[TOOL_MAXPATHLEN]; struct passwd *pwent = NULL; if (!optarg || (optarg[0] == '\0')) @@ -147,11 +144,34 @@ static int do_start(void *arg) return 1; } +int write_id_mapping(pid_t pid, const char *buf, size_t buf_size) +{ + char path[TOOL_MAXPATHLEN]; + int fd, ret; + + + ret = snprintf(path, TOOL_MAXPATHLEN, "/proc/%d/uid_map", pid); + if (ret < 0 || ret >= TOOL_MAXPATHLEN) + return -E2BIG; + + fd = open(path, O_WRONLY); + if (fd < 0) + return -1; + + errno = 0; + ret = lxc_write_nointr(fd, buf, buf_size); + close(fd); + if (ret < 0 || (size_t)ret != buf_size) + return -1; + + return 0; +} + int main(int argc, char *argv[]) { char *del; char **it, **args; - int opt, status; + int opt; int ret; char *namespaces = NULL; int flags = 0, daemonize = 0; @@ -284,7 +304,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - ret = write_id_mapping(ID_TYPE_UID, pid, umap, strlen(umap)); + ret = write_id_mapping(pid, umap, strlen(umap)); if (ret < 0) { close(start_arg.wait_fd); fprintf(stderr, "uid mapping failed\n"); @@ -301,19 +321,40 @@ int main(int argc, char *argv[]) if (my_iflist) { for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) { - if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0) - fprintf(stderr,"Could not move interface %s into container %d: %s\n", tmpif->mi_ifname, pid, strerror(errno)); + pid_t pid; + + pid = fork(); + if (pid < 0) + fprintf(stderr, "Failed to move network device " + "\"%s\" to network namespace\n", + tmpif->mi_ifname); + + if (pid == 0) { + char buf[256]; + + ret = snprintf(buf, 256, "%d", pid); + if (ret < 0 || ret >= 256) + exit(EXIT_FAILURE); + + execlp("ip", "ip", "link", "set", "dev", tmpif->mi_ifname, "netns", buf, (char *)NULL); + exit(EXIT_FAILURE); + } + + if (wait_for_pid(pid) != 0) + fprintf(stderr, "Could not move interface %s " + "into container %d: %s\n", + tmpif->mi_ifname, pid, strerror(errno)); } } if (daemonize) exit(EXIT_SUCCESS); - if (waitpid(pid, &status, 0) < 0) { + if (wait_for_pid(pid) != 0) { fprintf(stderr, "failed to wait for '%d'\n", pid); exit(EXIT_FAILURE); } /* Call exit() directly on this function because it retuns an exit code. */ - exit(lxc_error_set_and_log(pid, status)); + exit(EXIT_SUCCESS); } diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c index 71b4996590..7279b3d4cd 100644 --- a/src/lxc/tools/tool_utils.c +++ b/src/lxc/tools/tool_utils.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include +#include "arguments.h" #include "tool_utils.h" int lxc_fill_elevated_privileges(char *flaglist, int *flags) @@ -1131,3 +1133,64 @@ ssize_t lxc_read_nointr(int fd, void* buf, size_t count) goto again; return ret; } + +static int mount_fs(const char *source, const char *target, const char *type) +{ + /* the umount may fail */ + if (umount(target) < 0) + + if (mount(source, target, type, 0, NULL) < 0) + return -1; + + return 0; +} + +void lxc_setup_fs(void) +{ + (void)mount_fs("proc", "/proc", "proc"); + + /* if /dev has been populated by us, /dev/shm does not exist */ + if (access("/dev/shm", F_OK)) + (void)mkdir("/dev/shm", 0777); + + /* if we can't mount /dev/shm, continue anyway */ + (void)mount_fs("shmfs", "/dev/shm", "tmpfs"); + + /* If we were able to mount /dev/shm, then /dev exists */ + /* Sure, but it's read-only per config :) */ + if (access("/dev/mqueue", F_OK)) + (void)mkdir("/dev/mqueue", 0666); + + /* continue even without posix message queue support */ + (void)mount_fs("mqueue", "/dev/mqueue", "mqueue"); +} + +struct clone_arg { + int (*fn)(void *); + void *arg; +}; + +static int do_clone(void *arg) +{ + struct clone_arg *clone_arg = arg; + return clone_arg->fn(clone_arg->arg); +} + +pid_t lxc_clone(int (*fn)(void *), void *arg, int flags) +{ + struct clone_arg clone_arg = { + .fn = fn, + .arg = arg, + }; + + size_t stack_size = lxc_getpagesize(); + void *stack = alloca(stack_size); + pid_t ret; + +#ifdef __ia64__ + ret = __clone2(do_clone, stack, stack_size, flags | SIGCHLD, &clone_arg); +#else + ret = clone(do_clone, stack + stack_size, flags | SIGCHLD, &clone_arg); +#endif + return ret; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index 278402ab3a..b937137140 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -176,4 +176,28 @@ extern ssize_t lxc_write_nointr(int fd, const void* buf, size_t count); extern char *get_rundir(); +extern void lxc_setup_fs(void); + +static inline uint64_t lxc_getpagesize(void) +{ + int64_t pgsz; + + pgsz = sysconf(_SC_PAGESIZE); + if (pgsz <= 0) + pgsz = 1 << 12; + + return pgsz; +} + +#if defined(__ia64__) +int __clone2(int (*__fn) (void *__arg), void *__child_stack_base, + size_t __child_stack_size, int __flags, void *__arg, ...); +#else +int clone(int (*fn)(void *), void *child_stack, + int flags, void *arg, ... + /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ ); +#endif + +extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags); + #endif /* __LXC_UTILS_H */ From 1194822f0bc92e15d9521ae0521f594d1383710f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 21 Jan 2018 21:53:51 +0100 Subject: [PATCH 30/34] cmd: non-functional changes Signed-off-by: Christian Brauner --- src/lxc/cmd/lxc_init.c | 2 +- src/lxc/cmd/lxc_monitord.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lxc/cmd/lxc_init.c b/src/lxc/cmd/lxc_init.c index 95b680768a..315c643fa6 100644 --- a/src/lxc/cmd/lxc_init.c +++ b/src/lxc/cmd/lxc_init.c @@ -36,13 +36,13 @@ #include #include +#include #include "error.h" #include "initutils.h" #include "log.h" #include "namespace.h" #include "parse.h" -#include "version.h" /* option keys for long only options */ #define OPT_USAGE 0x1000 diff --git a/src/lxc/cmd/lxc_monitord.c b/src/lxc/cmd/lxc_monitord.c index ea292d000e..99f2bdb8b8 100644 --- a/src/lxc/cmd/lxc_monitord.c +++ b/src/lxc/cmd/lxc_monitord.c @@ -39,12 +39,13 @@ #include #include +#include + #include "af_unix.h" #include "log.h" #include "mainloop.h" #include "monitor.h" #include "utils.h" -#include "lxccontainer.h" #define CLIENTFDS_CHUNK 64 From 1a80fcdfc7894a5f404cce148007de77b81af7ac Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 21 Jan 2018 21:54:35 +0100 Subject: [PATCH 31/34] tools: non-functional changes Signed-off-by: Christian Brauner --- src/lxc/tools/arguments.c | 1 + src/lxc/tools/lxc_attach.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lxc/tools/arguments.c b/src/lxc/tools/arguments.c index 1be7eba58d..ff56c0f4e6 100644 --- a/src/lxc/tools/arguments.c +++ b/src/lxc/tools/arguments.c @@ -33,6 +33,7 @@ #include #include +#include #include #include "arguments.h" diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c index b2c405d3ad..253ea30922 100644 --- a/src/lxc/tools/lxc_attach.c +++ b/src/lxc/tools/lxc_attach.c @@ -21,8 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" - +#define _GNU_SOURCE #include #include #include From 6ecad2c49b40aff0156b5192a561c93af1742c2d Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 21 Jan 2018 22:03:47 +0100 Subject: [PATCH 32/34] tools: move lxc-monitor to API symbols only Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_monitor.c | 430 +++++++++++++++++++++++++++++++++++- src/lxc/tools/tool_utils.h | 1 + 2 files changed, 421 insertions(+), 10 deletions(-) diff --git a/src/lxc/tools/lxc_monitor.c b/src/lxc/tools/lxc_monitor.c index 0b094af114..294e8c2f05 100644 --- a/src/lxc/tools/lxc_monitor.c +++ b/src/lxc/tools/lxc_monitor.c @@ -20,22 +20,31 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#define _GNU_SOURCE +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include #include -#include +#include +#include +#include #include +#include #include -#include -#include -#include "lxc.h" -#include "log.h" -#include "monitor.h" +#include + #include "arguments.h" -#include "lxccontainer.h" +#include "tool_utils.h" static bool quit_monitord; @@ -82,6 +91,408 @@ static void close_fds(struct pollfd *fds, nfds_t nfds) } } +typedef enum { + lxc_msg_state, + lxc_msg_priority, + lxc_msg_exit_code, +} lxc_msg_type_t; + +struct lxc_msg { + lxc_msg_type_t type; + char name[NAME_MAX+1]; + int value; +}; + +typedef enum { + STOPPED, + STARTING, + RUNNING, + STOPPING, + ABORTING, + FREEZING, + FROZEN, + THAWED, + MAX_STATE, +} lxc_state_t; + +static const char *const strstate[] = { + "STOPPED", "STARTING", "RUNNING", "STOPPING", + "ABORTING", "FREEZING", "FROZEN", "THAWED", +}; + +const char *lxc_state2str(lxc_state_t state) +{ + if (state < STOPPED || state > MAX_STATE - 1) + return NULL; + return strstate[state]; +} + +/* Note we don't use SHA-1 here as we don't want to depend on HAVE_GNUTLS. + * FNV has good anti collision properties and we're not worried + * about pre-image resistance or one-way-ness, we're just trying to make + * the name unique in the 108 bytes of space we have. + */ +#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) +static uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval) +{ + unsigned char *bp; + + for(bp = buf; bp < (unsigned char *)buf + len; bp++) + { + /* xor the bottom with the current octet */ + hval ^= (uint64_t)*bp; + + /* gcc optimised: + * multiply by the 64 bit FNV magic prime mod 2^64 + */ + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); + } + + return hval; +} + +static int open_devnull(void) +{ + int fd = open("/dev/null", O_RDWR); + + if (fd < 0) + fprintf(stderr, "%s - Failed to open \"/dev/null\"\n", + strerror(errno)); + + return fd; +} + +static int set_stdfds(int fd) +{ + int ret; + + if (fd < 0) + return -1; + + ret = dup2(fd, STDIN_FILENO); + if (ret < 0) + return -1; + + ret = dup2(fd, STDOUT_FILENO); + if (ret < 0) + return -1; + + ret = dup2(fd, STDERR_FILENO); + if (ret < 0) + return -1; + + return 0; +} + +static int null_stdfds(void) +{ + int ret = -1; + int fd = open_devnull(); + + if (fd >= 0) { + ret = set_stdfds(fd); + close(fd); + } + + return ret; +} + +static int lxc_check_inherited(bool closeall, int *fds_to_ignore, size_t len_fds) +{ + struct dirent *direntp; + int fd, fddir; + size_t i; + DIR *dir; + +restart: + dir = opendir("/proc/self/fd"); + if (!dir) { + fprintf(stderr, "%s - Failed to open directory\n", + strerror(errno)); + return -1; + } + + fddir = dirfd(dir); + + while ((direntp = readdir(dir))) { + if (!strcmp(direntp->d_name, ".")) + continue; + + if (!strcmp(direntp->d_name, "..")) + continue; + + if (lxc_safe_int(direntp->d_name, &fd) < 0) + continue; + + for (i = 0; i < len_fds; i++) + if (fds_to_ignore[i] == fd) + break; + + if (fd == fddir || (i < len_fds && fd == fds_to_ignore[i])) + continue; + + if (fd == 0 || fd == 1 || fd == 2) + continue; + + if (closeall) { + close(fd); + closedir(dir); + goto restart; + } + } + + closedir(dir); + return 0; +} + +/* Enforces \0-termination for the abstract unix socket. This is not required + * but allows us to print it out. + * + * Older version of liblxc only allowed for 105 bytes to be used for the + * abstract unix domain socket name because the code for our abstract unix + * socket handling performed invalid checks. Since we \0-terminate we could now + * have a maximum of 106 chars. But to not break backwards compatibility we keep + * the limit at 105. + */ +static int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr) +{ + size_t len; + int ret; + char *path; + uint64_t hash; + + /* addr.sun_path is only 108 bytes, so we hash the full name and + * then append as much of the name as we can fit. + */ + memset(addr, 0, sizeof(*addr)); + addr->sun_family = AF_UNIX; + + /* strlen("lxc/") + strlen("/monitor-sock") + 1 = 18 */ + len = strlen(lxcpath) + 18; + path = alloca(len); + ret = snprintf(path, len, "lxc/%s/monitor-sock", lxcpath); + if (ret < 0 || (size_t)ret >= len) { + fprintf(stderr, "failed to create name for monitor socket\n"); + return -1; + } + + /* Note: snprintf() will \0-terminate addr->sun_path on the 106th byte + * and so the abstract socket name has 105 "meaningful" characters. This + * is absolutely intentional. For further info read the comment for this + * function above! + */ + len = sizeof(addr->sun_path) - 1; + hash = fnv_64a_buf(path, ret, FNV1A_64_INIT); + ret = snprintf(addr->sun_path, len, "@lxc/%016" PRIx64 "/%s", hash, lxcpath); + if (ret < 0) { + fprintf(stderr, "failed to create hashed name for monitor socket\n"); + return -1; + } + + /* replace @ with \0 */ + addr->sun_path[0] = '\0'; + + return 0; +} + +static int lxc_abstract_unix_connect(const char *path) +{ + int fd, ret; + size_t len; + struct sockaddr_un addr; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + + addr.sun_family = AF_UNIX; + + len = strlen(&path[1]); + /* do not enforce \0-termination */ + if (len >= sizeof(addr.sun_path)) { + close(fd); + errno = ENAMETOOLONG; + return -1; + } + /* addr.sun_path[0] has already been set to 0 by memset() */ + strncpy(&addr.sun_path[1], &path[1], strlen(&path[1])); + + ret = connect(fd, (struct sockaddr *)&addr, + offsetof(struct sockaddr_un, sun_path) + len + 1); + if (ret < 0) { + close(fd); + return -1; + } + + return fd; +} + +static int lxc_monitor_open(const char *lxcpath) +{ + struct sockaddr_un addr; + int fd; + size_t retry; + size_t len; + int ret = -1; + int backoff_ms[] = {10, 50, 100}; + + if (lxc_monitor_sock_name(lxcpath, &addr) < 0) + return -1; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + fprintf(stderr, "Failed to create socket: %s\n", strerror(errno)); + return -errno; + } + + len = strlen(&addr.sun_path[1]); + if (len >= sizeof(addr.sun_path) - 1) { + errno = ENAMETOOLONG; + ret = -errno; + fprintf(stderr, "name of monitor socket too long (%zu bytes): %s\n", len, strerror(errno)); + goto on_error; + } + + for (retry = 0; retry < sizeof(backoff_ms) / sizeof(backoff_ms[0]); retry++) { + fd = lxc_abstract_unix_connect(addr.sun_path); + if (fd != -1 || errno != ECONNREFUSED) + break; + fprintf(stderr, "Failed to connect to monitor socket. Retrying in %d ms: %s\n", backoff_ms[retry], strerror(errno)); + usleep(backoff_ms[retry] * 1000); + } + + if (fd < 0) { + ret = -errno; + fprintf(stderr, "Failed to connect to monitor socket: %s\n", strerror(errno)); + goto on_error; + } + + return fd; + +on_error: + close(fd); + return ret; +} + +static int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, + struct lxc_msg *msg, int timeout) +{ + nfds_t i; + int ret; + + ret = poll(fds, nfds, timeout * 1000); + if (ret == -1) + return -1; + else if (ret == 0) + return -2; /* timed out */ + + /* Only read from the first ready fd, the others will remain ready for + * when this routine is called again. + */ + for (i = 0; i < nfds; i++) { + if (fds[i].revents != 0) { + fds[i].revents = 0; + ret = recv(fds[i].fd, msg, sizeof(*msg), 0); + if (ret <= 0) { + fprintf(stderr, "%s - Failed to receive message. Did monitord die?\n", strerror(errno)); + return -1; + } + return ret; + } + } + + return -1; +} + +#define LXC_MONITORD_PATH LIBEXECDIR "/lxc/lxc-monitord" + +/* Used to spawn a monitord either on startup of a daemon container, or when + * lxc-monitor starts. + */ +static int lxc_monitord_spawn(const char *lxcpath) +{ + int ret; + int pipefd[2]; + char pipefd_str[TOOL_NUMSTRLEN64]; + pid_t pid1, pid2; + + char *const args[] = { + LXC_MONITORD_PATH, + (char *)lxcpath, + pipefd_str, + NULL, + }; + + /* double fork to avoid zombies when monitord exits */ + pid1 = fork(); + if (pid1 < 0) { + fprintf(stderr, "Failed to fork()\n"); + return -1; + } + + if (pid1) { + if (waitpid(pid1, NULL, 0) != pid1) + return -1; + return 0; + } + + if (pipe(pipefd) < 0) { + fprintf(stderr, "Failed to create pipe\n"); + exit(EXIT_FAILURE); + } + + pid2 = fork(); + if (pid2 < 0) { + fprintf(stderr, "Failed to fork()\n"); + exit(EXIT_FAILURE); + } + + if (pid2) { + char c; + /* Wait for daemon to create socket. */ + close(pipefd[1]); + + /* Sync with child, we're ignoring the return from read + * because regardless if it works or not, either way we've + * synced with the child process. the if-empty-statement + * construct is to quiet the warn-unused-result warning. + */ + if (read(pipefd[0], &c, 1)) + ; + + close(pipefd[0]); + + exit(EXIT_SUCCESS); + } + + if (setsid() < 0) { + fprintf(stderr, "Failed to setsid()\n"); + exit(EXIT_FAILURE); + } + + lxc_check_inherited(true, &pipefd[1], 1); + if (null_stdfds() < 0) { + fprintf(stderr, "Failed to dup2() standard file descriptors to /dev/null\n"); + exit(EXIT_FAILURE); + } + + close(pipefd[0]); + + ret = snprintf(pipefd_str, TOOL_NUMSTRLEN64, "%d", pipefd[1]); + if (ret < 0 || ret >= TOOL_NUMSTRLEN64) { + fprintf(stderr, "Failed to create pid argument to pass to monitord\n"); + exit(EXIT_FAILURE); + } + + execvp(args[0], args); + fprintf(stderr, "Failed to exec lxc-monitord\n"); + + exit(EXIT_FAILURE); +} + int main(int argc, char *argv[]) { char *regexp; @@ -109,7 +520,6 @@ int main(int argc, char *argv[]) if (lxc_log_init(&log)) exit(rc_main); - lxc_log_options_no_override(); /* REMOVE IN LXC 3.0 */ setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0); @@ -160,7 +570,7 @@ int main(int argc, char *argv[]) } nfds = my_args.lxcpath_cnt; - for (i = 0; i < nfds; i++) { + for (i = 0; (unsigned long)i < nfds; i++) { int fd; lxc_monitord_spawn(my_args.lxcpath[i]); diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h index b937137140..851fa97c44 100644 --- a/src/lxc/tools/tool_utils.h +++ b/src/lxc/tools/tool_utils.h @@ -34,6 +34,7 @@ #include "tool_list.h" #define TOOL_MAXPATHLEN 4096 +#define TOOL_NUMSTRLEN64 21 #ifndef CLONE_PARENT_SETTID #define CLONE_PARENT_SETTID 0x00100000 From c66687101f330bda1e10571d9a457fd02e9aabed Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 21 Jan 2018 22:09:42 +0100 Subject: [PATCH 33/34] include: remove getsubopt.* Signed-off-by: Christian Brauner --- src/include/getsubopt.c | 89 ----------------------------------------- src/include/getsubopt.h | 4 -- src/lxc/Makefile.am | 4 +- 3 files changed, 2 insertions(+), 95 deletions(-) delete mode 100644 src/include/getsubopt.c delete mode 100644 src/include/getsubopt.h diff --git a/src/include/getsubopt.c b/src/include/getsubopt.c deleted file mode 100644 index b75497b1a4..0000000000 --- a/src/include/getsubopt.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Android c-library does not have getsubopt, - * so code lifted from uClibc - * http://git.uclibc.org/uClibc/tree/libc/unistd/getsubopt.c - */ - -/* Parse comma separate list into words. - Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1996. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - - -#include -#include - -char *strchrnul(const char *s, int c) -{ - char *result; - - result = strchr( s, c ); - - if( !result ) - { - result = (char *)s + strlen( s ); - } - - return( result ); -} - -/* Parse comma separated suboption from *OPTIONP and match against - strings in TOKENS. If found return index and set *VALUEP to - optional value introduced by an equal sign. If the suboption is - not part of TOKENS return in *VALUEP beginning of unknown - suboption. On exit *OPTIONP is set to the beginning of the next - token or at the terminating NUL character. */ -int -getsubopt (char **optionp, char *const *tokens, char **valuep) -{ - char *endp, *vstart; - int cnt; - - if (**optionp == '\0') - return -1; - - /* Find end of next token. */ - endp = strchrnul (*optionp, ','); - - /* Find start of value. */ - vstart = memchr (*optionp, '=', endp - *optionp); - if (vstart == NULL) - vstart = endp; - - /* Try to match the characters between *OPTIONP and VSTART against - one of the TOKENS. */ - for (cnt = 0; tokens[cnt] != NULL; ++cnt) - if (strncmp (*optionp, tokens[cnt], vstart - *optionp) == 0 - && tokens[cnt][vstart - *optionp] == '\0') - { - /* We found the current option in TOKENS. */ - *valuep = vstart != endp ? vstart + 1 : NULL; - - if (*endp != '\0') - *endp++ = '\0'; - *optionp = endp; - - return cnt; - } - - /* The current suboption does not match any option. */ - *valuep = *optionp; - - if (*endp != '\0') - *endp++ = '\0'; - *optionp = endp; - - return -1; -} diff --git a/src/include/getsubopt.h b/src/include/getsubopt.h deleted file mode 100644 index e45cf66b01..0000000000 --- a/src/include/getsubopt.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _GETSUBOPT_H -#define _GETSUBOPT_H -int getsubopt (char **optionp, char *const *tokens, char **valuep); -#endif diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index cb057774b5..bcd37290a8 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -62,7 +62,7 @@ endif endif if !HAVE_GETSUBOPT -noinst_HEADERS += ../include/getsubopt.h +noinst_HEADERS += tools/include/getsubopt.h endif sodir=$(libdir) @@ -302,7 +302,7 @@ lxc_clone_SOURCES = tools/lxc_clone.c tools/arguments.c endif if !HAVE_GETSUBOPT -lxc_copy_SOURCES += ../include/getsubopt.c ../include/getsubopt.h +lxc_copy_SOURCES += tools/include/getsubopt.c tools/include/getsubopt.h endif if HAVE_STATIC_LIBCAP From 1323838283dd5859a5a6bec92088b210d270d4e5 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 8 Feb 2018 15:23:49 +0100 Subject: [PATCH 34/34] tools/lxc_unshare: satisfy Android Signed-off-by: Christian Brauner --- src/lxc/tools/lxc_unshare.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c index 98143d6623..54f0fd545f 100644 --- a/src/lxc/tools/lxc_unshare.c +++ b/src/lxc/tools/lxc_unshare.c @@ -42,6 +42,23 @@ #include "arguments.h" #include "tool_utils.h" +/* Define sethostname() if missing from the C library also workaround some + * quirky with having this defined in multiple places. + */ +static inline int sethostname_including_android(const char *name, size_t len) +{ +#ifndef HAVE_SETHOSTNAME +#ifdef __NR_sethostname + return syscall(__NR_sethostname, name, len); +#else + errno = ENOSYS; + return -1; +#endif +#else + return sethostname(name, len); +#endif +} + struct my_iflist { char *mi_ifname; @@ -127,7 +144,7 @@ static int do_start(void *arg) lxc_setup_fs(); if ((flags & CLONE_NEWUTS) && want_hostname) - if (sethostname(want_hostname, strlen(want_hostname)) < 0) { + if (sethostname_including_android(want_hostname, strlen(want_hostname)) < 0) { fprintf(stderr, "failed to set hostname %s: %s\n", want_hostname, strerror(errno)); exit(EXIT_FAILURE); }