3
0

Accepting request 875064 from home:lnussel:usrmove

Tools for usrmerge conversion

OBS-URL: https://build.opensuse.org/request/show/875064
OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=1
This commit is contained in:
Andreas Jaeger 2021-02-25 10:44:07 +00:00 committed by Git OBS Bridge
commit 101f37580f
11 changed files with 1721 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.osc

4
compat-usrmerge.changes Normal file
View File

@ -0,0 +1,4 @@
-------------------------------------------------------------------
Thu Feb 25 10:22:09 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- initial package

197
compat-usrmerge.spec Normal file
View File

@ -0,0 +1,197 @@
#
# spec file for package compat-usrmerge
#
# Copyright (c) 2020 SUSE LLC, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
%define nvr %{name}-%{version}-%{release}
Name: compat-usrmerge
Version: 84.87
Release: 0
Summary: Compat file triggers for usrmerge
License: MIT
Url: https://www.opensuse.org/
Source0: usrmerge.lua
Source1: usrmerge_files.lua
Source2: usrmergecheck.c
Source3: convertfs
Source4: xmv.c
Source5: usrmerge.attr
Source6: usrmerge_binsbindeps.lua
BuildRequires: gcc
BuildRequires: pkgconfig(rpm)
%description
%package tools
Summary: usrmerge tools
# have to turn requires off this off to avoid pulling in stuff
# before filessytem.
# xmv has very minimal glibc requirements and could probably be
# reduced further. The script runs only in the upgrade case,
# assuming that the tools work on the target system anyway.
AutoReq: 0
%description tools
%package build
Summary: usrmerge build tools
Requires: lua
%description build
%prep
%setup -qcT
%build
gcc -Wall %optflags -o usrmergecheck %{SOURCE2} `pkg-config --libs rpm`
gcc -Wall %optflags -o xmv %{SOURCE4}
%install
install -D -m755 usrmergecheck %{buildroot}%{_bindir}/usrmergecheck
mkdir -p %{buildroot}%{_rpmconfigdir}/lua
install -m644 %{SOURCE0} %{buildroot}%{_rpmconfigdir}/lua
install -m644 %{SOURCE1} %{buildroot}%{_rpmconfigdir}/lua
install -D -m755 %{SOURCE3} %{buildroot}%{_libexecdir}/convertfs
install -m755 xmv %{buildroot}%{_libexecdir}/xmv
install -D -m755 %{SOURCE5} %{buildroot}%{_fileattrsdir}/usrmerge.attr
install -m644 %{SOURCE6} %{buildroot}%{_rpmconfigdir}/lua
###
mkdir -p %{buildroot}/lib
mkdir -p %{buildroot}/%{_lib}
while read file; do
echo "usrmerge_files[\"$file\"] = 1" >> %{buildroot}%{_rpmconfigdir}/lua/usrmerge_files.lua
done <<EOF
/%{_lib}/libc-`rpm -q --qf "%{version}" glibc`.so
/%{_lib}/libc.so.6
%ifarch %arm
%ifarch armv6hl armv7hl
/%{_lib}/ld-linux-armhf.so.3
/%{_lib}/ld-linux.so.3
%else
/%{_lib}/ld-linux.so.3
%endif
%endif
%ifarch ia64
/%{_lib}/ld-linux-ia64.so.2
%endif
%ifarch ppc s390 mips hppa m68k
/%{_lib}/ld.so.1
%endif
%ifarch ppc64
/%{_lib}/ld64.so.1
%endif
%ifarch ppc64le
/%{_lib}/ld64.so.2
%endif
%ifarch s390x
/lib/ld64.so.1
/%{_lib}/ld64.so.1
%endif
%ifarch x86_64
/%{_lib}/ld-linux-x86-64.so.2
%endif
%ifarch %ix86 %sparc
/%{_lib}/ld-linux.so.2
%endif
%ifarch aarch64
/lib/ld-linux-aarch64.so.1
/%{_lib}/ld-linux-aarch64.so.1
%endif
%ifarch riscv64
/lib/ld-linux-riscv64-lp64d.so.1
/%{_lib}/ld-linux-riscv64-lp64d.so.1
%endif
EOF
#
%if 0
mkdir -p %{buildroot}/{sbin,bin,%{_lib}}
while read file; do
[ -n "$file" ] || continue
ln -s ../usr$file %{buildroot}$file
echo "%ghost %config(noreplace) $file"
done > files.list << EOF
%{lua:
package.path = package.path .. string.format(";%s/?.lua", rpm.expand("%{_sourcedir}"))
require("usrmerge_files")
for rp in pairs(usrmerge_files) do
print(rp.."\n")
end
}
EOF
%endif
%if 0%{?usrmerge_filetriggers}
%filetriggerin -p <lua> -- %{_sbindir} %{_bindir} %{_libdir}
require("usrmerge")
if posix.getenv("VERBOSE_FILETRIGGERS") then
usrmerge.debug = "%{nvr}(in)"
end
file = rpm.next_file()
while file do
usrmerge.add(file)
file = rpm.next_file()
end
io.flush()
%filetriggerpostun -p <lua> -- %{_sbindir} %{_bindir} %{_libdir}
-- the module is already gone if we get called for ourselves
if pcall(require, 'usrmerge') then
if posix.getenv("VERBOSE_FILETRIGGERS") then
usrmerge.debug = "%{nvr}(postun)"
end
file = rpm.next_file()
while file do
usrmerge.remove(file)
file = rpm.next_file()
end
io.flush()
end
%filetriggerpostun -p <lua> -- /sbin /bin /%{_lib}
-- the module is already gone if we get called for ourselves
if pcall(require, 'usrmerge') then
if posix.getenv("VERBOSE_FILETRIGGERS") then
usrmerge.debug = "%{nvr}(postun)"
end
file = rpm.next_file()
while file do
usrmerge.add_postun(file)
file = rpm.next_file()
end
io.flush()
end
%endif
%files
%dir %{_rpmconfigdir}/lua
%{_rpmconfigdir}/lua/usrmerge.lua
%{_rpmconfigdir}/lua/usrmerge_files.lua
%files tools
%{_bindir}/usrmergecheck
%{_libexecdir}/convertfs
%{_libexecdir}/xmv
%files build
%{_fileattrsdir}/usrmerge.attr
%dir %{_rpmconfigdir}/lua
%{_rpmconfigdir}/lua/usrmerge_binsbindeps.lua
%changelog

103
convertfs Normal file
View File

@ -0,0 +1,103 @@
#!/bin/bash
# based on code from dracut convertfs.sh
ROOT=
# the package is installed with AutoReq off, so no guarantee that
# coreutils actually works
if ! (cp --help && mountpoint --help && mountpoint --help) > /dev/null; then
echo "tools not functional, exit"
exit 1
fi
# clean up after ourselves no matter how we die.
cleanup() {
echo "Something failed, cleaning up"
for dir in bin sbin lib lib64; do
rm -rf -- "$ROOT/usr/${dir}.usrmerge"
done
}
trap 'ret=$?; [[ $ret -ne 0 ]] && cleanup;exit $ret;' EXIT
trap 'exit 1;' SIGINT
mountpoint -q "$ROOT/usr" || CP_HARDLINK="-l"
set -e
# merge / and /usr in new dir in /usr
for dir in bin sbin lib lib64; do
rm -rf -- "$ROOT/usr/${dir}.usrmerge"
[[ -L "$ROOT/$dir" ]] && continue
[[ -d "$ROOT/$dir" ]] || continue
echo "Make a copy of \`$ROOT/$dir'."
[[ -d "$ROOT/$dir" ]] \
&& cp -ax -l "$ROOT/$dir" "$ROOT/usr/${dir}.usrmerge"
echo "Merge the copy with \`$ROOT/usr/$dir'."
[[ -d "$ROOT/usr/${dir}.usrmerge" ]] \
|| mkdir -p "$ROOT/usr/${dir}.usrmerge"
cp -axT $CP_HARDLINK --backup --suffix=.usrmerge~ "$ROOT/usr/$dir" "$ROOT/usr/${dir}.usrmerge"
echo "Clean up duplicates in \`$ROOT/usr/$dir'."
# delete all symlinks that have been backed up. /usr versions
# override / ones
find "$ROOT/usr/${dir}.usrmerge" -type l -name '*.usrmerge~' -delete || :
# in rare cases the symlinks may point from /usr to /, so remove
# the link in that case
while read file; do
o=${file%%.usrmerge~}
[ -L "$o" ] && mv -f "$file" "$o"
done < <(find "$ROOT/usr/${dir}.usrmerge" \
-name '*.usrmerge~' -type f)
done
# switch over merged dirs in /usr
for dir in bin sbin lib lib64; do
if [ -d "$ROOT/usr/${dir}.usrmerge" ]; then
echo "Switch to new \`$ROOT/usr/$dir'."
/usr/libexec/xmv "$ROOT/usr/${dir}.usrmerge" "$ROOT/usr/$dir"
fi
done
# replace dirs in / with links to /usr
for dir in bin sbin lib lib64; do
if [ ! -L "$ROOT/$dir" -a -d "$ROOT/$dir" ]; then
echo "Create \`$ROOT/$dir' symlink."
rm -rf "$ROOT/${dir}.usrmerge" || :
ln -s usr/$dir "$ROOT/${dir}.usrmerge"
/usr/libexec/xmv "$ROOT/$dir" "$ROOT/${dir}.usrmerge"
fi
done
echo "Clean up backup files."
# everything seems to work; cleanup
for dir in bin sbin lib lib64; do
for pfx in usr/ /; do
# if we get killed in the middle of "rm -rf", ensure not to leave
# an incomplete directory, which is moved back by cleanup()
d="$ROOT/${pfx}${dir}.usrmerge"
if [ -d "$d" ]; then
echo "$d ..."
mv "$d" "$d~"
rm -rf "$d~"
fi
done
done
# XXX: confirm this is needed
for dir in lib lib64; do
[[ -d "$ROOT/$dir" ]] || continue
for lib in "$ROOT"/usr/${dir}/lib*.so*.usrmerge~; do
[[ -f $lib ]] || continue
mv -v $lib ${lib/.so/_so}
done
done
set +e
echo "Run ldconfig."
ldconfig -r "$ROOT"
#. $ROOT/etc/selinux/config
#if [ -n "$(command -v setfiles)" ] && [ "$SELINUX" != "disabled" ] && [ -f /etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts ]; then
# echo "Fixing SELinux labels"
# setfiles -r $ROOT -p /etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts $ROOT/sbin $ROOT/bin $ROOT/lib $ROOT/lib64 $ROOT/usr/lib $ROOT/usr/lib64 $ROOT/etc/ld.so.cache $ROOT/var/cache/ldconfig || :
#fi

10
usrmerge.attr Normal file
View File

@ -0,0 +1,10 @@
%__usrmerge_provides() %{lua:
-- XXX: use repo data of actual requires
require("usrmerge_binsbindeps")
local file = rpm.expand("%1")
local pfxlen = string.len(rpm.expand("%buildroot").."/usr")+1
if usrmerge_binsbindeps[string.sub(file, pfxlen)] then
print(string.sub(file, pfxlen))
end
}
%__usrmerge_path ^/usr/s?bin/.*

149
usrmerge.lua Normal file
View File

@ -0,0 +1,149 @@
usrmerge = { debug = nil } -- package
require("usrmerge_files")
-- for testing outside rpm
if posix == nil then
posix = require("posix")
function _symlink(old, new)
os.execute("ln -vs " .. old .. " " .. new)
end
posix.symlink = _symlink
end
function _log(msg)
if usrmerge.debug then
print(usrmerge.debug .. ": " .. msg)
end
end
function rootpath(path)
_, _, p = string.find(path, "^/usr(/.*)")
return p
end
function dirname(path)
_, _, d, b = string.find(path, "^(.*)/([^/]*)")
return d
end
function usrmerge._add(rp, relpath)
if not usrmerge_files[rp] then return end
if posix.stat(dirname(rp), "type") ~= "directory" then return end
createit = false
t = posix.stat(rp, "type")
if t == nil then
createit = true
elseif t == "link" then
dst = posix.readlink(rp)
if dst ~= relpath then
_log(rp .. ": fixing incorrect symlink (" .. dst .. " -> " .. relpath)
os.remove(rp)
createit = true
end
else
_log(rp .. " exist but is no link, skipping")
end
if createit then
_log("creating " .. rp .. " -> " .. relpath)
posix.symlink(relpath, rp)
end
end
function usrmerge.add(path)
rp = rootpath(path)
usrmerge._add(rp, ".." .. path)
end
-- if a legacy package with a file in /bin gets upgraded, it would
-- remove the link/file in /bin on uninstall. So we have to check
-- there and restore.
function usrmerge.add_postun(rp)
if posix.stat("/usr" .. rp, "type") then
usrmerge._add(rp, "../usr" .. rp)
end
end
-- needed for the build system to install all links of packages that got
-- installed via rpm2cpio so didn't call triggers
function usrmerge.addexisting()
for rp in pairs(usrmerge_files) do
usrmerge.add_postun(rp)
end
end
function usrmerge.remove(path)
rp = rootpath(path)
if not usrmerge_files[rp] then return end
if posix.stat(dirname(rp), "type") ~= "directory" then return end
t = posix.stat(path, "type")
if t then
_log(path .. " still exists, skipping")
return
end
t = posix.stat(rp, "type")
if t == "link" then
relpath = ".." .. path
dst = posix.readlink(rp)
if dst == relpath then
_log("remove " .. rp .. " -> " .. relpath)
os.remove(rp)
else
_log(rp .. " incorrect link (".. dst .."), skipping")
end
elseif t then
_log(rp .. " exist but is no link (".. t .."), skipping")
end
end
function usrmerge.migrate(d)
local errors = 0
for i, name in ipairs(posix.dir(d)) do
if name ~= '.' and name ~= '..' then
local p = d .. "/" .. name
local up = "/usr" .. p
local t = posix.stat(p, "type")
local ut = posix.stat(up, "type")
if ut == nil or (ut == "link" and t ~= "link") then
local f = posix.link
if t == "directory" then
-- can't hardlink dirs so move it
f = posix.rename
end
if ut ~= nil then
_log(" removing " .. up)
posix.unlink(up)
end
local ok, err, e = f(p, up)
if ok == nil then
print("FAILED " .. p .. " -> " .. up .. ": " .. err)
errors = errors + 1
else
_log(p .. " -> " .. up)
end
else
if t == "directory" then
print("BAD " .. p .. " is a directory but " .. up .. "exists")
errors = errors + 1
else
_log("skipped " .. p)
end
end
end
end
if errors > 0 then
print("have to continue despire errors")
end
local ok, err, e = posix.rename(d, d .. ".merged")
if ok == nil then
print("FAILED to move " .. d .. " out of the way")
else
ok, err, e = posix.symlink("usr" ..d, d)
if ok == nil then
print("FAILED to recreate " .. d .. " as link. Now we're in deep shit, sorry :-/")
end
end
end

112
usrmerge_binsbindeps.lua Normal file
View File

@ -0,0 +1,112 @@
usrmerge_binsbindeps = {
-- sgml-skel xorg-x11-Xvnc
["/bin/awk"] = 1,
-- glibc-locale-base jfbterm lsb uisp
["/bin/cat"] = 1,
-- lsb
["/bin/chgrp"] = 1,
-- logdigest lsb
["/bin/chmod"] = 1,
-- lsb
["/bin/chown"] = 1,
-- lsb lynx
["/bin/cp"] = 1,
-- dds2tar dt fpc-src lua-lmod petsc-devel petsc-openmpi1-devel petsc-openmpi2-devel petsc-openmpi3-devel petsc_3_14_1-gnu-mpich-hpc-devel petsc_3_14_1-gnu-mvapich2-hpc-devel petsc_3_14_1-gnu-openmpi1-hpc-devel petsc_3_14_1-gnu-openmpi2-hpc-devel petsc_3_14_1-gnu-openmpi3-hpc-devel python3-pymol rasmol texlive-latexmk-doc texlive-minitoc-doc texlive-seetexk-bin
["/bin/csh"] = 1,
-- lsb
["/bin/dd"] = 1,
-- lsb
["/bin/df"] = 1,
-- lsb
["/bin/echo"] = 1,
-- lsb
["/bin/false"] = 1,
-- lsb sendmail
["/bin/fuser"] = 1,
-- sysconfig-netconfig
["/bin/gawk"] = 1,
-- hplip os-prober
["/bin/grep"] = 1,
-- lsb mariadb openwsman-server patch2mail xorg-x11-Xvnc xplatproviders
["/bin/hostname"] = 1,
-- lsb
["/bin/kill"] = 1,
-- compiz-branding-SLED compiz-branding-openSUSE compiz-branding-upstream ini4j-javadoc install-initrd-Kubic install-initrd-MicroOS install-initrd-openSUSE ksh lsb
["/bin/ln"] = 1,
-- lsb nagios nagios-www ntp sca-appliance-common sysconfig-netconfig
["/bin/logger"] = 1,
-- lsb vnstat
["/bin/ls"] = 1,
-- lsb texlive-cjk-latex-extras
["/bin/mkdir"] = 1,
-- lsb
["/bin/mknod"] = 1,
-- aaa_base ctdb cvs yast2-printer
["/bin/mktemp"] = 1,
-- lsb
["/bin/more"] = 1,
-- lsb
["/bin/mount"] = 1,
-- lsb
["/bin/mv"] = 1,
-- sca-appliance-common
["/bin/ping"] = 1,
-- lsb
["/bin/ps"] = 1,
-- lsb
["/bin/pwd"] = 1,
-- canna compiz-branding-SLED compiz-branding-openSUSE compiz-branding-upstream ini4j-javadoc ksh lsb patch2mail tcl texlive-cjk-latex-extras tk yast2-network
["/bin/rm"] = 1,
-- lsb
["/bin/rmdir"] = 1,
-- clamav enscript gpm hplip lsb os-prober procmail yast2-bootloader
["/bin/sed"] = 1,
-- lsb
["/bin/sleep"] = 1,
-- lsb
["/bin/sort"] = 1,
-- lsb perl-Term-ReadKey
["/bin/stty"] = 1,
-- lsb vnstat
["/bin/su"] = 1,
-- lsb
["/bin/sync"] = 1,
-- clamav icecream lsb
["/bin/tar"] = 1,
-- logdigest lsb sound-theme-freedesktop tei_4
["/bin/touch"] = 1,
-- ksh lsb twin
["/bin/true"] = 1,
-- lsb
["/bin/umount"] = 1,
-- lsb
["/bin/uname"] = 1,
-- kdevplatform
["/bin/zsh"] = 1,
-- corosync eid-mw postgresql10-server postgresql11-server postgresql12-server postgresql13-server postgresql95-server postgresql96-server
["/sbin/chkconfig"] = 1,
-- sysconfig
["/sbin/ifup"] = 1,
-- libgtop-doc
["/sbin/install-info"] = 1,
-- vpnc
["/sbin/ip"] = 1,
-- setserial
["/sbin/isserial"] = 1,
-- mdadm
["/sbin/mkinitrd"] = 1,
-- avrdude os-prober uisp
["/sbin/modprobe"] = 1,
-- sysconfig
["/sbin/netconfig"] = 1,
-- cobbler
["/sbin/service"] = 1,
-- lsb
["/sbin/shutdown"] = 1,
-- xdm
["/sbin/startproc"] = 1,
-- budgie-screensaver xscreensaver
["/sbin/unix2_chkpwd"] = 1,
-- memtest86+
["/sbin/update-bootloader"] = 1,
}

695
usrmerge_files.lua Normal file
View File

@ -0,0 +1,695 @@
usrmerge_files = {
-- aaa_base
["/sbin/refresh_initrd"] = 1,
["/sbin/service"] = 1,
["/sbin/smart_agetty"] = 1,
-- apparmor-parser
["/sbin/apparmor_parser"] = 1,
["/sbin/rcapparmor"] = 1,
-- audit
["/sbin/audispd"] = 1,
["/sbin/auditctl"] = 1,
["/sbin/auditd"] = 1,
["/sbin/augenrules"] = 1,
["/sbin/aureport"] = 1,
["/sbin/ausearch"] = 1,
["/sbin/autrace"] = 1,
-- aws-efs-utils
["/sbin/mount.efs"] = 1,
-- bash
["/bin/bash"] = 1,
-- biosdevname
["/sbin/biosdevname"] = 1,
-- blktrace
["/bin/blkparse"] = 1,
["/bin/blktrace"] = 1,
["/bin/btrace"] = 1,
-- blog
["/sbin/blogctl"] = 1,
["/sbin/blogd"] = 1,
["/sbin/blogger"] = 1,
["/sbin/isserial"] = 1,
["/sbin/showconsole"] = 1,
-- btrfsprogs
["/sbin/btrfs"] = 1,
["/sbin/btrfs-convert"] = 1,
["/sbin/btrfs-image"] = 1,
["/sbin/btrfsck"] = 1,
["/sbin/btrfstune"] = 1,
["/sbin/fsck.btrfs"] = 1,
["/sbin/mkfs.btrfs"] = 1,
-- busybox-coreutils
["/bin/arch"] = 1,
["/bin/basename"] = 1,
["/bin/cat"] = 1,
["/bin/chgrp"] = 1,
["/bin/chmod"] = 1,
["/bin/chown"] = 1,
["/bin/cp"] = 1,
["/bin/date"] = 1,
["/bin/dd"] = 1,
["/bin/df"] = 1,
["/bin/echo"] = 1,
["/bin/false"] = 1,
["/bin/ln"] = 1,
["/bin/ls"] = 1,
["/bin/md5sum"] = 1,
["/bin/mkdir"] = 1,
["/bin/mknod"] = 1,
["/bin/mktemp"] = 1,
["/bin/mv"] = 1,
["/bin/pwd"] = 1,
["/bin/readlink"] = 1,
["/bin/rm"] = 1,
["/bin/rmdir"] = 1,
["/bin/sleep"] = 1,
["/bin/sort"] = 1,
["/bin/stat"] = 1,
["/bin/stty"] = 1,
["/bin/sync"] = 1,
["/bin/touch"] = 1,
["/bin/true"] = 1,
["/bin/uname"] = 1,
-- busybox-cpio
["/bin/cpio"] = 1,
-- busybox-ed
["/bin/ed"] = 1,
-- busybox-findutils
["/bin/find"] = 1,
-- busybox-gawk
["/bin/awk"] = 1,
-- busybox-grep
["/bin/egrep"] = 1,
["/bin/fgrep"] = 1,
["/bin/grep"] = 1,
-- busybox-gzip
["/bin/gunzip"] = 1,
["/bin/gzip"] = 1,
["/bin/zcat"] = 1,
-- busybox-hostname
["/bin/dnsdomainname"] = 1,
["/bin/hostname"] = 1,
-- busybox-iproute2
["/bin/ip"] = 1,
["/sbin/ip"] = 1,
-- busybox-iputils
["/bin/arping"] = 1,
["/bin/ping"] = 1,
["/bin/ping6"] = 1,
-- busybox-kbd
["/bin/chvt"] = 1,
["/bin/deallocvt"] = 1,
["/bin/openvt"] = 1,
["/bin/setfont"] = 1,
["/bin/setkeycodes"] = 1,
["/bin/setlogcons"] = 1,
["/bin/showkey"] = 1,
["/sbin/loadkmap"] = 1,
-- busybox-kmod
["/bin/lsmod"] = 1,
["/sbin/depmod"] = 1,
["/sbin/insmod"] = 1,
["/sbin/lsmod"] = 1,
["/sbin/modinfo"] = 1,
["/sbin/modprobe"] = 1,
["/sbin/rmmod"] = 1,
-- busybox-misc
["/bin/chattr"] = 1,
["/bin/fatattr"] = 1,
["/bin/iostat"] = 1,
["/bin/lsattr"] = 1,
["/bin/lzop"] = 1,
["/bin/makemime"] = 1,
["/bin/mpstat"] = 1,
["/bin/reformime"] = 1,
["/sbin/mdev"] = 1,
["/sbin/mkdosfs"] = 1,
["/sbin/mke2fs"] = 1,
["/sbin/mkfs.ext2"] = 1,
["/sbin/mkfs.vfat"] = 1,
["/sbin/setconsole"] = 1,
["/sbin/uevent"] = 1,
["/sbin/zcip"] = 1,
-- busybox-net-tools
["/bin/ifconfig"] = 1,
["/bin/netstat"] = 1,
["/bin/route"] = 1,
["/sbin/arp"] = 1,
["/sbin/ether-wake"] = 1,
["/sbin/iptunnel"] = 1,
["/sbin/nameif"] = 1,
["/sbin/slattach"] = 1,
-- busybox-policycoreutils
["/sbin/restorecon"] = 1,
["/sbin/setfiles"] = 1,
-- busybox-procps
["/bin/pgrep"] = 1,
["/bin/pkill"] = 1,
["/bin/ps"] = 1,
["/sbin/sysctl"] = 1,
-- busybox-psmisc
["/bin/fuser"] = 1,
-- busybox-sed
["/bin/sed"] = 1,
-- busybox-sh
["/bin/sh"] = 1,
-- busybox-sysvinit-tools
["/bin/fsync"] = 1,
["/bin/pidof"] = 1,
["/bin/usleep"] = 1,
["/sbin/killall5"] = 1,
["/sbin/pidof"] = 1,
-- busybox-tar
["/bin/tar"] = 1,
-- busybox-tunctl
["/sbin/tunctl"] = 1,
-- busybox-util-linux
["/bin/dmesg"] = 1,
["/bin/kill"] = 1,
["/bin/logger"] = 1,
["/bin/login"] = 1,
["/bin/more"] = 1,
["/bin/mount"] = 1,
["/bin/su"] = 1,
["/bin/umount"] = 1,
["/sbin/blkid"] = 1,
["/sbin/findfs"] = 1,
["/sbin/fsck"] = 1,
["/sbin/losetup"] = 1,
["/sbin/mkswap"] = 1,
["/sbin/nologin"] = 1,
-- busybox-vi
["/bin/vi"] = 1,
-- busybox-vlan
["/sbin/vconfig"] = 1,
-- ceph-common
["/sbin/mount.ceph"] = 1,
-- cifs-utils
["/sbin/mount.cifs"] = 1,
-- crda
["/sbin/crda"] = 1,
["/sbin/regdbdump"] = 1,
-- cryptsetup
["/sbin/cryptsetup"] = 1,
-- dash
["/bin/dash"] = 1,
-- davfs2
["/sbin/mount.davfs"] = 1,
["/sbin/umount.davfs"] = 1,
-- dbus-1
["/bin/dbus-cleanup-sockets"] = 1,
["/bin/dbus-daemon"] = 1,
["/bin/dbus-monitor"] = 1,
["/bin/dbus-send"] = 1,
["/bin/dbus-test-tool"] = 1,
["/bin/dbus-update-activation-environment"] = 1,
["/bin/dbus-uuidgen"] = 1,
-- dd_rescue
["/bin/dd_rescue"] = 1,
-- dd_rhelp
["/bin/dd_rhelp"] = 1,
-- device-mapper
["/sbin/dmsetup"] = 1,
-- dhcp-client
["/sbin/dhclient"] = 1,
["/sbin/dhclient-script"] = 1,
["/sbin/dhclient6"] = 1,
-- diod
["/sbin/mount.diod"] = 1,
-- dmraid
["/sbin/dmevent_tool"] = 1,
["/sbin/dmraid"] = 1,
-- dosfstools
["/sbin/dosfsck"] = 1,
["/sbin/dosfslabel"] = 1,
["/sbin/fsck.fat"] = 1,
["/sbin/fsck.msdos"] = 1,
["/sbin/fsck.vfat"] = 1,
["/sbin/mkfs.fat"] = 1,
["/sbin/mkfs.msdos"] = 1,
-- dracut
["/sbin/installkernel"] = 1,
["/sbin/mkinitrd"] = 1,
-- drbd-utils
["/sbin/drbdadm"] = 1,
["/sbin/drbdmeta"] = 1,
["/sbin/drbdmon"] = 1,
["/sbin/drbdsetup"] = 1,
-- e2fsprogs
["/sbin/badblocks"] = 1,
["/sbin/debugfs"] = 1,
["/sbin/dumpe2fs"] = 1,
["/sbin/e2fsck"] = 1,
["/sbin/e2image"] = 1,
["/sbin/e2label"] = 1,
["/sbin/e2mmpstatus"] = 1,
["/sbin/e2undo"] = 1,
["/sbin/fsck.ext2"] = 1,
["/sbin/fsck.ext3"] = 1,
["/sbin/fsck.ext4"] = 1,
["/sbin/logsave"] = 1,
["/sbin/mkfs.ext3"] = 1,
["/sbin/mkfs.ext4"] = 1,
["/sbin/resize2fs"] = 1,
["/sbin/tune2fs"] = 1,
-- ecryptfs-utils
["/sbin/mount.ecryptfs"] = 1,
["/sbin/mount.ecryptfs_private"] = 1,
["/sbin/umount.ecryptfs"] = 1,
["/sbin/umount.ecryptfs_private"] = 1,
-- elilo
["/sbin/elilo"] = 1,
["/sbin/eliloalt"] = 1,
-- exfat-utils
["/sbin/dumpexfat"] = 1,
["/sbin/exfatfsck"] = 1,
["/sbin/exfatlabel"] = 1,
["/sbin/fsck.exfat"] = 1,
["/sbin/mkexfatfs"] = 1,
["/sbin/mkfs.exfat"] = 1,
-- f2fs-tools-compat
["/sbin/defrag.f2fs"] = 1,
["/sbin/dump.f2fs"] = 1,
["/sbin/f2fstat"] = 1,
["/sbin/fibmap.f2fs"] = 1,
["/sbin/fsck.f2fs"] = 1,
["/sbin/mkfs.f2fs"] = 1,
["/sbin/parse.f2fs"] = 1,
["/sbin/resize.f2fs"] = 1,
["/sbin/sload.f2fs"] = 1,
-- fedfs-utils-client
["/sbin/mount.fedfs"] = 1,
-- fillup
["/bin/fillup"] = 1,
-- fuse
["/sbin/mount.fuse"] = 1,
-- fuse-exfat
["/sbin/mount.exfat"] = 1,
["/sbin/mount.exfat-fuse"] = 1,
-- fuse3
["/sbin/mount.fuse3"] = 1,
-- fxload
["/sbin/fxload"] = 1,
-- gawk
["/bin/gawk"] = 1,
-- glibc
["/sbin/ldconfig"] = 1,
-- glusterfs
["/sbin/mount.glusterfs"] = 1,
-- grubby
["/sbin/grubby"] = 1,
["/sbin/new-kernel-pkg"] = 1,
-- hdparm
["/sbin/hdparm"] = 1,
["/sbin/wiper.sh"] = 1,
-- hostname
["/bin/domainname"] = 1,
["/bin/nisdomainname"] = 1,
["/bin/ypdomainname"] = 1,
-- info
["/sbin/install-info"] = 1,
-- info4
["/sbin/install-info4"] = 1,
-- initviocons
["/bin/initviocons"] = 1,
-- insserv-compat
["/sbin/chkconfig"] = 1,
["/sbin/insserv"] = 1,
-- iputils
["/bin/clockdiff"] = 1,
["/bin/tracepath"] = 1,
["/bin/tracepath6"] = 1,
["/sbin/rdisc"] = 1,
-- ipvsadm
["/sbin/ipvsadm"] = 1,
["/sbin/ipvsadm-restore"] = 1,
["/sbin/ipvsadm-save"] = 1,
-- isapnp
["/sbin/isapnp"] = 1,
["/sbin/pnpdump"] = 1,
-- iscsiuio
["/sbin/brcm_iscsiuio"] = 1,
["/sbin/iscsiuio"] = 1,
-- jfsutils
["/sbin/fsck.jfs"] = 1,
["/sbin/jfs_debugfs"] = 1,
["/sbin/jfs_fsck"] = 1,
["/sbin/jfs_fscklog"] = 1,
["/sbin/jfs_logdump"] = 1,
["/sbin/jfs_mkfs"] = 1,
["/sbin/jfs_tune"] = 1,
["/sbin/mkfs.jfs"] = 1,
-- kbd
["/bin/clrunimap"] = 1,
["/bin/dumpkeys"] = 1,
["/bin/fgconsole"] = 1,
["/bin/getkeycodes"] = 1,
["/bin/getunimap"] = 1,
["/bin/kbd_mode"] = 1,
["/bin/kbdinfo"] = 1,
["/bin/kbdrate"] = 1,
["/bin/loadkeys"] = 1,
["/bin/loadunimap"] = 1,
["/bin/mapscrn"] = 1,
["/bin/outpsfheader"] = 1,
["/bin/psfaddtable"] = 1,
["/bin/psfgettable"] = 1,
["/bin/psfstriptable"] = 1,
["/bin/psfxtable"] = 1,
["/bin/resizecons"] = 1,
["/bin/screendump"] = 1,
["/bin/setleds"] = 1,
["/bin/setmetamode"] = 1,
["/bin/setpalette"] = 1,
["/bin/setvesablank"] = 1,
["/bin/setvtrgb"] = 1,
["/bin/showconsolefont"] = 1,
["/bin/spawn_console"] = 1,
["/bin/spawn_login"] = 1,
["/bin/unicode_start"] = 1,
["/bin/unicode_stop"] = 1,
["/sbin/fbtest"] = 1,
-- kexec-tools
["/sbin/kexec"] = 1,
-- keyutils
["/bin/keyctl"] = 1,
["/sbin/key.dns_resolver"] = 1,
["/sbin/request-key"] = 1,
-- klogd
["/sbin/klogd"] = 1,
-- kpartx
["/sbin/kpartx"] = 1,
-- ksh
["/bin/ksh93"] = 1,
-- libewf-tools
["/sbin/mount.ewf"] = 1,
["/sbin/umount.ewf"] = 1,
-- live-net-installer
["/bin/extend"] = 1,
-- lvm2
["/sbin/lvchange"] = 1,
["/sbin/lvconvert"] = 1,
["/sbin/lvcreate"] = 1,
["/sbin/lvdisplay"] = 1,
["/sbin/lvextend"] = 1,
["/sbin/lvm"] = 1,
["/sbin/lvmconfig"] = 1,
["/sbin/lvmdiskscan"] = 1,
["/sbin/lvmdump"] = 1,
["/sbin/lvmpolld"] = 1,
["/sbin/lvmsadc"] = 1,
["/sbin/lvmsar"] = 1,
["/sbin/lvreduce"] = 1,
["/sbin/lvremove"] = 1,
["/sbin/lvrename"] = 1,
["/sbin/lvresize"] = 1,
["/sbin/lvs"] = 1,
["/sbin/lvscan"] = 1,
["/sbin/pvchange"] = 1,
["/sbin/pvck"] = 1,
["/sbin/pvcreate"] = 1,
["/sbin/pvdisplay"] = 1,
["/sbin/pvmove"] = 1,
["/sbin/pvremove"] = 1,
["/sbin/pvresize"] = 1,
["/sbin/pvs"] = 1,
["/sbin/pvscan"] = 1,
["/sbin/vgcfgbackup"] = 1,
["/sbin/vgcfgrestore"] = 1,
["/sbin/vgchange"] = 1,
["/sbin/vgck"] = 1,
["/sbin/vgconvert"] = 1,
["/sbin/vgcreate"] = 1,
["/sbin/vgdisplay"] = 1,
["/sbin/vgexport"] = 1,
["/sbin/vgextend"] = 1,
["/sbin/vgimport"] = 1,
["/sbin/vgimportclone"] = 1,
["/sbin/vgmerge"] = 1,
["/sbin/vgmknodes"] = 1,
["/sbin/vgreduce"] = 1,
["/sbin/vgremove"] = 1,
["/sbin/vgrename"] = 1,
["/sbin/vgs"] = 1,
["/sbin/vgscan"] = 1,
["/sbin/vgsplit"] = 1,
-- mailx
["/bin/mail"] = 1,
-- makedev
["/sbin/MAKEDEV"] = 1,
-- mawk
["/bin/mawk"] = 1,
-- mcstrans
["/sbin/mcstransd"] = 1,
-- mdadm
["/sbin/mdadm"] = 1,
["/sbin/mdmon"] = 1,
-- mingetty
["/sbin/mingetty"] = 1,
-- mksh
["/bin/ksh"] = 1,
["/bin/lksh"] = 1,
["/bin/mksh"] = 1,
["/bin/pdksh"] = 1,
-- multipath-tools
["/sbin/mpathpersist"] = 1,
["/sbin/multipath"] = 1,
["/sbin/multipathd"] = 1,
-- munin
["/sbin/rcmunin-cgi-graph"] = 1,
["/sbin/rcmunin-cgi-html"] = 1,
-- munin-node
["/sbin/rcmunin-node"] = 1,
-- net-tools
["/sbin/plipconfig"] = 1,
-- net-tools-deprecated
["/sbin/ipmaddr"] = 1,
-- netconsole-tools
["/sbin/netconsole-server"] = 1,
-- nfs-client
["/sbin/mount.nfs"] = 1,
["/sbin/mount.nfs4"] = 1,
["/sbin/umount.nfs"] = 1,
["/sbin/umount.nfs4"] = 1,
-- nfs-kernel-server
["/sbin/nfsdcltrack"] = 1,
-- nilfs-utils
["/sbin/mkfs.nilfs2"] = 1,
["/sbin/mount.nilfs2"] = 1,
["/sbin/nilfs_cleanerd"] = 1,
["/sbin/umount.nilfs2"] = 1,
-- ntfs-3g
["/sbin/mount.lowntfs-3g"] = 1,
["/sbin/mount.ntfs"] = 1,
["/sbin/mount.ntfs-3g"] = 1,
-- ntfsprogs
["/sbin/mkfs.ntfs"] = 1,
-- ocfs2-tools
["/sbin/fsck.ocfs2"] = 1,
["/sbin/mkfs.ocfs2"] = 1,
["/sbin/mount.ocfs2"] = 1,
["/sbin/mounted.ocfs2"] = 1,
["/sbin/o2cluster"] = 1,
["/sbin/ocfs2_hb_ctl"] = 1,
["/sbin/tunefs.ocfs2"] = 1,
-- ocfs2-tools-o2cb
["/sbin/o2cb"] = 1,
["/sbin/o2cb.init"] = 1,
["/sbin/o2cb_ctl"] = 1,
["/sbin/ocfs2.init"] = 1,
-- ooRexx
["/sbin/rcooRexx"] = 1,
-- open-iscsi
["/sbin/iscsi-gen-initiatorname"] = 1,
["/sbin/iscsi-iname"] = 1,
["/sbin/iscsi_discovery"] = 1,
["/sbin/iscsi_fw_login"] = 1,
["/sbin/iscsi_offload"] = 1,
["/sbin/iscsiadm"] = 1,
["/sbin/iscsid"] = 1,
["/sbin/iscsistart"] = 1,
-- open-vm-tools
["/sbin/mount.vmhgfs"] = 1,
-- pam
["/sbin/faillock"] = 1,
["/sbin/mkhomedir_helper"] = 1,
["/sbin/pam_namespace_helper"] = 1,
["/sbin/pam_timestamp_check"] = 1,
["/sbin/unix2_chkpwd"] = 1,
["/sbin/unix_chkpwd"] = 1,
["/sbin/unix_update"] = 1,
-- pam-deprecated
["/sbin/pam_tally2"] = 1,
-- pam_mount
["/sbin/mount.crypt"] = 1,
["/sbin/mount.crypt_LUKS"] = 1,
["/sbin/mount.crypto_LUKS"] = 1,
["/sbin/umount.crypt"] = 1,
["/sbin/umount.crypt_LUKS"] = 1,
["/sbin/umount.crypto_LUKS"] = 1,
-- pciutils
["/sbin/lspci"] = 1,
["/sbin/setpci"] = 1,
-- pcmciautils
["/sbin/lspcmcia"] = 1,
["/sbin/pccardctl"] = 1,
-- perl-Bootloader
["/sbin/pbl"] = 1,
["/sbin/update-bootloader"] = 1,
-- plymouth
["/bin/plymouth"] = 1,
-- policycoreutils
["/sbin/restorecon_xattr"] = 1,
-- polkit-default-privs
["/sbin/chkstat-polkit"] = 1,
["/sbin/set_polkit_default_privs"] = 1,
-- powerd
["/sbin/detectups"] = 1,
["/sbin/powerd"] = 1,
-- rarpd
["/sbin/rarpd"] = 1,
-- rash
["/bin/rash"] = 1,
-- reiserfs
["/sbin/debugfs.reiserfs"] = 1,
["/sbin/debugreiserfs"] = 1,
["/sbin/fsck.reiserfs"] = 1,
["/sbin/mkfs.reiserfs"] = 1,
["/sbin/mkreiserfs"] = 1,
["/sbin/reiserfsck"] = 1,
["/sbin/reiserfstune"] = 1,
["/sbin/resize_reiserfs"] = 1,
["/sbin/tunefs.reiserfs"] = 1,
-- rpcbind
["/bin/rpcinfo"] = 1,
["/sbin/pmap_set2"] = 1,
["/sbin/rpcbind"] = 1,
["/sbin/rpcinfo"] = 1,
-- rpm
["/bin/rpm"] = 1,
-- rsyslog
["/sbin/rsyslogd"] = 1,
-- rungetty
["/sbin/rungetty"] = 1,
-- scsh
["/bin/scsh"] = 1,
-- scsirastools
["/sbin/getmd"] = 1,
["/sbin/mdevt"] = 1,
["/sbin/sgdefects"] = 1,
["/sbin/sgdiag"] = 1,
["/sbin/sgdiskmon"] = 1,
["/sbin/sgdskfl"] = 1,
["/sbin/sgevt"] = 1,
["/sbin/sgmode"] = 1,
["/sbin/sgraidmon"] = 1,
["/sbin/sgsafte"] = 1,
-- sdparm
["/sbin/sas_disk_blink"] = 1,
["/sbin/scsi_ch_swp"] = 1,
["/sbin/sdparm"] = 1,
-- supportutils
["/sbin/analyzevmcore"] = 1,
["/sbin/chkbin"] = 1,
["/sbin/getappcore"] = 1,
["/sbin/supportconfig"] = 1,
-- sysconfig
["/sbin/ifuser"] = 1,
["/sbin/rcnetwork"] = 1,
-- sysconfig-netconfig
["/sbin/netconfig"] = 1,
-- syslog-ng
["/sbin/syslog-ng"] = 1,
-- syslog-service
["/sbin/rcsyslog"] = 1,
-- syslogd
["/sbin/syslogd"] = 1,
-- systemd-sysvinit
["/sbin/halt"] = 1,
["/sbin/init"] = 1,
["/sbin/poweroff"] = 1,
["/sbin/reboot"] = 1,
["/sbin/runlevel"] = 1,
["/sbin/shutdown"] = 1,
["/sbin/telinit"] = 1,
-- sysvinit-tools
["/sbin/checkproc"] = 1,
["/sbin/fstab-decode"] = 1,
["/sbin/killproc"] = 1,
["/sbin/mkill"] = 1,
["/sbin/pidofproc"] = 1,
["/sbin/rvmtab"] = 1,
["/sbin/start_daemon"] = 1,
["/sbin/startproc"] = 1,
["/sbin/vhangup"] = 1,
-- tcsh
["/bin/csh"] = 1,
["/bin/tcsh"] = 1,
-- tomoyo-tools
["/sbin/tomoyo-init"] = 1,
-- udhcp
["/sbin/udhcpc"] = 1,
-- util-linux
["/bin/findmnt"] = 1,
["/bin/lsblk"] = 1,
["/sbin/agetty"] = 1,
["/sbin/blockdev"] = 1,
["/sbin/cfdisk"] = 1,
["/sbin/chcpu"] = 1,
["/sbin/ctrlaltdel"] = 1,
["/sbin/fdisk"] = 1,
["/sbin/fsck.cramfs"] = 1,
["/sbin/fsck.minix"] = 1,
["/sbin/fsfreeze"] = 1,
["/sbin/fstrim"] = 1,
["/sbin/hwclock"] = 1,
["/sbin/mkfs"] = 1,
["/sbin/mkfs.bfs"] = 1,
["/sbin/mkfs.cramfs"] = 1,
["/sbin/mkfs.minix"] = 1,
["/sbin/pivot_root"] = 1,
["/sbin/raw"] = 1,
["/sbin/sfdisk"] = 1,
["/sbin/swaplabel"] = 1,
["/sbin/swapoff"] = 1,
["/sbin/swapon"] = 1,
["/sbin/switch_root"] = 1,
["/sbin/wipefs"] = 1,
-- vim
["/bin/ex"] = 1,
["/bin/vim"] = 1,
-- virtualbox
["/sbin/vboxconfig"] = 1,
-- virtualbox-guest-tools
["/sbin/mount.vboxsf"] = 1,
["/sbin/vboxguestconfig"] = 1,
-- virtualbox-qt
["/sbin/vbox-fix-usb-rules.sh"] = 1,
-- wicked-service
["/sbin/ifdown"] = 1,
["/sbin/ifprobe"] = 1,
["/sbin/ifstatus"] = 1,
["/sbin/ifup"] = 1,
-- xen-tools-domU
["/bin/domu-xenstore"] = 1,
["/bin/xenstore-chmod"] = 1,
["/bin/xenstore-exists"] = 1,
["/bin/xenstore-list"] = 1,
["/bin/xenstore-ls"] = 1,
["/bin/xenstore-read"] = 1,
["/bin/xenstore-rm"] = 1,
["/bin/xenstore-watch"] = 1,
["/bin/xenstore-write"] = 1,
-- xfsdump
["/sbin/xfsdump"] = 1,
["/sbin/xfsrestore"] = 1,
-- xfsprogs
["/sbin/fsck.xfs"] = 1,
["/sbin/mkfs.xfs"] = 1,
["/sbin/xfs_repair"] = 1,
-- yast2
["/sbin/yast"] = 1,
["/sbin/yast2"] = 1,
-- zsh
["/bin/zsh"] = 1,
}

351
usrmergecheck.c Normal file
View File

@ -0,0 +1,351 @@
/*
Copyright (c) 2019,2020 SUSE LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <libintl.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>
#include <rpm/rpmlib.h>
#include <fcntl.h>
#include <rpm/rpmcli.h>
#include <rpm/header.h>
#include <rpm/rpmfiles.h>
static int verbose = 0;
const char *dirs[] = {
"/usr/bin",
"/usr/lib",
#if __WORDSIZE == 64
"/usr/lib64",
#endif
"/usr/sbin",
NULL
};
// rpmdb stores dirs with slash
const char *rpmdirs[] = {
"/bin/",
"/lib/",
#if __WORDSIZE == 64
"/lib64/",
#endif
"/sbin/",
NULL
};
static inline int startswith(const char* s, const char* pfx) {
return strncmp(s, pfx, strlen(pfx)) == 0;
}
static inline char stm(mode_t m) {
switch (m & S_IFMT) {
case S_IFBLK: return 'b';
case S_IFCHR: return 'c';
case S_IFDIR: return 'd';
case S_IFIFO: return 'p';
case S_IFLNK: return 'l';
case S_IFREG: return 'f';
case S_IFSOCK: return 'S';
}
return '?';
}
int check_directory(const char* dir);
int check_entry(const char* p)
{
struct stat st, stu;
const char* rp = p+strlen("/usr");
// if the file doesn't exist in /usr we're safe
if(lstat(p, &stu)) {
if (errno != ENOENT) {
perror(p);
return 1;
}
if (verbose > 1) printf("%s unique\n", p);
return 0;
}
if(lstat(rp, &st)) {
perror(rp);
return 1;
}
// differnt file type, check if one is link and can be dropped
if ((st.st_mode & S_IFMT) != (stu.st_mode & S_IFMT) || (S_ISLNK(st.st_mode) && S_ISLNK(stu.st_mode))) {
if (S_ISLNK(st.st_mode) || S_ISLNK(stu.st_mode)) {
struct stat sb1, sb2;
// if the link in / points to the file in /usr it's fine
// XXX: in theory there could be a weird
// chain of links pointing back and forth
// between /usr and /, we ignore that here
if(!stat(rp, &sb1) && !stat(p, &sb2) && sb1.st_ino == sb2.st_ino) {
if (verbose) printf("%s same file, ok\n", rp);
return 0;
}
}
fprintf(stderr, "%s mode mismatch %c vs %c\n", rp, stm(st.st_mode), stm(stu.st_mode));
return 1;
} else {
if (S_ISLNK(st.st_mode)) {
char t1[PATH_MAX] = {0};
char t2[PATH_MAX] = {0};
if(readlink(rp, t1, sizeof(t1)) == -1) {
perror(rp);
return 1;
}
if(readlink(p, t2, sizeof(t2)) == -1) {
perror(p);
return 1;
}
if (!strcmp(t1, t2)) {
if (verbose) {
printf("%s and %s both point %s, ok\n", rp, p, t1);
}
return 0;
} else {
fprintf(stderr, "%s link mismatch %s vs %s\n", rp, t1, t2);
}
} else if (!S_ISDIR(st.st_mode)) {
fprintf(stderr, "%s duplicated\n", rp);
return 1;
}
// both are directories, check recursive
return check_directory(p);
}
}
int check_directory(const char* dir)
{
DIR* dh;
struct dirent* d;
unsigned failed = 0;
dh = opendir(dir+strlen("/usr"));
if (!dh) {
perror(dir);
return 1;
}
while ((d = readdir(dh))) {
char p[PATH_MAX] = {0};
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
stpcpy(stpcpy(stpcpy(p, dir), "/"), d->d_name);
failed += check_entry(p);
}
return failed;
}
int check_filesystem(const char* rootdir)
{
unsigned failed = 0;
if (rootdir) {
if (chroot(rootdir)) {
perror("chroot");
return 1;
}
}
for (int i = 0; dirs[i]; ++i) {
struct stat st;
const char* d = dirs[i]+strlen("/usr");
if (lstat(d, &st)) {
if (errno != ENOENT)
perror(d);
continue;
}
if (S_ISDIR(st.st_mode)) {
failed += check_directory(dirs[i]);
} else if (S_ISLNK(st.st_mode)) {
char buf[PATH_MAX] = {0};
if(readlink(d, buf, sizeof(buf)) == -1) {
perror(d);
continue;
}
if (strcmp(buf, dirs[i]+1)) {
fprintf(stderr, "wrong link %s: %s should be %s\n", d, buf, dirs[i]+1);
}
}
}
if (failed) {
fprintf(stderr, ngettext("%u file prevents usrmerge\n", "%u files prevent usrmerge\n", failed), failed);
}
return failed == 0;
}
int rpm_findusrfile(rpmts ts, Header hdr, rpmfi orig_fi)
{
char fn[PATH_MAX] = "/usr";
strcpy(fn+strlen(fn), rpmfiFN(orig_fi));
rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_INSTFILENAMES, fn, 0);
if (mi) {
Header h;
int conflict = 1;
while ((h = rpmdbNextIterator(mi)) != NULL) {
rpmfiles files = rpmfilesNew(NULL, hdr, 0, 0);
rpmfi fi = rpmfilesIter(files, 0);
int fx = rpmfiFindFN(fi, fn);
if (fx != -1) {
rpmfiSetFX(fi, fx);
if (S_ISDIR(rpmfiFMode(fi)) && S_ISDIR(rpmfiFMode(orig_fi))) {
conflict = 2;
}
}
rpmfiFree(fi);
rpmfilesFree(files);
}
// we just look at the first one. If there's a
// second match and that is somewhow conflicting the
// system was screwed already.
rpmdbFreeIterator(mi);
return conflict;
}
return 0;
}
int check_rpmdb(char* rootdir)
{
unsigned failed = 0;
rpmcliConfigured();
rpmts ts = rpmtsCreate();
if (!ts) {
fprintf(stderr, "failed to create RPM transaction\n");
return -1;
}
if (rootdir)
rpmtsSetRootDir(ts, rootdir);
if (rpmtsOpenDB(ts, O_RDONLY) != 0) {
fprintf(stderr, "failed to open RPM database\n");
return -1;
}
rpmdbMatchIterator iter = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
Header hdr;
while ((hdr = rpmdbNextIterator(iter)) != NULL) {
rpmfiles files = rpmfilesNew(NULL, hdr, 0, 0);
rpmfi fi = rpmfilesIter(files, 0);
char skipdir[PATH_MAX] = {0};
int conflict = 0;
while (rpmfiNext(fi) >= 0) {
if (skipdir[0] && startswith(rpmfiFN(fi), skipdir)) {
if (verbose > 2)
printf("skipping %s as %s is known\n", rpmfiFN(fi), skipdir);
continue;
} else {
skipdir[0] = 0;
}
for (int i = 0; rpmdirs[i]; ++i) {
if(startswith(rpmfiODN(fi), rpmdirs[i])) {
rpm_mode_t m = rpmfiFMode(fi);
conflict = rpm_findusrfile(ts, hdr, fi);
if (conflict) {
if (conflict == 2) {
if (verbose > 2) {
fprintf(stderr, "directory %s ok\n", rpmfiFN(fi));
}
conflict = 0;
} else if (verbose > 1) {
char* n = headerGetAsString(hdr, RPMTAG_NEVRA);
fprintf(stderr, "%s: %s conflict\n", n, rpmfiFN(fi));
free(n);
}
} else if (S_ISDIR(m)) {
// an optimization so we don't have to check hundreds
// of kernel modules. If the file at hand is a directory
// and does not exist in /usr we can just skip the rest.
strcpy(skipdir, rpmfiFN(fi));
}
break;
}
}
}
rpmfiFree(fi);
rpmfilesFree(files);
if (conflict) {
++failed;
if (verbose == 1) {
char* n = headerGetAsString(hdr, RPMTAG_NEVRA);
printf("%s breaks\n", n);
free(n);
}
}
}
if (failed) {
fprintf(stderr, ngettext("%u package prevents usrmerge\n", "%u packages prevent usrmerge\n", failed), failed);
}
return failed == 0;
}
int main(int argc, char** argv)
{
enum { fs, rpmdb } mode = fs;
int c;
char* rootdir = NULL;
static struct option long_options[] = {
{"verbose", no_argument, 0, 'v' },
{"rpmdb", no_argument, 0, 128 },
{"root", required_argument, 0, 129 },
{0, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, "v", long_options, NULL)) != -1) {
switch(c) {
case 'v': ++verbose; break;
case 128: mode = rpmdb; break;
case 129: rootdir=strdup(optarg); break;
}
}
if (mode == rpmdb)
return check_rpmdb(rootdir) == 0;
return check_filesystem(rootdir) == 0;
}

76
xmv.c Normal file
View File

@ -0,0 +1,76 @@
/*
Copyright (c) 2020 SUSE LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#ifndef RENAME_EXCHANGE
# define RENAME_EXCHANGE (1 << 1)
#endif
static int verbose;
void help(const char* prog, int ret)
{
printf("Usage: %s SOURCE TARGET\n", prog);
puts("Exchange names of SOURCE and TARGET");
exit(ret);
}
int main(int argc, char** argv)
{
int c;
int r;
static struct option long_options[] = {
{"verbose", no_argument, 0, 'v' },
{"help", no_argument, 0, 255 },
{0, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, "v", long_options, NULL)) != -1) {
switch(c) {
case 'v': ++verbose; break;
case 255: help(argv[0], 0); break;
}
}
if (argc-optind < 2)
help(argv[0], 1);
r = syscall (SYS_renameat2, AT_FDCWD, argv[optind], AT_FDCWD, argv[optind+1], RENAME_EXCHANGE);
if (r < 0) {
perror("renameat2");
return 1;
}
return 0;
}