From 0d54daf204fd2bc41c45c7c159af6436d66b272c Mon Sep 17 00:00:00 2001
From: wujing <wujing50@huawei.com>
Date: Mon, 13 Apr 2020 05:48:03 -0400
Subject: [PATCH 07/49] check and save pid info file

Signed-off-by: wujing <wujing50@huawei.com>
---
 src/lxc/conf.c            |   1 +
 src/lxc/conf.h            |   2 +
 src/lxc/lxccontainer.c    |  29 +++++++++++-
 src/lxc/lxccontainer.h    |  12 +++++
 src/lxc/start.c           |  98 ++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/arguments.h |  16 +++++++
 src/lxc/tools/lxc_start.c |  28 +++++++++++
 src/lxc/utils.c           | 117 ++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/utils.h           |  69 +++++++++++++++++++++++++++
 9 files changed, 371 insertions(+), 1 deletion(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index e806605..43437af 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -3961,6 +3961,7 @@ void lxc_conf_free(struct lxc_conf *conf)
 	free(conf->shmount.path_host);
 	free(conf->shmount.path_cont);
 #ifdef HAVE_ISULAD
+	free(conf->container_info_file);
 	lxc_clear_init_args(conf);
 	lxc_clear_populate_devices(conf);
 #endif
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 7ed3cd0..23942ac 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -428,6 +428,8 @@ struct lxc_conf {
 	/* populate devices*/
 	struct lxc_list populate_devs;
 	mode_t umask;  //umask value
+
+	char *container_info_file;
 #endif
 
 };
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index a617172..33bb3ec 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -5293,6 +5293,31 @@ static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c)
 
 WRAP_API(int, lxcapi_seccomp_notify_fd)
 
+#ifdef HAVE_ISULAD
+/* 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 = NULL;
+
+	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 = safe_strdup(info_file);
+
+	container_mem_unlock(c);
+	return true;
+}
+
+WRAP_API_1(bool, lxcapi_set_container_info_file, const char *)
+#endif
+
 struct lxc_container *lxc_container_new(const char *name, const char *configpath)
 {
 	struct lxc_container *c;
@@ -5434,7 +5459,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->mount = lxcapi_mount;
 	c->umount = lxcapi_umount;
 	c->seccomp_notify_fd = lxcapi_seccomp_notify_fd;
-
+#ifdef HAVE_ISULAD
+	c->set_container_info_file = lxcapi_set_container_info_file;
+#endif
 	return c;
 
 err:
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 4577de7..edfff32 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -865,6 +865,18 @@ struct lxc_container {
 	 * \return pidfd of init process of the container.
 	 */
 	int (*init_pidfd)(struct lxc_container *c);
+
+#ifdef HAVE_ISULAD
+	/*! 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);
+#endif
 };
 
 /*!
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 5dcf828..f5f9565 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1537,6 +1537,94 @@ static inline int do_share_ns(void *arg)
 	return 0;
 }
 
+#ifdef HAVE_ISULAD
+static int lxc_write_container_info(char *filename, pid_t pid, pid_t p_pid,
+		unsigned long long start_at, unsigned long long p_start_at)
+{
+	FILE *pid_fp = NULL;
+	int ret = 0;
+
+	pid_fp = lxc_fopen(filename, "w");
+	if (pid_fp == NULL) {
+		SYSERROR("Failed to create pidfile '%s'",filename);
+		ret = -1;
+		goto out;
+	}
+
+	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;
+}
+
+static int lxc_check_container_info(char *filename, pid_t pid, pid_t p_pid,
+		unsigned long long start_at, unsigned long long p_start_at)
+{
+	int ret = 0;
+	int num;
+	char sbuf[1024] = {0}; /* bufs for stat */
+	int saved_pid;		/* process id */
+	int saved_ppid;		/* pid of parent process */
+	unsigned long long saved_start_time;	/* start time of process -- seconds since 1-1-70 */
+	unsigned long long saved_pstart_time;	/* start time of parent process -- seconds since 1-1-70 */
+
+	if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) {
+		SYSERROR("Failed to read pidfile %s", filename);
+		ret = -1;
+		goto out;
+	}
+
+	num = sscanf(sbuf, "%d %Lu %d %Lu", &saved_pid, &saved_start_time, &saved_ppid, &saved_pstart_time);
+	if (num != 4) {
+		SYSERROR("Call sscanf error");
+		ret = -1;
+		goto out;
+	}
+
+	if (pid != saved_pid || p_pid != saved_ppid
+	                || start_at != saved_start_time || p_start_at != saved_pstart_time) {
+		ERROR("Check container info failed");
+		ret = -1;
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+/* isuald: save pid/ppid info */
+static int lxc_save_container_info(char *filename, pid_t pid)
+{
+	int ret = 0;
+	pid_t p_pid = 0;
+	unsigned long long start_at = 0;
+	unsigned long long p_start_at = 0;
+
+	start_at = lxc_get_process_startat(pid);
+	p_pid = getpid();
+	p_start_at = lxc_get_process_startat(p_pid);
+
+	ret = lxc_write_container_info(filename, pid, p_pid, start_at, p_start_at);
+	if (ret != 0) {
+		goto out;
+	}
+
+	ret = lxc_check_container_info(filename, pid, p_pid, start_at, p_start_at);
+	if (ret != 0) {
+		goto out;
+	}
+
+out:
+	return ret;
+}
+#endif
+
 /* 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
@@ -1648,6 +1736,16 @@ static int lxc_spawn(struct lxc_handler *handler)
 	}
 	TRACE("Cloned child process %d", handler->pid);
 
+#ifdef HAVE_ISULAD
+    /* 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;
+        }
+    }
+#endif
+
 	/* Verify that we can actually make use of pidfds. */
 	if (!lxc_can_use_pidfd(handler->pidfd))
 		close_prot_errno_disarm(handler->pidfd);
diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h
index cb0ba74..91f4e9a 100644
--- a/src/lxc/tools/arguments.h
+++ b/src/lxc/tools/arguments.h
@@ -40,6 +40,9 @@ struct lxc_arguments {
 
 	/* for lxc-start */
 	const char *share_ns[32]; /* size must be greater than LXC_NS_MAX */
+#ifdef HAVE_ISULAD
+	const char *container_info; /* isulad: file used to store pid and ppid info of container */
+#endif
 
 	/* for lxc-console */
 	unsigned int ttynum;
@@ -152,6 +155,19 @@ struct lxc_arguments {
 #define OPT_SHARE_UTS OPT_USAGE - 5
 #define OPT_SHARE_PID OPT_USAGE - 6
 
+#ifdef HAVE_ISULAD
+#define OPT_INPUT_FIFO OPT_USAGE - 7
+#define OPT_OUTPUT_FIFO OPT_USAGE - 8
+#define OPT_STDERR_FIFO OPT_USAGE - 9
+#define OPT_CONTAINER_INFO OPT_USAGE - 10
+#define OPT_EXIT_FIFO OPT_USAGE - 11
+#define OPT_START_TIMEOUT OPT_USAGE - 12
+#define OPT_DISABLE_PTY OPT_USAGE - 13
+#define OPT_OPEN_STDIN OPT_USAGE - 14
+#define OPT_ATTACH_TIMEOUT OPT_USAGE - 15
+#define OPT_ATTACH_SUFFIX OPT_USAGE - 16
+#endif
+
 extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
 			       char *const argv[]);
 
diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
index 459b867..83ee75a 100644
--- a/src/lxc/tools/lxc_start.c
+++ b/src/lxc/tools/lxc_start.c
@@ -48,6 +48,9 @@ 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},
+#ifdef HAVE_ISULAD
+	{"container-pidfile", required_argument, 0, OPT_CONTAINER_INFO},
+#endif
 	LXC_COMMON_OPTIONS
 };
 
@@ -118,6 +121,11 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	case OPT_SHARE_PID:
 		args->share_ns[LXC_NS_PID] = arg;
 		break;
+#ifdef HAVE_ISULAD
+	case OPT_CONTAINER_INFO:
+		args->container_info = arg;
+		break;
+#endif
 	}
 	return 0;
 }
@@ -163,6 +171,9 @@ int main(int argc, char *argv[])
 		"/sbin/init",
 		NULL,
 	};
+#ifdef HAVE_ISULAD
+	char *container_info_file = NULL;
+#endif
 
 	lxc_list_init(&defines);
 
@@ -283,6 +294,20 @@ int main(int argc, char *argv[])
 			goto out;
 		}
 
+#ifdef HAVE_ISULAD
+	/* 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;
+		}
+	}
+#endif
+
 	if (my_args.console)
 		if (!c->set_config_item(c, "lxc.console.path", my_args.console))
 			goto out;
@@ -320,5 +345,8 @@ int main(int argc, char *argv[])
 
 out:
 	lxc_container_put(c);
+#ifdef HAVE_ISULAD
+	free(container_info_file);
+#endif
 	exit(err);
 }
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 160b3db..ebcdae0 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1931,4 +1931,121 @@ void lxc_write_error_message(int errfd, const char *format, ...)
 	if (sret < 0)
 		SYSERROR("Write errbuf failed");
 }
+
+/* isulad: read file to buffer */
+int lxc_file2str(const char *filename, char ret[], int cap)
+{
+    int fd, num_read;
+
+    if ((fd = lxc_open(filename, O_RDONLY | O_CLOEXEC, 0)) == -1)
+        return -1;
+    if ((num_read = read(fd, ret, cap - 1)) <= 0)
+        num_read = -1;
+    else
+        ret[num_read] = 0;
+    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(const char *S)
+{
+    int num;
+    proc_t *P = NULL;
+    char *tmp = NULL;
+
+    if (!S)
+        return NULL;
+
+    tmp = strrchr(S, ')');  /* split into "PID (cmd" and "<rest>" */
+    if (!tmp)
+        return NULL;
+    *tmp = '\0';            /* replace trailing ')' with NUL */
+
+    P = malloc(sizeof(proc_t));
+    if (P == NULL)
+        return NULL;
+    (void)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 != 2) {
+        ERROR("Call sscanf error: %s", errno ? 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 */
+                 "%ld %ld %ld %ld "
+                 "%Lu "  /* start_time */
+                 "%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,
+                 &P->priority, &P->nice, &P->timeout, &P->it_real_value,
+                 &P->start_time,
+                 &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 (num != 35) {
+        ERROR("Call sscanf error: %s", errno ? strerror(errno) : "");
+        free(P);
+        return NULL;
+    }
+    if (P->tty == 0)
+        P->tty = -1;  /* the old notty val, update elsewhere bef. moving to 0 */
+    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)) {
+        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) {
+        ERROR("Failed to get proc stat info");
+        goto out;
+    }
+
+    startat = pid_info->start_time;
+out:
+    free(pid_info);
+    return startat;
+}
 #endif
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 3c30565..11d6548 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -44,6 +44,73 @@ extern char *get_rundir(void);
 #endif
 #endif
 
+#ifdef HAVE_ISULAD
+/* isulad:
+ 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;
+#endif
+
 static inline int lxc_set_cloexec(int fd)
 {
 	return fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -246,6 +313,8 @@ extern int fix_stdio_permissions(uid_t uid);
 
 #ifdef HAVE_ISULAD
 extern void lxc_write_error_message(int errfd, const char *format, ...);
+extern int lxc_file2str(const char *filename, char ret[], int cap);
+extern int unsigned long long lxc_get_process_startat(pid_t pid);
 #endif
 
 #endif /* __LXC_UTILS_H */
-- 
1.8.3.1

