LCOV - code coverage report
Current view: top level - basic - process-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 193 285 67.7 %
Date: 2015-07-29 18:47:03 Functions: 19 20 95.0 %

          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             : }

Generated by: LCOV version 1.11