Sync from SUSE:ALP:Source:Standard:1.0 compat-usrmerge revision db3ea9074a430717229ef191e990fb4f
This commit is contained in:
commit
48b0560f90
23
.gitattributes
vendored
Normal file
23
.gitattributes
vendored
Normal 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
72
compat-usrmerge.changes
Normal 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
207
compat-usrmerge.spec
Normal 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
139
convertfs
Normal 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
10
usrmerge.attr
Normal 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
149
usrmerge.lua
Normal 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
99
usrmerge_binsbindeps.lua
Normal 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
655
usrmerge_files.lua
Normal 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
351
usrmergecheck.c
Normal 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
158
usrmergefiles.py
Normal 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
105
xmv.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user