From daa20154e4bb89c1dba7d3433a9770593870a814989f948c6fa862d561c28b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Schr=C3=B6ter?= Date: Fri, 3 May 2024 11:47:46 +0200 Subject: [PATCH] Sync from SUSE:SLFO:Main compat-usrmerge revision db3ea9074a430717229ef191e990fb4f --- .gitattributes | 23 ++ compat-usrmerge.changes | 72 +++++ compat-usrmerge.spec | 207 +++++++++++++ convertfs | 139 +++++++++ usrmerge.attr | 10 + usrmerge.lua | 149 +++++++++ usrmerge_binsbindeps.lua | 99 ++++++ usrmerge_files.lua | 655 +++++++++++++++++++++++++++++++++++++++ usrmergecheck.c | 351 +++++++++++++++++++++ usrmergefiles.py | 158 ++++++++++ xmv.c | 105 +++++++ 11 files changed, 1968 insertions(+) create mode 100644 .gitattributes create mode 100644 compat-usrmerge.changes create mode 100644 compat-usrmerge.spec create mode 100644 convertfs create mode 100644 usrmerge.attr create mode 100644 usrmerge.lua create mode 100644 usrmerge_binsbindeps.lua create mode 100644 usrmerge_files.lua create mode 100644 usrmergecheck.c create mode 100644 usrmergefiles.py create mode 100644 xmv.c 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/compat-usrmerge.changes b/compat-usrmerge.changes new file mode 100644 index 0000000..666c6f4 --- /dev/null +++ b/compat-usrmerge.changes @@ -0,0 +1,72 @@ +------------------------------------------------------------------- +Thu Oct 7 11:57:22 UTC 2021 - Ludwig Nussel + +- Fix logic for detecting conflicts with directories (boo#1191111) + +------------------------------------------------------------------- +Fri Aug 27 08:39:30 UTC 2021 - Ludwig Nussel + +- exit file triggers early if alread usrmerged + +------------------------------------------------------------------- +Fri Aug 27 06:35:26 UTC 2021 - Ludwig Nussel + +- statically link xmv to avoid glibc 2.34 dependency + (__libc_start_main@GLIBC_2.34) +- turn on filetriggers in main package. Needed for single transaction upgrades + (boo#1189788) + +------------------------------------------------------------------- +Tue Jun 15 15:27:41 UTC 2021 - Ludwig Nussel + +- another fix for split /usr to avoid running out of space (boo#1186781) +- unsafe fallback also for ENOSYS on renameat2 as seen on WSL + +------------------------------------------------------------------- +Tue Jun 8 12:03:52 UTC 2021 - Ludwig Nussel + +- early exit in case of overlayfs (boo#1187027) + +------------------------------------------------------------------- +Tue Jun 8 07:37:33 UTC 2021 - Fabian Vogt + +- Avoid dependency on mountpoint from util-linux +- Also check for availability of find + +------------------------------------------------------------------- +Mon Jun 7 09:02:56 UTC 2021 - Ludwig Nussel + +- fix conversion with split /usr (boo#1186781) + +------------------------------------------------------------------- +Wed Jun 2 15:29:15 UTC 2021 - Ludwig Nussel + +- exit early if one of the affected directories has mountpoint + beneath it + +------------------------------------------------------------------- +Tue Jun 1 23:27:08 UTC 2021 - Niklas Haas + +- add fallback for filesystems without renameat2 (boo#1186637) + +------------------------------------------------------------------- +Thu Mar 25 09:50:48 UTC 2021 - Ludwig Nussel + +- catch boolean deps + +------------------------------------------------------------------- +Thu Mar 18 12:24:15 UTC 2021 - Ludwig Nussel + +- cp can't handle copying a dir over non-directories. So move those + away in advance. Happened with /lib/udev existing as link on older + distros + +------------------------------------------------------------------- +Mon Mar 15 17:41:10 UTC 2021 - Ludwig Nussel + +- update file lists based on current factory data + +------------------------------------------------------------------- +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..55df725 --- /dev/null +++ b/compat-usrmerge.spec @@ -0,0 +1,207 @@ +# +# spec file for package compat-usrmerge +# +# Copyright (c) 2021 SUSE LLC +# +# 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 https://bugs.opensuse.org/ +# + + +%define nvr %{name}-%{version}-%{release} + +Name: compat-usrmerge +Version: 84.87 +Release: 0 +Summary: UsrMerge related scripts +License: MIT +URL: https://en.opensuse.org/openSUSE:Usr_merge +Source0: usrmerge.lua +# ./usrmergefiles.py --files https://download.opensuse.org/tumbleweed/repo/oss +Source1: usrmerge_files.lua +Source2: usrmergecheck.c +Source3: convertfs +Source4: xmv.c +Source5: usrmerge.attr +# ./usrmergefiles.py --requires https://download.opensuse.org/tumbleweed/repo/oss +Source6: usrmerge_binsbindeps.lua +Source7: usrmergefiles.py +BuildRequires: gcc +BuildRequires: glibc-static +BuildRequires: pkgconfig(rpm) + +%description +Scripts and data files related to UsrMerge +(https://en.opensuse.org/openSUSE:Usr_merge). Normally not needd. + +%package tools +Summary: UsrMerge tools +Requires: (compat-usrmerge if compat-usrmerge) +# 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 +Tools related to UsrMerge to check the state of the system and to +convert an existing system to UsrMerge. + +%package build +Summary: UsrMerge build tools +Requires: lua + +%description build +Build tools related to UsrMerge. This is required for rpmbuild to +generate proper provides tags for packages that used to have +binaries in /(s)bin. + +%prep +%setup -qcT + +%build +gcc -Wall %optflags -o usrmergecheck %{SOURCE2} `pkg-config --libs rpm` +gcc -Wall %optflags -static -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 + +%filetriggerin -p -- %{_sbindir} %{_bindir} %{_libdir} +if posix.stat("/lib", "type") ~= "directory" then return end +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} +if posix.stat("/lib", "type") ~= "directory" then return end +-- 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} +if posix.stat("/lib", "type") ~= "directory" then return end +-- 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 + +%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..ca90e1f --- /dev/null +++ b/convertfs @@ -0,0 +1,139 @@ +#!/bin/bash +# based on code from dracut convertfs.sh + +ROOT= + +is_usrmerged() { + local r=1 + for dir in bin sbin lib lib64; do + [ -d "$ROOT/$dir" ] || continue + [ -L "$ROOT/$dir" ] || return 1 + r=0 + done + return "$r" +} + +# check if there's anything to do +is_usrmerged && exit 0 + +# the package is installed with AutoReq off, so no guarantee that +# coreutils actually works +if ! { cp --help && find --help; } > /dev/null; then + echo "tools not functional, exit" + exit 1 +fi + +# clean up after ourselves no matter how we die. +cleanup() { + echo "UsrMerge conversion failed, cleaning up" + for dir in bin sbin lib lib64; do + rm -rf -- "$ROOT/usr/${dir}.usrmerge" + done + echo "!!! ATTENTION: Do NOT proceed if you see this message during" + echo "!!! distribution upgrade. Chances are high that your system might" + echo "!!! break beyond repair if you do." +} + +trap 'ret=$?; [[ $ret -ne 0 ]] && cleanup;exit $ret;' EXIT +trap 'exit 1;' SIGINT + +set -e + +if [ "$(stat -f -c %T "${ROOT:-/}")" = "overlayfs" ]; then + echo "UsrMerge conversion does not work on overlayfs" + exit 1 +fi + +CP_HARDLINK="-l" +while read dev mp other; do + [ "$mp" = "$ROOT/usr" ] && CP_HARDLINK="" + for dir in bin sbin lib lib64; do + [ -d "$ROOT/$dir" ] || continue + if [ "${mp#$ROOT/$dir}" != "$mp" ] || [ "${mp#$ROOT/usr/$dir}" != "$mp" ]; then + echo "Please unmount $mp before the conversion" + exit 1 + fi + done +done < /proc/mounts + +# 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 $CP_HARDLINK "$ROOT/$dir" "$ROOT/usr/${dir}.usrmerge" + # cp can't handle copying a dir over non-directories. So move + # those away in advance. Happened with /lib/udev existing as + # link on older distros + while read d; do + f="$ROOT/usr/$dir.usrmerge/$d" + if test -L "$f" -o \( -e "$f" -a ! -d "$f" \); then + echo "Warning: /$dir/$d conflicts with directory /usr/$dir/$d and will be removed" + rm -rf "$f.usrmerge~" + mv "$f" "$f.usrmerge~" + fi + done < <(find "$ROOT/usr/$dir" -xdev -type d -printf "%P\n" ) + echo "Merge the copy with \`$ROOT/usr/$dir'." + [[ -d "$ROOT/usr/${dir}.usrmerge" ]] \ + || mkdir -p "$ROOT/usr/${dir}.usrmerge" + cp -axT -l --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" -xdev -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" \ + -xdev -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 --one-file-system -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 --one-file-system -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" || : 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..2985d3b --- /dev/null +++ b/usrmerge_binsbindeps.lua @@ -0,0 +1,99 @@ +usrmerge_binsbindeps = { +-- 2ping 389-ds 389-ds-snmp 4ti2 AppStream ... +["/bin/sh"] = 1, +-- 4store AppCSXCAD Cadence ComputeLibrary HepMC-devel ... +["/bin/bash"] = 1, +-- FreeCAD Herwig-libs Mesa Mesa-libEGL1 Mesa-libGL1 ... +["/sbin/ldconfig"] = 1, +-- aaa_base ctdb cvs yast2-printer +["/bin/mktemp"] = 1, +-- avrdude os-prober uisp +["/sbin/modprobe"] = 1, +-- bind +["/sbin/start_daemon"] = 1, +-- budgie-screensaver xscreensaver +["/sbin/unix2_chkpwd"] = 1, +-- canna compiz-branding-SLED compiz-branding-openSUSE compiz-branding-upstream ini4j-javadoc ... +["/bin/rm"] = 1, +-- clamav enscript gpm hplip lsb ... +["/bin/sed"] = 1, +-- clamav icecream lsb +["/bin/tar"] = 1, +-- cobbler +["/sbin/service"] = 1, +-- compiz-branding-SLED compiz-branding-openSUSE compiz-branding-upstream ini4j-javadoc install-initrd-Kubic ... +["/bin/ln"] = 1, +-- corosync eid-mw postgresql10-server +["/sbin/chkconfig"] = 1, +-- dds2tar dt fpc-src lua-lmod petsc-devel ... +["/bin/csh"] = 1, +-- glibc-locale-base jfbterm lsb uisp +["/bin/cat"] = 1, +-- hplip os-prober +["/bin/grep"] = 1, +-- kdevplatform +["/bin/zsh"] = 1, +-- ksh lsb twin +["/bin/true"] = 1, +-- libgtop-doc +["/sbin/install-info"] = 1, +-- logdigest lsb +["/bin/chmod"] = 1, +-- logdigest lsb sound-theme-freedesktop tei_4 +["/bin/touch"] = 1, +-- lsb +["/bin/chgrp"] = 1, +["/bin/chown"] = 1, +["/bin/dd"] = 1, +["/bin/df"] = 1, +["/bin/echo"] = 1, +["/bin/false"] = 1, +["/bin/kill"] = 1, +["/bin/mknod"] = 1, +["/bin/more"] = 1, +["/bin/mount"] = 1, +["/bin/mv"] = 1, +["/bin/ps"] = 1, +["/bin/pwd"] = 1, +["/bin/rmdir"] = 1, +["/bin/sleep"] = 1, +["/bin/sort"] = 1, +["/bin/sync"] = 1, +["/bin/umount"] = 1, +["/bin/uname"] = 1, +["/sbin/shutdown"] = 1, +-- lsb lynx +["/bin/cp"] = 1, +-- lsb mariadb openwsman-server patch2mail xorg-x11-Xvnc ... +["/bin/hostname"] = 1, +-- lsb nagios nagios-www ntp sca-appliance-common ... +["/bin/logger"] = 1, +-- lsb perl-Term-ReadKey +["/bin/stty"] = 1, +-- lsb sendmail +["/bin/fuser"] = 1, +-- lsb texlive-cjk-latex-extras +["/bin/mkdir"] = 1, +-- lsb vnstat +["/bin/ls"] = 1, +["/bin/su"] = 1, +-- mdadm +["/sbin/mkinitrd"] = 1, +-- memtest86+ +["/sbin/update-bootloader"] = 1, +-- sca-appliance-common +["/bin/ping"] = 1, +-- setserial +["/sbin/isserial"] = 1, +-- sgml-skel xorg-x11-Xvnc +["/bin/awk"] = 1, +-- sysconfig +["/sbin/ifup"] = 1, +["/sbin/netconfig"] = 1, +-- sysconfig-netconfig +["/bin/gawk"] = 1, +-- vpnc +["/sbin/ip"] = 1, +-- xdm +["/sbin/startproc"] = 1, +} diff --git a/usrmerge_files.lua b/usrmerge_files.lua new file mode 100644 index 0000000..134cbc7 --- /dev/null +++ b/usrmerge_files.lua @@ -0,0 +1,655 @@ +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, +["/bin/sh"] = 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/setconsole"] = 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, +-- ceph-common +["/sbin/mount.ceph"] = 1, +-- cifs-utils +["/sbin/mount.cifs"] = 1, +["/sbin/mount.smb3"] = 1, +-- coreutils coreutils-single +["/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, +-- cpio +["/bin/cpio"] = 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/mkdosfs"] = 1, +["/sbin/mkfs.fat"] = 1, +["/sbin/mkfs.msdos"] = 1, +["/sbin/mkfs.vfat"] = 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/mke2fs"] = 1, +["/sbin/mkfs.ext2"] = 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, +-- ed +["/bin/ed"] = 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, +-- findutils +["/bin/find"] = 1, +-- fuse +["/sbin/mount.fuse"] = 1, +-- fuse-exfat +["/sbin/mount.exfat"] = 1, +["/sbin/mount.exfat-fuse"] = 1, +-- fxload +["/sbin/fxload"] = 1, +-- gawk +["/bin/gawk"] = 1, +-- gawk mawk +["/bin/awk"] = 1, +-- glibc +["/sbin/ldconfig"] = 1, +-- glusterfs +["/sbin/mount.glusterfs"] = 1, +-- grep +["/bin/egrep"] = 1, +["/bin/fgrep"] = 1, +["/bin/grep"] = 1, +-- grubby +["/sbin/grubby"] = 1, +["/sbin/new-kernel-pkg"] = 1, +-- gzip +["/bin/gunzip"] = 1, +["/bin/gzip"] = 1, +["/bin/zcat"] = 1, +-- hdparm +["/sbin/hdparm"] = 1, +["/sbin/wiper.sh"] = 1, +-- hostname +["/bin/dnsdomainname"] = 1, +["/bin/domainname"] = 1, +["/bin/hostname"] = 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, +-- iproute2 +["/bin/ip"] = 1, +["/sbin/ip"] = 1, +-- iputils +["/bin/arping"] = 1, +["/bin/clockdiff"] = 1, +["/bin/ping"] = 1, +["/bin/ping6"] = 1, +["/bin/tracepath"] = 1, +["/bin/tracepath6"] = 1, +["/sbin/rdisc"] = 1, +-- ipvsadm +["/sbin/ipvsadm"] = 1, +["/sbin/ipvsadm-restore"] = 1, +["/sbin/ipvsadm-save"] = 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/chvt"] = 1, +["/bin/clrunimap"] = 1, +["/bin/deallocvt"] = 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/openvt"] = 1, +["/bin/outpsfheader"] = 1, +["/bin/psfaddtable"] = 1, +["/bin/psfgettable"] = 1, +["/bin/psfstriptable"] = 1, +["/bin/psfxtable"] = 1, +["/bin/resizecons"] = 1, +["/bin/screendump"] = 1, +["/bin/setfont"] = 1, +["/bin/setkeycodes"] = 1, +["/bin/setleds"] = 1, +["/bin/setlogcons"] = 1, +["/bin/setmetamode"] = 1, +["/bin/setpalette"] = 1, +["/bin/setvesablank"] = 1, +["/bin/setvtrgb"] = 1, +["/bin/showconsolefont"] = 1, +["/bin/showkey"] = 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, +-- kmod +["/bin/lsmod"] = 1, +["/sbin/depmod"] = 1, +["/sbin/insmod"] = 1, +["/sbin/lsmod"] = 1, +["/sbin/modinfo"] = 1, +["/sbin/modprobe"] = 1, +["/sbin/rmmod"] = 1, +-- kpartx +["/sbin/kpartx"] = 1, +-- ksh +["/bin/ksh93"] = 1, +-- ksh mksh +["/bin/ksh"] = 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, +-- mailutils 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/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/ether-wake"] = 1, +["/sbin/nameif"] = 1, +["/sbin/plipconfig"] = 1, +["/sbin/slattach"] = 1, +-- net-tools-deprecated +["/bin/ifconfig"] = 1, +["/bin/netstat"] = 1, +["/bin/route"] = 1, +["/sbin/arp"] = 1, +["/sbin/ipmaddr"] = 1, +["/sbin/iptunnel"] = 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/pwhistory_helper"] = 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/umount.crypt"] = 1, +["/sbin/umount.crypt_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"] = 1, +["/sbin/restorecon_xattr"] = 1, +["/sbin/setfiles"] = 1, +-- polkit-default-privs +["/sbin/chkstat-polkit"] = 1, +["/sbin/set_polkit_default_privs"] = 1, +-- powerd +["/sbin/detectups"] = 1, +["/sbin/powerd"] = 1, +-- procps +["/bin/pgrep"] = 1, +["/bin/pkill"] = 1, +["/bin/ps"] = 1, +["/sbin/sysctl"] = 1, +-- psmisc +["/bin/fuser"] = 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, +-- sed +["/bin/sed"] = 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, +-- 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 +["/bin/fsync"] = 1, +["/bin/usleep"] = 1, +["/sbin/checkproc"] = 1, +["/sbin/fstab-decode"] = 1, +["/sbin/killall5"] = 1, +["/sbin/killproc"] = 1, +["/sbin/mkill"] = 1, +["/sbin/pidofproc"] = 1, +["/sbin/rvmtab"] = 1, +["/sbin/start_daemon"] = 1, +["/sbin/startproc"] = 1, +["/sbin/vhangup"] = 1, +-- tar +["/bin/tar"] = 1, +-- tcsh +["/bin/csh"] = 1, +["/bin/tcsh"] = 1, +-- tomoyo-tools +["/sbin/tomoyo-init"] = 1, +-- tunctl +["/sbin/tunctl"] = 1, +-- udhcp +["/sbin/udhcpc"] = 1, +-- util-linux +["/bin/dmesg"] = 1, +["/bin/kill"] = 1, +["/bin/login"] = 1, +["/bin/more"] = 1, +["/bin/mount"] = 1, +["/bin/su"] = 1, +["/bin/umount"] = 1, +["/sbin/agetty"] = 1, +["/sbin/blkid"] = 1, +["/sbin/blockdev"] = 1, +["/sbin/cfdisk"] = 1, +["/sbin/chcpu"] = 1, +["/sbin/ctrlaltdel"] = 1, +["/sbin/fdisk"] = 1, +["/sbin/findfs"] = 1, +["/sbin/fsck"] = 1, +["/sbin/fsck.cramfs"] = 1, +["/sbin/fsck.minix"] = 1, +["/sbin/fsfreeze"] = 1, +["/sbin/fstrim"] = 1, +["/sbin/hwclock"] = 1, +["/sbin/losetup"] = 1, +["/sbin/mkfs"] = 1, +["/sbin/mkfs.bfs"] = 1, +["/sbin/mkfs.cramfs"] = 1, +["/sbin/mkfs.minix"] = 1, +["/sbin/mkswap"] = 1, +["/sbin/nologin"] = 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, +-- util-linux-systemd +["/bin/findmnt"] = 1, +["/bin/logger"] = 1, +["/bin/lsblk"] = 1, +-- vim +["/bin/ex"] = 1, +["/bin/vi"] = 1, +["/bin/vim"] = 1, +-- virtualbox +["/sbin/vboxconfig"] = 1, +-- virtualbox-guest-tools +["/sbin/mount.vboxsf"] = 1, +-- virtualbox-qt +["/sbin/vbox-fix-usb-rules.sh"] = 1, +-- vlan +["/sbin/vconfig"] = 1, +-- wicked-service +["/sbin/ifdown"] = 1, +["/sbin/ifprobe"] = 1, +["/sbin/ifstatus"] = 1, +["/sbin/ifup"] = 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/usrmergefiles.py b/usrmergefiles.py new file mode 100644 index 0000000..772850d --- /dev/null +++ b/usrmergefiles.py @@ -0,0 +1,158 @@ +#!/usr/bin/python3 +# Copyright (c) 2021 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. + +from itertools import filterfalse, chain, islice +from lxml import etree as ET +from urllib.parse import urljoin +import argparse +import gzip +import hashlib +import io +import logging +import re +import requests +import sys + + +def parse_repomd(baseurl, what, code): + url = urljoin(baseurl, 'repodata/repomd.xml') + repomd = requests.get(url) + if repomd.status_code != requests.codes.ok: + return False + + ns = {'r': 'http://linux.duke.edu/metadata/repo'} + root = ET.fromstring(repomd.content) + filelists = root.find('.//r:data[@type="{}"]'.format(what), ns) + location = filelists.find('r:location', ns).get('href') + sha256_expected = filelists.find('r:checksum[@type="sha256"]', ns).text + + url = urljoin(baseurl, location) + with requests.get(url, stream=True) as res: + if res.status_code != requests.codes.ok: + raise Exception(url + ' does not exist') + sha256 = hashlib.sha256(res.content).hexdigest() + if sha256 != sha256_expected: + raise Exception('checksums do not match {} != {}'.format(sha256, sha256_expected)) + + content = gzip.GzipFile(fileobj=io.BytesIO(res.content)) + + root = ET.fromstring(content.read()) + code(root) + + return False + +def ignored(package): + # busybox has stuff in / that is normally not there + return package.startswith('busybox-') or package.endswith("-32bit") + +def ddd(a, l): + if len(a) < l: + return a + + return chain(islice(a, l), ['...']) + + +def printaslua(files, name): + pkgs = dict() + for fn in sorted(files.keys()): + pkgs.setdefault(' '.join(ddd(sorted(files[fn]), 5)), set()).add(fn) + print('{} = {{'.format(name)) + for p in sorted(pkgs.keys()): + print("-- "+p) + for fn in sorted(pkgs[p]): + print('["{}"] = 1,'.format(fn)) + + print('}') + + +def handle_filelists(root): + files = dict() +# umr = re.compile(r'^\/(s?bin|lib(?:64)?)/([^/]+)') + umr = re.compile(r'^\/(s?bin)/([^/]+)') + ns = {'r': 'http://linux.duke.edu/metadata/filelists'} + for pn in root.findall(".//r:package", ns): + package = pn.get('name') + if ignored(package): + continue + for fn in pn.findall("r:file", ns): + m = umr.match(fn.text) + if m: +# print("{}: {} {}".format(package, m.group(1), m.group(2))) + files.setdefault(fn.text, set()).add(package) + + printaslua(files, 'usrmerge_files') + + +def handle_requires(root): + files = dict() + umr = re.compile(r'^\/(s?bin)/([^/]+)') + ns = {'c': 'http://linux.duke.edu/metadata/common', + 'r': 'http://linux.duke.edu/metadata/rpm' } + for pn in root.findall(".//c:package", ns): + package = pn.find('c:name', ns).text + if ignored(package): + continue + for rn in pn.findall(".//r:requires", ns): + for fn in rn.findall(".//r:entry", ns): + r = fn.get('name') + m = umr.match(r) + if m: + files.setdefault(r,set()).add(package) + + printaslua(files, 'usrmerge_binsbindeps') + +def main(args): + + # do some work here + logger = logging.getLogger("usrmergefiles") + logger.info("main") + + if args.files: + parse_repomd(args.url[0], "filelists", handle_filelists) + + if args.requires: + parse_repomd(args.url[0], "primary", handle_requires) + + return 0 + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='boilerplate python commmand line program') + parser.add_argument("--dry", action="store_true", help="dry run") + parser.add_argument("--debug", action="store_true", help="debug output") + parser.add_argument("--verbose", action="store_true", help="verbose") + parser.add_argument("--files", action="store_true", help="dump /bin and /sbin files") + parser.add_argument("--requires", action="store_true", help="dump requires of /bin and /sbin") + parser.add_argument("url", nargs='*', help="some file name") + + args = parser.parse_args() + + if args.debug: + level = logging.DEBUG + elif args.verbose: + level = logging.INFO + else: + level = None + + logging.basicConfig(level = level) + + sys.exit(main(args)) + +# vim: sw=4 et diff --git a/xmv.c b/xmv.c new file mode 100644 index 0000000..cdddb95 --- /dev/null +++ b/xmv.c @@ -0,0 +1,105 @@ +/* + 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 +#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); + + const char *source = argv[optind], *target = argv[optind+1]; + r = syscall (SYS_renameat2, AT_FDCWD, source, AT_FDCWD, target, RENAME_EXCHANGE); + if (r < 0) { + // FS not supporting RENAME_EXCHANGE -> EINVAL + // No renameat2 syscall -> ENOSYS (eg WSL) + if (errno != EINVAL && errno != ENOSYS) { + perror("renameat2"); + return 1; + } + + // Fallback for systems without renameat2 support + puts("!!! WARNING: rename2 RENAME_EXCHANGE not supported !!!"); + puts("!!! fallback to unsafe rename !!!"); + char tmp[PATH_MAX]; + r = snprintf(tmp, sizeof(tmp), "%s.XXXXXX", target); + if (r < 0) { + perror("asprintf"); + return 1; + } + // not intended to be use in /tmp so good enough + mktemp(tmp); + + r = renameat(AT_FDCWD, target, AT_FDCWD, tmp); + if (!r) + r = renameat(AT_FDCWD, source, AT_FDCWD, target); + if (!r) + r = renameat(AT_FDCWD, tmp, AT_FDCWD, source); + + if (r < 0) { + perror("renameat"); + return 1; + } + } + + return 0; +}