From: 2xsec Date: Fri, 29 Jun 2018 14:24:58 +0000 (+0900) Subject: tools: lxc-monitor: share internal API symbols X-Git-Tag: lxc-3.1.0~225^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=457e3c5dafd18cb99660da1e2dfcf2b3b90d3061;p=thirdparty%2Flxc.git tools: lxc-monitor: share internal API symbols Signed-off-by: 2xsec --- diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 19b8d5cbc..57c552390 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -275,7 +275,7 @@ 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 -lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c tools/tool_utils.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 diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c index 40e54c90b..4bbf679db 100644 --- a/src/lxc/monitor.c +++ b/src/lxc/monitor.c @@ -303,10 +303,10 @@ int lxc_monitord_spawn(const char *lxcpath) pid_t pid1, pid2; char *const args[] = { - LXC_MONITORD_PATH, - (char *)lxcpath, - pipefd_str, - NULL, + LXC_MONITORD_PATH, + (char *)lxcpath, + pipefd_str, + NULL, }; /* double fork to avoid zombies when monitord exits */ @@ -318,8 +318,10 @@ int lxc_monitord_spawn(const char *lxcpath) if (pid1) { DEBUG("Going to wait for pid %d.", pid1); + if (waitpid(pid1, NULL, 0) != pid1) return -1; + DEBUG("Finished waiting on pid %d.", pid1); return 0; } diff --git a/src/lxc/tools/lxc_monitor.c b/src/lxc/tools/lxc_monitor.c index 8d9b7e63c..abeccdeed 100644 --- a/src/lxc/tools/lxc_monitor.c +++ b/src/lxc/tools/lxc_monitor.c @@ -44,16 +44,27 @@ #include +#include "af_unix.h" #include "arguments.h" -#include "tool_utils.h" +#include "log.h" +#include "monitor.h" +#include "state.h" +#include "utils.h" + +#define LXC_MONITORD_PATH LIBEXECDIR "/lxc/lxc-monitord" static bool quit_monitord; -static int my_parser(struct lxc_arguments* args, int c, char* arg) +lxc_log_define(lxc_monitor, lxc); + +static int my_parser(struct lxc_arguments *args, int c, char *arg) { switch (c) { - case 'Q': quit_monitord = true; break; + case 'Q': + quit_monitord = true; + break; } + return 0; } @@ -87,119 +98,11 @@ static void close_fds(struct pollfd *fds, nfds_t nfds) if (nfds < 1) return; - for (i = 0; i < nfds; ++i) { + for (i = 0; i < nfds; ++i) close(fds[i].fd); - } -} - -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) +static int lxc_tool_check_inherited(bool closeall, int *fds_to_ignore, size_t len_fds) { struct dirent *direntp; int fd, fddir; @@ -209,8 +112,7 @@ static int lxc_check_inherited(bool closeall, int *fds_to_ignore, size_t len_fds restart: dir = opendir("/proc/self/fd"); if (!dir) { - fprintf(stderr, "%s - Failed to open directory\n", - strerror(errno)); + SYSERROR("Failed to open directory"); return -1; } @@ -247,199 +149,51 @@ restart: 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() */ - memcpy(&addr.sun_path[1], &path[1], len); - - 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 backoff_ms[] = {10, 50, 100}; - - if (lxc_monitor_sock_name(lxcpath, &addr) < 0) - return -1; - - len = strlen(&addr.sun_path[1]); - if (len >= sizeof(addr.sun_path) - 1) { - errno = ENAMETOOLONG; - fprintf(stderr, "name of monitor socket too long (%zu bytes): %s\n", len, strerror(errno)); - return -errno; - } - - 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) { - fprintf(stderr, "Failed to connect to monitor socket: %s\n", strerror(errno)); - return -errno; - } - - return fd; -} - -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) +static int lxc_tool_monitord_spawn(const char *lxcpath) { int ret; int pipefd[2]; - char pipefd_str[TOOL_NUMSTRLEN64]; + char pipefd_str[LXC_NUMSTRLEN64]; pid_t pid1, pid2; char *const args[] = { - LXC_MONITORD_PATH, - (char *)lxcpath, - pipefd_str, - NULL, + 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"); + SYSERROR("Failed to fork()"); 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); + SYSERROR("Failed to create pipe"); + _exit(EXIT_FAILURE); } pid2 = fork(); if (pid2 < 0) { - fprintf(stderr, "Failed to fork()\n"); - exit(EXIT_FAILURE); + SYSERROR("Failed to fork()"); + _exit(EXIT_FAILURE); } if (pid2) { char c; + /* Wait for daemon to create socket. */ close(pipefd[1]); @@ -453,32 +207,32 @@ static int lxc_monitord_spawn(const char *lxcpath) close(pipefd[0]); - exit(EXIT_SUCCESS); + _exit(EXIT_SUCCESS); } if (setsid() < 0) { - fprintf(stderr, "Failed to setsid()\n"); - exit(EXIT_FAILURE); + SYSERROR("Failed to setsid()"); + _exit(EXIT_FAILURE); } - lxc_check_inherited(true, &pipefd[1], 1); + lxc_tool_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); + ERROR("Failed to dup2() standard file descriptors to /dev/null"); + _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); + ret = snprintf(pipefd_str, LXC_NUMSTRLEN64, "%d", pipefd[1]); + if (ret < 0 || ret >= LXC_NUMSTRLEN64) { + ERROR("Failed to create pid argument to pass to monitord"); + _exit(EXIT_FAILURE); } execvp(args[0], args); - fprintf(stderr, "Failed to exec lxc-monitord\n"); + SYSERROR("Failed to exec lxc-monitord"); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } int main(int argc, char *argv[]) @@ -511,60 +265,67 @@ int main(int argc, char *argv[]) if (quit_monitord) { int ret = EXIT_SUCCESS; + for (i = 0; i < my_args.lxcpath_cnt; i++) { int fd; fd = lxc_monitor_open(my_args.lxcpath[i]); if (fd < 0) { - fprintf(stderr, "Unable to open monitor on path: %s\n", my_args.lxcpath[i]); + ERROR("Unable to open monitor on path: %s", my_args.lxcpath[i]); ret = EXIT_FAILURE; continue; } + if (write(fd, "quit", 4) < 0) { - fprintf(stderr, "Unable to close monitor on path: %s\n", my_args.lxcpath[i]); + SYSERROR("Unable to close monitor on path: %s", my_args.lxcpath[i]); ret = EXIT_FAILURE; close(fd); continue; } + close(fd); } + exit(ret); } len = strlen(my_args.name) + 3; regexp = malloc(len + 3); if (!regexp) { - fprintf(stderr, "failed to allocate memory\n"); + ERROR("Failed to allocate memory"); exit(rc_main); } + rc_snp = snprintf(regexp, len, "^%s$", my_args.name); if (rc_snp < 0 || rc_snp >= len) { - fprintf(stderr, "Name too long\n"); + ERROR("Name too long"); goto error; } if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) { - fprintf(stderr, "failed to compile the regex '%s'\n", my_args.name); + ERROR("Failed to compile the regex '%s'", my_args.name); goto error; } fds = malloc(my_args.lxcpath_cnt * sizeof(struct pollfd)); if (!fds) { - fprintf(stderr, "out of memory\n"); + ERROR("Out of memory"); goto cleanup; } nfds = my_args.lxcpath_cnt; + for (i = 0; (unsigned long)i < nfds; i++) { int fd; - lxc_monitord_spawn(my_args.lxcpath[i]); + lxc_tool_monitord_spawn(my_args.lxcpath[i]); fd = lxc_monitor_open(my_args.lxcpath[i]); if (fd < 0) { close_fds(fds, i); goto cleanup; } + fds[i].fd = fd; fds[i].events = POLLIN; fds[i].revents = 0; @@ -573,9 +334,8 @@ int main(int argc, char *argv[]) setlinebuf(stdout); for (;;) { - if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) { + if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) goto close_and_clean; - } msg.name[sizeof(msg.name)-1] = '\0'; if (regexec(&preg, msg.name, 0, NULL, 0)) @@ -595,6 +355,7 @@ int main(int argc, char *argv[]) break; } } + rc_main = 0; close_and_clean: