1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 4 Jun 2018 19:49:47 +0200
Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value
env. variables
To be able to automatically detect if the last boot was successful,
We want to keep count of succesful / failed boots in some integer
environment variable.
This commit adds a grub-editenvt "incr" command to increment such
integer value env. variables by 1 for use from various boot scripts.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/util/grub-editenv.c b/util/grub-editenv.c
index f3662c95ba6..d848038abea 100644
--- a/util/grub-editenv.c
+++ b/util/grub-editenv.c
@@ -53,6 +53,9 @@ static struct argp_option options[] = {
/* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */
{N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE,
N_("Delete variables."), 0},
+ /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand. */
+ {N_("incr [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE,
+ N_("Increase value of integer variables."), 0},
{0, 0, 0, OPTION_DOC, N_("Options:"), -1},
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
@@ -247,6 +250,51 @@ unset_variables (const char *name, int argc, char *argv[])
grub_envblk_close (envblk);
}
+struct get_int_value_params {
+ char *varname;
+ int value;
+};
+
+static int
+get_int_value (const char *varname, const char *value, void *hook_data)
+{
+ struct get_int_value_params *params = hook_data;
+
+ if (strcmp (varname, params->varname) == 0) {
+ params->value = strtol (value, NULL, 10);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+incr_variables (const char *name, int argc, char *argv[])
+{
+ grub_envblk_t envblk;
+ char buf[16];
+
+ envblk = open_envblk_file (name);
+ while (argc)
+ {
+ struct get_int_value_params params = {
+ .varname = argv[0],
+ .value = 0, /* Consider unset variables 0 */
+ };
+
+ grub_envblk_iterate (envblk, ¶ms, get_int_value);
+ snprintf(buf, sizeof(buf), "%d", params.value + 1);
+
+ if (! grub_envblk_set (envblk, argv[0], buf))
+ grub_util_error ("%s", _("environment block too small"));
+
+ argc--;
+ argv++;
+ }
+
+ write_envblk (name, envblk);
+ grub_envblk_close (envblk);
+}
+
int
main (int argc, char *argv[])
{
@@ -286,6 +334,8 @@ main (int argc, char *argv[])
set_variables (filename, argc - curindex, argv + curindex);
else if (strcmp (command, "unset") == 0)
unset_variables (filename, argc - curindex, argv + curindex);
+ else if (strcmp (command, "incr") == 0)
+ incr_variables (filename, argc - curindex, argv + curindex);
else
{
char *program = xstrdup(program_name);
|