]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/condition.c
core: add @system special value to ConditionUser=
[thirdparty/systemd.git] / src / shared / condition.c
CommitLineData
b77c08e0
TG
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
b77c08e0 20#include <errno.h>
a8fbdf54 21#include <fcntl.h>
84ac7bea 22#include <fnmatch.h>
a8fbdf54 23#include <limits.h>
84ac7bea 24#include <stdlib.h>
b77c08e0 25#include <string.h>
a8fbdf54 26#include <sys/stat.h>
c465a29f 27#include <sys/types.h>
a8fbdf54 28#include <time.h>
b77c08e0 29#include <unistd.h>
b77c08e0 30
d1bddcec 31#include "sd-id128.h"
84ac7bea 32
b5efdb8a 33#include "alloc-util.h"
d1bddcec 34#include "apparmor-util.h"
84ac7bea 35#include "architecture.h"
430f0182 36#include "audit-util.h"
2822da4f 37#include "cap-list.h"
3ffd4af2 38#include "condition.h"
84ac7bea 39#include "extract-word.h"
3ffd4af2 40#include "fd-util.h"
fb8b0869 41#include "fileio.h"
7d50b32a 42#include "glob-util.h"
958b66ea 43#include "hostname-util.h"
84ac7bea 44#include "ima-util.h"
a8fbdf54
TA
45#include "list.h"
46#include "macro.h"
4349cd7c 47#include "mount-util.h"
6bedfcbb 48#include "parse-util.h"
84ac7bea 49#include "path-util.h"
4e731273 50#include "proc-cmdline.h"
84ac7bea
LP
51#include "selinux-util.h"
52#include "smack-util.h"
8fcde012 53#include "stat-util.h"
8b43440b 54#include "string-table.h"
07630cea 55#include "string-util.h"
c465a29f 56#include "user-util.h"
84ac7bea
LP
57#include "util.h"
58#include "virt.h"
b77c08e0
TG
59
60Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
61 Condition *c;
d1bddcec 62 int r;
b77c08e0 63
b80ba1da 64 assert(type >= 0);
b77c08e0 65 assert(type < _CONDITION_TYPE_MAX);
8a9c6071 66 assert((!parameter) == (type == CONDITION_NULL));
b77c08e0
TG
67
68 c = new0(Condition, 1);
69 if (!c)
70 return NULL;
71
72 c->type = type;
73 c->trigger = trigger;
74 c->negate = negate;
75
d1bddcec
LP
76 r = free_and_strdup(&c->parameter, parameter);
77 if (r < 0) {
78 free(c);
79 return NULL;
b77c08e0
TG
80 }
81
82 return c;
83}
84
85void condition_free(Condition *c) {
86 assert(c);
87
88 free(c->parameter);
89 free(c);
90}
91
447021aa 92Condition* condition_free_list(Condition *first) {
b77c08e0
TG
93 Condition *c, *n;
94
95 LIST_FOREACH_SAFE(conditions, c, n, first)
96 condition_free(c);
447021aa
ZJS
97
98 return NULL;
b77c08e0
TG
99}
100
a4705396 101static int condition_test_kernel_command_line(Condition *c) {
07318c29
LP
102 _cleanup_free_ char *line = NULL;
103 const char *p;
b77c08e0
TG
104 bool equal;
105 int r;
b77c08e0
TG
106
107 assert(c);
108 assert(c->parameter);
109 assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
110
111 r = proc_cmdline(&line);
112 if (r < 0)
592fd144 113 return r;
b77c08e0
TG
114
115 equal = !!strchr(c->parameter, '=');
07318c29 116
c58bd76a 117 for (p = line;;) {
07318c29
LP
118 _cleanup_free_ char *word = NULL;
119 bool found;
120
12ba2c44 121 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
592fd144
LP
122 if (r < 0)
123 return r;
124 if (r == 0)
a4705396 125 break;
07318c29
LP
126
127 if (equal)
128 found = streq(word, c->parameter);
129 else {
130 const char *f;
131
132 f = startswith(word, c->parameter);
133 found = f && (*f == '=' || *f == 0);
b77c08e0
TG
134 }
135
07318c29 136 if (found)
a4705396 137 return true;
b77c08e0 138 }
b77c08e0 139
a4705396 140 return false;
b77c08e0
TG
141}
142
c465a29f
FS
143static int condition_test_user(Condition *c) {
144 uid_t id;
145 int r;
146 _cleanup_free_ char *username = NULL;
147 const char *u;
148
149 assert(c);
150 assert(c->parameter);
151 assert(c->type == CONDITION_USER);
152
153 r = parse_uid(c->parameter, &id);
154 if (r >= 0)
155 return id == getuid() || id == geteuid();
156
534bab66
FS
157 if (streq("@system", c->parameter))
158 return getuid() <= SYSTEM_UID_MAX || geteuid() <= SYSTEM_UID_MAX;
159
c465a29f
FS
160 username = getusername_malloc();
161 if (!username)
162 return -ENOMEM;
163
164 if (streq(username, c->parameter))
165 return 1;
166
167 if (getpid() == 1)
168 return streq(c->parameter, "root");
169
170 u = c->parameter;
171 r = get_user_creds(&u, &id, NULL, NULL, NULL);
172 if (r < 0)
173 return 0;
174
175 return id == getuid() || id == geteuid();
176}
177
178static int condition_test_group(Condition *c) {
179 gid_t id;
180 int r;
181
182 assert(c);
183 assert(c->parameter);
184 assert(c->type == CONDITION_GROUP);
185
186 r = parse_gid(c->parameter, &id);
187 if (r >= 0)
188 return in_gid(id);
189
190 /* Avoid any NSS lookups if we are PID1 */
191 if (getpid() == 1)
192 return streq(c->parameter, "root");
193
194 return in_group(c->parameter) > 0;
195}
196
a4705396 197static int condition_test_virtualization(Condition *c) {
248fab74 198 int b, v;
b77c08e0
TG
199
200 assert(c);
201 assert(c->parameter);
202 assert(c->type == CONDITION_VIRTUALIZATION);
203
239a5707
ZJS
204 if (streq(c->parameter, "private-users"))
205 return running_in_userns();
206
75f86906 207 v = detect_virtualization();
592fd144
LP
208 if (v < 0)
209 return v;
b77c08e0
TG
210
211 /* First, compare with yes/no */
212 b = parse_boolean(c->parameter);
0809d774
ZJS
213 if (b >= 0)
214 return b == !!v;
b77c08e0
TG
215
216 /* Then, compare categorization */
0809d774
ZJS
217 if (streq(c->parameter, "vm"))
218 return VIRTUALIZATION_IS_VM(v);
b77c08e0 219
0809d774
ZJS
220 if (streq(c->parameter, "container"))
221 return VIRTUALIZATION_IS_CONTAINER(v);
b77c08e0
TG
222
223 /* Finally compare id */
75f86906 224 return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
b77c08e0
TG
225}
226
a4705396 227static int condition_test_architecture(Condition *c) {
592fd144 228 int a, b;
099524d7
LP
229
230 assert(c);
231 assert(c->parameter);
232 assert(c->type == CONDITION_ARCHITECTURE);
233
234 a = uname_architecture();
235 if (a < 0)
592fd144 236 return a;
099524d7
LP
237
238 if (streq(c->parameter, "native"))
239 b = native_architecture();
2cb62395 240 else {
099524d7 241 b = architecture_from_string(c->parameter);
2cb62395
LP
242 if (b < 0) /* unknown architecture? Then it's definitely not ours */
243 return false;
244 }
099524d7 245
a4705396 246 return a == b;
099524d7
LP
247}
248
a4705396 249static int condition_test_host(Condition *c) {
dc92e62c 250 _cleanup_free_ char *h = NULL;
b77c08e0 251 sd_id128_t x, y;
b77c08e0 252 int r;
b77c08e0
TG
253
254 assert(c);
255 assert(c->parameter);
256 assert(c->type == CONDITION_HOST);
257
258 if (sd_id128_from_string(c->parameter, &x) >= 0) {
259
260 r = sd_id128_get_machine(&y);
261 if (r < 0)
592fd144 262 return r;
b77c08e0 263
a4705396 264 return sd_id128_equal(x, y);
b77c08e0
TG
265 }
266
267 h = gethostname_malloc();
268 if (!h)
592fd144 269 return -ENOMEM;
b77c08e0 270
a4705396 271 return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
b77c08e0
TG
272}
273
a4705396 274static int condition_test_ac_power(Condition *c) {
b77c08e0
TG
275 int r;
276
277 assert(c);
278 assert(c->parameter);
279 assert(c->type == CONDITION_AC_POWER);
280
281 r = parse_boolean(c->parameter);
282 if (r < 0)
592fd144 283 return r;
b77c08e0 284
a4705396 285 return (on_ac_power() != 0) == !!r;
b77c08e0
TG
286}
287
d1bddcec
LP
288static int condition_test_security(Condition *c) {
289 assert(c);
290 assert(c->parameter);
291 assert(c->type == CONDITION_SECURITY);
292
293 if (streq(c->parameter, "selinux"))
6355e756 294 return mac_selinux_have();
d1bddcec 295 if (streq(c->parameter, "smack"))
a4705396 296 return mac_smack_use();
d1bddcec 297 if (streq(c->parameter, "apparmor"))
a4705396 298 return mac_apparmor_use();
d1bddcec 299 if (streq(c->parameter, "audit"))
a4705396 300 return use_audit();
d1bddcec 301 if (streq(c->parameter, "ima"))
a4705396 302 return use_ima();
d1bddcec 303
a4705396 304 return false;
d1bddcec
LP
305}
306
307static int condition_test_capability(Condition *c) {
308 _cleanup_fclose_ FILE *f = NULL;
2822da4f 309 int value;
d1bddcec
LP
310 char line[LINE_MAX];
311 unsigned long long capabilities = -1;
312
313 assert(c);
314 assert(c->parameter);
315 assert(c->type == CONDITION_CAPABILITY);
316
317 /* If it's an invalid capability, we don't have it */
2822da4f
LP
318 value = capability_from_name(c->parameter);
319 if (value < 0)
d1bddcec
LP
320 return -EINVAL;
321
322 /* If it's a valid capability we default to assume
323 * that we have it */
324
325 f = fopen("/proc/self/status", "re");
326 if (!f)
327 return -errno;
328
329 while (fgets(line, sizeof(line), f)) {
330 truncate_nl(line);
331
332 if (startswith(line, "CapBnd:")) {
333 (void) sscanf(line+7, "%llx", &capabilities);
334 break;
335 }
336 }
337
a4705396 338 return !!(capabilities & (1ULL << value));
d1bddcec
LP
339}
340
341static int condition_test_needs_update(Condition *c) {
342 const char *p;
343 struct stat usr, other;
344
345 assert(c);
346 assert(c->parameter);
347 assert(c->type == CONDITION_NEEDS_UPDATE);
348
349 /* If the file system is read-only we shouldn't suggest an update */
350 if (path_is_read_only_fs(c->parameter) > 0)
a4705396 351 return false;
d1bddcec
LP
352
353 /* Any other failure means we should allow the condition to be true,
96d49011 354 * so that we rather invoke too many update tools than too
d1bddcec
LP
355 * few. */
356
357 if (!path_is_absolute(c->parameter))
a4705396 358 return true;
d1bddcec 359
63c372cb 360 p = strjoina(c->parameter, "/.updated");
d1bddcec 361 if (lstat(p, &other) < 0)
a4705396 362 return true;
d1bddcec
LP
363
364 if (lstat("/usr/", &usr) < 0)
a4705396 365 return true;
d1bddcec 366
fb8b0869
IS
367 /*
368 * First, compare seconds as they are always accurate...
369 */
370 if (usr.st_mtim.tv_sec != other.st_mtim.tv_sec)
371 return usr.st_mtim.tv_sec > other.st_mtim.tv_sec;
372
373 /*
374 * ...then compare nanoseconds.
375 *
376 * A false positive is only possible when /usr's nanoseconds > 0
377 * (otherwise /usr cannot be strictly newer than the target file)
378 * AND the target file's nanoseconds == 0
379 * (otherwise the filesystem supports nsec timestamps, see stat(2)).
380 */
381 if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
382 _cleanup_free_ char *timestamp_str = NULL;
383 uint64_t timestamp;
384 int r;
385
ec2ebfd5 386 r = parse_env_file(p, NULL, "TIMESTAMP_NSEC", &timestamp_str, NULL);
fb8b0869 387 if (r < 0) {
ec2ebfd5 388 log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
fb8b0869
IS
389 return true;
390 } else if (r == 0) {
391 log_debug("No data in timestamp file '%s', using mtime", p);
392 return true;
393 }
394
395 r = safe_atou64(timestamp_str, &timestamp);
396 if (r < 0) {
ec2ebfd5 397 log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
fb8b0869
IS
398 return true;
399 }
400
ec2ebfd5 401 timespec_store(&other.st_mtim, timestamp);
fb8b0869
IS
402 }
403
404 return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
d1bddcec
LP
405}
406
407static int condition_test_first_boot(Condition *c) {
408 int r;
409
410 assert(c);
411 assert(c->parameter);
412 assert(c->type == CONDITION_FIRST_BOOT);
413
414 r = parse_boolean(c->parameter);
415 if (r < 0)
416 return r;
417
a4705396 418 return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
d1bddcec
LP
419}
420
421static int condition_test_path_exists(Condition *c) {
422 assert(c);
423 assert(c->parameter);
424 assert(c->type == CONDITION_PATH_EXISTS);
425
a4705396 426 return access(c->parameter, F_OK) >= 0;
d1bddcec
LP
427}
428
429static int condition_test_path_exists_glob(Condition *c) {
430 assert(c);
431 assert(c->parameter);
432 assert(c->type == CONDITION_PATH_EXISTS_GLOB);
433
a4705396 434 return glob_exists(c->parameter) > 0;
d1bddcec
LP
435}
436
437static int condition_test_path_is_directory(Condition *c) {
438 assert(c);
439 assert(c->parameter);
440 assert(c->type == CONDITION_PATH_IS_DIRECTORY);
441
a4705396 442 return is_dir(c->parameter, true) > 0;
d1bddcec
LP
443}
444
445static int condition_test_path_is_symbolic_link(Condition *c) {
446 assert(c);
447 assert(c->parameter);
448 assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
449
a4705396 450 return is_symlink(c->parameter) > 0;
d1bddcec
LP
451}
452
453static int condition_test_path_is_mount_point(Condition *c) {
454 assert(c);
455 assert(c->parameter);
456 assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
457
e1873695 458 return path_is_mount_point(c->parameter, NULL, AT_SYMLINK_FOLLOW) > 0;
d1bddcec
LP
459}
460
461static int condition_test_path_is_read_write(Condition *c) {
462 assert(c);
463 assert(c->parameter);
464 assert(c->type == CONDITION_PATH_IS_READ_WRITE);
465
a4705396 466 return path_is_read_only_fs(c->parameter) <= 0;
d1bddcec
LP
467}
468
469static int condition_test_directory_not_empty(Condition *c) {
470 int r;
471
472 assert(c);
473 assert(c->parameter);
474 assert(c->type == CONDITION_DIRECTORY_NOT_EMPTY);
475
476 r = dir_is_empty(c->parameter);
a4705396 477 return r <= 0 && r != -ENOENT;
d1bddcec
LP
478}
479
480static int condition_test_file_not_empty(Condition *c) {
481 struct stat st;
482
483 assert(c);
484 assert(c->parameter);
485 assert(c->type == CONDITION_FILE_NOT_EMPTY);
486
487 return (stat(c->parameter, &st) >= 0 &&
488 S_ISREG(st.st_mode) &&
a4705396 489 st.st_size > 0);
d1bddcec
LP
490}
491
492static int condition_test_file_is_executable(Condition *c) {
493 struct stat st;
494
495 assert(c);
496 assert(c->parameter);
497 assert(c->type == CONDITION_FILE_IS_EXECUTABLE);
498
499 return (stat(c->parameter, &st) >= 0 &&
500 S_ISREG(st.st_mode) &&
a4705396 501 (st.st_mode & 0111));
d1bddcec
LP
502}
503
504static int condition_test_null(Condition *c) {
505 assert(c);
d1bddcec
LP
506 assert(c->type == CONDITION_NULL);
507
508 /* Note that during parsing we already evaluate the string and
509 * store it in c->negate */
a4705396 510 return true;
d1bddcec
LP
511}
512
513int condition_test(Condition *c) {
514
515 static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
516 [CONDITION_PATH_EXISTS] = condition_test_path_exists,
517 [CONDITION_PATH_EXISTS_GLOB] = condition_test_path_exists_glob,
518 [CONDITION_PATH_IS_DIRECTORY] = condition_test_path_is_directory,
519 [CONDITION_PATH_IS_SYMBOLIC_LINK] = condition_test_path_is_symbolic_link,
520 [CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
521 [CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
522 [CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
523 [CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
524 [CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
525 [CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
526 [CONDITION_VIRTUALIZATION] = condition_test_virtualization,
527 [CONDITION_SECURITY] = condition_test_security,
528 [CONDITION_CAPABILITY] = condition_test_capability,
529 [CONDITION_HOST] = condition_test_host,
530 [CONDITION_AC_POWER] = condition_test_ac_power,
531 [CONDITION_ARCHITECTURE] = condition_test_architecture,
532 [CONDITION_NEEDS_UPDATE] = condition_test_needs_update,
533 [CONDITION_FIRST_BOOT] = condition_test_first_boot,
c465a29f
FS
534 [CONDITION_USER] = condition_test_user,
535 [CONDITION_GROUP] = condition_test_group,
d1bddcec
LP
536 [CONDITION_NULL] = condition_test_null,
537 };
cc50ef13
LP
538
539 int r, b;
d1bddcec
LP
540
541 assert(c);
542 assert(c->type >= 0);
543 assert(c->type < _CONDITION_TYPE_MAX);
544
a4705396 545 r = condition_tests[c->type](c);
cc50ef13
LP
546 if (r < 0) {
547 c->result = CONDITION_ERROR;
a4705396 548 return r;
cc50ef13 549 }
a4705396 550
cc50ef13
LP
551 b = (r > 0) == !c->negate;
552 c->result = b ? CONDITION_SUCCEEDED : CONDITION_FAILED;
553 return b;
d1bddcec
LP
554}
555
59fccdc5 556void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
b77c08e0
TG
557 assert(c);
558 assert(f);
559
560 if (!prefix)
561 prefix = "";
562
563 fprintf(f,
564 "%s\t%s: %s%s%s %s\n",
565 prefix,
59fccdc5 566 to_string(c->type),
b77c08e0
TG
567 c->trigger ? "|" : "",
568 c->negate ? "!" : "",
569 c->parameter,
cc50ef13 570 condition_result_to_string(c->result));
b77c08e0
TG
571}
572
59fccdc5 573void condition_dump_list(Condition *first, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
b77c08e0
TG
574 Condition *c;
575
576 LIST_FOREACH(conditions, c, first)
59fccdc5 577 condition_dump(c, f, prefix, to_string);
b77c08e0
TG
578}
579
580static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
651c3318
LP
581 [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
582 [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
583 [CONDITION_HOST] = "ConditionHost",
584 [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
585 [CONDITION_SECURITY] = "ConditionSecurity",
586 [CONDITION_CAPABILITY] = "ConditionCapability",
587 [CONDITION_AC_POWER] = "ConditionACPower",
588 [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
589 [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
b77c08e0
TG
590 [CONDITION_PATH_EXISTS] = "ConditionPathExists",
591 [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
592 [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
593 [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
594 [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
595 [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
596 [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
597 [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
598 [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
c465a29f
FS
599 [CONDITION_USER] = "ConditionUser",
600 [CONDITION_GROUP] = "ConditionGroup",
b77c08e0
TG
601 [CONDITION_NULL] = "ConditionNull"
602};
603
604DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
cc50ef13 605
59fccdc5 606static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
651c3318
LP
607 [CONDITION_ARCHITECTURE] = "AssertArchitecture",
608 [CONDITION_VIRTUALIZATION] = "AssertVirtualization",
609 [CONDITION_HOST] = "AssertHost",
610 [CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",
611 [CONDITION_SECURITY] = "AssertSecurity",
612 [CONDITION_CAPABILITY] = "AssertCapability",
613 [CONDITION_AC_POWER] = "AssertACPower",
614 [CONDITION_NEEDS_UPDATE] = "AssertNeedsUpdate",
615 [CONDITION_FIRST_BOOT] = "AssertFirstBoot",
59fccdc5
LP
616 [CONDITION_PATH_EXISTS] = "AssertPathExists",
617 [CONDITION_PATH_EXISTS_GLOB] = "AssertPathExistsGlob",
618 [CONDITION_PATH_IS_DIRECTORY] = "AssertPathIsDirectory",
619 [CONDITION_PATH_IS_SYMBOLIC_LINK] = "AssertPathIsSymbolicLink",
620 [CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
621 [CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
622 [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
623 [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
624 [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
c465a29f
FS
625 [CONDITION_USER] = "AssertUser",
626 [CONDITION_GROUP] = "AssertGroup",
59fccdc5
LP
627 [CONDITION_NULL] = "AssertNull"
628};
629
630DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
631
cc50ef13
LP
632static const char* const condition_result_table[_CONDITION_RESULT_MAX] = {
633 [CONDITION_UNTESTED] = "untested",
634 [CONDITION_SUCCEEDED] = "succeeded",
635 [CONDITION_FAILED] = "failed",
636 [CONDITION_ERROR] = "error",
637};
638
639DEFINE_STRING_TABLE_LOOKUP(condition_result, ConditionResult);