Line data Source code
1 : /***
2 : This file is part of systemd.
3 :
4 : Copyright 2010 Lennart Poettering
5 :
6 : systemd is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU Lesser General Public License as published by
8 : the Free Software Foundation; either version 2.1 of the License, or
9 : (at your option) any later version.
10 :
11 : systemd is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should have received a copy of the GNU Lesser General Public License
17 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 : ***/
19 :
20 : #include <stdbool.h>
21 : #include <sys/types.h>
22 : #include <string.h>
23 : #include <stdio.h>
24 : #include <assert.h>
25 : #include <errno.h>
26 : #include <unistd.h>
27 : #include <sys/wait.h>
28 : #include <signal.h>
29 : #include <ctype.h>
30 :
31 : #include "fileio.h"
32 : #include "util.h"
33 : #include "log.h"
34 : #include "signal-util.h"
35 : #include "process-util.h"
36 :
37 6 : int get_process_state(pid_t pid) {
38 : const char *p;
39 : char state;
40 : int r;
41 12 : _cleanup_free_ char *line = NULL;
42 :
43 6 : assert(pid >= 0);
44 :
45 6 : p = procfs_file_alloca(pid, "stat");
46 :
47 6 : r = read_one_line_file(p, &line);
48 6 : if (r == -ENOENT)
49 1 : return -ESRCH;
50 5 : if (r < 0)
51 0 : return r;
52 :
53 5 : p = strrchr(line, ')');
54 5 : if (!p)
55 0 : return -EIO;
56 :
57 5 : p++;
58 :
59 5 : if (sscanf(p, " %c", &state) != 1)
60 0 : return -EIO;
61 :
62 5 : return (unsigned char) state;
63 : }
64 :
65 3 : int get_process_comm(pid_t pid, char **name) {
66 : const char *p;
67 : int r;
68 :
69 3 : assert(name);
70 3 : assert(pid >= 0);
71 :
72 3 : p = procfs_file_alloca(pid, "comm");
73 :
74 3 : r = read_one_line_file(p, name);
75 3 : if (r == -ENOENT)
76 0 : return -ESRCH;
77 :
78 3 : return r;
79 : }
80 :
81 2 : int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
82 4 : _cleanup_fclose_ FILE *f = NULL;
83 2 : char *r = NULL, *k;
84 : const char *p;
85 : int c;
86 :
87 2 : assert(line);
88 2 : assert(pid >= 0);
89 :
90 2 : p = procfs_file_alloca(pid, "cmdline");
91 :
92 2 : f = fopen(p, "re");
93 2 : if (!f) {
94 0 : if (errno == ENOENT)
95 0 : return -ESRCH;
96 0 : return -errno;
97 : }
98 :
99 2 : if (max_length == 0) {
100 1 : size_t len = 0, allocated = 0;
101 :
102 27 : while ((c = getc(f)) != EOF) {
103 :
104 25 : if (!GREEDY_REALLOC(r, allocated, len+2)) {
105 0 : free(r);
106 0 : return -ENOMEM;
107 : }
108 :
109 25 : r[len++] = isprint(c) ? c : ' ';
110 : }
111 :
112 1 : if (len > 0)
113 1 : r[len-1] = 0;
114 :
115 : } else {
116 1 : bool space = false;
117 : size_t left;
118 :
119 1 : r = new(char, max_length);
120 1 : if (!r)
121 0 : return -ENOMEM;
122 :
123 1 : k = r;
124 1 : left = max_length;
125 6 : while ((c = getc(f)) != EOF) {
126 :
127 5 : if (isprint(c)) {
128 5 : if (space) {
129 0 : if (left <= 4)
130 0 : break;
131 :
132 0 : *(k++) = ' ';
133 0 : left--;
134 0 : space = false;
135 : }
136 :
137 5 : if (left <= 4)
138 1 : break;
139 :
140 4 : *(k++) = (char) c;
141 4 : left--;
142 : } else
143 0 : space = true;
144 : }
145 :
146 1 : if (left <= 4) {
147 1 : size_t n = MIN(left-1, 3U);
148 1 : memcpy(k, "...", n);
149 1 : k[n] = 0;
150 : } else
151 0 : *k = 0;
152 : }
153 :
154 : /* Kernel threads have no argv[] */
155 2 : if (isempty(r)) {
156 0 : _cleanup_free_ char *t = NULL;
157 : int h;
158 :
159 0 : free(r);
160 :
161 0 : if (!comm_fallback)
162 0 : return -ENOENT;
163 :
164 0 : h = get_process_comm(pid, &t);
165 0 : if (h < 0)
166 0 : return h;
167 :
168 0 : r = strjoin("[", t, "]", NULL);
169 0 : if (!r)
170 0 : return -ENOMEM;
171 : }
172 :
173 2 : *line = r;
174 2 : return 0;
175 : }
176 :
177 205 : int is_kernel_thread(pid_t pid) {
178 : const char *p;
179 : size_t count;
180 : char c;
181 : bool eof;
182 : FILE *f;
183 :
184 205 : if (pid == 0)
185 0 : return 0;
186 :
187 205 : assert(pid > 0);
188 :
189 205 : p = procfs_file_alloca(pid, "cmdline");
190 205 : f = fopen(p, "re");
191 205 : if (!f) {
192 0 : if (errno == ENOENT)
193 0 : return -ESRCH;
194 0 : return -errno;
195 : }
196 :
197 205 : count = fread(&c, 1, 1, f);
198 205 : eof = feof(f);
199 205 : fclose(f);
200 :
201 : /* Kernel threads have an empty cmdline */
202 :
203 205 : if (count <= 0)
204 104 : return eof ? 1 : -errno;
205 :
206 101 : return 0;
207 : }
208 :
209 2 : int get_process_capeff(pid_t pid, char **capeff) {
210 : const char *p;
211 : int r;
212 :
213 2 : assert(capeff);
214 2 : assert(pid >= 0);
215 :
216 2 : p = procfs_file_alloca(pid, "status");
217 :
218 2 : r = get_status_field(p, "\nCapEff:", capeff);
219 2 : if (r == -ENOENT)
220 0 : return -ESRCH;
221 :
222 2 : return r;
223 : }
224 :
225 5 : static int get_process_link_contents(const char *proc_file, char **name) {
226 : int r;
227 :
228 5 : assert(proc_file);
229 5 : assert(name);
230 :
231 5 : r = readlink_malloc(proc_file, name);
232 5 : if (r == -ENOENT)
233 0 : return -ESRCH;
234 5 : if (r < 0)
235 2 : return r;
236 :
237 3 : return 0;
238 : }
239 :
240 3 : int get_process_exe(pid_t pid, char **name) {
241 : const char *p;
242 : char *d;
243 : int r;
244 :
245 3 : assert(pid >= 0);
246 :
247 3 : p = procfs_file_alloca(pid, "exe");
248 3 : r = get_process_link_contents(p, name);
249 3 : if (r < 0)
250 2 : return r;
251 :
252 1 : d = endswith(*name, " (deleted)");
253 1 : if (d)
254 0 : *d = '\0';
255 :
256 1 : return 0;
257 : }
258 :
259 2 : static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
260 4 : _cleanup_fclose_ FILE *f = NULL;
261 : char line[LINE_MAX];
262 : const char *p;
263 :
264 2 : assert(field);
265 2 : assert(uid);
266 :
267 2 : if (pid == 0)
268 0 : return getuid();
269 :
270 2 : p = procfs_file_alloca(pid, "status");
271 2 : f = fopen(p, "re");
272 2 : if (!f) {
273 0 : if (errno == ENOENT)
274 0 : return -ESRCH;
275 0 : return -errno;
276 : }
277 :
278 17 : FOREACH_LINE(line, f, return -errno) {
279 : char *l;
280 :
281 17 : l = strstrip(line);
282 :
283 17 : if (startswith(l, field)) {
284 2 : l += strlen(field);
285 2 : l += strspn(l, WHITESPACE);
286 :
287 2 : l[strcspn(l, WHITESPACE)] = 0;
288 :
289 2 : return parse_uid(l, uid);
290 : }
291 15 : }
292 :
293 0 : return -EIO;
294 : }
295 :
296 1 : int get_process_uid(pid_t pid, uid_t *uid) {
297 1 : return get_process_id(pid, "Uid:", uid);
298 : }
299 :
300 1 : int get_process_gid(pid_t pid, gid_t *gid) {
301 : assert_cc(sizeof(uid_t) == sizeof(gid_t));
302 1 : return get_process_id(pid, "Gid:", gid);
303 : }
304 :
305 1 : int get_process_cwd(pid_t pid, char **cwd) {
306 : const char *p;
307 :
308 1 : assert(pid >= 0);
309 :
310 1 : p = procfs_file_alloca(pid, "cwd");
311 :
312 1 : return get_process_link_contents(p, cwd);
313 : }
314 :
315 1 : int get_process_root(pid_t pid, char **root) {
316 : const char *p;
317 :
318 1 : assert(pid >= 0);
319 :
320 1 : p = procfs_file_alloca(pid, "root");
321 :
322 1 : return get_process_link_contents(p, root);
323 : }
324 :
325 1 : int get_process_environ(pid_t pid, char **env) {
326 2 : _cleanup_fclose_ FILE *f = NULL;
327 2 : _cleanup_free_ char *outcome = NULL;
328 : int c;
329 : const char *p;
330 1 : size_t allocated = 0, sz = 0;
331 :
332 1 : assert(pid >= 0);
333 1 : assert(env);
334 :
335 1 : p = procfs_file_alloca(pid, "environ");
336 :
337 1 : f = fopen(p, "re");
338 1 : if (!f) {
339 0 : if (errno == ENOENT)
340 0 : return -ESRCH;
341 0 : return -errno;
342 : }
343 :
344 5589 : while ((c = fgetc(f)) != EOF) {
345 5587 : if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
346 0 : return -ENOMEM;
347 :
348 5587 : if (c == '\0')
349 35 : outcome[sz++] = '\n';
350 : else
351 5552 : sz += cescape_char(c, outcome + sz);
352 : }
353 :
354 1 : if (!outcome) {
355 0 : outcome = strdup("");
356 0 : if (!outcome)
357 0 : return -ENOMEM;
358 : } else
359 1 : outcome[sz] = '\0';
360 :
361 1 : *env = outcome;
362 1 : outcome = NULL;
363 :
364 1 : return 0;
365 : }
366 :
367 7 : int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
368 : int r;
369 14 : _cleanup_free_ char *line = NULL;
370 : long unsigned ppid;
371 : const char *p;
372 :
373 7 : assert(pid >= 0);
374 7 : assert(_ppid);
375 :
376 7 : if (pid == 0) {
377 0 : *_ppid = getppid();
378 0 : return 0;
379 : }
380 :
381 7 : p = procfs_file_alloca(pid, "stat");
382 7 : r = read_one_line_file(p, &line);
383 7 : if (r == -ENOENT)
384 0 : return -ESRCH;
385 7 : if (r < 0)
386 0 : return r;
387 :
388 : /* Let's skip the pid and comm fields. The latter is enclosed
389 : * in () but does not escape any () in its value, so let's
390 : * skip over it manually */
391 :
392 7 : p = strrchr(line, ')');
393 7 : if (!p)
394 0 : return -EIO;
395 :
396 7 : p++;
397 :
398 7 : if (sscanf(p, " "
399 : "%*c " /* state */
400 : "%lu ", /* ppid */
401 : &ppid) != 1)
402 0 : return -EIO;
403 :
404 7 : if ((long unsigned) (pid_t) ppid != ppid)
405 0 : return -ERANGE;
406 :
407 7 : *_ppid = (pid_t) ppid;
408 :
409 7 : return 0;
410 : }
411 :
412 1 : int wait_for_terminate(pid_t pid, siginfo_t *status) {
413 : siginfo_t dummy;
414 :
415 1 : assert(pid >= 1);
416 :
417 1 : if (!status)
418 0 : status = &dummy;
419 :
420 : for (;;) {
421 1 : zero(*status);
422 :
423 1 : if (waitid(P_PID, pid, status, WEXITED) < 0) {
424 :
425 0 : if (errno == EINTR)
426 0 : continue;
427 :
428 0 : return -errno;
429 : }
430 :
431 1 : return 0;
432 0 : }
433 : }
434 :
435 : /*
436 : * Return values:
437 : * < 0 : wait_for_terminate() failed to get the state of the
438 : * process, the process was terminated by a signal, or
439 : * failed for an unknown reason.
440 : * >=0 : The process terminated normally, and its exit code is
441 : * returned.
442 : *
443 : * That is, success is indicated by a return value of zero, and an
444 : * error is indicated by a non-zero value.
445 : *
446 : * A warning is emitted if the process terminates abnormally,
447 : * and also if it returns non-zero unless check_exit_code is true.
448 : */
449 1 : int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
450 : int r;
451 : siginfo_t status;
452 :
453 1 : assert(name);
454 1 : assert(pid > 1);
455 :
456 1 : r = wait_for_terminate(pid, &status);
457 1 : if (r < 0)
458 0 : return log_warning_errno(r, "Failed to wait for %s: %m", name);
459 :
460 1 : if (status.si_code == CLD_EXITED) {
461 1 : if (status.si_status != 0)
462 0 : log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
463 : "%s failed with error code %i.", name, status.si_status);
464 : else
465 1 : log_debug("%s succeeded.", name);
466 :
467 1 : return status.si_status;
468 0 : } else if (status.si_code == CLD_KILLED ||
469 0 : status.si_code == CLD_DUMPED) {
470 :
471 0 : log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
472 0 : return -EPROTO;
473 : }
474 :
475 0 : log_warning("%s failed due to unknown reason.", name);
476 0 : return -EPROTO;
477 : }
478 :
479 0 : int kill_and_sigcont(pid_t pid, int sig) {
480 : int r;
481 :
482 0 : r = kill(pid, sig) < 0 ? -errno : 0;
483 :
484 0 : if (r >= 0)
485 0 : kill(pid, SIGCONT);
486 :
487 0 : return r;
488 : }
489 :
490 11 : int getenv_for_pid(pid_t pid, const char *field, char **_value) {
491 22 : _cleanup_fclose_ FILE *f = NULL;
492 11 : char *value = NULL;
493 : int r;
494 11 : bool done = false;
495 : size_t l;
496 : const char *path;
497 :
498 11 : assert(pid >= 0);
499 11 : assert(field);
500 11 : assert(_value);
501 :
502 11 : path = procfs_file_alloca(pid, "environ");
503 :
504 11 : f = fopen(path, "re");
505 11 : if (!f) {
506 11 : if (errno == ENOENT)
507 0 : return -ESRCH;
508 11 : return -errno;
509 : }
510 :
511 0 : l = strlen(field);
512 0 : r = 0;
513 :
514 : do {
515 : char line[LINE_MAX];
516 : unsigned i;
517 :
518 0 : for (i = 0; i < sizeof(line)-1; i++) {
519 : int c;
520 :
521 0 : c = getc(f);
522 0 : if (_unlikely_(c == EOF)) {
523 0 : done = true;
524 0 : break;
525 0 : } else if (c == 0)
526 0 : break;
527 :
528 0 : line[i] = c;
529 : }
530 0 : line[i] = 0;
531 :
532 0 : if (memcmp(line, field, l) == 0 && line[l] == '=') {
533 0 : value = strdup(line + l + 1);
534 0 : if (!value)
535 0 : return -ENOMEM;
536 :
537 0 : r = 1;
538 0 : break;
539 : }
540 :
541 0 : } while (!done);
542 :
543 0 : *_value = value;
544 0 : return r;
545 : }
546 :
547 3 : bool pid_is_unwaited(pid_t pid) {
548 : /* Checks whether a PID is still valid at all, including a zombie */
549 :
550 3 : if (pid <= 0)
551 1 : return false;
552 :
553 2 : if (kill(pid, 0) >= 0)
554 1 : return true;
555 :
556 1 : return errno != ESRCH;
557 : }
558 :
559 7 : bool pid_is_alive(pid_t pid) {
560 : int r;
561 :
562 : /* Checks whether a PID is still valid and not a zombie */
563 :
564 7 : if (pid <= 0)
565 1 : return false;
566 :
567 6 : r = get_process_state(pid);
568 6 : if (r == -ESRCH || r == 'Z')
569 1 : return false;
570 :
571 5 : return true;
572 : }
|