21

When you upgrade or reinstall a package with dpkg (and ultimately anything that uses it, like apt-get etc) it backs up the existing files by creating a hard link to the file before replacing it. That way if the unpack fails it can easily put back the existing files. That's great, since it protects the operating system from Bad Things™ happening.

Except... it only works if your filesystem supports hard links. Not all filesystems do - such as FAT filesystems.

I am working on a distribution of Debian for a specific embedded ARM platform, and the boot environment requires that certain files (the kernel included) are on a FAT filesystem so the boot code is able to locate and load them.

When you go to upgrade the kernel package (or any other package that has files in that FAT partition) the install fails with:

dpkg: error processing archive linux-image3.18.11+_3.18.11.2.armadillian_armhf.deb (--install):
 unable to make backup link of `./boot/vmlinuz-3.18.11+' before installing new version: Operation not permitted

And the whole upgrade fails.

I have scoured the web, and the only references I can find are specific people with specific problems when doing specific upgrades, the answer to which is usually "Delete /boot/vmlinuz-3.18.11+ and try again", and yes, that fixes that specific problem.

But that's not the answer for me. I am an OS distributor, not an OS user, so I need a way to fix this that doesn't involve the end user manually deleting their kernel files before doing an upgrade. I need a way to tell dpkg to "copy, not hard link" for files on /boot (or all files for all I care, though that would slow down the upgrade operation somewhat), or better yet "If a hard link fails, don't complain, just copy it instead".

I have tried such things as the --force-unsafe-io and even --force-all flags to dpkg, but nothing has any effect.

  • Sounds like time for a wishlist bug. :-) – Faheem Mitha Jun 7 '15 at 13:07
13

The behaviour you're seeing is implemented in archives.c in the dpkg source, line 1030 (for version 1.18.1):

debug(dbg_eachfiledetail, "tarobject nondirectory, 'link' backup");
if (link(fnamevb.buf,fnametmpvb.buf))
  ohshite(_("unable to make backup link of '%.255s' before installing new version"),
          ti->name);

It seems to me that you could handle the link failure by falling back to the rename behaviour used lines 1003 and following; something like (this is untested):

debug(dbg_eachfiledetail, "tarobject nondirectory, 'link' backup");
if (link(fnamevb.buf,fnametmpvb.buf)) {
  debug(dbg_eachfiledetail,"link failed, nonatomic");
  nifd->namenode->flags |= fnnf_no_atomic_overwrite;
  if (rename(fnamevb.buf,fnametmpvb.buf))
    ohshite(_("unable to move aside '%.255s' to install new version"),
            ti->name);
}

I'm not a dpkg expert though... (And there's no option already available in dpkg to provide this behaviour.)

  • Certainly packaging my own version of dpkg is a possibility, though I'd prefer not to have the overhead of tracking upstream changes in my version. – Majenko Jun 7 '15 at 13:27
  • Ok, I can confirm that this works fine, so it is certainly an option. Another option that occurs to me that may be a possibility is to manually move the offending files in the package's preinst script, but as the kernel is built by the standard kernel packaging scripts I'm not sure how I'd modify that. Also there wouldn't be an automatic rollback facility. – Majenko Jun 7 '15 at 16:29
  • 1
    Indeed, that would work; you could also investigate dpkg hooks (dpkg --pre-invoke=). – Stephen Kitt Jun 7 '15 at 16:57
  • +1 How are you not a dpkg expert when you know this! – nikhil Jun 11 '15 at 20:11
  • 1
    raspberrypi kernel is also updated via a similar trick, using dpkg-divert. Taken from raspberrypi.stackexchange.com/questions/51410/…, – akarapatis Dec 28 '18 at 8:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.