From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1kAiWj-0004vB-T2 for mharc-grub-devel@gnu.org; Tue, 25 Aug 2020 19:38:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44432) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kAiWi-0004v1-Dr for grub-devel@gnu.org; Tue, 25 Aug 2020 19:38:52 -0400 Received: from mail-wr1-x444.google.com ([2a00:1450:4864:20::444]:36747) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kAiWd-0004mG-Ob for grub-devel@gnu.org; Tue, 25 Aug 2020 19:38:52 -0400 Received: by mail-wr1-x444.google.com with SMTP id x7so517701wro.3 for ; Tue, 25 Aug 2020 16:38:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=surgut.co.uk; s=google; h=sender:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=ZLHAUexTcSiyTS4UbqxKSy4fDyX6Hr6Bue6RjIKpf9Y=; b=WklYMP3uoeMdCnSmFi4pRHRfDOWAXerakB/UBqmvZTtkW5cH0HpVZl9wenHnr6My4V xJUV2S0INv/j5MYWzHSEUwwz1MyD2XIxVuzkLW3ZtCVPrASoeRVJOj13cCMcVHWYNPv3 /Yi9dRsty3THjF1NihiVjwFucNmW6ttwk/ZTE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :mime-version:content-transfer-encoding; bh=ZLHAUexTcSiyTS4UbqxKSy4fDyX6Hr6Bue6RjIKpf9Y=; b=gG0+QNTTvbdIMWqsfrLF6nM5z6p0DRqZEy+hxSmlQ+Y4Qoi4ZLiORFVDnO9tsdwbHv Ldsdgv+QSq4TCpNr58CWojAR6XcNiBxqJykByl0tcD7taE7rntrvf18IOW2t1Z5WXzal ssqdpo3l8eIyAdL+885WBurUVaU2oLbQ9eG65ZsgzOmjAxr9jStiCOuvjbXqa/mAvaJw SxURzAHb7119RD+tp58SOcBXZNv3Tadn/dGnwx6ZtHo9WhO4D68Hq8oUpopUH/S1H/c4 6mEUMsrX0MLUgg5jVXgiSCf8g1ALrYVIMljDd8usBFPu5GoJf3ZTn++dfVEYG42CRVg5 fTSQ== X-Gm-Message-State: AOAM533vuGTBH4rxQSaZdj2263C1J3eeU1sawa8V+KTYGAXalIYHvyyd 9DYWQSl/M1HcIzvZXRqQsypdiRG86VP3WQ== X-Google-Smtp-Source: ABdhPJwxhyIcE0j6CQPwT23mCDEgwq9JqgH5YRqB/CA5iaifH2N1Q8jawKLfnLndhFBv9tZ5FN/lUg== X-Received: by 2002:a5d:4604:: with SMTP id t4mr1352475wrq.250.1598398724469; Tue, 25 Aug 2020 16:38:44 -0700 (PDT) Received: from localhost ([2a01:4b00:85fd:d700:296b:b2a:f267:4531]) by smtp.gmail.com with ESMTPSA id g7sm917918wrv.82.2020.08.25.16.38.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Aug 2020 16:38:43 -0700 (PDT) Sender: Dimitri John Ledkov From: Dimitri John Ledkov To: grub-devel@gnu.org Cc: juliank@ubuntu.com, cjwatson@debian.org, steve.langasek@ubuntu.com, Dimitri John Ledkov Subject: [PATCH] grub-install: Add backup and restore Date: Wed, 26 Aug 2020 00:38:20 +0100 Message-Id: <20200825233820.315098-1-xnox@ubuntu.com> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2a00:1450:4864:20::444; envelope-from=dimitri.ledkov@surgut.co.uk; helo=mail-wr1-x444.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.248, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 Aug 2020 23:38:52 -0000 Refactor clean_grub_dir to create a backup of all the files, instead of just irrevocably removing them as the first action. If available, register on_exit handle to restore the backup if any errors occur, or remove the backup if everything was successful. If on_exit is not available, the backup remains on disk for manual recovery. This allows safer upgrades of MBR & modules, such that modules/images/fonts/translations are consistent with MBR in case of errors. For example accidental grub-install /dev/non-existent-disk currently clobbers and upgrades modules in /boot/grub, despite not actually updating any MBR. This increases peak disk-usage slightly, by requiring temporarily twice the disk space to complete grub-install. Also add modinfo.sh to the cleanup/backup/restore codepath, to ensure it is also cleaned / backed up / restored. Signed-off-by: Dimitri John Ledkov --- configure.ac | 2 +- util/grub-install-common.c | 105 +++++++++++++++++++++++++++++++------ 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 7c10a4db7..71cd414c3 100644 --- a/configure.ac +++ b/configure.ac @@ -419,7 +419,7 @@ else fi # Check for functions and headers. -AC_CHECK_FUNCS(posix_memalign memalign getextmntent) +AC_CHECK_FUNCS(posix_memalign memalign getextmntent on_exit) AC_CHECK_HEADERS(sys/param.h sys/mount.h sys/mnttab.h limits.h) # glibc 2.25 still includes sys/sysmacros.h in sys/types.h but emits deprecation diff --git a/util/grub-install-common.c b/util/grub-install-common.c index 0295d40f5..e5f069a13 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -185,38 +185,113 @@ grub_install_mkdir_p (const char *dst) free (t); } +static int +strcmp_ext (const char *a, const char *b, const char *ext) +{ + char *bsuffix = grub_util_path_concat_ext (1, b, ext); + int r = strcmp (a, bsuffix); + free (bsuffix); + return r; +} + +enum clean_grub_dir_mode +{ + CLEAN = 0, + CLEAN_BACKUP = 1, + CREATE_BACKUP = 2, + RESTORE_BACKUP = 3, +}; + static void -clean_grub_dir (const char *di) +clean_grub_dir_real (const char *di, enum clean_grub_dir_mode mode) { grub_util_fd_dir_t d; grub_util_fd_dirent_t de; + char suffix[2] = ""; + + if ((mode == CLEAN_BACKUP) || (mode == RESTORE_BACKUP)) + { + strcpy (suffix, "-"); + } d = grub_util_fd_opendir (di); if (!d) - grub_util_error (_("cannot open directory `%s': %s"), - di, grub_util_fd_strerror ()); + { + if (mode == CLEAN_BACKUP) + return; + grub_util_error (_("cannot open directory `%s': %s"), + di, grub_util_fd_strerror ()); + } while ((de = grub_util_fd_readdir (d))) { const char *ext = strrchr (de->d_name, '.'); - if ((ext && (strcmp (ext, ".mod") == 0 - || strcmp (ext, ".lst") == 0 - || strcmp (ext, ".img") == 0 - || strcmp (ext, ".mo") == 0) - && strcmp (de->d_name, "menu.lst") != 0) - || strcmp (de->d_name, "efiemu32.o") == 0 - || strcmp (de->d_name, "efiemu64.o") == 0) + if ((ext && (strcmp_ext (ext, ".mod", suffix) == 0 + || strcmp_ext (ext, ".lst", suffix) == 0 + || strcmp_ext (ext, ".img", suffix) == 0 + || strcmp_ext (ext, ".mo", suffix) == 0) + && strcmp_ext (de->d_name, "menu.lst", suffix) != 0) + || strcmp_ext (de->d_name, "modinfo.sh", suffix) == 0 + || strcmp_ext (de->d_name, "efiemu32.o", suffix) == 0 + || strcmp_ext (de->d_name, "efiemu64.o", suffix) == 0) { - char *x = grub_util_path_concat (2, di, de->d_name); - if (grub_util_unlink (x) < 0) - grub_util_error (_("cannot delete `%s': %s"), x, - grub_util_fd_strerror ()); - free (x); + char *srcf = grub_util_path_concat (2, di, de->d_name); + + if (mode == CREATE_BACKUP) + { + char *dstf = grub_util_path_concat_ext (2, di, de->d_name, "-"); + if (grub_util_rename (srcf, dstf) < 0) + grub_util_error (_("cannot backup `%s': %s"), srcf, + grub_util_fd_strerror ()); + free (dstf); + } + else if (mode == RESTORE_BACKUP) + { + char *dstf = grub_util_path_concat_ext (2, di, de->d_name); + dstf[strlen (dstf) - 1] = 0; + if (grub_util_rename (srcf, dstf) < 0) + grub_util_error (_("cannot restore `%s': %s"), dstf, + grub_util_fd_strerror ()); + free (dstf); + } + else + { + if (grub_util_unlink (srcf) < 0) + grub_util_error (_("cannot delete `%s': %s"), srcf, + grub_util_fd_strerror ()); + } + free (srcf); } } grub_util_fd_closedir (d); } +static void +restore_backup_on_exit (int status, void *arg) +{ + if (status == 0) + { + clean_grub_dir_real ((char *) arg, CLEAN_BACKUP); + } + else + { + clean_grub_dir_real ((char *) arg, CLEAN); + clean_grub_dir_real ((char *) arg, RESTORE_BACKUP); + } + free (arg); + arg = NULL; +} + +static void +clean_grub_dir (const char *di) +{ + clean_grub_dir_real (di, CLEAN_BACKUP); + clean_grub_dir_real (di, CREATE_BACKUP); +#if defined(HAVE_ON_EXIT) + on_exit (restore_backup_on_exit, strdup (di)); +#endif +} + struct install_list { int is_default; -- 2.27.0