我有一个我创建的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。
答案 0 :(得分:3)
无法从包脚本(preinst,postinst,prerm,postrm ......)中调用APT命令(apt-get,aptitude ..)。
启用这样会引发很多问题,特别是对于程序包安装的依赖性和排序。
通过使用适当的包(pre)依赖关系或为用户提供易于使用的工具(如模块助手和其他工具),已经使用了各种解决方法。
在您的情况下,您的软件包可能与popularcontest冲突以卸载它。此外,如果您的用户拥有“您的”包,则意味着他们已经在其sources.list中添加了一个条目,因此他们可以添加另一个!
答案 1 :(得分:1)
正如富兰克林指出的那样,启用它会产生很多问题,但是如果内部使用你的包可以处理它们,仍然会很可怕所以请尝试<强烈的>避免它,已经说过这种方法会涉及:
您需要临时移动以下文件:
现在你可以运行apt-get / dpkg,如果你只想更新你可以运行的索引apt-get update
,重新启用锁并继续,否则准备好处理dpkg数据库。
如果您想安装/删除软件,那么您需要考虑到apt-get / 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
的安装
为了避免这种混淆,您需要手动处理dpkg更改,因为文件被apt-get / dpkg实例覆盖,您需要将更改保存在不同的位置并将它们应用到原始文件仅在主apt-get / dpkg实例完成之后,因为您的脚本将在此之前结束,您需要留下一个cronjob条目或者是一个手工制作的守护进程。
由于上述过程在某种程度上可能会很麻烦,所以我要保留一个简单的实现,在使用它之前一定要理解它并期待极端情况。
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实例,因此您可以定义临时文件以用作apt / dpkg队列,例如:
如果您选择依赖aptdaemon或类似工具,则需要将其添加到控制文件中的PreDepends字段,并从维护者脚本中调用它。
您的守护程序需要等待/var/lib/dpkg/lock
文件解锁才能运行其apt-get / dpkg实例。
由于上面的过程可能会有点麻烦,我会留下一个天真的实现,一定要在使用它之前理解它并期待极端情况。
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