LCOV - code coverage report
Current view: top level - shared - condition.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 305 419 72.8 %
Date: 2019-08-23 13:36:53 Functions: 36 40 90.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 225 474 47.5 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <fcntl.h>
       5                 :            : #include <fnmatch.h>
       6                 :            : #include <limits.h>
       7                 :            : #include <stdlib.h>
       8                 :            : #include <string.h>
       9                 :            : #include <sys/stat.h>
      10                 :            : #include <sys/types.h>
      11                 :            : #include <sys/utsname.h>
      12                 :            : #include <time.h>
      13                 :            : #include <unistd.h>
      14                 :            : 
      15                 :            : #include "sd-id128.h"
      16                 :            : 
      17                 :            : #include "alloc-util.h"
      18                 :            : #include "apparmor-util.h"
      19                 :            : #include "architecture.h"
      20                 :            : #include "audit-util.h"
      21                 :            : #include "cap-list.h"
      22                 :            : #include "cgroup-util.h"
      23                 :            : #include "condition.h"
      24                 :            : #include "cpu-set-util.h"
      25                 :            : #include "efivars.h"
      26                 :            : #include "env-file.h"
      27                 :            : #include "extract-word.h"
      28                 :            : #include "fd-util.h"
      29                 :            : #include "fileio.h"
      30                 :            : #include "glob-util.h"
      31                 :            : #include "hostname-util.h"
      32                 :            : #include "ima-util.h"
      33                 :            : #include "limits-util.h"
      34                 :            : #include "list.h"
      35                 :            : #include "macro.h"
      36                 :            : #include "mountpoint-util.h"
      37                 :            : #include "parse-util.h"
      38                 :            : #include "path-util.h"
      39                 :            : #include "proc-cmdline.h"
      40                 :            : #include "process-util.h"
      41                 :            : #include "selinux-util.h"
      42                 :            : #include "smack-util.h"
      43                 :            : #include "stat-util.h"
      44                 :            : #include "string-table.h"
      45                 :            : #include "string-util.h"
      46                 :            : #include "tomoyo-util.h"
      47                 :            : #include "user-util.h"
      48                 :            : #include "util.h"
      49                 :            : #include "virt.h"
      50                 :            : 
      51                 :        664 : Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
      52                 :            :         Condition *c;
      53                 :            : 
      54         [ -  + ]:        664 :         assert(type >= 0);
      55         [ -  + ]:        664 :         assert(type < _CONDITION_TYPE_MAX);
      56         [ -  + ]:        664 :         assert((!parameter) == (type == CONDITION_NULL));
      57                 :            : 
      58                 :        664 :         c = new(Condition, 1);
      59         [ -  + ]:        664 :         if (!c)
      60                 :          0 :                 return NULL;
      61                 :            : 
      62                 :        664 :         *c = (Condition) {
      63                 :            :                 .type = type,
      64                 :            :                 .trigger = trigger,
      65                 :            :                 .negate = negate,
      66                 :            :         };
      67                 :            : 
      68         [ +  + ]:        664 :         if (parameter) {
      69                 :        656 :                 c->parameter = strdup(parameter);
      70         [ -  + ]:        656 :                 if (!c->parameter)
      71                 :          0 :                         return mfree(c);
      72                 :            :         }
      73                 :            : 
      74                 :        664 :         return c;
      75                 :            : }
      76                 :            : 
      77                 :        664 : void condition_free(Condition *c) {
      78         [ -  + ]:        664 :         assert(c);
      79                 :            : 
      80                 :        664 :         free(c->parameter);
      81                 :        664 :         free(c);
      82                 :        664 : }
      83                 :            : 
      84                 :      17564 : Condition* condition_free_list_type(Condition *head, ConditionType type) {
      85                 :            :         Condition *c, *n;
      86                 :            : 
      87         [ +  + ]:      17568 :         LIST_FOREACH_SAFE(conditions, c, n, head)
      88   [ -  +  #  # ]:          4 :                 if (type < 0 || c->type == type) {
      89   [ -  +  -  +  :          4 :                         LIST_REMOVE(conditions, head, c);
             -  +  -  + ]
      90                 :          4 :                         condition_free(c);
      91                 :            :                 }
      92                 :            : 
      93   [ +  +  -  + ]:      17564 :         assert(type >= 0 || !head);
      94                 :      17564 :         return head;
      95                 :            : }
      96                 :            : 
      97                 :          8 : static int condition_test_kernel_command_line(Condition *c) {
      98                 :          8 :         _cleanup_free_ char *line = NULL;
      99                 :            :         const char *p;
     100                 :            :         bool equal;
     101                 :            :         int r;
     102                 :            : 
     103         [ -  + ]:          8 :         assert(c);
     104         [ -  + ]:          8 :         assert(c->parameter);
     105         [ -  + ]:          8 :         assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
     106                 :            : 
     107                 :          8 :         r = proc_cmdline(&line);
     108         [ -  + ]:          8 :         if (r < 0)
     109                 :          0 :                 return r;
     110                 :            : 
     111                 :          8 :         equal = strchr(c->parameter, '=');
     112                 :            : 
     113                 :         80 :         for (p = line;;) {
     114      [ +  -  + ]:         80 :                 _cleanup_free_ char *word = NULL;
     115                 :            :                 bool found;
     116                 :            : 
     117                 :         80 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX);
     118         [ -  + ]:         80 :                 if (r < 0)
     119                 :          0 :                         return r;
     120         [ +  + ]:         80 :                 if (r == 0)
     121                 :          8 :                         break;
     122                 :            : 
     123         [ +  + ]:         72 :                 if (equal)
     124                 :         36 :                         found = streq(word, c->parameter);
     125                 :            :                 else {
     126                 :            :                         const char *f;
     127                 :            : 
     128                 :         36 :                         f = startswith(word, c->parameter);
     129   [ -  +  #  #  :         36 :                         found = f && IN_SET(*f, 0, '=');
                   #  # ]
     130                 :            :                 }
     131                 :            : 
     132         [ -  + ]:         72 :                 if (found)
     133                 :          0 :                         return true;
     134                 :            :         }
     135                 :            : 
     136                 :          8 :         return false;
     137                 :            : }
     138                 :            : 
     139                 :            : typedef enum {
     140                 :            :         /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest
     141                 :            :          * should be listed first. */
     142                 :            :         ORDER_LOWER_OR_EQUAL,
     143                 :            :         ORDER_GREATER_OR_EQUAL,
     144                 :            :         ORDER_LOWER,
     145                 :            :         ORDER_GREATER,
     146                 :            :         ORDER_EQUAL,
     147                 :            :         ORDER_UNEQUAL,
     148                 :            :         _ORDER_MAX,
     149                 :            :         _ORDER_INVALID = -1
     150                 :            : } OrderOperator;
     151                 :            : 
     152                 :        244 : static OrderOperator parse_order(const char **s) {
     153                 :            : 
     154                 :            :         static const char *const prefix[_ORDER_MAX] = {
     155                 :            :                 [ORDER_LOWER_OR_EQUAL] = "<=",
     156                 :            :                 [ORDER_GREATER_OR_EQUAL] = ">=",
     157                 :            :                 [ORDER_LOWER] = "<",
     158                 :            :                 [ORDER_GREATER] = ">",
     159                 :            :                 [ORDER_EQUAL] = "=",
     160                 :            :                 [ORDER_UNEQUAL] = "!=",
     161                 :            :         };
     162                 :            : 
     163                 :            :         OrderOperator i;
     164                 :            : 
     165         [ +  + ]:        884 :         for (i = 0; i < _ORDER_MAX; i++) {
     166                 :            :                 const char *e;
     167                 :            : 
     168                 :        868 :                 e = startswith(*s, prefix[i]);
     169         [ +  + ]:        868 :                 if (e) {
     170                 :        228 :                         *s = e;
     171                 :        228 :                         return i;
     172                 :            :                 }
     173                 :            :         }
     174                 :            : 
     175                 :         16 :         return _ORDER_INVALID;
     176                 :            : }
     177                 :            : 
     178                 :        220 : static bool test_order(int k, OrderOperator p) {
     179                 :            : 
     180   [ +  +  +  +  :        220 :         switch (p) {
                +  +  - ]
     181                 :            : 
     182                 :         40 :         case ORDER_LOWER:
     183                 :         40 :                 return k < 0;
     184                 :            : 
     185                 :         36 :         case ORDER_LOWER_OR_EQUAL:
     186                 :         36 :                 return k <= 0;
     187                 :            : 
     188                 :         36 :         case ORDER_EQUAL:
     189                 :         36 :                 return k == 0;
     190                 :            : 
     191                 :         24 :         case ORDER_UNEQUAL:
     192                 :         24 :                 return k != 0;
     193                 :            : 
     194                 :         36 :         case ORDER_GREATER_OR_EQUAL:
     195                 :         36 :                 return k >= 0;
     196                 :            : 
     197                 :         48 :         case ORDER_GREATER:
     198                 :         48 :                 return k > 0;
     199                 :            : 
     200                 :          0 :         default:
     201                 :          0 :                 assert_not_reached("unknown order");
     202                 :            : 
     203                 :            :         }
     204                 :            : }
     205                 :            : 
     206                 :         96 : static int condition_test_kernel_version(Condition *c) {
     207                 :            :         OrderOperator order;
     208                 :            :         struct utsname u;
     209                 :            :         const char *p;
     210                 :         96 :         bool first = true;
     211                 :            : 
     212         [ -  + ]:         96 :         assert(c);
     213         [ -  + ]:         96 :         assert(c->parameter);
     214         [ -  + ]:         96 :         assert(c->type == CONDITION_KERNEL_VERSION);
     215                 :            : 
     216         [ -  + ]:         96 :         assert_se(uname(&u) >= 0);
     217                 :            : 
     218                 :         96 :         p = c->parameter;
     219                 :            : 
     220                 :         56 :         for (;;) {
     221      [ +  +  + ]:        152 :                 _cleanup_free_ char *word = NULL;
     222                 :            :                 const char *s;
     223                 :            :                 int r;
     224                 :            : 
     225                 :        152 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
     226         [ -  + ]:        152 :                 if (r < 0)
     227         [ #  # ]:          0 :                         return log_debug_errno(r, "Failed to parse condition string \"%s\": %m", p);
     228         [ +  + ]:        152 :                 if (r == 0)
     229                 :         52 :                         break;
     230                 :            : 
     231                 :        100 :                 s = strstrip(word);
     232                 :        100 :                 order = parse_order(&s);
     233         [ +  + ]:        100 :                 if (order >= 0) {
     234                 :         84 :                         s += strspn(s, WHITESPACE);
     235         [ +  + ]:         84 :                         if (isempty(s)) {
     236         [ +  + ]:         64 :                                 if (first) {
     237                 :            :                                         /* For backwards compatibility, allow whitespace between the operator and
     238                 :            :                                          * value, without quoting, but only in the first expression. */
     239                 :         60 :                                         word = mfree(word);
     240                 :         60 :                                         r = extract_first_word(&p, &word, NULL, 0);
     241         [ -  + ]:         60 :                                         if (r < 0)
     242         [ #  # ]:          0 :                                                 return log_debug_errno(r, "Failed to parse condition string \"%s\": %m", p);
     243         [ +  + ]:         60 :                                         if (r == 0)
     244         [ +  - ]:          4 :                                                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p);
     245                 :         56 :                                         s = word;
     246                 :            :                                 } else
     247         [ +  - ]:          4 :                                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p);
     248                 :            :                         }
     249                 :            : 
     250                 :         76 :                         r = test_order(str_verscmp(u.release, s), order);
     251                 :            :                 } else
     252                 :            :                         /* No prefix? Then treat as glob string */
     253                 :         16 :                         r = fnmatch(s, u.release, 0) == 0;
     254                 :            : 
     255         [ +  + ]:         92 :                 if (r == 0)
     256                 :         36 :                         return false;
     257                 :            : 
     258                 :         56 :                 first = false;
     259                 :            :         }
     260                 :            : 
     261                 :         52 :         return true;
     262                 :            : }
     263                 :            : 
     264                 :         72 : static int condition_test_memory(Condition *c) {
     265                 :            :         OrderOperator order;
     266                 :            :         uint64_t m, k;
     267                 :            :         const char *p;
     268                 :            :         int r;
     269                 :            : 
     270         [ -  + ]:         72 :         assert(c);
     271         [ -  + ]:         72 :         assert(c->parameter);
     272         [ -  + ]:         72 :         assert(c->type == CONDITION_MEMORY);
     273                 :            : 
     274                 :         72 :         m = physical_memory();
     275                 :            : 
     276                 :         72 :         p = c->parameter;
     277                 :         72 :         order = parse_order(&p);
     278         [ -  + ]:         72 :         if (order < 0)
     279                 :          0 :                 order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
     280                 :            : 
     281                 :         72 :         r = safe_atou64(p, &k);
     282         [ -  + ]:         72 :         if (r < 0)
     283         [ #  # ]:          0 :                 return log_debug_errno(r, "Failed to parse size: %m");
     284                 :            : 
     285         [ +  + ]:         72 :         return test_order(CMP(m, k), order);
     286                 :            : }
     287                 :            : 
     288                 :         72 : static int condition_test_cpus(Condition *c) {
     289                 :            :         OrderOperator order;
     290                 :            :         const char *p;
     291                 :            :         unsigned k;
     292                 :            :         int r, n;
     293                 :            : 
     294         [ -  + ]:         72 :         assert(c);
     295         [ -  + ]:         72 :         assert(c->parameter);
     296         [ -  + ]:         72 :         assert(c->type == CONDITION_CPUS);
     297                 :            : 
     298                 :         72 :         n = cpus_in_affinity_mask();
     299         [ -  + ]:         72 :         if (n < 0)
     300         [ #  # ]:          0 :                 return log_debug_errno(n, "Failed to determine CPUs in affinity mask: %m");
     301                 :            : 
     302                 :         72 :         p = c->parameter;
     303                 :         72 :         order = parse_order(&p);
     304         [ -  + ]:         72 :         if (order < 0)
     305                 :          0 :                 order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
     306                 :            : 
     307                 :         72 :         r = safe_atou(p, &k);
     308         [ -  + ]:         72 :         if (r < 0)
     309         [ #  # ]:          0 :                 return log_debug_errno(r, "Failed to parse number of CPUs: %m");
     310                 :            : 
     311         [ +  + ]:         72 :         return test_order(CMP((unsigned) n, k), order);
     312                 :            : }
     313                 :            : 
     314                 :         28 : static int condition_test_user(Condition *c) {
     315                 :            :         uid_t id;
     316                 :            :         int r;
     317                 :         28 :         _cleanup_free_ char *username = NULL;
     318                 :            :         const char *u;
     319                 :            : 
     320         [ -  + ]:         28 :         assert(c);
     321         [ -  + ]:         28 :         assert(c->parameter);
     322         [ -  + ]:         28 :         assert(c->type == CONDITION_USER);
     323                 :            : 
     324                 :         28 :         r = parse_uid(c->parameter, &id);
     325         [ +  + ]:         28 :         if (r >= 0)
     326   [ +  +  -  + ]:          8 :                 return id == getuid() || id == geteuid();
     327                 :            : 
     328         [ +  + ]:         20 :         if (streq("@system", c->parameter))
     329   [ +  -  -  + ]:          4 :                 return uid_is_system(getuid()) || uid_is_system(geteuid());
     330                 :            : 
     331                 :         16 :         username = getusername_malloc();
     332         [ -  + ]:         16 :         if (!username)
     333                 :          0 :                 return -ENOMEM;
     334                 :            : 
     335         [ +  + ]:         16 :         if (streq(username, c->parameter))
     336                 :          4 :                 return 1;
     337                 :            : 
     338         [ -  + ]:         12 :         if (getpid_cached() == 1)
     339                 :          0 :                 return streq(c->parameter, "root");
     340                 :            : 
     341                 :         12 :         u = c->parameter;
     342                 :         12 :         r = get_user_creds(&u, &id, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
     343         [ +  + ]:         12 :         if (r < 0)
     344                 :          8 :                 return 0;
     345                 :            : 
     346   [ +  -  -  + ]:          4 :         return id == getuid() || id == geteuid();
     347                 :            : }
     348                 :            : 
     349                 :         88 : static int condition_test_control_group_controller(Condition *c) {
     350                 :            :         int r;
     351                 :         88 :         CGroupMask system_mask, wanted_mask = 0;
     352                 :            : 
     353         [ -  + ]:         88 :         assert(c);
     354         [ -  + ]:         88 :         assert(c->parameter);
     355         [ -  + ]:         88 :         assert(c->type == CONDITION_CONTROL_GROUP_CONTROLLER);
     356                 :            : 
     357                 :         88 :         r = cg_mask_supported(&system_mask);
     358         [ -  + ]:         88 :         if (r < 0)
     359         [ #  # ]:          0 :                 return log_debug_errno(r, "Failed to determine supported controllers: %m");
     360                 :            : 
     361                 :         88 :         r = cg_mask_from_string(c->parameter, &wanted_mask);
     362   [ +  -  +  + ]:         88 :         if (r < 0 || wanted_mask <= 0) {
     363                 :            :                 /* This won't catch the case that we have an unknown controller
     364                 :            :                  * mixed in with valid ones -- these are only assessed on the
     365                 :            :                  * validity of the valid controllers found. */
     366         [ +  - ]:          8 :                 log_debug("Failed to parse cgroup string: %s", c->parameter);
     367                 :          8 :                 return 1;
     368                 :            :         }
     369                 :            : 
     370                 :         80 :         return FLAGS_SET(system_mask, wanted_mask);
     371                 :            : }
     372                 :            : 
     373                 :         88 : static int condition_test_group(Condition *c) {
     374                 :            :         gid_t id;
     375                 :            :         int r;
     376                 :            : 
     377         [ -  + ]:         88 :         assert(c);
     378         [ -  + ]:         88 :         assert(c->parameter);
     379         [ -  + ]:         88 :         assert(c->type == CONDITION_GROUP);
     380                 :            : 
     381                 :         88 :         r = parse_gid(c->parameter, &id);
     382         [ +  + ]:         88 :         if (r >= 0)
     383                 :         44 :                 return in_gid(id);
     384                 :            : 
     385                 :            :         /* Avoid any NSS lookups if we are PID1 */
     386         [ -  + ]:         44 :         if (getpid_cached() == 1)
     387                 :          0 :                 return streq(c->parameter, "root");
     388                 :            : 
     389                 :         44 :         return in_group(c->parameter) > 0;
     390                 :            : }
     391                 :            : 
     392                 :         68 : static int condition_test_virtualization(Condition *c) {
     393                 :            :         int b, v;
     394                 :            : 
     395         [ -  + ]:         68 :         assert(c);
     396         [ -  + ]:         68 :         assert(c->parameter);
     397         [ -  + ]:         68 :         assert(c->type == CONDITION_VIRTUALIZATION);
     398                 :            : 
     399         [ +  + ]:         68 :         if (streq(c->parameter, "private-users"))
     400                 :          4 :                 return running_in_userns();
     401                 :            : 
     402                 :         64 :         v = detect_virtualization();
     403         [ -  + ]:         64 :         if (v < 0)
     404                 :          0 :                 return v;
     405                 :            : 
     406                 :            :         /* First, compare with yes/no */
     407                 :         64 :         b = parse_boolean(c->parameter);
     408         [ -  + ]:         64 :         if (b >= 0)
     409                 :          0 :                 return b == !!v;
     410                 :            : 
     411                 :            :         /* Then, compare categorization */
     412         [ +  + ]:         64 :         if (streq(c->parameter, "vm"))
     413                 :          4 :                 return VIRTUALIZATION_IS_VM(v);
     414                 :            : 
     415         [ +  + ]:         60 :         if (streq(c->parameter, "container"))
     416                 :          8 :                 return VIRTUALIZATION_IS_CONTAINER(v);
     417                 :            : 
     418                 :            :         /* Finally compare id */
     419   [ -  +  #  # ]:         52 :         return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
     420                 :            : }
     421                 :            : 
     422                 :         12 : static int condition_test_architecture(Condition *c) {
     423                 :            :         int a, b;
     424                 :            : 
     425         [ -  + ]:         12 :         assert(c);
     426         [ -  + ]:         12 :         assert(c->parameter);
     427         [ -  + ]:         12 :         assert(c->type == CONDITION_ARCHITECTURE);
     428                 :            : 
     429                 :         12 :         a = uname_architecture();
     430         [ -  + ]:         12 :         if (a < 0)
     431                 :          0 :                 return a;
     432                 :            : 
     433         [ -  + ]:         12 :         if (streq(c->parameter, "native"))
     434                 :          0 :                 b = native_architecture();
     435                 :            :         else {
     436                 :         12 :                 b = architecture_from_string(c->parameter);
     437         [ +  + ]:         12 :                 if (b < 0) /* unknown architecture? Then it's definitely not ours */
     438                 :          4 :                         return false;
     439                 :            :         }
     440                 :            : 
     441                 :          8 :         return a == b;
     442                 :            : }
     443                 :            : 
     444                 :         16 : static int condition_test_host(Condition *c) {
     445                 :         16 :         _cleanup_free_ char *h = NULL;
     446                 :            :         sd_id128_t x, y;
     447                 :            :         int r;
     448                 :            : 
     449         [ -  + ]:         16 :         assert(c);
     450         [ -  + ]:         16 :         assert(c->parameter);
     451         [ -  + ]:         16 :         assert(c->type == CONDITION_HOST);
     452                 :            : 
     453         [ +  + ]:         16 :         if (sd_id128_from_string(c->parameter, &x) >= 0) {
     454                 :            : 
     455                 :          8 :                 r = sd_id128_get_machine(&y);
     456         [ -  + ]:          8 :                 if (r < 0)
     457                 :          0 :                         return r;
     458                 :            : 
     459                 :          8 :                 return sd_id128_equal(x, y);
     460                 :            :         }
     461                 :            : 
     462                 :          8 :         h = gethostname_malloc();
     463         [ -  + ]:          8 :         if (!h)
     464                 :          0 :                 return -ENOMEM;
     465                 :            : 
     466                 :          8 :         return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
     467                 :            : }
     468                 :            : 
     469                 :         12 : static int condition_test_ac_power(Condition *c) {
     470                 :            :         int r;
     471                 :            : 
     472         [ -  + ]:         12 :         assert(c);
     473         [ -  + ]:         12 :         assert(c->parameter);
     474         [ -  + ]:         12 :         assert(c->type == CONDITION_AC_POWER);
     475                 :            : 
     476                 :         12 :         r = parse_boolean(c->parameter);
     477         [ -  + ]:         12 :         if (r < 0)
     478                 :          0 :                 return r;
     479                 :            : 
     480                 :         12 :         return (on_ac_power() != 0) == !!r;
     481                 :            : }
     482                 :            : 
     483                 :         32 : static int condition_test_security(Condition *c) {
     484         [ -  + ]:         32 :         assert(c);
     485         [ -  + ]:         32 :         assert(c->parameter);
     486         [ -  + ]:         32 :         assert(c->type == CONDITION_SECURITY);
     487                 :            : 
     488         [ +  + ]:         32 :         if (streq(c->parameter, "selinux"))
     489                 :          4 :                 return mac_selinux_use();
     490         [ +  + ]:         28 :         if (streq(c->parameter, "smack"))
     491                 :          4 :                 return mac_smack_use();
     492         [ +  + ]:         24 :         if (streq(c->parameter, "apparmor"))
     493                 :          4 :                 return mac_apparmor_use();
     494         [ +  + ]:         20 :         if (streq(c->parameter, "audit"))
     495                 :          4 :                 return use_audit();
     496         [ +  + ]:         16 :         if (streq(c->parameter, "ima"))
     497                 :          4 :                 return use_ima();
     498         [ +  + ]:         12 :         if (streq(c->parameter, "tomoyo"))
     499                 :          4 :                 return mac_tomoyo_use();
     500         [ +  + ]:          8 :         if (streq(c->parameter, "uefi-secureboot"))
     501                 :          4 :                 return is_efi_secure_boot();
     502                 :            : 
     503                 :          4 :         return false;
     504                 :            : }
     505                 :            : 
     506                 :          0 : static int condition_test_capability(Condition *c) {
     507                 :          0 :         unsigned long long capabilities = (unsigned long long) -1;
     508                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     509                 :            :         int value, r;
     510                 :            : 
     511         [ #  # ]:          0 :         assert(c);
     512         [ #  # ]:          0 :         assert(c->parameter);
     513         [ #  # ]:          0 :         assert(c->type == CONDITION_CAPABILITY);
     514                 :            : 
     515                 :            :         /* If it's an invalid capability, we don't have it */
     516                 :          0 :         value = capability_from_name(c->parameter);
     517         [ #  # ]:          0 :         if (value < 0)
     518                 :          0 :                 return -EINVAL;
     519                 :            : 
     520                 :            :         /* If it's a valid capability we default to assume
     521                 :            :          * that we have it */
     522                 :            : 
     523                 :          0 :         f = fopen("/proc/self/status", "re");
     524         [ #  # ]:          0 :         if (!f)
     525                 :          0 :                 return -errno;
     526                 :            : 
     527                 :          0 :         for (;;) {
     528      [ #  #  # ]:          0 :                 _cleanup_free_ char *line = NULL;
     529                 :            :                 const char *p;
     530                 :            : 
     531                 :          0 :                 r = read_line(f, LONG_LINE_MAX, &line);
     532         [ #  # ]:          0 :                 if (r < 0)
     533                 :          0 :                         return r;
     534         [ #  # ]:          0 :                 if (r == 0)
     535                 :          0 :                         break;
     536                 :            : 
     537                 :          0 :                 p = startswith(line, "CapBnd:");
     538         [ #  # ]:          0 :                 if (p) {
     539         [ #  # ]:          0 :                         if (sscanf(line+7, "%llx", &capabilities) != 1)
     540                 :          0 :                                 return -EIO;
     541                 :            : 
     542                 :          0 :                         break;
     543                 :            :                 }
     544                 :            :         }
     545                 :            : 
     546                 :          0 :         return !!(capabilities & (1ULL << value));
     547                 :            : }
     548                 :            : 
     549                 :          0 : static int condition_test_needs_update(Condition *c) {
     550                 :            :         const char *p;
     551                 :            :         struct stat usr, other;
     552                 :            : 
     553         [ #  # ]:          0 :         assert(c);
     554         [ #  # ]:          0 :         assert(c->parameter);
     555         [ #  # ]:          0 :         assert(c->type == CONDITION_NEEDS_UPDATE);
     556                 :            : 
     557                 :            :         /* If the file system is read-only we shouldn't suggest an update */
     558         [ #  # ]:          0 :         if (path_is_read_only_fs(c->parameter) > 0)
     559                 :          0 :                 return false;
     560                 :            : 
     561                 :            :         /* Any other failure means we should allow the condition to be true,
     562                 :            :          * so that we rather invoke too many update tools than too
     563                 :            :          * few. */
     564                 :            : 
     565         [ #  # ]:          0 :         if (!path_is_absolute(c->parameter))
     566                 :          0 :                 return true;
     567                 :            : 
     568   [ #  #  #  #  :          0 :         p = strjoina(c->parameter, "/.updated");
          #  #  #  #  #  
                #  #  # ]
     569         [ #  # ]:          0 :         if (lstat(p, &other) < 0)
     570                 :          0 :                 return true;
     571                 :            : 
     572         [ #  # ]:          0 :         if (lstat("/usr/", &usr) < 0)
     573                 :          0 :                 return true;
     574                 :            : 
     575                 :            :         /*
     576                 :            :          * First, compare seconds as they are always accurate...
     577                 :            :          */
     578         [ #  # ]:          0 :         if (usr.st_mtim.tv_sec != other.st_mtim.tv_sec)
     579                 :          0 :                 return usr.st_mtim.tv_sec > other.st_mtim.tv_sec;
     580                 :            : 
     581                 :            :         /*
     582                 :            :          * ...then compare nanoseconds.
     583                 :            :          *
     584                 :            :          * A false positive is only possible when /usr's nanoseconds > 0
     585                 :            :          * (otherwise /usr cannot be strictly newer than the target file)
     586                 :            :          * AND the target file's nanoseconds == 0
     587                 :            :          * (otherwise the filesystem supports nsec timestamps, see stat(2)).
     588                 :            :          */
     589   [ #  #  #  # ]:          0 :         if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
     590         [ #  # ]:          0 :                 _cleanup_free_ char *timestamp_str = NULL;
     591                 :            :                 uint64_t timestamp;
     592                 :            :                 int r;
     593                 :            : 
     594                 :          0 :                 r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", &timestamp_str);
     595         [ #  # ]:          0 :                 if (r < 0) {
     596         [ #  # ]:          0 :                         log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
     597                 :          0 :                         return true;
     598         [ #  # ]:          0 :                 } else if (r == 0) {
     599         [ #  # ]:          0 :                         log_debug("No data in timestamp file '%s', using mtime", p);
     600                 :          0 :                         return true;
     601                 :            :                 }
     602                 :            : 
     603                 :          0 :                 r = safe_atou64(timestamp_str, &timestamp);
     604         [ #  # ]:          0 :                 if (r < 0) {
     605         [ #  # ]:          0 :                         log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
     606                 :          0 :                         return true;
     607                 :            :                 }
     608                 :            : 
     609                 :          0 :                 timespec_store(&other.st_mtim, timestamp);
     610                 :            :         }
     611                 :            : 
     612                 :          0 :         return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
     613                 :            : }
     614                 :            : 
     615                 :          0 : static int condition_test_first_boot(Condition *c) {
     616                 :            :         int r;
     617                 :            : 
     618         [ #  # ]:          0 :         assert(c);
     619         [ #  # ]:          0 :         assert(c->parameter);
     620         [ #  # ]:          0 :         assert(c->type == CONDITION_FIRST_BOOT);
     621                 :            : 
     622                 :          0 :         r = parse_boolean(c->parameter);
     623         [ #  # ]:          0 :         if (r < 0)
     624                 :          0 :                 return r;
     625                 :            : 
     626                 :          0 :         return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
     627                 :            : }
     628                 :            : 
     629                 :         16 : static int condition_test_path_exists(Condition *c) {
     630         [ -  + ]:         16 :         assert(c);
     631         [ -  + ]:         16 :         assert(c->parameter);
     632         [ -  + ]:         16 :         assert(c->type == CONDITION_PATH_EXISTS);
     633                 :            : 
     634                 :         16 :         return access(c->parameter, F_OK) >= 0;
     635                 :            : }
     636                 :            : 
     637                 :          8 : static int condition_test_path_exists_glob(Condition *c) {
     638         [ -  + ]:          8 :         assert(c);
     639         [ -  + ]:          8 :         assert(c->parameter);
     640         [ -  + ]:          8 :         assert(c->type == CONDITION_PATH_EXISTS_GLOB);
     641                 :            : 
     642                 :          8 :         return glob_exists(c->parameter) > 0;
     643                 :            : }
     644                 :            : 
     645                 :          4 : static int condition_test_path_is_directory(Condition *c) {
     646         [ -  + ]:          4 :         assert(c);
     647         [ -  + ]:          4 :         assert(c->parameter);
     648         [ -  + ]:          4 :         assert(c->type == CONDITION_PATH_IS_DIRECTORY);
     649                 :            : 
     650                 :          4 :         return is_dir(c->parameter, true) > 0;
     651                 :            : }
     652                 :            : 
     653                 :          4 : static int condition_test_path_is_symbolic_link(Condition *c) {
     654         [ -  + ]:          4 :         assert(c);
     655         [ -  + ]:          4 :         assert(c->parameter);
     656         [ -  + ]:          4 :         assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
     657                 :            : 
     658                 :          4 :         return is_symlink(c->parameter) > 0;
     659                 :            : }
     660                 :            : 
     661                 :         12 : static int condition_test_path_is_mount_point(Condition *c) {
     662         [ -  + ]:         12 :         assert(c);
     663         [ -  + ]:         12 :         assert(c->parameter);
     664         [ -  + ]:         12 :         assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
     665                 :            : 
     666                 :         12 :         return path_is_mount_point(c->parameter, NULL, AT_SYMLINK_FOLLOW) > 0;
     667                 :            : }
     668                 :            : 
     669                 :          4 : static int condition_test_path_is_read_write(Condition *c) {
     670         [ -  + ]:          4 :         assert(c);
     671         [ -  + ]:          4 :         assert(c->parameter);
     672         [ -  + ]:          4 :         assert(c->type == CONDITION_PATH_IS_READ_WRITE);
     673                 :            : 
     674                 :          4 :         return path_is_read_only_fs(c->parameter) <= 0;
     675                 :            : }
     676                 :            : 
     677                 :          4 : static int condition_test_directory_not_empty(Condition *c) {
     678                 :            :         int r;
     679                 :            : 
     680         [ -  + ]:          4 :         assert(c);
     681         [ -  + ]:          4 :         assert(c->parameter);
     682         [ -  + ]:          4 :         assert(c->type == CONDITION_DIRECTORY_NOT_EMPTY);
     683                 :            : 
     684                 :          4 :         r = dir_is_empty(c->parameter);
     685   [ +  -  +  - ]:          4 :         return r <= 0 && r != -ENOENT;
     686                 :            : }
     687                 :            : 
     688                 :          4 : static int condition_test_file_not_empty(Condition *c) {
     689                 :            :         struct stat st;
     690                 :            : 
     691         [ -  + ]:          4 :         assert(c);
     692         [ -  + ]:          4 :         assert(c->parameter);
     693         [ -  + ]:          4 :         assert(c->type == CONDITION_FILE_NOT_EMPTY);
     694                 :            : 
     695                 :          4 :         return (stat(c->parameter, &st) >= 0 &&
     696   [ +  -  +  - ]:          8 :                 S_ISREG(st.st_mode) &&
     697         [ +  - ]:          4 :                 st.st_size > 0);
     698                 :            : }
     699                 :            : 
     700                 :          8 : static int condition_test_file_is_executable(Condition *c) {
     701                 :            :         struct stat st;
     702                 :            : 
     703         [ -  + ]:          8 :         assert(c);
     704         [ -  + ]:          8 :         assert(c->parameter);
     705         [ -  + ]:          8 :         assert(c->type == CONDITION_FILE_IS_EXECUTABLE);
     706                 :            : 
     707                 :          8 :         return (stat(c->parameter, &st) >= 0 &&
     708   [ +  -  +  - ]:         16 :                 S_ISREG(st.st_mode) &&
     709         [ +  + ]:          8 :                 (st.st_mode & 0111));
     710                 :            : }
     711                 :            : 
     712                 :          8 : static int condition_test_null(Condition *c) {
     713         [ -  + ]:          8 :         assert(c);
     714         [ -  + ]:          8 :         assert(c->type == CONDITION_NULL);
     715                 :            : 
     716                 :            :         /* Note that during parsing we already evaluate the string and
     717                 :            :          * store it in c->negate */
     718                 :          8 :         return true;
     719                 :            : }
     720                 :            : 
     721                 :        664 : int condition_test(Condition *c) {
     722                 :            : 
     723                 :            :         static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
     724                 :            :                 [CONDITION_PATH_EXISTS]              = condition_test_path_exists,
     725                 :            :                 [CONDITION_PATH_EXISTS_GLOB]         = condition_test_path_exists_glob,
     726                 :            :                 [CONDITION_PATH_IS_DIRECTORY]        = condition_test_path_is_directory,
     727                 :            :                 [CONDITION_PATH_IS_SYMBOLIC_LINK]    = condition_test_path_is_symbolic_link,
     728                 :            :                 [CONDITION_PATH_IS_MOUNT_POINT]      = condition_test_path_is_mount_point,
     729                 :            :                 [CONDITION_PATH_IS_READ_WRITE]       = condition_test_path_is_read_write,
     730                 :            :                 [CONDITION_DIRECTORY_NOT_EMPTY]      = condition_test_directory_not_empty,
     731                 :            :                 [CONDITION_FILE_NOT_EMPTY]           = condition_test_file_not_empty,
     732                 :            :                 [CONDITION_FILE_IS_EXECUTABLE]       = condition_test_file_is_executable,
     733                 :            :                 [CONDITION_KERNEL_COMMAND_LINE]      = condition_test_kernel_command_line,
     734                 :            :                 [CONDITION_KERNEL_VERSION]           = condition_test_kernel_version,
     735                 :            :                 [CONDITION_VIRTUALIZATION]           = condition_test_virtualization,
     736                 :            :                 [CONDITION_SECURITY]                 = condition_test_security,
     737                 :            :                 [CONDITION_CAPABILITY]               = condition_test_capability,
     738                 :            :                 [CONDITION_HOST]                     = condition_test_host,
     739                 :            :                 [CONDITION_AC_POWER]                 = condition_test_ac_power,
     740                 :            :                 [CONDITION_ARCHITECTURE]             = condition_test_architecture,
     741                 :            :                 [CONDITION_NEEDS_UPDATE]             = condition_test_needs_update,
     742                 :            :                 [CONDITION_FIRST_BOOT]               = condition_test_first_boot,
     743                 :            :                 [CONDITION_USER]                     = condition_test_user,
     744                 :            :                 [CONDITION_GROUP]                    = condition_test_group,
     745                 :            :                 [CONDITION_CONTROL_GROUP_CONTROLLER] = condition_test_control_group_controller,
     746                 :            :                 [CONDITION_NULL]                     = condition_test_null,
     747                 :            :                 [CONDITION_CPUS]                     = condition_test_cpus,
     748                 :            :                 [CONDITION_MEMORY]                   = condition_test_memory,
     749                 :            :         };
     750                 :            : 
     751                 :            :         int r, b;
     752                 :            : 
     753         [ -  + ]:        664 :         assert(c);
     754         [ -  + ]:        664 :         assert(c->type >= 0);
     755         [ -  + ]:        664 :         assert(c->type < _CONDITION_TYPE_MAX);
     756                 :            : 
     757                 :        664 :         r = condition_tests[c->type](c);
     758         [ +  + ]:        664 :         if (r < 0) {
     759                 :          8 :                 c->result = CONDITION_ERROR;
     760                 :          8 :                 return r;
     761                 :            :         }
     762                 :            : 
     763                 :        656 :         b = (r > 0) == !c->negate;
     764         [ +  + ]:        656 :         c->result = b ? CONDITION_SUCCEEDED : CONDITION_FAILED;
     765                 :        656 :         return b;
     766                 :            : }
     767                 :            : 
     768                 :        352 : bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata) {
     769                 :            :         Condition *c;
     770                 :        352 :         int triggered = -1;
     771                 :            : 
     772         [ -  + ]:        352 :         assert(!!logger == !!to_string);
     773                 :            : 
     774                 :            :         /* If the condition list is empty, then it is true */
     775         [ +  + ]:        352 :         if (!first)
     776                 :        348 :                 return true;
     777                 :            : 
     778                 :            :         /* Otherwise, if all of the non-trigger conditions apply and
     779                 :            :          * if any of the trigger conditions apply (unless there are
     780                 :            :          * none) we return true */
     781         [ +  - ]:          4 :         LIST_FOREACH(conditions, c, first) {
     782                 :            :                 int r;
     783                 :            : 
     784                 :          4 :                 r = condition_test(c);
     785                 :            : 
     786         [ -  + ]:          4 :                 if (logger) {
     787         [ #  # ]:          0 :                         const char *p = c->type == CONDITION_NULL ? "true" : c->parameter;
     788         [ #  # ]:          0 :                         assert(p);
     789                 :            : 
     790         [ #  # ]:          0 :                         if (r < 0)
     791                 :          0 :                                 logger(userdata, LOG_WARNING, r, PROJECT_FILE, __LINE__, __func__,
     792                 :            :                                        "Couldn't determine result for %s=%s%s%s, assuming failed: %m",
     793                 :          0 :                                        to_string(c->type),
     794         [ #  # ]:          0 :                                        c->trigger ? "|" : "",
     795         [ #  # ]:          0 :                                        c->negate ? "!" : "",
     796                 :            :                                        p);
     797                 :            :                         else
     798                 :          0 :                                 logger(userdata, LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__,
     799                 :            :                                        "%s=%s%s%s %s.",
     800                 :          0 :                                        to_string(c->type),
     801         [ #  # ]:          0 :                                        c->trigger ? "|" : "",
     802                 :          0 :                                        c->negate ? "!" : "",
     803                 :            :                                        p,
     804         [ #  # ]:          0 :                                        condition_result_to_string(c->result));
     805                 :            :                 }
     806                 :            : 
     807   [ +  -  +  - ]:          4 :                 if (!c->trigger && r <= 0)
     808                 :          4 :                         return false;
     809                 :            : 
     810   [ #  #  #  # ]:          0 :                 if (c->trigger && triggered <= 0)
     811                 :          0 :                         triggered = r > 0;
     812                 :            :         }
     813                 :            : 
     814                 :          0 :         return triggered != 0;
     815                 :            : }
     816                 :            : 
     817                 :          0 : void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
     818         [ #  # ]:          0 :         assert(c);
     819         [ #  # ]:          0 :         assert(f);
     820                 :            : 
     821                 :          0 :         prefix = strempty(prefix);
     822                 :            : 
     823                 :          0 :         fprintf(f,
     824                 :            :                 "%s\t%s: %s%s%s %s\n",
     825                 :            :                 prefix,
     826                 :          0 :                 to_string(c->type),
     827         [ #  # ]:          0 :                 c->trigger ? "|" : "",
     828                 :          0 :                 c->negate ? "!" : "",
     829                 :            :                 c->parameter,
     830         [ #  # ]:          0 :                 condition_result_to_string(c->result));
     831                 :          0 : }
     832                 :            : 
     833                 :       9616 : void condition_dump_list(Condition *first, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
     834                 :            :         Condition *c;
     835                 :            : 
     836         [ -  + ]:       9616 :         LIST_FOREACH(conditions, c, first)
     837                 :          0 :                 condition_dump(c, f, prefix, to_string);
     838                 :       9616 : }
     839                 :            : 
     840                 :            : static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
     841                 :            :         [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
     842                 :            :         [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
     843                 :            :         [CONDITION_HOST] = "ConditionHost",
     844                 :            :         [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
     845                 :            :         [CONDITION_KERNEL_VERSION] = "ConditionKernelVersion",
     846                 :            :         [CONDITION_SECURITY] = "ConditionSecurity",
     847                 :            :         [CONDITION_CAPABILITY] = "ConditionCapability",
     848                 :            :         [CONDITION_AC_POWER] = "ConditionACPower",
     849                 :            :         [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
     850                 :            :         [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
     851                 :            :         [CONDITION_PATH_EXISTS] = "ConditionPathExists",
     852                 :            :         [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
     853                 :            :         [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
     854                 :            :         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
     855                 :            :         [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
     856                 :            :         [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
     857                 :            :         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
     858                 :            :         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
     859                 :            :         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
     860                 :            :         [CONDITION_USER] = "ConditionUser",
     861                 :            :         [CONDITION_GROUP] = "ConditionGroup",
     862                 :            :         [CONDITION_CONTROL_GROUP_CONTROLLER] = "ConditionControlGroupController",
     863                 :            :         [CONDITION_NULL] = "ConditionNull",
     864                 :            :         [CONDITION_CPUS] = "ConditionCPUs",
     865                 :            :         [CONDITION_MEMORY] = "ConditionMemory",
     866                 :            : };
     867                 :            : 
     868   [ +  +  +  + ]:        360 : DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
     869                 :            : 
     870                 :            : static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
     871                 :            :         [CONDITION_ARCHITECTURE] = "AssertArchitecture",
     872                 :            :         [CONDITION_VIRTUALIZATION] = "AssertVirtualization",
     873                 :            :         [CONDITION_HOST] = "AssertHost",
     874                 :            :         [CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",
     875                 :            :         [CONDITION_KERNEL_VERSION] = "AssertKernelVersion",
     876                 :            :         [CONDITION_SECURITY] = "AssertSecurity",
     877                 :            :         [CONDITION_CAPABILITY] = "AssertCapability",
     878                 :            :         [CONDITION_AC_POWER] = "AssertACPower",
     879                 :            :         [CONDITION_NEEDS_UPDATE] = "AssertNeedsUpdate",
     880                 :            :         [CONDITION_FIRST_BOOT] = "AssertFirstBoot",
     881                 :            :         [CONDITION_PATH_EXISTS] = "AssertPathExists",
     882                 :            :         [CONDITION_PATH_EXISTS_GLOB] = "AssertPathExistsGlob",
     883                 :            :         [CONDITION_PATH_IS_DIRECTORY] = "AssertPathIsDirectory",
     884                 :            :         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "AssertPathIsSymbolicLink",
     885                 :            :         [CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
     886                 :            :         [CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
     887                 :            :         [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
     888                 :            :         [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
     889                 :            :         [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
     890                 :            :         [CONDITION_USER] = "AssertUser",
     891                 :            :         [CONDITION_GROUP] = "AssertGroup",
     892                 :            :         [CONDITION_CONTROL_GROUP_CONTROLLER] = "AssertControlGroupController",
     893                 :            :         [CONDITION_NULL] = "AssertNull",
     894                 :            :         [CONDITION_CPUS] = "AssertCPUs",
     895                 :            :         [CONDITION_MEMORY] = "AssertMemory",
     896                 :            : };
     897                 :            : 
     898   [ +  +  +  + ]:        216 : DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
     899                 :            : 
     900                 :            : static const char* const condition_result_table[_CONDITION_RESULT_MAX] = {
     901                 :            :         [CONDITION_UNTESTED] = "untested",
     902                 :            :         [CONDITION_SUCCEEDED] = "succeeded",
     903                 :            :         [CONDITION_FAILED] = "failed",
     904                 :            :         [CONDITION_ERROR] = "error",
     905                 :            : };
     906                 :            : 
     907   [ +  +  +  + ]:         48 : DEFINE_STRING_TABLE_LOOKUP(condition_result, ConditionResult);

Generated by: LCOV version 1.14