• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15057632786

15 May 2025 09:01PM UTC coverage: 72.267% (+0.02%) from 72.244%
15057632786

push

github

bluca
man: document how to hook stuff into system wakeup

Fixes: #6364

298523 of 413084 relevant lines covered (72.27%)

738132.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

32.0
/src/bootctl/bootctl-set-efivar.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <uchar.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "bootctl.h"
8
#include "bootctl-set-efivar.h"
9
#include "efi-loader.h"
10
#include "efivars.h"
11
#include "stdio-util.h"
12
#include "utf8.h"
13
#include "virt.h"
14

15
static int parse_timeout(const char *arg1, char16_t **ret_timeout, size_t *ret_timeout_size) {
×
16
        char utf8[DECIMAL_STR_MAX(usec_t)];
×
17
        char16_t *encoded;
×
18
        usec_t timeout;
×
19
        bool menu_disabled = false;
×
20
        int r;
×
21

22
        assert(arg1);
×
23
        assert(ret_timeout);
×
24
        assert(ret_timeout_size);
×
25

26
        assert_cc(STRLEN("menu-disabled") < ELEMENTSOF(utf8));
×
27

28
        /* Note: Since there is no way to query if the bootloader supports the string tokens, we explicitly
29
         * set their numerical value(s) instead. This means that some of the sd-boot internal ABI has leaked
30
         * although the ship has sailed and the side-effects are self-contained.
31
         */
32
        if (streq(arg1, "menu-force"))
×
33
                timeout = USEC_INFINITY;
×
34
        else if (streq(arg1, "menu-hidden"))
×
35
                timeout = 0;
×
36
        else if (streq(arg1, "menu-disabled")) {
×
37
                uint64_t loader_features = 0;
×
38

39
                (void) efi_loader_get_features(&loader_features);
×
40
                if (!(loader_features & EFI_LOADER_FEATURE_MENU_DISABLE)) {
×
41
                        if (!arg_graceful)
×
42
                                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Loader does not support 'menu-disabled'.");
×
43

44
                        log_warning("Loader does not support 'menu-disabled', setting anyway.");
×
45
                }
46
                menu_disabled = true;
×
47
        } else {
48
                r = parse_time(arg1, &timeout, USEC_PER_SEC);
×
49
                if (r < 0)
×
50
                        return log_error_errno(r, "Failed to parse timeout '%s': %m", arg1);
×
51
                if (timeout != USEC_INFINITY && timeout > UINT32_MAX * USEC_PER_SEC)
×
52
                        log_warning("Timeout is too long and will be treated as 'menu-force' instead.");
×
53
        }
54

55
        if (menu_disabled)
×
56
                xsprintf(utf8, "menu-disabled");
×
57
        else
58
                xsprintf(utf8, USEC_FMT, MIN(timeout / USEC_PER_SEC, UINT32_MAX));
×
59

60
        encoded = utf8_to_utf16(utf8, SIZE_MAX);
×
61
        if (!encoded)
×
62
                return log_oom();
×
63

64
        *ret_timeout = encoded;
×
65
        *ret_timeout_size = char16_strlen(encoded) * 2 + 2;
×
66
        return 0;
×
67
}
68

69
static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target, size_t *ret_target_size) {
5✔
70
        char16_t *encoded = NULL;
5✔
71
        int r;
5✔
72

73
        assert(arg1);
5✔
74
        assert(ret_target);
5✔
75
        assert(ret_target_size);
5✔
76

77
        if (streq(arg1, "@current")) {
5✔
78
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntrySelected"), NULL, (void *) ret_target, ret_target_size);
×
79
                if (r < 0)
×
80
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m");
×
81

82
        } else if (streq(arg1, "@oneshot")) {
5✔
83
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), NULL, (void *) ret_target, ret_target_size);
×
84
                if (r < 0)
×
85
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
×
86

87
        } else if (streq(arg1, "@default")) {
5✔
88
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), NULL, (void *) ret_target, ret_target_size);
×
89
                if (r < 0)
×
90
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
×
91

92
        } else if (streq(arg1, "@sysfail")) {
5✔
93
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail"), NULL, (void *) ret_target, ret_target_size);
×
94
                if (r < 0)
×
95
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySysFail': %m");
×
96

97
        } else if (arg1[0] == '@' && !streq(arg1, "@saved"))
5✔
98
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
×
99
        else {
100
                encoded = utf8_to_utf16(arg1, SIZE_MAX);
5✔
101
                if (!encoded)
5✔
102
                        return log_oom();
×
103

104
                *ret_target = encoded;
5✔
105
                *ret_target_size = char16_strlen(encoded) * 2 + 2;
5✔
106
        }
107

108
        return 0;
109
}
110

111
int verb_set_efivar(int argc, char *argv[], void *userdata) {
5✔
112
        int r;
5✔
113

114
        /* Note: changing EFI variables is the primary purpose of these verbs, hence unlike in the other
115
         * verbs that might touch EFI variables where we skip things gracefully, here we fail loudly if we
116
         * are not run on EFI or EFI variable modifications were turned off. */
117

118
        if (arg_touch_variables < 0) {
5✔
119
                if (arg_root)
5✔
120
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
121
                                               "Acting on %s, refusing EFI variable setup.",
122
                                               arg_image ? "image" : "root directory");
123

124
                if (detect_container() > 0)
5✔
125
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
126
                                               "'%s' operation not supported in a container.",
127
                                               argv[0]);
128
                if (!is_efi_boot())
5✔
129
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
130
                                               "Not booted with UEFI.");
131

132
                if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderInfo")), F_OK) < 0) {
5✔
133
                        if (errno == ENOENT) {
×
134
                                log_error_errno(errno, "Not booted with a supported boot loader.");
×
135
                                return -EOPNOTSUPP;
×
136
                        }
137

138
                        return log_error_errno(errno, "Failed to detect whether boot loader supports '%s' operation: %m", argv[0]);
×
139
                }
140

141
        } else if (!arg_touch_variables)
×
142
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
143
                                       "'%s' operation cannot be combined with --variables=no.",
144
                                       argv[0]);
145

146
        const char *variable;
5✔
147
        int (* arg_parser)(const char *, char16_t **, size_t *);
5✔
148

149
        if (streq(argv[0], "set-default")) {
5✔
150
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntryDefault");
151
                arg_parser = parse_loader_entry_target_arg;
152
        } else if (streq(argv[0], "set-sysfail")) {
×
153
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail");
154
                arg_parser = parse_loader_entry_target_arg;
155
        } else if (streq(argv[0], "set-oneshot")) {
×
156
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot");
157
                arg_parser = parse_loader_entry_target_arg;
158
        } else if (streq(argv[0], "set-timeout")) {
×
159
                variable = EFI_LOADER_VARIABLE_STR("LoaderConfigTimeout");
160
                arg_parser = parse_timeout;
161
        } else if (streq(argv[0], "set-timeout-oneshot")) {
×
162
                variable = EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot");
163
                arg_parser = parse_timeout;
164
        } else
165
                assert_not_reached();
×
166

167
        if (isempty(argv[1])) {
5✔
168
                r = efi_set_variable(variable, NULL, 0);
×
169
                if (r < 0 && r != -ENOENT)
×
170
                        return log_error_errno(r, "Failed to remove EFI variable '%s': %m", variable);
×
171
        } else {
172
                _cleanup_free_ char16_t *value = NULL;
5✔
173
                size_t value_size = 0;
5✔
174

175
                r = arg_parser(argv[1], &value, &value_size);
5✔
176
                if (r < 0)
5✔
177
                        return r;
178
                r = efi_set_variable(variable, value, value_size);
5✔
179
                if (r < 0)
5✔
180
                        return log_error_errno(r, "Failed to update EFI variable '%s': %m", variable);
×
181
        }
182

183
        return 0;
184
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc