Apt-get Commands from Inside Poston

I have a deb package that I created. Starting with a postinst script, I would like to run:

apt-get update 

The package adds proxies to the apt system, dropping the file in /etc/apt/apt.conf.d/. I would like to get the apt system to execute the equivalent of apt-get update. However, I cannot run this command directly from postinst, since the apt lock file has already been placed by dpkg, which installs this package! Are there any debconf tools / commands for this?

As a bonus, I would like to be able to remove the package from preinst / postinst:

 apt-get remove popularitycontest 

NOTE. This package is for an internal project, not a deb that will ever be released in the wild or shipped to Debian.

+4
source share
3 answers

Cannot invoke APT command (apt-get, aptitude ..) from script package (preinst, postinst, prerm, postrm ...).

Enabling this will cause many problems, especially for the dependency and installation order of the package.

Various workarounds have been used either using the appropriate package dependencies (pre), or by providing an easy-to-use tool for your users (for example, a module helper and other tools).

In your case, your package may simply conflict with popularcontest to remove it. Also, if your user has “your” package, it means that they have already added an entry to their .list source so that they can add another one!

+3
source

Nested dpkg / apt-get approach

As Franklin emphasizes, this will create many problems , but if it is for internal use, your package can handle them, it will still be scary, so try to avoid this by saying that the approach will include:

  • Disable apt / dpkg temporary locks
  • Update / install / uninstall software
  • Merge changes into dpkg database
  • Enable lock back apt / dpkg
  • Profit

1. Disable apt / dpkg temporary locks

You need to temporarily move the following files:

  • / var / Library / Dpkg / lock
  • / var / Library / Dpkg / updates /
  • / var / cache / sq / archive / lock

2. Update / install / uninstall software

Now you can run apt-get / dpkg if you want to update the index, which you can run apt-get update , enable locks again and continue, otherwise be ready to work with the dpkg database.

If you want to install / uninstall the software, you need to take into account that apt-get / dpkg writes its final state to:

  • / var / Library / Dpkg / status

Suppose you have a system with the following packages: firefox, htop, curl , and let your package foo remove curl , so when you install your package you must have firefox, htop, foo , since dpkg updates its state once per instance your nested state will be overridden by the parent process, leaving the following status as firefox, htop, curl, foo

So, you will not have curl files, but for dpkg the package will still be installed, this will also happen with new software and dependencies.

Suppose your foo packages install apache2 , which depend on apache2-data , you expect them in your dpkg database as: firefox, htop, curl, foo, apache2, apache2-data , however you will have firefox, htop, curl, foo , the nested result was overridden by the parent process, which knew only about installing foo

3. Merge the changes into the dpkg database

To avoid this confusion, you will need to take care of the dpkg changes manually, since the file is redefined using the apt-get / dpkg instance, you will need to save the changes in another place and apply them to the source file only after , the main instance of apt-get / dpkg will be executed, since your script will complete before this happens, you need to leave a cronjob entry or a manual daemon.

4. Enable back lock apt / dpkg

5. Profit

Since the above process can be somehow unpleasant, I leave the naive implementation, do not forget to understand it before using it and expect corner cases.

 package=my-pkg _dpkg_suspend_process() { #unlock standard files busybox mv /var/lib/dpkg/lock /var/lib/dpkg/lock.suspended busybox rm -rf /var/lib/dpkg/updates.suspended/ busybox mv /var/lib/dpkg/updates/ /var/lib/dpkg/updates.suspended busybox mkdir /var/lib/dpkg/updates/ busybox mv /var/cache/apt/archives/lock /var/cache/apt/archives/lock.suspended #debconf missing file descriptors workaround busybox cp /usr/share/debconf/confmodule /usr/share/debconf/confmodule.bk busybox cp /usr/share/minos/debconf/confmodule /usr/share/debconf/confmodule #while apt is being executed it modifies the status file which brings conflicts #to new packages if they're installed/removed in abused apt instances, therefore #the status-old file (which represent the original state in which the first #apt instance was launched) is used to create temporal diffs which will be merged #at the end busybox cp /var/lib/dpkg/status /var/lib/dpkg/status.suspended busybox cp /var/lib/dpkg/status-old /var/lib/dpkg/status-orig busybox cp /var/lib/dpkg/status-orig /var/lib/dpkg/status } _dpkg_continue_process() { #relock standard files busybox rm -rf /var/lib/dpkg/updates busybox mv /var/lib/dpkg/lock.suspended /var/lib/dpkg/lock busybox mv /var/lib/dpkg/updates.suspended /var/lib/dpkg/updates busybox mv /var/cache/apt/archives/lock.suspended /var/cache/apt/archives/lock busybox mv /var/lib/dpkg/status.suspended /var/lib/dpkg/status #debconf missing file descriptors workaround busybox mv /usr/share/debconf/confmodule.bk /usr/share/debconf/confmodule #keep status-old file to survive multiple abused apt instances busybox mv /var/lib/dpkg/status-orig /var/lib/dpkg/status-old } _dpkg_sync_status_db() { _dpkg_sync_status_db_script="/var/lib/dpkg/dpkg-sync-status-db" _dpkg_sync_status_db_script_generator() { printf "%s\\n" "#!/bin/sh" printf "%s\\n" "#autogenerated by ${package}: $(date +%d-%m-%Y:%H:%M)" printf "\\n" printf "%s\\n" '##close stdout' printf "%s\\n" '#exec 1<&-' printf "%s\\n" '##close stderr' printf "%s\\n" '#exec 2<&-' printf "%s\\n" '##open stdout as $log_file file for read and write.' printf "%s\\n" "#exec 1<> /tmp/${package}.\${$}.debug" printf "%s\\n" '##redirect stderr to stdout' printf "%s\\n" '#exec 2>&1' printf "%s\\n" '#set -x #enable trace mode' printf "\\n" printf "%s\\n" "while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done" printf "\\n" printf "%s\\n" 'pkgs__add="$(cat /var/lib/apt/apt-add-queue)"' printf "%s\\n" 'if [ -n "${pkgs__add}" ]; then' printf "%s\\n" ' for pkg in $pkgs__add; do' printf "%s\\n" ' if ! busybox grep "^Package: ${pkg}$" /var/lib/dpkg/status >/dev/null 2>&1; then' printf "%s\\n" ' busybox sed -n "/Package: ${pkg}$/,/^$/p" \' printf "%s\\n" " /var/lib/dpkg/status-append-queue >> /var/lib/dpkg/status" printf "%s\\n" " fi" printf "%s\\n" " done" printf "%s\\n" "fi" printf "\\n" printf "%s\\n" 'pkgs__rm="$(cat /var/lib/apt/apt-rm-queue)"' printf "%s\\n" 'if [ -n "${pkgs__rm}" ]; then' printf "%s\\n" ' for pkg in $pkgs__rm; do' printf "%s\\n" ' busybox sed -i "/Package: ${pkg}$/,/^$/d" /var/lib/dpkg/status' printf "%s\\n" " done" printf "%s\\n" "fi" printf "\\n" printf "%s\\n" "mv /var/lib/apt/apt-add-queue /var/lib/apt/apt-add-queue.bk" printf "%s\\n" "mv /var/lib/apt/apt-rm-queue /var/lib/apt/apt-rm-queue.bk" printf "%s\\n" "mv /var/lib/dpkg/status-append-queue /var/lib/dpkg/status-append-queue.bk" printf "\\n" printf "%s\\n" "rm -rf /var/lib/apt/apt-add-queue /var/lib/apt/apt-rm-queue" printf "%s\\n" "rm -rf ${_dpkg_sync_status_db_script}" } _dpkg_sync_status_db_script_generator > "${_dpkg_sync_status_db_script}" chmod +x "${_dpkg_sync_status_db_script}" _daemonize /bin/sh -c "${_dpkg_sync_status_db_script}" } _daemonize() { #http://blog.n01se.net/blog-n01se-net-p-145.html [ -z "${1}" ] && return 1 ( #1. fork, to guarantee the child is not a process #group leader, necessary for setsid) and have the #parent exit (to allow control to return to the shell) #2. redirect stdin/stdout/stderr before running child [ -t 0 ] && exec </dev/null [ -t 1 ] && exec >/dev/null [ -t 2 ] && exec 2>/dev/null if ! command -v "setsid" >/dev/null 2>&1; then #2.1 guard against HUP and INT (in child) trap '' 1 2 fi #3. ensure cwd isn't a mounted fs so it does't block #umount invocations cd / #4. umask (leave this to caller) #umask 0 #5. close unneeded fds #XCU 2.7 Redirection says: open files are represented by #decimal numbers starting with zero. The largest possible #value is implementation-defined; however, all #implementations shall support at least 0 to 9, inclusive, #for use by the application. i=3; while [ "${i}" -le "9" ]; do eval "exec ${i}>&-" i="$(($i + 1))" done #6. create new session, so the child has no #controlling terminal, this prevents the child from #accesing a terminal (using /dev/tty) and getting #signals from the controlling terminal (eg HUP, INT) if command -v "setsid" >/dev/null 2>&1; then exec setsid " $@ " elif command -v "nohup" >/dev/null 2>&1; then exec nohup " $@ " >/dev/null 2>&1 else if [ ! -f "${1}" ]; then " $@ " else exec " $@ " fi fi ) & #2.2 guard against HUP (in parent) if ! command -v "setsid" >/dev/null 2>&1 \ && ! command -v "nohup" >/dev/null 2>&1; then disown -h "${!}" fi } _apt_add_queue() { for pkg in "${@}"; do if busybox grep "${pkg}" /var/lib/apt/apt-rm-queue >/dev/null 2>&1; then busybox sed -i "/^${pkg}$/d" /var/lib/apt/apt-rm-queue else if ! busybox grep "^Package: ${pkg}$" /var/lib/dpkg/status >/dev/null 2>&1; then printf "%s\\n" "${pkg}" >> /var/lib/apt/apt-add-queue fi fi done; unset pkg } _apt_rm_queue() { for pkg in "${@}"; do if busybox grep "${pkg}" /var/lib/apt/apt-add-queue >/dev/null 2>&1; then busybox sed -i "/^${pkg}$/d" /var/lib/apt/apt-add-queue else if busybox grep "^Package: ${pkg}$" /var/lib/dpkg/status >/dev/null 2>&1; then printf "%s\\n" "${pkg}" >> /var/lib/apt/apt-rm-queue fi fi done; unset pkg } _apt_install() { [ -z "${1}" ] && return _apt_add_queue $(printf "%s\\n" "${@}" | busybox sed "s:${package}::g") } _apt_purge() { [ -z "${1}" ] && return _apt_rm_queue $(printf "%s\\n" "${@}" | busybox sed "s:${package}::g") } _apt_run() { [ ! -f /var/lib/apt/apt-add-queue ] && [ ! -f /var/lib/apt/apt-rm-queue ] && return pkgs__add="$(cat /var/lib/apt/apt-add-queue 2>/dev/null)" if [ -n "${pkgs__add}" ]; then _dpkg_suspend_process busybox awk '/^Package: /{print $2}' /var/lib/dpkg/status | \ busybox sort > /var/lib/dpkg/status-pkgs.orig _apt_run__output="$(DEBIAN_FRONTEND=noninteractive apt-get install \ --no-install-recommends -y -o Dpkg::Options::="--force-confdef" \ -o Dpkg::Options::="--force-confold" --force-yes ${pkgs__add} 2>&1)" || \ printf "%s\\n" "${_apt_run__output}" >&2 busybox awk '/^Package: /{print $2}' /var/lib/dpkg/status | \ busybox sort > /var/lib/dpkg/status-pkgs.current _dpkg__added_pkgs="$(busybox diff -Naur /var/lib/dpkg/status-pkgs.orig \ /var/lib/dpkg/status-pkgs.current | busybox awk '/^\+[a-zA-Z]/{gsub("^+","");print;}')" busybox rm -rf /var/lib/dpkg/status-pkgs* #add dependencies if [ -n "${_dpkg__added_pkgs}" ]; then printf "%s\\n" "${_dpkg__added_pkgs}" >> /var/lib/apt/apt-add-queue printf "%s\\n" "$(busybox sort /var/lib/apt/apt-add-queue | busybox uniq)" \ > /var/lib/apt/apt-add-queue fi #extract dpkg status output to append it at the end for pkg in $_dpkg__added_pkgs; do busybox sed -n '/Package: '"${pkg}"'$/,/^$/p' /var/lib/dpkg/status \ >> /var/lib/dpkg/status-append-queue done _dpkg_continue_process fi pkgs__rm="$(cat /var/lib/apt/apt-rm-queue 2>/dev/null)" if [ -n "${pkgs__rm}" ]; then _dpkg_suspend_process busybox awk '/^Package: /{print $2}' /var/lib/dpkg/status | \ busybox sort > /var/lib/dpkg/status-pkgs.orig _apt_run__output="$(DEBIAN_FRONTEND=noninteractive apt-get purge \ -y ${pkgs__rm} 2>&1)" || printf "%s\\n" "${_apt_run__output}" >&2 busybox awk '/^Package: /{print $2}' /var/lib/dpkg/status | \ busybox sort > /var/lib/dpkg/status-pkgs.current _dpkg__removed_pkgs="$(busybox diff -Naur /var/lib/dpkg/status-pkgs.orig \ /var/lib/dpkg/status-pkgs.current | busybox awk '/^-[a-zA-Z]/{gsub("^-","");print;}')" busybox rm -rf /var/lib/dpkg/status-pkgs* #remove dependencies if [ -n "${_dpkg__removed_pkgs}" ]; then printf "%s\\n" "${_dpkg__removed_pkgs}" >> /var/lib/apt/apt-rm-queue printf "%s\\n" "$(busybox sort /var/lib/apt/apt-rm-queue | busybox uniq)" \ > /var/lib/apt/apt-rm-queue fi _dpkg_continue_process fi _dpkg_sync_status_db } _apt_install foo bar _apt_purge ugly packages _apt_run 
+1
source

Daemon dpkg / apt-get approach

As Franklin emphasizes, this will create many problems , but if it is for internal use, your package can handle them, it will still be scary, so try to avoid this by saying that the approach will include:

  • Define and populate apt-get install / uninstall queues
  • Alternatively dependent on aptdaemon or a similar tool [optional]
  • Leave behind the daemon that acts on specific apt-get / dpkg queues after installation
  • Alternatively add a cronjob entry that will delete itself [optional]
  • Profit

1. Define and populate apt-get install / uninstall queues

Since you will not run additional instances of dpkg / apt-get, you can define temporary files to use as apt / dpkg queues, for example:

  • / var / library / sq / sq-add-in queue
  • / var / library / sq / sq-queue

2. Depends on aptdaemon

If you want to depend on aptdaemon or a similar tool, you need to add it to the PreDepends field in the control file and name it from your supporting script.

3. Leave for a daemon that acts on certain apt-get / dpkg queues after installation

Your daemon will need to wait for the /var/lib/dpkg/lock file to unlock to run its apt-get / dpkg instances.

4. Add a cronjob entry that removes itself

5. Profit

Since the above process can be somehow unpleasant, I leave the naive implementation, do not forget to understand it before using it and expect corner cases.

 package=my-pkg _daemonize() { #http://blog.n01se.net/blog-n01se-net-p-145.html [ -z "${1}" ] && return 1 ( #1. fork, to guarantee the child is not a process #group leader, necessary for setsid) and have the #parent exit (to allow control to return to the shell) #2. redirect stdin/stdout/stderr before running child [ -t 0 ] && exec </dev/null [ -t 1 ] && exec >/dev/null [ -t 2 ] && exec 2>/dev/null if ! command -v "setsid" >/dev/null 2>&1; then #2.1 guard against HUP and INT (in child) trap '' 1 2 fi #3. ensure cwd isn't a mounted fs so it does't block #umount invocations cd / #4. umask (leave this to caller) #umask 0 #5. close unneeded fds #XCU 2.7 Redirection says: open files are represented by #decimal numbers starting with zero. The largest possible #value is implementation-defined; however, all #implementations shall support at least 0 to 9, inclusive, #for use by the application. i=3; while [ "${i}" -le "9" ]; do eval "exec ${i}>&-" i="$(($i + 1))" done #6. create new session, so the child has no #controlling terminal, this prevents the child from #accesing a terminal (using /dev/tty) and getting #signals from the controlling terminal (eg HUP, INT) if command -v "setsid" >/dev/null 2>&1; then exec setsid " $@ " elif command -v "nohup" >/dev/null 2>&1; then exec nohup " $@ " >/dev/null 2>&1 else if [ ! -f "${1}" ]; then " $@ " else exec " $@ " fi fi ) & #2.2 guard against HUP (in parent) if ! command -v "setsid" >/dev/null 2>&1 \ && ! command -v "nohup" >/dev/null 2>&1; then disown -h "${!}" fi } _apt_add_queue() { for pkg in "${@}"; do if busybox grep "${pkg}" /var/lib/apt/apt-rm-queue >/dev/null 2>&1; then busybox sed -i "/^${pkg}$/d" /var/lib/apt/apt-rm-queue else if ! busybox grep "^Package: ${pkg}$" /var/lib/dpkg/status >/dev/null 2>&1; then printf "%s\\n" "${pkg}" >> /var/lib/apt/apt-add-queue fi fi done; unset pkg } _apt_rm_queue() { for pkg in "${@}"; do if busybox grep "${pkg}" /var/lib/apt/apt-add-queue >/dev/null 2>&1; then busybox sed -i "/^${pkg}$/d" /var/lib/apt/apt-add-queue else if busybox grep "^Package: ${pkg}$" /var/lib/dpkg/status >/dev/null 2>&1; then printf "%s\\n" "${pkg}" >> /var/lib/apt/apt-rm-queue fi fi done; unset pkg } _apt_install() { [ -z "${1}" ] && return _apt_add_queue $(printf "%s\\n" "${@}" | busybox sed "s:${package}::g") } _apt_purge() { [ -z "${1}" ] && return _apt_rm_queue $(printf "%s\\n" "${@}" | busybox sed "s:${package}::g") } _apt_daemon() { [ ! -f /var/lib/apt/apt-add-queue ] && [ ! -f /var/lib/apt/apt-rm-queue ] && return _apt_daemon__script="/var/lib/apt/apt-daemon" _apt_daemon_generator() { printf "%s\\n" "#!/bin/sh" printf "%s\\n" "#autogenerated by ${package}: $(date +%d-%m-%Y:%H:%M)" printf "\\n" printf "%s\\n" "if [ -f /var/lib/apt/apt-add-queue ]; then" printf "%s\\n" " cp /usr/share/debconf/confmodule /usr/share/debconf/confmodule.bk" printf "%s\\n" " cp /usr/share/minos/debconf/confmodule /usr/share/debconf/confmodule" printf "%s\\n" " while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done" printf "%s\\n" " DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \\" printf "%s\\n" " -o Dpkg::Options::=\"--force-confdef\" \\" printf "%s\\n" " -o Dpkg::Options::=\"--force-confold\" \\" printf "%s\\n" " --force-yes \$(cat /var/lib/apt/apt-add-queue)" printf "%s\\n" " mv /usr/share/debconf/confmodule.bk /usr/share/debconf/confmodule" printf "%s\\n" "fi" printf "\\n" printf "%s\\n" "if [ -f /var/lib/apt/apt-rm-queue ]; then" printf "%s\\n" " cp /usr/share/debconf/confmodule /usr/share/debconf/confmodule.bk" printf "%s\\n" " cp /usr/share/minos/debconf/confmodule /usr/share/debconf/confmodule" printf "%s\\n" " while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done" printf "%s\\n" " DEBIAN_FRONTEND=noninteractive apt-get purge -y \$(cat /var/lib/apt/apt-rm-queue)" printf "%s\\n" " mv /usr/share/debconf/confmodule.bk /usr/share/debconf/confmodule" printf "%s\\n" "fi" printf "\\n" printf "%s\\n" "mv /var/lib/apt/apt-add-queue /var/lib/apt/apt-add-queue.bk" printf "%s\\n" "mv /var/lib/apt/apt-rm-queue /var/lib/apt/apt-rm-queue.bk" printf "\\n" printf "%s\\n" "rm -rf /var/lib/apt/apt-add-queue" printf "%s\\n" "rm -rf /var/lib/apt/apt-rm-queue" printf "%s\\n" "rm -rf \"${_apt_daemon__script}\"" } _apt_daemon_generator > "${_apt_daemon__script}" && chmod +x "${_apt_daemon__script}" _daemonize /bin/sh -c "${_apt_daemon__script}" printf "%s\\n" "${package}: package changes will be applied shortly upon completion of this apt/dpkg instance" printf "%s\\n" "${package}: DO NOT POWEROFF the system until it completes" } _apt_install foo bar _apt_purge ugly packages _apt_daemon 
0
source

Source: https://habr.com/ru/post/1500367/


All Articles