From 10aa38b436cde63126d70b943fd6533b95e89673 Mon Sep 17 00:00:00 2001 From: LiFeng Date: Fri, 11 Jan 2019 22:53:56 -0500 Subject: [PATCH 010/139] Save pid/ppid info into file for isulad Signed-off-by: LiFeng --- src/lxc/conf.c | 1 + src/lxc/conf.h | 2 + src/lxc/lxccontainer.c | 24 ++++++++++ src/lxc/lxccontainer.h | 10 ++++ src/lxc/start.c | 41 +++++++++++++++++ src/lxc/tools/arguments.h | 2 + src/lxc/tools/lxc_start.c | 20 ++++++++ src/lxc/utils.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/utils.h | 66 +++++++++++++++++++++++++++ 9 files changed, 280 insertions(+) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 7b7f95b..0b4b63b 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -4194,6 +4194,7 @@ void lxc_conf_free(struct lxc_conf *conf) /* isulad add begin */ lxc_clear_init_args(conf); lxc_clear_populate_devices(conf); + free(conf->container_info_file); /* isulad add end */ free(conf); } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index cced868..e0954f9 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -403,6 +403,8 @@ struct lxc_conf { size_t init_argc; /* populate devices*/ struct lxc_list populate_devs; + + char *container_info_file; /* isulad add end */ }; diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 318c71e..5679b9b 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -4988,6 +4988,29 @@ static bool do_lxcapi_set_terminal_default_fifos(struct lxc_container *c, const WRAP_API_2(bool, lxcapi_set_terminal_default_fifos, const char *, const char *) +/* isulad add set info file path */ +static bool do_lxcapi_set_container_info_file(struct lxc_container *c, const char *info_file) +{ + struct lxc_conf *conf; + + if (!c || !c->lxc_conf || !info_file) + return false; + if (container_mem_lock(c)) { + ERROR("Error getting mem lock"); + return false; + } + + conf = c->lxc_conf; + if (conf->container_info_file) + free(conf->container_info_file); + conf->container_info_file = strdup(info_file); + + container_mem_unlock(c); + return true; +} + +WRAP_API_1(bool, lxcapi_set_container_info_file, const char *) + struct lxc_container *lxc_container_new(const char *name, const char *configpath) { struct lxc_container *c; @@ -5113,6 +5136,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath /* isulad add begin */ c->set_terminal_init_fifos = lxcapi_set_terminal_default_fifos; + c->set_container_info_file = lxcapi_set_container_info_file; /* isulad add end */ return c; diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 486531e..3c845fe 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -857,6 +857,16 @@ struct lxc_container { * \return \c true on success, else \c false. */ bool (*set_terminal_init_fifos)(struct lxc_container *c, const char *in, const char *out); + + /*! isulad add + * \brief An API call to set the path of info file + * + * \param c Container. + * \param info_file Value of the path of info file. + * + * \return \c true on success, else \c false. + */ + bool (*set_container_info_file) (struct lxc_container *c, const char *info_file); }; /*! diff --git a/src/lxc/start.c b/src/lxc/start.c index d64bdac..9d71dd7 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1553,6 +1553,39 @@ static inline int do_share_ns(void *arg) return 0; } +/* isuald: save pid/ppid info */ +static int lxc_save_container_info(char *filename, pid_t pid) +{ + FILE *pid_fp = NULL; + int ret = 0; + pid_t p_pid = 0; + unsigned long long start_at = 0; + unsigned long long p_start_at = 0; + + pid_fp = fopen(filename, "w"); + if (pid_fp == NULL) { + SYSERROR("Failed to create pidfile '%s'",filename); + ret = -1; + goto out; + } + + start_at = lxc_get_process_startat(pid); + + p_pid = getpid(); + p_start_at = lxc_get_process_startat(p_pid); + + if (fprintf(pid_fp, "%d %llu %d %llu\n", pid, start_at, p_pid, p_start_at) < 0) { + SYSERROR("Failed to write '%s'", filename); + ret = -1; + goto out; + } +out: + if (pid_fp) + fclose(pid_fp); + pid_fp = NULL; + return ret; +} + /* lxc_spawn() performs crucial setup tasks and clone()s the new process which * exec()s the requested container binary. * Note that lxc_spawn() runs in the parent namespaces. Any operations performed @@ -1683,6 +1716,14 @@ static int lxc_spawn(struct lxc_handler *handler) } TRACE("Cloned child process %d", handler->pid); + /* isulad: save pid/ppid info into file*/ + if (handler->conf->container_info_file) { + if (lxc_save_container_info(handler->conf->container_info_file, handler->pid)) { + ERROR("Failed to save cloned container pid"); + goto out_delete_net; + } + } + for (i = 0; i < LXC_NS_MAX; i++) if (handler->ns_on_clone_flags & ns_info[i].clone_flag) INFO("Cloned %s", ns_info[i].flag_name); diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index b7af2b5..b6df23f 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -63,6 +63,7 @@ struct lxc_arguments { /* for lxc-start */ const char *share_ns[32]; /* size must be greater than LXC_NS_MAX */ const char *terminal_fifos[2]; /* isulad add, fifos used to redirct stdin/out/err */ + const char *container_info; /* isulad: file used to store pid and ppid info of container */ /* for lxc-console */ unsigned int ttynum; @@ -176,6 +177,7 @@ struct lxc_arguments { /* isulad add begin */ #define OPT_INPUT_FIFO OPT_USAGE - 7 #define OPT_OUTPUT_FIFO OPT_USAGE - 8 +#define OPT_CONTAINER_INFO OPT_USAGE - 9 /* isulad add end*/ extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c index 8f03f11..2f94d67 100644 --- a/src/lxc/tools/lxc_start.c +++ b/src/lxc/tools/lxc_start.c @@ -69,8 +69,11 @@ static const struct option my_longopts[] = { {"share-ipc", required_argument, 0, OPT_SHARE_IPC}, {"share-uts", required_argument, 0, OPT_SHARE_UTS}, {"share-pid", required_argument, 0, OPT_SHARE_PID}, + /* isulad add begin */ {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, + {"container-pidfile", required_argument, 0, OPT_CONTAINER_INFO}, + /* isulad add end */ LXC_COMMON_OPTIONS }; @@ -148,6 +151,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) case OPT_OUTPUT_FIFO: args->terminal_fifos[1] = arg; break; + case OPT_CONTAINER_INFO: + args->container_info = arg; + break; } return 0; } @@ -189,6 +195,7 @@ int main(int argc, char *argv[]) struct lxc_log log; int err = EXIT_FAILURE; char *rcfile = NULL; + char *container_info_file = NULL; /* isulad: info file*/ char *const default_args[] = { "/sbin/init", NULL, @@ -313,6 +320,18 @@ int main(int argc, char *argv[]) goto out; } + /* isulad: container info file used to store pid and ppid info of container*/ + if (my_args.container_info != NULL) { + if (ensure_path(&container_info_file, my_args.container_info) < 0) { + ERROR("Failed to ensure container's piddile '%s'", my_args.container_info); + goto out; + } + if (!c->set_container_info_file(c, container_info_file)) { + ERROR("Failed to set container's piddile '%s'", container_info_file); + goto out; + } + } + if (my_args.console) if (!c->set_config_item(c, "lxc.console.path", my_args.console)) goto out; @@ -353,5 +372,6 @@ int main(int argc, char *argv[]) out: lxc_container_put(c); + free(container_info_file); exit(err); } diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 67c3b3e..4728284 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -1828,3 +1828,117 @@ int lxc_setup_keyring(void) return ret; } + +/* isulad: read file to buffer */ +static int lxc_file2str(const char *filename, char ret[], int cap) +{ + int fd, num_read; + + if ((fd = open(filename, O_RDONLY | O_CLOEXEC)) == -1) + return -1;/*lint !e960*/ + if ((num_read = read(fd, ret, cap - 1)) <= 0) + num_read = -1;/*lint !e960*/ + else + ret[num_read] = 0;/*lint !e613*//*lint !e960*/ + close(fd); + + return num_read; +} + +/* isuald: lxc_stat2proc() makes sure it can handle arbitrary executable file basenames + * for `cmd', i.e. those with embedded whitespace or embedded ')'s. + * Such names confuse %s (see scanf(3)), so the string is split and %39c + * is used instead. (except for embedded ')' "(%[^)]c)" would work. + */ +static proc_t *lxc_stat2proc(char *S) +{ + int num; + proc_t *P = NULL; + char *tmp = NULL; + + if (!S) + return NULL;/*lint !e960*/ + + tmp = strrchr(S, ')'); /* split into "PID (cmd" and "" *//*lint !e586*/ + if (!tmp) + return NULL;/*lint !e960*/ + *tmp = '\0'; /* replace trailing ')' with NUL */ + + P = malloc(sizeof(proc_t)); + if (!P) + return NULL;/*lint !e960*/ + memset(P, 0x00, sizeof(proc_t)); + + /* parse these two strings separately, skipping the leading "(". */ + num = sscanf(S, "%d (%15c", &P->pid, P->cmd); /* comm[16] in kernel */ + if (num < 0 && errno) { + ERROR("Call sscanf error: %s", strerror(errno)); + free(P); + return NULL; + } + num = sscanf(tmp + 2, /* skip space after ')' too */ + "%c " + "%d %d %d %d %d " + "%lu %lu %lu %lu %lu " + "%Lu %Lu %Lu %Lu " /* utime stime cutime cstime *//*lint !e566*/ + "%ld %ld %ld %ld " + "%Lu " /* start_time *//*lint !e566*/ + "%lu " + "%ld " + "%lu %lu %lu %lu %lu %lu " + "%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */ + "%lu %lu %lu " + "%d %d " + "%lu %lu", + &P->state, + &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid, + &P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt, + &P->utime, &P->stime, &P->cutime, &P->cstime,/*lint !e561*/ + &P->priority, &P->nice, &P->timeout, &P->it_real_value, + &P->start_time,/*lint !e561*/ + &P->vsize, + &P->rss, + &P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp, + &P->kstk_eip, + &P->wchan, &P->nswap, &P->cnswap, + &P->exit_signal, &P->processor, /* 2.2.1 ends with "exit_signal" */ + &P->rtprio, &P->sched /* both added to 2.5.18 */ + ); + + if (P->tty == 0) + P->tty = -1; /* the old notty val, update elsewhere bef. moving to 0 *//*lint !e960*/ + return P; +} + +/* isulad: get starttime of process pid */ +unsigned long long lxc_get_process_startat(pid_t pid) +{ + int sret = 0; + unsigned long long startat = 0; + proc_t *pid_info = NULL; + char filename[PATH_MAX] = {0}; + char sbuf[1024] = {0}; /* bufs for stat */ + + sret = snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); + if (sret < 0 || sret >= sizeof(filename)) {/*lint !e574*/ + ERROR("Failed to sprintf filename"); + goto out; + } + + if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) { + SYSERROR("Failed to read pidfile %s", filename); + goto out; + } + + pid_info = lxc_stat2proc(sbuf); + if (!pid_info) {/*lint !e574*/ + ERROR("Failed to get proc stat info"); + goto out; + } + + startat = pid_info->start_time; +out: + free(pid_info); + return startat; +} + diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 2d38178..8e4ed89 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -56,6 +56,71 @@ extern char *get_rundir(void); #endif #endif +/* isuald: + ld cutime, cstime, priority, nice, timeout, it_real_value, rss, + c state, + d ppid, pgrp, session, tty, tpgid, + s signal, blocked, sigignore, sigcatch, + lu flags, min_flt, cmin_flt, maj_flt, cmaj_flt, utime, stime, + lu rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip, + lu start_time, vsize, wchan, nswap, cnswap, +*/ + +/* Basic data structure which holds all information we can get about a process. + * (unless otherwise specified, fields are read from /proc/#/stat) + * + * Most of it comes from task_struct in linux/sched.h + */ +typedef struct proc_t { + // 1st 16 bytes + int pid; /* process id */ + int ppid; /* pid of parent process */ + + char state; /* single-char code for process state (S=sleeping) */ + + unsigned long long + utime, /* user-mode CPU time accumulated by process */ + stime, /* kernel-mode CPU time accumulated by process */ + // and so on... + cutime, /* cumulative utime of process and reaped children */ + cstime, /* cumulative stime of process and reaped children */ + start_time; /* start time of process -- seconds since 1-1-70 */ + + long + priority, /* kernel scheduling priority */ + timeout, /* ? */ + nice, /* standard unix nice level of process */ + rss, /* resident set size from /proc/#/stat (pages) */ + it_real_value; /* ? */ + unsigned long + rtprio, /* real-time priority */ + sched, /* scheduling class */ + vsize, /* number of pages of virtual memory ... */ + rss_rlim, /* resident set size limit? */ + flags, /* kernel flags for the process */ + min_flt, /* number of minor page faults since process start */ + maj_flt, /* number of major page faults since process start */ + cmin_flt, /* cumulative min_flt of process and child processes */ + cmaj_flt, /* cumulative maj_flt of process and child processes */ + nswap, /* ? */ + cnswap, /* cumulative nswap ? */ + start_code, /* address of beginning of code segment */ + end_code, /* address of end of code segment */ + start_stack, /* address of the bottom of stack for the process */ + kstk_esp, /* kernel stack pointer */ + kstk_eip, /* kernel instruction pointer */ + wchan; /* address of kernel wait channel proc is sleeping in */ + + char cmd[16]; /* basename of executable file in call to exec(2) */ + int + pgrp, /* process group id */ + session, /* session id */ + tty, /* full device number of controlling terminal */ + tpgid, /* terminal process group id */ + exit_signal, /* might not be SIGCHLD */ + processor; /* current (or most recent?) CPU */ +} proc_t; + static inline int lxc_set_cloexec(int fd) { return fcntl(fd, F_SETFD, FD_CLOEXEC); @@ -245,5 +310,6 @@ extern int recursive_destroy(char *dirname); extern int lxc_setup_keyring(void); extern int fd_nonblock(int fd); +extern int unsigned long long lxc_get_process_startat(pid_t pid); #endif /* __LXC_UTILS_H */ -- 1.8.3.1