Sync from SUSE:SLFO:Main compat-usrmerge revision db3ea9074a430717229ef191e990fb4f

This commit is contained in:
Adrian Schröter 2024-05-03 11:47:46 +02:00
commit daa20154e4
11 changed files with 1968 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

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

72
compat-usrmerge.changes Normal file
View File

@ -0,0 +1,72 @@
-------------------------------------------------------------------
Thu Oct 7 11:57:22 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- Fix logic for detecting conflicts with directories (boo#1191111)
-------------------------------------------------------------------
Fri Aug 27 08:39:30 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- exit file triggers early if alread usrmerged
-------------------------------------------------------------------
Fri Aug 27 06:35:26 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- 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 <lnussel@suse.de>
- 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 <lnussel@suse.de>
- early exit in case of overlayfs (boo#1187027)
-------------------------------------------------------------------
Tue Jun 8 07:37:33 UTC 2021 - Fabian Vogt <fvogt@suse.com>
- Avoid dependency on mountpoint from util-linux
- Also check for availability of find
-------------------------------------------------------------------
Mon Jun 7 09:02:56 UTC 2021 - Ludwig Nussel <lnussel@suse.com>
- fix conversion with split /usr (boo#1186781)
-------------------------------------------------------------------
Wed Jun 2 15:29:15 UTC 2021 - Ludwig Nussel <lnussel@suse.com>
- exit early if one of the affected directories has mountpoint
beneath it
-------------------------------------------------------------------
Tue Jun 1 23:27:08 UTC 2021 - Niklas Haas <obs@haasn.xyz>
- add fallback for filesystems without renameat2 (boo#1186637)
-------------------------------------------------------------------
Thu Mar 25 09:50:48 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- catch boolean deps
-------------------------------------------------------------------
Thu Mar 18 12:24:15 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- 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 <lnussel@suse.de>
- update file lists based on current factory data
-------------------------------------------------------------------
Thu Feb 25 10:22:09 UTC 2021 - Ludwig Nussel <lnussel@suse.de>
- initial package

207
compat-usrmerge.spec Normal file
View File

@ -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 <<EOF
/%{_lib}/libc-`rpm -q --qf "%%{version}" glibc`.so
/%{_lib}/libc.so.6
%ifarch %arm
%ifarch armv6hl armv7hl
/%{_lib}/ld-linux-armhf.so.3
/%{_lib}/ld-linux.so.3
%else
/%{_lib}/ld-linux.so.3
%endif
%endif
%ifarch ia64
/%{_lib}/ld-linux-ia64.so.2
%endif
%ifarch ppc s390 mips hppa m68k
/%{_lib}/ld.so.1
%endif
%ifarch ppc64
/%{_lib}/ld64.so.1
%endif
%ifarch ppc64le
/%{_lib}/ld64.so.2
%endif
%ifarch s390x
/lib/ld64.so.1
/%{_lib}/ld64.so.1
%endif
%ifarch x86_64
/%{_lib}/ld-linux-x86-64.so.2
%endif
%ifarch %ix86 %sparc
/%{_lib}/ld-linux.so.2
%endif
%ifarch aarch64
/lib/ld-linux-aarch64.so.1
/%{_lib}/ld-linux-aarch64.so.1
%endif
%ifarch riscv64
/lib/ld-linux-riscv64-lp64d.so.1
/%{_lib}/ld-linux-riscv64-lp64d.so.1
%endif
EOF
#
%if 0
mkdir -p %{buildroot}/{sbin,bin,%{_lib}}
while read file; do
[ -n "$file" ] || continue
ln -s ../usr$file %{buildroot}$file
echo "%ghost %config(noreplace) $file"
done > files.list << EOF
%{lua:
package.path = package.path .. string.format(";%s/?.lua", rpm.expand("%{_sourcedir}"))
require("usrmerge_files")
for rp in pairs(usrmerge_files) do
print(rp.."\n")
end
}
EOF
%endif
%filetriggerin -p <lua> -- %{_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 <lua> -- %{_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 <lua> -- /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

139
convertfs Normal file
View File

@ -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" || :

10
usrmerge.attr Normal file
View File

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

149
usrmerge.lua Normal file
View File

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

99
usrmerge_binsbindeps.lua Normal file
View File

@ -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,
}

655
usrmerge_files.lua Normal file
View File

@ -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,
}

351
usrmergecheck.c Normal file
View File

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

158
usrmergefiles.py Normal file
View File

@ -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

105
xmv.c Normal file
View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <limits.h>
#ifndef RENAME_EXCHANGE
# define RENAME_EXCHANGE (1 << 1)
#endif
static int verbose;
void help(const char* prog, int ret)
{
printf("Usage: %s SOURCE TARGET\n", prog);
puts("Exchange names of SOURCE and TARGET");
exit(ret);
}
int main(int argc, char** argv)
{
int c;
int r;
static struct option long_options[] = {
{"verbose", no_argument, 0, 'v' },
{"help", no_argument, 0, 255 },
{0, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, "v", long_options, NULL)) != -1) {
switch(c) {
case 'v': ++verbose; break;
case 255: help(argv[0], 0); break;
}
}
if (argc-optind < 2)
help(argv[0], 1);
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;
}