From 379558c0a9affaef66eea173f58952e2848b654c 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 128/220] 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 f3662c9..d848038 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, &params, 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);
-- 
1.8.3.1

