4

I have a simple script that applies a patch to a given package, and, since each time said package is upgraded the patch gets overridden, I would really like to automatically apply the patch after every upgrade.

To accomplish this, I created a file in /etc/apt/apt.conf.d/ and added a hook for DPkg::Post-Invoke. As documented by man apt-get, this hook is run by apt-get after installing a package with dpkg. However this hook does not seem to have any information whatsoever about which particular package has been installed, so I cannot know if I have to apply the patch or not. Nothing gets passed to its stdin, nothing gets passed as argument, and the man page says nothing about it.

So to solve this I did the only thing that I could think of: I added another hook for DPkg::Pre-Install-Pkgs, which gets run by apt-get before packages are installed. This hook gets (through stdin) the list of .deb files which are going to be installd by dpkg, so I just check whether any file name matches the name of the package I want to patch, and if so I create a file in /tmp. When my other hook is executed, it first checks for the existence of said file and, if present, applies the patch to the package that has just been installed.

Here's the file I've created in /etc/apt/apt.conf.d/:

DPkg::Pre-Install-Pkgs {
    "while read -r pkg; do case $pkg in *somepkg*) touch /tmp/.patch && exit 0; esac done < /dev/stdin";
};

DPkg::Post-Invoke {
    "[ -f /tmp/.patch ] && /home/marco/scripts/apply_somepkg_patch.sh && rm -f /tmp/.patch; exit 0";
};

To be clear: the apply_somepkg_patch.sh simply edits the contents of a file provided by the package. I want said file to be upgraded and patched each time, I don't want to "lock" it so it doesn't get upgraded.

Now, while this all works just fine, it looks really dirty and somehow wrong to me. Is there any cleaner way to accomplish this? Perhaps only using the DPkg::Post-Invoke hook? Or, in other words, is there a way to know which package got installed in the DPkg::Post-Invoke hook?


EDIT: adding a detailed example of what I'm doing just to be 101% clear, even though I don't think it adds any more information to what I said above.

Suppose somepkg is the package I'm talking about, and somefile is the file installed by such package which I want to patch.

  1. First installation of somepkg, content of somefile:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt3 = a, b, c, d
    some_opt4 = some_value
    
  2. Apply patch, changing it to:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt3 = X, Y, Z, d
    some_opt4 = some_value
    
  3. Upgrade of somepkg, contents somefile after upgrade:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt5 = some_value
    some_opt3 = a, b, c, d
    some_opt6 = some_value
    some_opt4 = some_value
    
  4. Apply patch, changing it to:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt5 = some_value
    some_opt3 = X, Y, Z, d
    some_opt6 = some_value
    some_opt4 = some_value
    

Now, what's the somepackage, where somefile is, what's inside somefile: this is all completely irrelevant for my question. All you need to know is that I want to dynamically modify the contents of somefile, which is part of somepkg, after getting the upgraded version of the file.

This obviously cannot be done statically: I need a script to read somefile, parse its content and patch it accordingly. Therefore, if I want my script to be automatically ran each time somepkg gets updated, I need to make apt-get run it automatically for me.

  • “each time said package is upgraded the patch gets overridden” Have you tried dpkg-divert? Most patches can be made persistent with a local diversion (but not all, e.g. if you need to patch only part of a file). – Gilles Jan 5 at 18:16
  • @Gilles I don't think I get what you're saying: if you're suggesting to use dpkg-divert to "lock" a file and prevent it from being modified, I don't want this. I want the file to be updated and, only then, patched. – Marco Bonelli Jan 5 at 18:22
  • Do the package have a .d directory? – Braiam Jan 5 at 18:23
  • @Braiam No, it does not. It is a simple package which only consists of a binary program and some configuration files. I just want to keep patching one of those programmatically after each upgrade. – Marco Bonelli Jan 5 at 18:27
  • Would you mind sharing the specifics of your patch? There are a number of possible approaches, but which one is best depends on the precise scenario. – Stephen Kitt Jan 5 at 19:14
2

There’s no nice way to do this with apt or dpkg hooks of the style you’re currently using. There might be a simple way of handling such patches on upgrades for the specific package and file you’re modifying, but if you want a generic solution, I think the best approach in Debian currently is to use file triggers.

This involves creating a (simple) package which will take care of patching the file on upgrades of the other package (the one containing the file you wish to patch). Your patching package needs to declare its interest in a file trigger; to do so, add a file named debian/triggers) containing the single line

interest /path/to/the/file/to/patch

Then in the package’s postinst (debian/postinst), check if the first argument is triggered, and if it is, run your patching script (or merge that in your postinst). If you want to keep your patching script separate, you could ship it in your patching package to keep things contained.

Once all that’s done, build and install your patching package, and then whenever you upgrade the package you’re modifying, your patching package’s postinst will be called.

  • Wow that's really neat. I spent some time looking around and came across triggers too, but I never thought about creating my own package just to use a trigger. Thanks for your answer, will give it a try tomorrow. – Marco Bonelli Jan 5 at 22:51
  • I successfully created a custom package like you sugested and it seems to work like a charm! One thing that should be noted though is that lintian emits a warning uses-implicit-await-trigger for the interest trigger, so I replaced the trigger name with interests-await to be explicit. Thanks again for the answer. – Marco Bonelli Jan 6 at 19:31

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.