about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris West (Faux) <git@goeswhere.com>2018-02-08 10:40:08 +0000
committerLeah Neukirchen <leah@vuxu.org>2018-02-08 14:57:55 +0100
commit7ff44f4b90a718195d4521b3caa48eeeb7699fbf (patch)
tree38d9f581282ddc57d3082f6d3c5aa0bfc81c4b11
parent4fb94664c8534663a6d3dd575e6645881ea05a43 (diff)
downloadextrace-7ff44f4b90a718195d4521b3caa48eeeb7699fbf.tar.gz
extrace-7ff44f4b90a718195d4521b3caa48eeeb7699fbf.tar.xz
extrace-7ff44f4b90a718195d4521b3caa48eeeb7699fbf.zip
extrace: use openat() for speedup
This reduces the timeframe where the inherently racy access to /proc is
done, and removes some unnecessary snprintf.

Closes: #2 [via git-merge-pr]
-rw-r--r--extrace.c45
1 files changed, 28 insertions, 17 deletions
diff --git a/extrace.c b/extrace.c
index 30a8c43..25d16ac 100644
--- a/extrace.c
+++ b/extrace.c
@@ -107,6 +107,13 @@ struct {
 } pid_db[PID_DB_SIZE];
 
 static int
+open_proc_dir(pid_t pid) {
+	char name[48];
+	snprintf(name, sizeof name, "/proc/%d", pid);
+	return open(name, O_DIRECTORY);
+}
+
+static int
 pid_depth(pid_t pid)
 {
 	pid_t ppid = 0;
@@ -231,14 +238,14 @@ print_shquoted(const char *s)
 }
 
 static void
-print_env(pid_t pid)
+print_env(int proc_dir_fd)
 {
-	char name[PATH_MAX];
+	int fd;
 	FILE *env;
 
 	fprintf(output, "  ");
-	snprintf(name, sizeof name, "/proc/%d/environ", pid);
-	if ((env = fopen(name, "r"))) {
+	fd = openat(proc_dir_fd, "environ", O_RDONLY);
+	if (fd >= 0 && (env = fdopen(fd, "r"))) {
 		char *line = 0, *eq = 0;
 		size_t linelen = 0;
 		while (getdelim(&line, &linelen, '\0', env) >= 0) {
@@ -264,7 +271,7 @@ print_env(pid_t pid)
 static void
 handle_msg(struct cn_msg *cn_hdr)
 {
-	char cmdline[CMDLINE_MAX], name[PATH_MAX];
+	char cmdline[CMDLINE_MAX];
 	char exe[PATH_MAX];
 	char cwd[PATH_MAX];
 	char *argvrest;
@@ -275,10 +282,17 @@ handle_msg(struct cn_msg *cn_hdr)
 	if (ev->what == PROC_EVENT_EXEC) {
 		pid_t pid = ev->event_data.exec.process_pid;
 		int i = 0;
+		int proc_dir_fd = open_proc_dir(pid);
+		if (proc_dir_fd < 0) {
+			/* TODO: warn we dropped something? */
+			return;
+		}
 
 		d = pid_depth(pid);
-		if (d < 0)
+		if (d < 0) {
+			close(proc_dir_fd);
 			return;
+		}
 
 		if (show_exit || !flat) {
 			for (i = 0; i < PID_DB_SIZE - 1; i++)
@@ -293,11 +307,9 @@ handle_msg(struct cn_msg *cn_hdr)
 			pid_db[i].start = ev->timestamp_ns;
 		}
 
-		snprintf(name, sizeof name, "/proc/%d/cmdline", pid);
-
 		memset(&cmdline, 0, sizeof cmdline);
-		fd = open(name, O_RDONLY);
-		if (fd > 0) {
+		fd = openat(proc_dir_fd, "cmdline", O_RDONLY);
+		if (fd >= 0) {
 			r = read(fd, cmdline, sizeof cmdline);
 			close(fd);
 
@@ -305,8 +317,7 @@ handle_msg(struct cn_msg *cn_hdr)
 				cmdline[r] = 0;
 
 			if (full_path) {
-				snprintf(name, sizeof name, "/proc/%d/exe", pid);
-				r2 = readlink(name, exe, sizeof exe);
+				r2 = readlinkat(proc_dir_fd, "exe", exe, sizeof exe);
 				if (r2 > 0)
 					exe[r2] = 0;
 			}
@@ -315,8 +326,7 @@ handle_msg(struct cn_msg *cn_hdr)
 		}
 
 		if (show_cwd) {
-			snprintf(name, sizeof name, "/proc/%d/cwd", pid);
-			r3 = readlink(name, cwd, sizeof cwd);
+			r3 = readlinkat(proc_dir_fd, "cwd", cwd, sizeof cwd);
 			if (r3 > 0)
 				cwd[r3] = 0;
 		}
@@ -351,9 +361,10 @@ handle_msg(struct cn_msg *cn_hdr)
 		if (r == sizeof cmdline)
 			fprintf(output, "... <truncated>");
 
-		if (show_env) {
-			print_env(pid);
-		}
+		if (show_env)
+			print_env(proc_dir_fd);
+
+		close(proc_dir_fd);
 
 		fprintf(output, "\n");
 		fflush(output);