Hi,

Adam Purkrt wrote:
> tried stracing grub-mkrescue:
> renergy ~ # grep de.mo~ gentoo-grub-mkrescue.strace
> rename("/tmp/grub.Y1wajm/boot/grub/locale/de.mo", 
> "/tmp/grub.Y1wajm/boot/grub/locale/de.mo~") = 0
> unlink("/tmp/grub.Y1wajm/boot/grub/locale/de.mo~") = 0
> rename("/tmp/grub.Y1wajm/boot/grub/locale/de.mo", 
> "/tmp/grub.Y1wajm/boot/grub/locale/de.mo~") = 0
> newfstatat(AT_FDCWD, "/tmp/grub.Y1wajm/boot/grub/locale/de.mo~", 
> {st_mode=S_IFREG|0644, st_size=150650, ...}, AT_SYMLINK_NOFOLLOW) = 0
> newfstatat(AT_FDCWD, "/tmp/grub.Y1wajm/boot/grub/locale/de.mo~", 
> {st_mode=S_IFREG|0644, st_size=150650, ...}, 0) = 0
> unlink("/tmp/grub.Y1wajm/boot/grub/locale/de.mo~") = 0
>
> So it is grub-mkrescue that is creating the .mo~ files, but then deletes
> them; this cycle (which I do not like, but should be ok) repeats twice, or
> rather should repeat twice - but the actual result is the file is there,
> despite last syscall regarding it being "unlink"

Really puzzling.

It is explainable to see two occasions were "de.mo" already existed.
This probably happens because copy_locales() is called three times for
I386_PC (legacy BIOS), I386_EFI, and X86_64_EFI.
But i lack of ideas why unlink(2) should leave "de.mo~" existing
without error indication.

And why did the ".mo~" files not exist when you looked in /tmp after
the intentionally failed xorriso run ?

Can it be a race condition ?

What happens if you let xorriso fail and look immediately ?

  # First remove or rename all /tmp/grub.* directories

  grub-mkrescue -o /does_not_exist/output.iso ; ls -a 
/tmp/grub.*/boot/grub/locale

xorriso will fail early. So the time until ls can look might be short
enough, compared with the time which xorriso would need to assess the
files in /tmp/grub.XYZXYZ and to copy their content into the ISO.

-----------------------------------------------------------------------

The only workaround i can propose for now is a xorriso wrapper script
which would wait a few seconds before starting xorriso and/or actively
remove /tmp/grub.XYZXYZ/boot/grub/locale/*.mo~ .

Such a script would be submitted to grub-mkrescue by the --xorriso=
option:

  grub-mkrescue -o /does_not_exist/output.iso \
                --xorriso="$HOME"/my_xorriso_wrapper.sh

It has to give answer to the assessment run of grub-mkrescue:

  # grub-mkrescue inquires features by running these arguments
  if test "$*" = "-as mkisofs -help"
  then
    "$xorriso" "$@"
    exit $?
  fi

Then it would do its extra activities and finally run
  xorriso "$@"

The extra activity could be to just sleep 5 seconds or to examine the
arguments "$@" for the /tmp/grub.XYZXYZ path and to compose the path
pattern for a run of rm.

The following code snippet is from
  
https://dev.lovelyhq.com/libburnia/libisoburn/raw/branch/master/frontend/grub-mkrescue-sed.sh
I guess it can be made more simple and elegant. Nevertheless, this has
already been tested with grub-mkrescue.

  # Look for the name of the /tmp directory with the GRUB2 files.
  # It is the next argument after -r. But as default accept any /tmp/grub.*
  next_is_dir=0
  dir="."
  for i in "$@"
  do
    if test x"$i" = x"-r"
    then
      next_is_dir=1
    elif test $next_is_dir = 1
    then
      next_is_dir=0
      if echo "$i" | grep '^/tmp/grub.' >/dev/null 2>&1
      then
        test -d "$i" && dir="$i"
      fi
    elif test "$dir" = "."
    then
      if echo "$i" | grep '^/tmp/grub.' >/dev/null 2>&1
      then
        test -d "$i" && dir="$i"
      fi
    fi
  done

-----------------------------------------------------------------------
Source code musings:

I guess the rename(2) and unlink(2) calls come from
util/grub-install-common.c function clean_grub_dir_real(), which has
modes CREATE_BACKUP and RESTORE_BACKUP calling grub_util_rename(),
mode CLEAN_BACKUP which calls grub_util_unlink() with the ~-name,
and mode CLEAN_NEW which calls grub_util_unlink() with the original
name.
It seems that CREATE_BACKUP and CLEAN_BACKUP are effectively used
in the run which you straced.

grub_unlink() is probably the version from
  include/grub/osdep/hostfile_unix.h
which calls unlink(2).  

Well, grub-mkrescue does not need backups of its freshly installed
files. But in the case of overwriting an existing GRUB installation
the backup is a valuable feature.
So before we could make plans to avoid backups in the special case
of grub-mkrescue we would need to discover a strong motivation by
explaining the ineffectiveness of unlink().

Another remaining riddle:
The calls to newfstatat() probably stem from calls to fstatat(2)
or a macro mock-up of it.
But i fail to find the GRUB function which would call it.


Have a nice day :)

Thomas


Reply via email to