LCOV - code coverage report
Current view: top level - shared - bus-unit-procs.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 201 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 7 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 174 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "bus-unit-procs.h"
       4                 :            : #include "hashmap.h"
       5                 :            : #include "list.h"
       6                 :            : #include "locale-util.h"
       7                 :            : #include "macro.h"
       8                 :            : #include "path-util.h"
       9                 :            : #include "process-util.h"
      10                 :            : #include "sort-util.h"
      11                 :            : #include "string-util.h"
      12                 :            : #include "terminal-util.h"
      13                 :            : 
      14                 :            : struct CGroupInfo {
      15                 :            :         char *cgroup_path;
      16                 :            :         bool is_const; /* If false, cgroup_path should be free()'d */
      17                 :            : 
      18                 :            :         Hashmap *pids; /* PID → process name */
      19                 :            :         bool done;
      20                 :            : 
      21                 :            :         struct CGroupInfo *parent;
      22                 :            :         LIST_FIELDS(struct CGroupInfo, siblings);
      23                 :            :         LIST_HEAD(struct CGroupInfo, children);
      24                 :            :         size_t n_children;
      25                 :            : };
      26                 :            : 
      27                 :          0 : static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) {
      28                 :          0 :         struct CGroupInfo *parent = NULL, *cg;
      29                 :            :         int r;
      30                 :            : 
      31         [ #  # ]:          0 :         assert(cgroups);
      32         [ #  # ]:          0 :         assert(ret);
      33                 :            : 
      34                 :          0 :         path = empty_to_root(path);
      35                 :            : 
      36                 :          0 :         cg = hashmap_get(cgroups, path);
      37         [ #  # ]:          0 :         if (cg) {
      38                 :          0 :                 *ret = cg;
      39                 :          0 :                 return 0;
      40                 :            :         }
      41                 :            : 
      42         [ #  # ]:          0 :         if (!empty_or_root(path)) {
      43                 :            :                 const char *e, *pp;
      44                 :            : 
      45                 :          0 :                 e = strrchr(path, '/');
      46         [ #  # ]:          0 :                 if (!e)
      47                 :          0 :                         return -EINVAL;
      48                 :            : 
      49                 :          0 :                 pp = strndupa(path, e - path);
      50                 :            : 
      51                 :          0 :                 r = add_cgroup(cgroups, pp, false, &parent);
      52         [ #  # ]:          0 :                 if (r < 0)
      53                 :          0 :                         return r;
      54                 :            :         }
      55                 :            : 
      56                 :          0 :         cg = new0(struct CGroupInfo, 1);
      57         [ #  # ]:          0 :         if (!cg)
      58                 :          0 :                 return -ENOMEM;
      59                 :            : 
      60         [ #  # ]:          0 :         if (is_const)
      61                 :          0 :                 cg->cgroup_path = (char*) path;
      62                 :            :         else {
      63                 :          0 :                 cg->cgroup_path = strdup(path);
      64         [ #  # ]:          0 :                 if (!cg->cgroup_path) {
      65                 :          0 :                         free(cg);
      66                 :          0 :                         return -ENOMEM;
      67                 :            :                 }
      68                 :            :         }
      69                 :            : 
      70                 :          0 :         cg->is_const = is_const;
      71                 :          0 :         cg->parent = parent;
      72                 :            : 
      73                 :          0 :         r = hashmap_put(cgroups, cg->cgroup_path, cg);
      74         [ #  # ]:          0 :         if (r < 0) {
      75         [ #  # ]:          0 :                 if (!is_const)
      76                 :          0 :                         free(cg->cgroup_path);
      77                 :          0 :                 free(cg);
      78                 :          0 :                 return r;
      79                 :            :         }
      80                 :            : 
      81         [ #  # ]:          0 :         if (parent) {
      82   [ #  #  #  # ]:          0 :                 LIST_PREPEND(siblings, parent->children, cg);
      83                 :          0 :                 parent->n_children++;
      84                 :            :         }
      85                 :            : 
      86                 :          0 :         *ret = cg;
      87                 :          0 :         return 1;
      88                 :            : }
      89                 :            : 
      90                 :          0 : static int add_process(
      91                 :            :                 Hashmap *cgroups,
      92                 :            :                 const char *path,
      93                 :            :                 pid_t pid,
      94                 :            :                 const char *name) {
      95                 :            : 
      96                 :            :         struct CGroupInfo *cg;
      97                 :            :         int r;
      98                 :            : 
      99         [ #  # ]:          0 :         assert(cgroups);
     100         [ #  # ]:          0 :         assert(name);
     101         [ #  # ]:          0 :         assert(pid > 0);
     102                 :            : 
     103                 :          0 :         r = add_cgroup(cgroups, path, true, &cg);
     104         [ #  # ]:          0 :         if (r < 0)
     105                 :          0 :                 return r;
     106                 :            : 
     107                 :          0 :         r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops);
     108         [ #  # ]:          0 :         if (r < 0)
     109                 :          0 :                 return r;
     110                 :            : 
     111                 :          0 :         return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name);
     112                 :            : }
     113                 :            : 
     114                 :          0 : static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
     115         [ #  # ]:          0 :         assert(cgroups);
     116         [ #  # ]:          0 :         assert(cg);
     117                 :            : 
     118         [ #  # ]:          0 :         while (cg->children)
     119                 :          0 :                 remove_cgroup(cgroups, cg->children);
     120                 :            : 
     121                 :          0 :         hashmap_remove(cgroups, cg->cgroup_path);
     122                 :            : 
     123         [ #  # ]:          0 :         if (!cg->is_const)
     124                 :          0 :                 free(cg->cgroup_path);
     125                 :            : 
     126                 :          0 :         hashmap_free(cg->pids);
     127                 :            : 
     128         [ #  # ]:          0 :         if (cg->parent)
     129   [ #  #  #  #  :          0 :                 LIST_REMOVE(siblings, cg->parent->children, cg);
             #  #  #  # ]
     130                 :            : 
     131                 :          0 :         free(cg);
     132                 :          0 : }
     133                 :            : 
     134                 :          0 : static int cgroup_info_compare_func(struct CGroupInfo * const *a, struct CGroupInfo * const *b) {
     135                 :          0 :         return strcmp((*a)->cgroup_path, (*b)->cgroup_path);
     136                 :            : }
     137                 :            : 
     138                 :          0 : static int dump_processes(
     139                 :            :                 Hashmap *cgroups,
     140                 :            :                 const char *cgroup_path,
     141                 :            :                 const char *prefix,
     142                 :            :                 unsigned n_columns,
     143                 :            :                 OutputFlags flags) {
     144                 :            : 
     145                 :            :         struct CGroupInfo *cg;
     146                 :            :         int r;
     147                 :            : 
     148         [ #  # ]:          0 :         assert(prefix);
     149                 :            : 
     150                 :          0 :         cgroup_path = empty_to_root(cgroup_path);
     151                 :            : 
     152                 :          0 :         cg = hashmap_get(cgroups, cgroup_path);
     153         [ #  # ]:          0 :         if (!cg)
     154                 :          0 :                 return 0;
     155                 :            : 
     156         [ #  # ]:          0 :         if (!hashmap_isempty(cg->pids)) {
     157                 :            :                 const char *name;
     158                 :          0 :                 size_t n = 0, i;
     159                 :            :                 pid_t *pids;
     160                 :            :                 void *pidp;
     161                 :            :                 Iterator j;
     162                 :            :                 int width;
     163                 :            : 
     164                 :            :                 /* Order processes by their PID */
     165   [ #  #  #  # ]:          0 :                 pids = newa(pid_t, hashmap_size(cg->pids));
     166                 :            : 
     167         [ #  # ]:          0 :                 HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j)
     168                 :          0 :                         pids[n++] = PTR_TO_PID(pidp);
     169                 :            : 
     170         [ #  # ]:          0 :                 assert(n == hashmap_size(cg->pids));
     171                 :          0 :                 typesafe_qsort(pids, n, pid_compare_func);
     172                 :            : 
     173         [ #  # ]:          0 :                 width = DECIMAL_STR_WIDTH(pids[n-1]);
     174                 :            : 
     175         [ #  # ]:          0 :                 for (i = 0; i < n; i++) {
     176                 :          0 :                         _cleanup_free_ char *e = NULL;
     177                 :            :                         const char *special;
     178                 :            :                         bool more;
     179                 :            : 
     180                 :          0 :                         name = hashmap_get(cg->pids, PID_TO_PTR(pids[i]));
     181         [ #  # ]:          0 :                         assert(name);
     182                 :            : 
     183         [ #  # ]:          0 :                         if (n_columns != 0) {
     184                 :            :                                 unsigned k;
     185                 :            : 
     186         [ #  # ]:          0 :                                 k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
     187                 :            : 
     188                 :          0 :                                 e = ellipsize(name, k, 100);
     189         [ #  # ]:          0 :                                 if (e)
     190                 :          0 :                                         name = e;
     191                 :            :                         }
     192                 :            : 
     193   [ #  #  #  # ]:          0 :                         more = i+1 < n || cg->children;
     194         [ #  # ]:          0 :                         special = special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT);
     195                 :            : 
     196                 :          0 :                         fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
     197                 :            :                                 prefix,
     198                 :            :                                 special,
     199                 :          0 :                                 width, pids[i],
     200                 :            :                                 name);
     201                 :            :                 }
     202                 :            :         }
     203                 :            : 
     204         [ #  # ]:          0 :         if (cg->children) {
     205                 :            :                 struct CGroupInfo **children, *child;
     206                 :          0 :                 size_t n = 0, i;
     207                 :            : 
     208                 :            :                 /* Order subcgroups by their name */
     209   [ #  #  #  # ]:          0 :                 children = newa(struct CGroupInfo*, cg->n_children);
     210         [ #  # ]:          0 :                 LIST_FOREACH(siblings, child, cg->children)
     211                 :          0 :                         children[n++] = child;
     212         [ #  # ]:          0 :                 assert(n == cg->n_children);
     213                 :          0 :                 typesafe_qsort(children, n, cgroup_info_compare_func);
     214                 :            : 
     215         [ #  # ]:          0 :                 if (n_columns != 0)
     216         [ #  # ]:          0 :                         n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
     217                 :            : 
     218         [ #  # ]:          0 :                 for (i = 0; i < n; i++) {
     219         [ #  # ]:          0 :                         _cleanup_free_ char *pp = NULL;
     220                 :            :                         const char *name, *special;
     221                 :            :                         bool more;
     222                 :            : 
     223                 :          0 :                         child = children[i];
     224                 :            : 
     225                 :          0 :                         name = strrchr(child->cgroup_path, '/');
     226         [ #  # ]:          0 :                         if (!name)
     227                 :          0 :                                 return -EINVAL;
     228                 :          0 :                         name++;
     229                 :            : 
     230                 :          0 :                         more = i+1 < n;
     231         [ #  # ]:          0 :                         special = special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT);
     232                 :            : 
     233                 :          0 :                         fputs(prefix, stdout);
     234                 :          0 :                         fputs(special, stdout);
     235                 :          0 :                         fputs(name, stdout);
     236                 :          0 :                         fputc('\n', stdout);
     237                 :            : 
     238         [ #  # ]:          0 :                         special = special_glyph(more ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE);
     239                 :            : 
     240                 :          0 :                         pp = strjoin(prefix, special);
     241         [ #  # ]:          0 :                         if (!pp)
     242                 :          0 :                                 return -ENOMEM;
     243                 :            : 
     244                 :          0 :                         r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags);
     245         [ #  # ]:          0 :                         if (r < 0)
     246                 :          0 :                                 return r;
     247                 :            :                 }
     248                 :            :         }
     249                 :            : 
     250                 :          0 :         cg->done = true;
     251                 :          0 :         return 0;
     252                 :            : }
     253                 :            : 
     254                 :          0 : static int dump_extra_processes(
     255                 :            :                 Hashmap *cgroups,
     256                 :            :                 const char *prefix,
     257                 :            :                 unsigned n_columns,
     258                 :            :                 OutputFlags flags) {
     259                 :            : 
     260                 :          0 :         _cleanup_free_ pid_t *pids = NULL;
     261                 :          0 :         _cleanup_hashmap_free_ Hashmap *names = NULL;
     262                 :            :         struct CGroupInfo *cg;
     263                 :          0 :         size_t n_allocated = 0, n = 0, k;
     264                 :            :         Iterator i;
     265                 :            :         int width, r;
     266                 :            : 
     267                 :            :         /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
     268                 :            :          * combined, sorted, linear list. */
     269                 :            : 
     270         [ #  # ]:          0 :         HASHMAP_FOREACH(cg, cgroups, i) {
     271                 :            :                 const char *name;
     272                 :            :                 void *pidp;
     273                 :            :                 Iterator j;
     274                 :            : 
     275         [ #  # ]:          0 :                 if (cg->done)
     276                 :          0 :                         continue;
     277                 :            : 
     278         [ #  # ]:          0 :                 if (hashmap_isempty(cg->pids))
     279                 :          0 :                         continue;
     280                 :            : 
     281                 :          0 :                 r = hashmap_ensure_allocated(&names, &trivial_hash_ops);
     282         [ #  # ]:          0 :                 if (r < 0)
     283                 :          0 :                         return r;
     284                 :            : 
     285         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids)))
     286                 :          0 :                         return -ENOMEM;
     287                 :            : 
     288         [ #  # ]:          0 :                 HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) {
     289                 :          0 :                         pids[n++] = PTR_TO_PID(pidp);
     290                 :            : 
     291                 :          0 :                         r = hashmap_put(names, pidp, (void*) name);
     292         [ #  # ]:          0 :                         if (r < 0)
     293                 :          0 :                                 return r;
     294                 :            :                 }
     295                 :            :         }
     296                 :            : 
     297         [ #  # ]:          0 :         if (n == 0)
     298                 :          0 :                 return 0;
     299                 :            : 
     300                 :          0 :         typesafe_qsort(pids, n, pid_compare_func);
     301         [ #  # ]:          0 :         width = DECIMAL_STR_WIDTH(pids[n-1]);
     302                 :            : 
     303         [ #  # ]:          0 :         for (k = 0; k < n; k++) {
     304                 :          0 :                 _cleanup_free_ char *e = NULL;
     305                 :            :                 const char *name;
     306                 :            : 
     307                 :          0 :                 name = hashmap_get(names, PID_TO_PTR(pids[k]));
     308         [ #  # ]:          0 :                 assert(name);
     309                 :            : 
     310         [ #  # ]:          0 :                 if (n_columns != 0) {
     311                 :            :                         unsigned z;
     312                 :            : 
     313         [ #  # ]:          0 :                         z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
     314                 :            : 
     315                 :          0 :                         e = ellipsize(name, z, 100);
     316         [ #  # ]:          0 :                         if (e)
     317                 :          0 :                                 name = e;
     318                 :            :                 }
     319                 :            : 
     320                 :          0 :                 fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
     321                 :            :                         prefix,
     322                 :            :                         special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET),
     323                 :          0 :                         width, pids[k],
     324                 :            :                         name);
     325                 :            :         }
     326                 :            : 
     327                 :          0 :         return 0;
     328                 :            : }
     329                 :            : 
     330                 :          0 : int unit_show_processes(
     331                 :            :                 sd_bus *bus,
     332                 :            :                 const char *unit,
     333                 :            :                 const char *cgroup_path,
     334                 :            :                 const char *prefix,
     335                 :            :                 unsigned n_columns,
     336                 :            :                 OutputFlags flags,
     337                 :            :                 sd_bus_error *error) {
     338                 :            : 
     339                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     340                 :          0 :         Hashmap *cgroups = NULL;
     341                 :            :         struct CGroupInfo *cg;
     342                 :            :         int r;
     343                 :            : 
     344         [ #  # ]:          0 :         assert(bus);
     345         [ #  # ]:          0 :         assert(unit);
     346                 :            : 
     347         [ #  # ]:          0 :         if (flags & OUTPUT_FULL_WIDTH)
     348                 :          0 :                 n_columns = 0;
     349         [ #  # ]:          0 :         else if (n_columns <= 0)
     350                 :          0 :                 n_columns = columns();
     351                 :            : 
     352                 :          0 :         prefix = strempty(prefix);
     353                 :            : 
     354                 :          0 :         r = sd_bus_call_method(
     355                 :            :                         bus,
     356                 :            :                         "org.freedesktop.systemd1",
     357                 :            :                         "/org/freedesktop/systemd1",
     358                 :            :                         "org.freedesktop.systemd1.Manager",
     359                 :            :                         "GetUnitProcesses",
     360                 :            :                         error,
     361                 :            :                         &reply,
     362                 :            :                         "s",
     363                 :            :                         unit);
     364         [ #  # ]:          0 :         if (r < 0)
     365                 :          0 :                 return r;
     366                 :            : 
     367                 :          0 :         cgroups = hashmap_new(&path_hash_ops);
     368         [ #  # ]:          0 :         if (!cgroups)
     369                 :          0 :                 return -ENOMEM;
     370                 :            : 
     371                 :          0 :         r = sd_bus_message_enter_container(reply, 'a', "(sus)");
     372         [ #  # ]:          0 :         if (r < 0)
     373                 :          0 :                 goto finish;
     374                 :            : 
     375                 :          0 :         for (;;) {
     376                 :          0 :                 const char *path = NULL, *name = NULL;
     377                 :            :                 uint32_t pid;
     378                 :            : 
     379                 :          0 :                 r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name);
     380         [ #  # ]:          0 :                 if (r < 0)
     381                 :          0 :                         goto finish;
     382         [ #  # ]:          0 :                 if (r == 0)
     383                 :          0 :                         break;
     384                 :            : 
     385                 :          0 :                 r = add_process(cgroups, path, pid, name);
     386         [ #  # ]:          0 :                 if (r == -ENOMEM)
     387                 :          0 :                         goto finish;
     388         [ #  # ]:          0 :                 if (r < 0)
     389         [ #  # ]:          0 :                         log_warning_errno(r, "Invalid process description in GetUnitProcesses reply: cgroup=\"%s\" pid="PID_FMT" command=\"%s\", ignoring: %m",
     390                 :            :                                           path, pid, name);
     391                 :            :         }
     392                 :            : 
     393                 :          0 :         r = sd_bus_message_exit_container(reply);
     394         [ #  # ]:          0 :         if (r < 0)
     395                 :          0 :                 goto finish;
     396                 :            : 
     397                 :          0 :         r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags);
     398         [ #  # ]:          0 :         if (r < 0)
     399                 :          0 :                 goto finish;
     400                 :            : 
     401                 :          0 :         r = dump_extra_processes(cgroups, prefix, n_columns, flags);
     402                 :            : 
     403                 :          0 : finish:
     404         [ #  # ]:          0 :         while ((cg = hashmap_first(cgroups)))
     405                 :          0 :                remove_cgroup(cgroups, cg);
     406                 :            : 
     407                 :          0 :         hashmap_free(cgroups);
     408                 :            : 
     409                 :          0 :         return r;
     410                 :            : }

Generated by: LCOV version 1.14