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_NEW,
+ CLEAN_BACKUP,
+ CREATE_BACKUP,
+ RESTORE_BACKUP
+};
+
+#ifdef HAVE_ATEXIT
+static size_t backup_dirs_size = 0;
+static char **backup_dirs = NULL;
+static pid_t backup_process = 0;
+static int grub_install_backup_ponr = 0;
+
+void
+grub_set_install_backup_ponr (void)
+{
+ grub_install_backup_ponr = 1;
+}
+#endif
+
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;
+ const char *suffix = "";
+
+ if ((mode == CLEAN_BACKUP) || (mode == RESTORE_BACKUP))
+ 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, ".efi", 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 (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);
}
+#ifdef HAVE_ATEXIT
+static void
+restore_backup_atexit (void)
+{
+ size_t i;
+
+ /*
+ * Some child inherited atexit() handler, did not clear it, and called it.
+ * Thus skip clean or restore logic.
+ */
+ if (backup_process != getpid ())
+ return;
+
+ for (i = 0; i < backup_dirs_size; i++)
+ {
+ /*
+ * If past point of no return simply clean the backups. Otherwise
+ * cleanup newly installed files, and restore the backups.
+ */
+ if (grub_install_backup_ponr)
+ clean_grub_dir_real (backup_dirs[i], CLEAN_BACKUP);
+ else
+ {
+ clean_grub_dir_real (backup_dirs[i], CLEAN_NEW);
+ clean_grub_dir_real (backup_dirs[i], RESTORE_BACKUP);
+ }
+ free (backup_dirs[i]);
+ }
+
+ backup_dirs_size = 0;
+
+ free (backup_dirs);
+}
+
+static void
+append_to_backup_dirs (const char *dir)
+{
+ backup_dirs = xrealloc (backup_dirs, sizeof (char *) * (backup_dirs_size + 1));
+ backup_dirs[backup_dirs_size] = xstrdup (dir);
+ backup_dirs_size++;
+ if (!backup_process)
+ {
+ atexit (restore_backup_atexit);
+ backup_process = getpid ();
+ }
+}
+#else
+static void
+append_to_backup_dirs (const char *dir __attribute__ ((unused)))
+{
+}
+#endif
+
+static void
+clean_grub_dir (const char *di)
+{
+ clean_grub_dir_real (di, CLEAN_BACKUP);
+ clean_grub_dir_real (di, CREATE_BACKUP);
+ append_to_backup_dirs (di);
+}
+
struct install_list
{
int is_default;
/* Now perform the installation. */
if (install_bootsector)
- grub_util_bios_setup (platdir, "boot.img", "core.img",
- install_drive, force,
- fs_probe, allow_floppy, add_rs_codes,
- !grub_install_is_short_mbrgap_supported ());
+ {
+ grub_util_bios_setup (platdir, "boot.img", "core.img",
+ install_drive, force,
+ fs_probe, allow_floppy, add_rs_codes,
+ !grub_install_is_short_mbrgap_supported ());
+
+ grub_set_install_backup_ponr ();
+ }
break;
}
case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
/* Now perform the installation. */
if (install_bootsector)
- grub_util_sparc_setup (platdir, "boot.img", "core.img",
- install_drive, force,
- fs_probe, allow_floppy,
- 0 /* unused */, 0 /* unused */ );
+ {
+ grub_util_sparc_setup (platdir, "boot.img", "core.img",
+ install_drive, force,
+ fs_probe, allow_floppy,
+ 0 /* unused */, 0 /* unused */ );
+
+ grub_set_install_backup_ponr ();
+ }
break;
}
grub_elf = grub_util_path_concat (2, core_services, "grub.elf");
grub_install_copy_file (imgfile, grub_elf, 1);
+ grub_set_install_backup_ponr ();
+
f = grub_util_fopen (mach_kernel, "a+");
if (!f)
grub_util_error (_("Can't create file: %s"), strerror (errno));
boot_efi = grub_util_path_concat (2, core_services, "boot.efi");
grub_install_copy_file (imgfile, boot_efi, 1);
+ grub_set_install_backup_ponr ();
+
f = grub_util_fopen (mach_kernel, "r+");
if (!f)
grub_util_error (_("Can't create file: %s"), strerror (errno));
{
char *dst = grub_util_path_concat (2, efidir, efi_file);
grub_install_copy_file (imgfile, dst, 1);
+
+ grub_set_install_backup_ponr ();
+
free (dst);
}
if (!removable && update_nvram)
break;
}
+ /*
+ * Either there are no platform specific code, or it didn't raise
+ * ponr. Raise it here, because usually this is already past point
+ * of no return. If we leave this flag false, at exit all the modules
+ * will be removed from the prefix which would be very confusing.
+ */
+ grub_set_install_backup_ponr ();
+
fprintf (stderr, "%s\n", _("Installation finished. No error reported."));
/* Free resources. */