commit 101f37580fb9b3ec5462224a996cc5073005c79d80b072ca9cd43dde8274a03a Author: Andreas Jaeger Date: Thu Feb 25 10:44:07 2021 +0000 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 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes new file mode 100644 index 0000000..486c239 --- /dev/null +++ b/compat-usrmerge.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Thu Feb 25 10:22:09 UTC 2021 - Ludwig Nussel + +- initial package diff --git a/compat-usrmerge.spec b/compat-usrmerge.spec new file mode 100644 index 0000000..817fe8a --- /dev/null +++ b/compat-usrmerge.spec @@ -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 < 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 -- %{_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 -- %{_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 -- /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 diff --git a/convertfs b/convertfs new file mode 100644 index 0000000..1cc7d2b --- /dev/null +++ b/convertfs @@ -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 diff --git a/usrmerge.attr b/usrmerge.attr new file mode 100644 index 0000000..57cd261 --- /dev/null +++ b/usrmerge.attr @@ -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/.* diff --git a/usrmerge.lua b/usrmerge.lua new file mode 100644 index 0000000..9122227 --- /dev/null +++ b/usrmerge.lua @@ -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 diff --git a/usrmerge_binsbindeps.lua b/usrmerge_binsbindeps.lua new file mode 100644 index 0000000..dd7dcd9 --- /dev/null +++ b/usrmerge_binsbindeps.lua @@ -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, +} diff --git a/usrmerge_files.lua b/usrmerge_files.lua new file mode 100644 index 0000000..bd72b92 --- /dev/null +++ b/usrmerge_files.lua @@ -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, +} diff --git a/usrmergecheck.c b/usrmergecheck.c new file mode 100644 index 0000000..ab068e8 --- /dev/null +++ b/usrmergecheck.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/xmv.c b/xmv.c new file mode 100644 index 0000000..f7c31a4 --- /dev/null +++ b/xmv.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}