|
5 | 5 | #include <fnmatch.h> |
6 | 6 | #include <limits.h> |
7 | 7 | #include <stdlib.h> |
| 8 | +#include <sys/stat.h> |
8 | 9 | #include <sys/types.h> |
9 | 10 | #include <sys/utsname.h> |
10 | 11 | #include <time.h> |
@@ -450,6 +451,81 @@ static int condition_test_architecture(Condition *c, char **env) { |
450 | 451 | return a == b; |
451 | 452 | } |
452 | 453 |
|
| 454 | +#define DTCOMPAT_FILE "/sys/firmware/devicetree/base/compatible" |
| 455 | +static int condition_test_firmware_devicetree_compatible(const char *dtcarg) { |
| 456 | + int r; |
| 457 | + _cleanup_free_ char *dtcompat = NULL; |
| 458 | + _cleanup_strv_free_ char **dtcompatlist = NULL; |
| 459 | + size_t size; |
| 460 | + |
| 461 | + r = read_full_virtual_file(DTCOMPAT_FILE, &dtcompat, &size); |
| 462 | + if (r < 0) { |
| 463 | + /* if the path doesn't exist it is incompatible */ |
| 464 | + if (r != -ENOENT) |
| 465 | + log_debug_errno(r, "Failed to open() '%s', assuming machine is incompatible: %m", DTCOMPAT_FILE); |
| 466 | + return false; |
| 467 | + } |
| 468 | + |
| 469 | + /* Not sure this can happen, but play safe. */ |
| 470 | + if (size == 0) { |
| 471 | + log_debug("%s has zero length, assuming machine is incompatible", DTCOMPAT_FILE); |
| 472 | + return false; |
| 473 | + } |
| 474 | + |
| 475 | + /* |
| 476 | + * /sys/firmware/devicetree/base/compatible consists of one or more |
| 477 | + * strings, each ending in '\0'. So the last character in dtcompat must |
| 478 | + * be a '\0'. |
| 479 | + */ |
| 480 | + if (dtcompat[size - 1] != '\0') { |
| 481 | + log_debug("%s is in an unknown format, assuming machine is incompatible", DTCOMPAT_FILE); |
| 482 | + return false; |
| 483 | + } |
| 484 | + |
| 485 | + dtcompatlist = strv_parse_nulstr(dtcompat, size); |
| 486 | + if (!dtcompatlist) |
| 487 | + return -ENOMEM; |
| 488 | + |
| 489 | + return strv_contains(dtcompatlist, dtcarg); |
| 490 | +} |
| 491 | + |
| 492 | +static int condition_test_firmware(Condition *c, char **env) { |
| 493 | + sd_char *dtc; |
| 494 | + |
| 495 | + assert(c); |
| 496 | + assert(c->parameter); |
| 497 | + assert(c->type == CONDITION_FIRMWARE); |
| 498 | + |
| 499 | + if (streq(c->parameter, "device-tree")) { |
| 500 | + if (access("/sys/firmware/device-tree/", F_OK) < 0) { |
| 501 | + if (errno != ENOENT) |
| 502 | + log_debug_errno(errno, "Unexpected error when checking for /sys/firmware/device-tree/: %m"); |
| 503 | + return false; |
| 504 | + } else |
| 505 | + return true; |
| 506 | + } else if ((dtc = startswith(c->parameter, "device-tree-compatible("))) { |
| 507 | + _cleanup_free_ char *dtcarg = NULL; |
| 508 | + char *end; |
| 509 | + |
| 510 | + end = strchr(dtc, ')'); |
| 511 | + if (!end || *(end + 1) != '\0') { |
| 512 | + log_debug("Malformed Firmware condition \"%s\"", c->parameter); |
| 513 | + return false; |
| 514 | + } |
| 515 | + |
| 516 | + dtcarg = strndup(dtc, end - dtc); |
| 517 | + if (!dtcarg) |
| 518 | + return -ENOMEM; |
| 519 | + |
| 520 | + return condition_test_firmware_devicetree_compatible(dtcarg); |
| 521 | + } else if (streq(c->parameter, "uefi")) |
| 522 | + return is_efi_boot(); |
| 523 | + else { |
| 524 | + log_debug("Unsupported Firmware condition \"%s\"", c->parameter); |
| 525 | + return false; |
| 526 | + } |
| 527 | +} |
| 528 | + |
453 | 529 | static int condition_test_host(Condition *c, char **env) { |
454 | 530 | _cleanup_free_ char *h = NULL; |
455 | 531 | sd_id128_t x, y; |
@@ -843,6 +919,7 @@ int condition_test(Condition *c, char **env) { |
843 | 919 | [CONDITION_HOST] = condition_test_host, |
844 | 920 | [CONDITION_AC_POWER] = condition_test_ac_power, |
845 | 921 | [CONDITION_ARCHITECTURE] = condition_test_architecture, |
| 922 | + [CONDITION_FIRMWARE] = condition_test_firmware, |
846 | 923 | [CONDITION_NEEDS_UPDATE] = condition_test_needs_update, |
847 | 924 | [CONDITION_FIRST_BOOT] = condition_test_first_boot, |
848 | 925 | [CONDITION_USER] = condition_test_user, |
@@ -949,6 +1026,7 @@ void condition_dump_list(Condition *first, FILE *f, const char *prefix, conditio |
949 | 1026 |
|
950 | 1027 | static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { |
951 | 1028 | [CONDITION_ARCHITECTURE] = "ConditionArchitecture", |
| 1029 | + [CONDITION_FIRMWARE] = "ConditionFirmware", |
952 | 1030 | [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", |
953 | 1031 | [CONDITION_HOST] = "ConditionHost", |
954 | 1032 | [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", |
@@ -981,6 +1059,7 @@ DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType); |
981 | 1059 |
|
982 | 1060 | static const char* const assert_type_table[_CONDITION_TYPE_MAX] = { |
983 | 1061 | [CONDITION_ARCHITECTURE] = "AssertArchitecture", |
| 1062 | + [CONDITION_FIRMWARE] = "AssertFirmware", |
984 | 1063 | [CONDITION_VIRTUALIZATION] = "AssertVirtualization", |
985 | 1064 | [CONDITION_HOST] = "AssertHost", |
986 | 1065 | [CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine", |
|
0 commit comments