git

Форк
0
/
procinfo.c 
176 строк · 4.7 Кб
1
#include "git-compat-util.h"
2

3
#include "strbuf.h"
4
#include "strvec.h"
5
#include "trace2.h"
6

7
/*
8
 * We need more complex parsing in stat_parent_pid() and
9
 * parse_proc_stat() below than a dumb fscanf(). That's because while
10
 * the statcomm field is surrounded by parentheses, the process itself
11
 * is free to insert any arbitrary byte sequence its its name. That
12
 * can include newlines, spaces, closing parentheses etc.
13
 *
14
 * See do_task_stat() in fs/proc/array.c in linux.git, this is in
15
 * contrast with the escaped version of the name found in
16
 * /proc/%d/status.
17
 *
18
 * So instead of using fscanf() we'll read N bytes from it, look for
19
 * the first "(", and then the last ")", anything in-between is our
20
 * process name.
21
 *
22
 * How much N do we need? On Linux /proc/sys/kernel/pid_max is 2^15 by
23
 * default, but it can be raised set to values of up to 2^22. So
24
 * that's 7 digits for a PID. We have 2 PIDs in the first four fields
25
 * we're interested in, so 2 * 7 = 14.
26
 *
27
 * We then have 3 spaces between those four values, and we'd like to
28
 * get to the space between the 4th and the 5th (the "pgrp" field) to
29
 * make sure we read the entire "ppid" field. So that brings us up to
30
 * 14 + 3 + 1 = 18. Add the two parentheses around the "comm" value
31
 * and it's 20. The "state" value itself is then one character (now at
32
 * 21).
33
 *
34
 * Finally the maximum length of the "comm" name itself is 15
35
 * characters, e.g. a setting of "123456789abcdefg" will be truncated
36
 * to "123456789abcdef". See PR_SET_NAME in prctl(2). So all in all
37
 * we'd need to read 21 + 15 = 36 bytes.
38
 *
39
 * Let's just read 2^6 (64) instead for good measure. If PID_MAX ever
40
 * grows past 2^22 we'll be future-proof. We'll then anchor at the
41
 * last ")" we find to locate the parent PID.
42
 */
43
#define STAT_PARENT_PID_READ_N 64
44

45
static int parse_proc_stat(struct strbuf *sb, struct strbuf *name,
46
			    int *statppid)
47
{
48
	const char *comm_lhs = strchr(sb->buf, '(');
49
	const char *comm_rhs = strrchr(sb->buf, ')');
50
	const char *ppid_lhs, *ppid_rhs;
51
	char *p;
52
	pid_t ppid;
53

54
	if (!comm_lhs || !comm_rhs)
55
		goto bad_kernel;
56

57
	/*
58
	 * We're at the ")", that's followed by " X ", where X is a
59
	 * single "state" character. So advance by 4 bytes.
60
	 */
61
	ppid_lhs = comm_rhs + 4;
62

63
	/*
64
	 * Read until the space between the "ppid" and "pgrp" fields
65
	 * to make sure we're anchored after the untruncated "ppid"
66
	 * field..
67
	 */
68
	ppid_rhs = strchr(ppid_lhs, ' ');
69
	if (!ppid_rhs)
70
		goto bad_kernel;
71

72
	ppid = strtol(ppid_lhs, &p, 10);
73
	if (ppid_rhs == p) {
74
		const char *comm = comm_lhs + 1;
75
		size_t commlen = comm_rhs - comm;
76

77
		strbuf_add(name, comm, commlen);
78
		*statppid = ppid;
79

80
		return 0;
81
	}
82

83
bad_kernel:
84
	/*
85
	 * We were able to read our STAT_PARENT_PID_READ_N bytes from
86
	 * /proc/%d/stat, but the content is bad. Broken kernel?
87
	 * Should not happen, but handle it gracefully.
88
	 */
89
	return -1;
90
}
91

92
static int stat_parent_pid(pid_t pid, struct strbuf *name, int *statppid)
93
{
94
	struct strbuf procfs_path = STRBUF_INIT;
95
	struct strbuf sb = STRBUF_INIT;
96
	FILE *fp;
97
	int ret = -1;
98

99
	/* try to use procfs if it's present. */
100
	strbuf_addf(&procfs_path, "/proc/%d/stat", pid);
101
	fp = fopen(procfs_path.buf, "r");
102
	if (!fp)
103
		goto cleanup;
104

105
	/*
106
	 * We could be more strict here and assert that we read at
107
	 * least STAT_PARENT_PID_READ_N. My reading of procfs(5) is
108
	 * that on any modern kernel (at least since 2.6.0 released in
109
	 * 2003) even if all the mandatory numeric fields were zero'd
110
	 * out we'd get at least 100 bytes, but let's just check that
111
	 * we got anything at all and trust the parse_proc_stat()
112
	 * function to handle its "Bad Kernel?" error checking.
113
	 */
114
	if (!strbuf_fread(&sb, STAT_PARENT_PID_READ_N, fp))
115
		goto cleanup;
116
	if (parse_proc_stat(&sb, name, statppid) < 0)
117
		goto cleanup;
118

119
	ret = 0;
120
cleanup:
121
	if (fp)
122
		fclose(fp);
123
	strbuf_release(&procfs_path);
124
	strbuf_release(&sb);
125

126
	return ret;
127
}
128

129
static void push_ancestry_name(struct strvec *names, pid_t pid)
130
{
131
	struct strbuf name = STRBUF_INIT;
132
	int ppid;
133

134
	if (stat_parent_pid(pid, &name, &ppid) < 0)
135
		goto cleanup;
136

137
	strvec_push(names, name.buf);
138

139
	/*
140
	 * Both errors and reaching the end of the process chain are
141
	 * reported as fields of 0 by proc(5)
142
	 */
143
	if (ppid)
144
		push_ancestry_name(names, ppid);
145
cleanup:
146
	strbuf_release(&name);
147

148
	return;
149
}
150

151
void trace2_collect_process_info(enum trace2_process_info_reason reason)
152
{
153
	struct strvec names = STRVEC_INIT;
154

155
	if (!trace2_is_enabled())
156
		return;
157

158
	switch (reason) {
159
	case TRACE2_PROCESS_INFO_EXIT:
160
		/*
161
		 * The Windows version of this calls its
162
		 * get_peak_memory_info() here. We may want to insert
163
		 * similar process-end statistics here in the future.
164
		 */
165
		break;
166
	case TRACE2_PROCESS_INFO_STARTUP:
167
		push_ancestry_name(&names, getppid());
168

169
		if (names.nr)
170
			trace2_cmd_ancestry(names.v);
171
		strvec_clear(&names);
172
		break;
173
	}
174

175
	return;
176
}
177

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.