8

How can I run a command before apt-get starts to download a package?

I know about the dpkg pre-invoke hook ( hook a script to apt-get ), but that seems to be run after the download.

$ apt-get update
Get: 11 http://security.debian.org/ wheezy/updates/main qemu amd64 1.1.2+dfsg-6a+deb7u7 [115 kB]
Fetched 70.9 MB in 10s (6,776 kB/s)
refreshing freenet index
--2015-05-19 15:55:25--  http://127.0.0.1:8888/freenet:USK@oRy7ltZLJM-w-kcOBdiZS1pAA8P-BxZ3BPiiqkmfk0E,6a1KFG6S-Bwp6E-MplW52iH~Y3La6GigQVQDeMjI6rg,AQACAAE/deb.mempo.org/-42/

What we need is to run a command before the download. More exactly: The script must run after calling apt-get but before apt-get accesses any online resource.

Is there something like a Pre-Download hook?

It is important that the installation can be done without having to replace the script apt-get (and without doing anything else which could be undone by an update).

  • 2
    You could declare a function named `apt-get` which would itself call the real `apt-get`. Depending on the scope you want it to have, the function could be declared either in `/etc/profile` or `~/.profile` or `~/.bashrc`. – user43791 May 19 '15 at 20:23
  • What exactly does "The script must run after calling apt-get but before apt-get accesses any online resource" mean? What part of the producion apt-get needs to be running before your hook can execute properly? – jthill May 20 '15 at 01:27
  • @jthill we need to trigger a download of a given URL before any other URL gets accessed. The reason is that we download from freenet (decentralized anonymous datastore used as deb repository) and we want to trigger one aggressive search for the most recent version before downloading anything. – Arne Babenhauserheide May 23 '15 at 18:54
  • From comments, you're asking how to replace a system command in a way that can't be bypassed and can't be removed even by the system's installer. You're asking how to rootkit the system. – jthill May 23 '15 at 20:29
  • It would be helpful if you could describe your use case. Or in other words, what are you trying to do? – Faheem Mitha May 27 '15 at 11:02
  • @jithill: I’m not asking how to rootkit the system, but how to trigger a blocking search for the most recent version of the p2p repository before accessing it. For that I have to issue a download from a specific URL. – Arne Babenhauserheide May 29 '15 at 13:38

5 Answers5

9

What about using apt pre/post-invoke hooks?

Essentially it is similar to dpkg pre/post-invoke hooks but for apt (which I'm assuming is actually the important one in your usage scenario). AFAIK there are others but I've only used like this.

E.g.

$ sudo cat /etc/apt/apt.conf.d/05new-hook
APT::Update::Pre-Invoke {"your-command-here"};
Jeremy Davis
  • 777
  • 8
  • 19
  • 2
    Apt doesn't provide a pre-invoke hook for Upgrade or Install though, so this only works for `apt-get update`. – Andrew Domaszek May 16 '17 at 14:09
  • True, but I was answering the question specifically! :) You can use dpkg hooks (as per the OP) for anything which requires pre/post install tweaks. – Jeremy Davis May 17 '17 at 03:31
  • Kind of; assuming that update is always run before upgrade/install. Hooking all commands before network access occurs appears to be impossible with the currently (2017-05-17) available apt hooks. This is still the best answer for scripting but it doesn't help for things like existing automatic update scripts. – Andrew Domaszek May 17 '17 at 13:37
  • Oh ok, I get you now. Sorry; yes you have a really good point. So you can tweak apt-get update, but apt-get install will still download, before the dpkg hooks will run?! Hmmm, that really sucks! – Jeremy Davis May 19 '17 at 08:03
  • What you are trying to do? If you want auto updates but only install from specific repos (e.g. Debian security), then you can use cronapt with a script like TurnKey's cronapt script[1]. Split your sources.list entries into separate files; the ones that you want auto updates from go in security.sources.list. [1] https://github.com/turnkeylinux/common/blob/master/conf/turnkey.d/cronapt – Jeremy Davis May 19 '17 at 08:36
  • I'm trying to perform network detection to disable apt when my laptop's VMs are roaming off my home network. The best solution I've come up with in the past couple days is a custom proxy script that returns HTTP 500 when it isn't on the right network. – Andrew Domaszek May 19 '17 at 18:50
  • Yeah sounds a bit tricky. Depending on what VM software you're using, and your host OS, but if you're using VirtualBox and your host OS is Linux, you could perhaps use a network hook (ifup/ifdown hooks) to adjust VBox's networking (via VBoxManage) to host-only when you're roaming? I don't know enough about Win/Mac networking, but I'd assume something similar could be done there too? I'm not even sure it would work and it may not meet your needs anyway (if you still want remote network access (just not apt). – Jeremy Davis May 21 '17 at 22:22
3

First determine where is apt-get using whereis apt-get or which apt-get; I will assume it's in /usr/bin/apt-get

Then create a file in /usr/local/bin/apt-get with this content:

#!/bin/bash
# (commands to run before apt-get)
exec /usr/bin/apt-get "$@"

now chmod +x /usr/local/bin/apt-get.

This should survive all upgrades of the distribution but it should not change the behavior of apt-get (aside from running the command before doing anything else). As bonus, it could parse the command line arguments to only run the command when it is truly needed.

(This answer builds upon the answer from Mohammad Etemaddar, merged with the feedback from muru)

2

You can use an "alias" in the .bashrc file. For example, put that in your root .bashrc file:

alias apt-get='echo blahblah && apt-get'

Command-line arguments will be added automatically to the end of the alias.

Just replace echo blahblah by the command you need.

But in this case, it only works when you're executing commands as root (not sudo).

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Roman
  • 369
  • 3
  • 8
1

First determine where is apt-get using whereis apt-get; I will assume it's in /usr/bin/apt-get

as muru says, You can create a script named apt-get in /usr/local/bin/ which is before /usr/bin in Debian and Ubuntu $PATH. Then put the following code to it (/usr/local/bin/apt-get):

#!/bin/bash
commands to run before apt-get
/usr/bin/apt-get "$@"

Thanks muru for offer as comment.

Other way:

Of course there's another way which is not better than previous one.

You can mv /usr/bin/apt-get /usr/bin/apt-get2

Then create a file in /usr/bin/apt-get with this content:

#!/bin/bash
commands to run before apt-get
apt-get2 "$@"

now chmod +x /usr/bin/apt-get

Mohammad Etemaddar
  • 12,227
  • 7
  • 24
  • 35
0

Try an alias in the .bashrc file. It only works when logged in to the account that the file corresponds to. The syntax of an alias is:

alias newcommand='command1; command2; command3' So your line might look a bit like this:

alias apt-get='firstcommand; apt-get'

Or this:

alias apt-get='firstcommand && apt-get'

With the second, apt-get will only execute if firstcommand succeeds.

Will
  • 771
  • 1
  • 5
  • 12