LCOV - code coverage report
Current view: top level - core - killall.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 125 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 5 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 144 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2010 ProFUSION embedded systems
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <errno.h>
       7                 :            : #include <signal.h>
       8                 :            : #include <sys/wait.h>
       9                 :            : #include <unistd.h>
      10                 :            : 
      11                 :            : #include "alloc-util.h"
      12                 :            : #include "def.h"
      13                 :            : #include "dirent-util.h"
      14                 :            : #include "fd-util.h"
      15                 :            : #include "format-util.h"
      16                 :            : #include "killall.h"
      17                 :            : #include "parse-util.h"
      18                 :            : #include "process-util.h"
      19                 :            : #include "set.h"
      20                 :            : #include "string-util.h"
      21                 :            : #include "terminal-util.h"
      22                 :            : #include "util.h"
      23                 :            : 
      24                 :          0 : static bool ignore_proc(pid_t pid, bool warn_rootfs) {
      25                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
      26                 :            :         const char *p;
      27                 :          0 :         char c = 0;
      28                 :            :         uid_t uid;
      29                 :            :         int r;
      30                 :            : 
      31                 :            :         /* We are PID 1, let's not commit suicide */
      32         [ #  # ]:          0 :         if (pid <= 1)
      33                 :          0 :                 return true;
      34                 :            : 
      35                 :            :         /* Ignore kernel threads */
      36                 :          0 :         r = is_kernel_thread(pid);
      37         [ #  # ]:          0 :         if (r != 0)
      38                 :          0 :                 return true; /* also ignore processes where we can't determine this */
      39                 :            : 
      40                 :          0 :         r = get_process_uid(pid, &uid);
      41         [ #  # ]:          0 :         if (r < 0)
      42                 :          0 :                 return true; /* not really, but better safe than sorry */
      43                 :            : 
      44                 :            :         /* Non-root processes otherwise are always subject to be killed */
      45         [ #  # ]:          0 :         if (uid != 0)
      46                 :          0 :                 return false;
      47                 :            : 
      48   [ #  #  #  #  :          0 :         p = procfs_file_alloca(pid, "cmdline");
                   #  # ]
      49                 :          0 :         f = fopen(p, "re");
      50         [ #  # ]:          0 :         if (!f)
      51                 :          0 :                 return true; /* not really, but has the desired effect */
      52                 :            : 
      53                 :            :         /* Try to read the first character of the command line. If the cmdline is empty (which might be the case for
      54                 :            :          * kernel threads but potentially also other stuff), this line won't do anything, but we don't care much, as
      55                 :            :          * actual kernel threads are already filtered out above. */
      56                 :          0 :         (void) fread(&c, 1, 1, f);
      57                 :            : 
      58                 :            :         /* Processes with argv[0][0] = '@' we ignore from the killing spree.
      59                 :            :          *
      60                 :            :          * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
      61         [ #  # ]:          0 :         if (c != '@')
      62                 :          0 :                 return false;
      63                 :            : 
      64   [ #  #  #  # ]:          0 :         if (warn_rootfs &&
      65                 :          0 :             pid_from_same_root_fs(pid) == 0) {
      66                 :            : 
      67                 :          0 :                 _cleanup_free_ char *comm = NULL;
      68                 :            : 
      69                 :          0 :                 (void) get_process_comm(pid, &comm);
      70                 :            : 
      71         [ #  # ]:          0 :                 log_notice("Process " PID_FMT " (%s) has been marked to be excluded from killing. It is "
      72                 :            :                            "running from the root file system, and thus likely to block re-mounting of the "
      73                 :            :                            "root file system to read-only. Please consider moving it into an initrd file "
      74                 :            :                            "system instead.", pid, strna(comm));
      75                 :            :         }
      76                 :            : 
      77                 :          0 :         return true;
      78                 :            : }
      79                 :            : 
      80                 :          0 : static void log_children_no_yet_killed(Set *pids) {
      81         [ #  # ]:          0 :         _cleanup_free_ char *lst_child = NULL;
      82                 :            :         Iterator i;
      83                 :            :         void *p;
      84                 :            : 
      85         [ #  # ]:          0 :         SET_FOREACH(p, pids, i) {
      86         [ #  # ]:          0 :                 _cleanup_free_ char *s = NULL;
      87                 :            : 
      88         [ #  # ]:          0 :                 if (get_process_comm(PTR_TO_PID(p), &s) < 0)
      89                 :          0 :                         (void) asprintf(&s, PID_FMT, PTR_TO_PID(p));
      90                 :            : 
      91         [ #  # ]:          0 :                 if (!strextend(&lst_child, ", ", s, NULL)) {
      92                 :          0 :                         log_oom();
      93                 :          0 :                         return;
      94                 :            :                 }
      95                 :            :         }
      96                 :            : 
      97         [ #  # ]:          0 :         if (isempty(lst_child))
      98                 :          0 :                 return;
      99                 :            : 
     100         [ #  # ]:          0 :         log_warning("Waiting for process: %s", lst_child + 2);
     101                 :            : }
     102                 :            : 
     103                 :          0 : static int wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
     104                 :            :         usec_t until, date_log_child, n;
     105                 :            : 
     106         [ #  # ]:          0 :         assert(mask);
     107                 :            : 
     108                 :            :         /* Return the number of children remaining in the pids set: That correspond to the number
     109                 :            :          * of processes still "alive" after the timeout */
     110                 :            : 
     111         [ #  # ]:          0 :         if (set_isempty(pids))
     112                 :          0 :                 return 0;
     113                 :            : 
     114                 :          0 :         n = now(CLOCK_MONOTONIC);
     115                 :          0 :         until = usec_add(n, timeout);
     116                 :          0 :         date_log_child = usec_add(n, 10u * USEC_PER_SEC);
     117         [ #  # ]:          0 :         if (date_log_child > until)
     118                 :          0 :                 date_log_child = usec_add(n, timeout / 2u);
     119                 :            : 
     120                 :          0 :         for (;;) {
     121                 :            :                 struct timespec ts;
     122                 :            :                 int k;
     123                 :            :                 void *p;
     124                 :            :                 Iterator i;
     125                 :            : 
     126                 :            :                 /* First, let the kernel inform us about killed
     127                 :            :                  * children. Most processes will probably be our
     128                 :            :                  * children, but some are not (might be our
     129                 :            :                  * grandchildren instead...). */
     130                 :          0 :                 for (;;) {
     131                 :            :                         pid_t pid;
     132                 :            : 
     133                 :          0 :                         pid = waitpid(-1, NULL, WNOHANG);
     134         [ #  # ]:          0 :                         if (pid == 0)
     135                 :          0 :                                 break;
     136         [ #  # ]:          0 :                         if (pid < 0) {
     137         [ #  # ]:          0 :                                 if (errno == ECHILD)
     138                 :          0 :                                         break;
     139                 :            : 
     140         [ #  # ]:          0 :                                 return log_error_errno(errno, "waitpid() failed: %m");
     141                 :            :                         }
     142                 :            : 
     143                 :          0 :                         (void) set_remove(pids, PID_TO_PTR(pid));
     144                 :            :                 }
     145                 :            : 
     146                 :            :                 /* Now explicitly check who might be remaining, who
     147                 :            :                  * might not be our child. */
     148         [ #  # ]:          0 :                 SET_FOREACH(p, pids, i) {
     149                 :            : 
     150                 :            :                         /* kill(pid, 0) sends no signal, but it tells
     151                 :            :                          * us whether the process still exists. */
     152         [ #  # ]:          0 :                         if (kill(PTR_TO_PID(p), 0) == 0)
     153                 :          0 :                                 continue;
     154                 :            : 
     155         [ #  # ]:          0 :                         if (errno != ESRCH)
     156                 :          0 :                                 continue;
     157                 :            : 
     158                 :          0 :                         set_remove(pids, p);
     159                 :            :                 }
     160                 :            : 
     161         [ #  # ]:          0 :                 if (set_isempty(pids))
     162                 :          0 :                         return 0;
     163                 :            : 
     164                 :          0 :                 n = now(CLOCK_MONOTONIC);
     165   [ #  #  #  # ]:          0 :                 if (date_log_child > 0 && n >= date_log_child) {
     166                 :          0 :                         log_children_no_yet_killed(pids);
     167                 :            :                         /* Log the children not yet killed only once */
     168                 :          0 :                         date_log_child = 0;
     169                 :            :                 }
     170                 :            : 
     171         [ #  # ]:          0 :                 if (n >= until)
     172                 :          0 :                         return set_size(pids);
     173                 :            : 
     174         [ #  # ]:          0 :                 if (date_log_child > 0)
     175                 :          0 :                         timespec_store(&ts, MIN(until - n, date_log_child - n));
     176                 :            :                 else
     177                 :          0 :                         timespec_store(&ts, until - n);
     178                 :            : 
     179                 :          0 :                 k = sigtimedwait(mask, NULL, &ts);
     180         [ #  # ]:          0 :                 if (k != SIGCHLD) {
     181                 :            : 
     182   [ #  #  #  # ]:          0 :                         if (k < 0 && errno != EAGAIN)
     183         [ #  # ]:          0 :                                 return log_error_errno(errno, "sigtimedwait() failed: %m");
     184                 :            : 
     185         [ #  # ]:          0 :                         if (k >= 0)
     186         [ #  # ]:          0 :                                 log_warning("sigtimedwait() returned unexpected signal.");
     187                 :            :                 }
     188                 :            :         }
     189                 :            : }
     190                 :            : 
     191                 :          0 : static int killall(int sig, Set *pids, bool send_sighup) {
     192                 :          0 :         _cleanup_closedir_ DIR *dir = NULL;
     193                 :            :         struct dirent *d;
     194                 :          0 :         int n_killed = 0;
     195                 :            : 
     196                 :            :         /* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
     197                 :            :          * Returns the number of processes to which the specified signal was sent */
     198                 :            : 
     199                 :          0 :         dir = opendir("/proc");
     200         [ #  # ]:          0 :         if (!dir)
     201         [ #  # ]:          0 :                 return log_warning_errno(errno, "opendir(/proc) failed: %m");
     202                 :            : 
     203   [ #  #  #  # ]:          0 :         FOREACH_DIRENT_ALL(d, dir, break) {
     204                 :            :                 pid_t pid;
     205                 :            :                 int r;
     206                 :            : 
     207   [ #  #  #  # ]:          0 :                 if (!IN_SET(d->d_type, DT_DIR, DT_UNKNOWN))
     208                 :          0 :                         continue;
     209                 :            : 
     210         [ #  # ]:          0 :                 if (parse_pid(d->d_name, &pid) < 0)
     211                 :          0 :                         continue;
     212                 :            : 
     213   [ #  #  #  #  :          0 :                 if (ignore_proc(pid, sig == SIGKILL && !in_initrd()))
                   #  # ]
     214                 :          0 :                         continue;
     215                 :            : 
     216         [ #  # ]:          0 :                 if (sig == SIGKILL) {
     217                 :          0 :                         _cleanup_free_ char *s = NULL;
     218                 :            : 
     219                 :          0 :                         get_process_comm(pid, &s);
     220         [ #  # ]:          0 :                         log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s));
     221                 :            :                 }
     222                 :            : 
     223         [ #  # ]:          0 :                 if (kill(pid, sig) >= 0) {
     224                 :          0 :                         n_killed++;
     225         [ #  # ]:          0 :                         if (pids) {
     226                 :          0 :                                 r = set_put(pids, PID_TO_PTR(pid));
     227         [ #  # ]:          0 :                                 if (r < 0)
     228                 :          0 :                                         log_oom();
     229                 :            :                         }
     230         [ #  # ]:          0 :                 } else if (errno != ENOENT)
     231         [ #  # ]:          0 :                         log_warning_errno(errno, "Could not kill %d: %m", pid);
     232                 :            : 
     233         [ #  # ]:          0 :                 if (send_sighup) {
     234                 :            :                         /* Optionally, also send a SIGHUP signal, but
     235                 :            :                         only if the process has a controlling
     236                 :            :                         tty. This is useful to allow handling of
     237                 :            :                         shells which ignore SIGTERM but react to
     238                 :            :                         SIGHUP. We do not send this to processes that
     239                 :            :                         have no controlling TTY since we don't want to
     240                 :            :                         trigger reloads of daemon processes. Also we
     241                 :            :                         make sure to only send this after SIGTERM so
     242                 :            :                         that SIGTERM is always first in the queue. */
     243                 :            : 
     244         [ #  # ]:          0 :                         if (get_ctty_devnr(pid, NULL) >= 0)
     245                 :            :                                 /* it's OK if the process is gone, just ignore the result */
     246                 :          0 :                                 (void) kill(pid, SIGHUP);
     247                 :            :                 }
     248                 :            :         }
     249                 :            : 
     250                 :          0 :         return n_killed;
     251                 :            : }
     252                 :            : 
     253                 :          0 : int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
     254                 :            :         int n_children_left;
     255                 :            :         sigset_t mask, oldmask;
     256                 :          0 :         _cleanup_set_free_ Set *pids = NULL;
     257                 :            : 
     258                 :            :         /* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
     259                 :            :          * Return:
     260                 :            :          *  - The number of processes still "alive" after the timeout (that should have been killed)
     261                 :            :          *    if the function needs to wait for the end of the processes (wait_for_exit).
     262                 :            :          *  - Otherwise, the number of processes to which the specified signal was sent */
     263                 :            : 
     264         [ #  # ]:          0 :         if (wait_for_exit)
     265                 :          0 :                 pids = set_new(NULL);
     266                 :            : 
     267         [ #  # ]:          0 :         assert_se(sigemptyset(&mask) == 0);
     268         [ #  # ]:          0 :         assert_se(sigaddset(&mask, SIGCHLD) == 0);
     269         [ #  # ]:          0 :         assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
     270                 :            : 
     271   [ #  #  #  # ]:          0 :         if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
     272         [ #  # ]:          0 :                 log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
     273                 :            : 
     274                 :          0 :         n_children_left = killall(sig, pids, send_sighup);
     275                 :            : 
     276   [ #  #  #  # ]:          0 :         if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
     277         [ #  # ]:          0 :                 log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
     278                 :            : 
     279   [ #  #  #  # ]:          0 :         if (wait_for_exit && n_children_left > 0)
     280                 :          0 :                 n_children_left = wait_for_children(pids, &mask, timeout);
     281                 :            : 
     282         [ #  # ]:          0 :         assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
     283                 :            : 
     284                 :          0 :         return n_children_left;
     285                 :            : }

Generated by: LCOV version 1.14