From 091e9a9121c04a96a3d8a227a133ca6616f0b86f Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68@huawei.com>
Date: Fri, 11 Jan 2019 22:53:56 -0500
Subject: [PATCH 010/131] Save pid/ppid info into file for isulad

Signed-off-by: LiFeng <lifeng68@huawei.com>
---
 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 7b7f95b7..0b4b63b8 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 cced868c..e0954f92 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 318c71e6..5679b9b4 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 486531e5..3c845fea 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 d64bdac1..9d71dd79 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 b7af2b51..b6df23f8 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 8f03f111..2f94d671 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 67c3b3ef..4728284f 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 "<rest>" *//*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 2d38178c..8e4ed894 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 */
-- 
2.23.0

