来自deb postinst的Apt-get命令

时间:2013-09-03 19:01:39

标签: debian apt dpkg debconf

我有一个我创建的deb包。从postinst脚本,我想运行:

apt-get update

该软件包通过删除/etc/apt/apt.conf.d/中的文件为apt系统添加代理。我想强制apt系统做相当于“apt-get update”的操作。但是,我不能直接从postinst运行该命令,因为dpkg已经安装了apt锁文件,而正在安装此软件包!是否有一些debconf工具/命令来执行此操作?

作为奖励,我希望能够从preinst / postinst中删除一个包:

apt-get remove popularitycontest

注意 - 此软件包适用于内部项目 - 而不是将要发布到野外或提交给Debian的deb。

3 个答案:

答案 0 :(得分:3)

无法从包脚本(preinst,postinst,prerm,postrm ......)中调用APT命令(apt-get,aptitude ..)。

启用这样会引发很多问题,特别是对于程序包安装的依赖性和排序。

通过使用适当的包(pre)依赖关系或为用户提供易于使用的工具(如模块助手和其他工具),已经使用了各种解决方法。

在您的情况下,您的软件包可能与popularcontest冲突以卸载它。此外,如果您的用户拥有“您的”包,则意味着他们已经在其sources.list中添加了一个条目,因此他们可以添加另一个!

答案 1 :(得分:1)

嵌套dpkg / apt-get方法

正如富兰克林指出的那样,启用它会产生很多问题,但是如果内部使用你的包可以处理它们,仍然会很可怕所以请尝试<强烈的>避免它,已经说过这种方法会涉及:

  1. 暂时禁用apt / dpkg锁
  2. 更新/安装/删除软件
  3. 合并对dpkg数据库的更改
  4. 启用后apt / dpkg锁
  5. 利润
  6. 1。暂时禁用apt / dpkg锁

    您需要临时移动以下文件:

    • 的/ var / lib中/ dpkg的/锁定
    • 的/ var / lib中/ dpkg的/更新/
    • 的/ var /缓存/公寓/档案/锁定

    2。更新/安装/删除软件

    现在你可以运行apt-get / dpkg,如果你只想更新你可以运行的索引apt-get update,重新启用锁并继续,否则准备好处理dpkg数据库。

    如果您想安装/删除软件,那么您需要考虑到apt-get / dpkg将其最终状态写入:

    • 的/ var / lib中/ dpkg的/状态

    假设您的系统包含以下软件包:firefox, htop, curl,并且假设您的软件包foo删除了curl,那么在安装时你的软件包应该有firefox, htop, foo但是因为dpkg每个实例更新一次状态,所以父进程会覆盖嵌套状态,并保持以下状态firefox, htop, curl, foo

    所以,你不会有curl文件,但是dpkg仍然会安装软件包,新软件和依赖项也会发生这种情况。

    假设您的foo软件包安装apache2,这取决于apache2-data,您希望它们在您的dpkg数据库中显示为:firefox, htop, curl, foo, apache2, apache2-data,但是您&# 39; ll有firefox, htop, curl, foo,嵌套输出被父进程覆盖,父进程只知道foo的安装

    3。合并对dpkg数据库的更改

    为了避免这种混淆,您需要手动处理dpkg更改,因为文件被apt-get / dpkg实例覆盖,您需要将更改保存在不同的位置并将它们应用到原始文件仅在主apt-get / dpkg实例完成之后,因为您的脚本将在此之前结束,您需要留下一个cronjob条目或者是一个手工制作的守护进程。

    4。启用后apt / dpkg锁

    5。利润

    由于上述过程在某种程度上可能会很麻烦,所以我要保留一个简单的实现,在使用它之前一定要理解它并期待极端情况。

    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 (e.g. 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
    

答案 2 :(得分:0)

守护进程dpkg / apt-get方法

正如富兰克林指出的那样,启用它会产生很多问题,但是如果它是供内部使用的,你的包可以处理它们,仍然会很可怕所以请尝试避免它,已经说过这种方法会涉及:

  1. 定义并填充安装/删除apt-get队列
  2. 或者取决于aptdaemon或类似工具[可选]
  3. 留下一个守护进程,该守护进程在安装后定义的apt-get / dpkg队列中起作用
  4. 或者添加删除自己的cronjob条目[可选]
  5. 利润
  6. 1。定义并填充安装/删除apt-get队列

    由于您不会运行其他dpkg / apt-get实例,因此您可以定义临时文件以用作apt / dpkg队列,例如:

    • 的/ var / lib中/公寓/公寓加队列
    • 的/ var / lib中/公寓/公寓-RM-队列

    2。取决于aptdaemon

    如果您选择依赖aptdaemon或类似工具,则需要将其添加到控制文件中的PreDepends字段,并从维护者脚本中调用它。

    3。留下一个守护进程,该守护进程在安装后定义的apt-get / dpkg队列中起作用

    您的守护程序需要等待/var/lib/dpkg/lock文件解锁才能运行其apt-get / dpkg实例。

    4。添加删除自己的cronjob条目

    5。利润

    由于上面的过程可能会有点麻烦,我会留下一个天真的实现,一定要在使用它之前理解它并期待极端情况。

    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 (e.g. 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