我知道创建 Debian 软件包的基本知识。但我希望创建一个在安装时标记要删除的其他软件包。
在控制文件的软件包的 Debian 文件夹下,我尝试将我想要删除的软件包放在“冲突”或“中断”字段下,但没有成功。apt-get 拒绝安装我的软件包,并且不会删除冲突或中断下的软件包...
我遗漏了什么?在 Debian 手册中找不到相应的说明...
答案1
使用传统方法是不可能的,但是你可以滥用 apt-get 来暂时删除它的锁文件,该方法包括:
- 暂时禁用 apt/dpkg 锁
- 更新/安装/删除软件
- 将更改合并到 dpkg 数据库
- 启用 apt/dpkg 锁
- 利润
1. 暂时禁用 apt/dpkg 锁
将以下文件暂时移至另一个位置:
- /var/lib/dpkg/锁
- /var/lib/dpkg/更新/
- /var/cache/apt/archives/lock
2. 更新/安装/删除软件
运行 apt-get 安装/删除软件,确认 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
,但是你将拥有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
#umo unt 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