remodified approach with potential usecase attached
This commit is contained in:
parent
4fe3e8e9a4
commit
8fa4201ef6
|
|
@ -1,83 +1,293 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Log file for tracking changes
|
||||
LOGFILE="/var/log/fix-ownership.log"
|
||||
echo "Starting ownership change process on $(date)" > "$LOGFILE"
|
||||
status_output=$(bootc status)
|
||||
|
||||
# Cache to track unchanged users and groups
|
||||
UNCHANGED_USERS=()
|
||||
UNCHANGED_GROUPS=()
|
||||
USER_EXISTS=false
|
||||
GROUP_EXISTS=false
|
||||
# extract the rollback checksum
|
||||
rollback_checksum=$(echo "$status_output" | awk '/rollback:/{flag=1} /checksum:/{if(flag){print $2; exit}}')
|
||||
|
||||
# function to check if a user is unchanged
|
||||
is_user_unchanged() {
|
||||
local user="$1"
|
||||
[[ " ${UNCHANGED_USERS[@]} " =~ " ${user} " ]]
|
||||
# retrun if rollback_checksum is empty
|
||||
if [ -z "$rollback_checksum" ]; then
|
||||
echo "Rollback deployment not found no need to sync "
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# source /etc/os-release to get the ID
|
||||
source /etc/os-release
|
||||
|
||||
# extract the ID and remove quotes
|
||||
os_id="${ID//\"}"
|
||||
|
||||
prefix="/ostree/deploy/"
|
||||
# Adjust the regex as needed to match specific patterns or wildcards
|
||||
prefix=$(find "$prefix" -type d -regex ".*${os_id}.*" -print -quit)
|
||||
prefix="${prefix}/deploy"
|
||||
|
||||
# Regular expression to find folders matching the checksums
|
||||
rollback_folder=$(find "$prefix" -type d -regex ".*${rollback_checksum}.*" -print -quit)
|
||||
|
||||
# Define the suffixes
|
||||
suffix_group="usr/lib/group"
|
||||
suffix_passwd="usr/lib/passwd"
|
||||
|
||||
# Construct the paths for process_* function
|
||||
BOOTED_GROUP_PATH="/${suffix_group}"
|
||||
BOOTED_PASSWD_PATH="/${suffix_passwd}"
|
||||
ROLLBACK_GROUP_PATH="${rollback_folder}/${suffix_group}"
|
||||
ROLLBACK_PASSWD_PATH="${rollback_folder}/${suffix_passwd}"
|
||||
|
||||
# Array to store booted username and UID
|
||||
declare -A passwd_booted=()
|
||||
# Array to store rollback username and UID
|
||||
declare -A passwd_rollback=()
|
||||
declare -A passwd_gid_rollback=()
|
||||
# Create a key-value list for UID mismatches
|
||||
declare -A uid_mismatch=()
|
||||
declare -A uid_missing=()
|
||||
|
||||
|
||||
# Array to store rollback groupname and gid
|
||||
declare -A group_rollback=()
|
||||
# Array to map groups and subgroups if present in rollback_group
|
||||
declare -A subgroup_mapping=()
|
||||
declare -A group_booted=()
|
||||
# Create a key-value list for gid mismatches
|
||||
declare -A gid_mismatch=()
|
||||
declare -A missing_groups=()
|
||||
|
||||
|
||||
|
||||
get_username_by_uid() {
|
||||
local uid=$1
|
||||
local mode=$2 # "booted" or "rollback"
|
||||
local username=""
|
||||
|
||||
if [[ $mode == "booted" ]]; then
|
||||
for user in "${!passwd_booted[@]}"; do
|
||||
if [[ "${passwd_booted[$user]}" == "$uid" ]]; then
|
||||
username="$user"
|
||||
break
|
||||
fi
|
||||
done
|
||||
elif [[ $mode == "rollback" ]]; then
|
||||
for user in "${!passwd_rollback[@]}"; do
|
||||
if [[ "${passwd_rollback[$user]}" == "$uid" ]]; then
|
||||
username="$user"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$username"
|
||||
}
|
||||
|
||||
# function to check if a group is unchanged
|
||||
is_group_unchanged() {
|
||||
local group="$1"
|
||||
[[ " ${UNCHANGED_GROUPS[@]} " =~ " ${group} " ]]
|
||||
get_groupname_by_gid() {
|
||||
local gid=$1
|
||||
local mode=$2 # "booted" or "rollback"
|
||||
local groupname=""
|
||||
|
||||
if [[ $mode == "booted" ]]; then
|
||||
for group in "${!group_booted[@]}"; do
|
||||
if [[ "${group_booted[$group]}" == "$gid" ]]; then
|
||||
groupname="$group"
|
||||
break
|
||||
fi
|
||||
done
|
||||
elif [[ $mode == "rollback" ]]; then
|
||||
for group in "${!group_rollback[@]}"; do
|
||||
if [[ "${group_rollback[$group]}" == "$gid" ]]; then
|
||||
groupname="$group"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$groupname"
|
||||
}
|
||||
|
||||
# function to process a single file
|
||||
process_file() {
|
||||
local filepath="$1"
|
||||
# Read booted_passwd file and store username and UID in an associative array
|
||||
while IFS=: read -r username password uid gid userinfo homedir command; do
|
||||
passwd_booted["$username"]="$uid"
|
||||
done < $BOOTED_PASSWD_PATH
|
||||
|
||||
# gather username, UID, group name, and GID of the file/folder
|
||||
FILE_UID=$(stat -c "%u" "$filepath")
|
||||
FILE_GID=$(stat -c "%g" "$filepath")
|
||||
FILE_USER=$(stat -c "%U" "$filepath")
|
||||
FILE_GROUP=$(stat -c "%G" "$filepath")
|
||||
|
||||
# skip files owned by unchanged users and groups
|
||||
if is_user_unchanged "$FILE_USER" && is_group_unchanged "$FILE_GROUP"; then
|
||||
return
|
||||
fi
|
||||
# Read rollback_passwd file and store username and UID in an associative array
|
||||
while IFS=: read -r username password uid gid userinfo homedir command; do
|
||||
passwd_rollback["$username"]="$uid"
|
||||
passwd_gid_rollback["$username"]="$gid"
|
||||
done < $ROLLBACK_PASSWD_PATH
|
||||
|
||||
# check if the user exists in /lib/passwd
|
||||
if grep -q "^${FILE_USER}:" /lib/passwd; then
|
||||
EXPECTED_UID=$(getent passwd "$FILE_USER" | cut -d: -f3)
|
||||
USER_EXISTS=true
|
||||
fi
|
||||
|
||||
# check if the group exists in /lib/group
|
||||
if grep -q "^${FILE_GROUP}:" /lib/group; then
|
||||
EXPECTED_GID=$(getent group "$FILE_GROUP" | cut -d: -f3)
|
||||
GROUP_EXISTS=true
|
||||
fi
|
||||
# Check for users in rollback_passwd but not in booted_passwd
|
||||
for username in "${!passwd_rollback[@]}"; do
|
||||
if [[ -z "${passwd_booted[$username]}" ]]; then
|
||||
# Add user with details from rollback_passwd
|
||||
uid_missing["${passwd_rollback[$username]}"]="$username"
|
||||
elif [[ "${passwd_rollback[$username]}" != "${passwd_booted[$username]}" ]]; then
|
||||
# UID mismatch - store in key-value list
|
||||
uid_mismatch["${passwd_rollback[$username]}"]="${passwd_booted[$username]}"
|
||||
fi
|
||||
done
|
||||
|
||||
# compare UID
|
||||
if $USER_EXISTS then
|
||||
if [[ "$FILE_UID" != "$EXPECTED_UID" ]]; then
|
||||
echo "Fixing UID for $filepath: $FILE_UID -> $EXPECTED_UID" >> "$LOGFILE"
|
||||
chown "$EXPECTED_UID" "$filepath"
|
||||
else
|
||||
# mark user as unchanged
|
||||
UNCHANGED_USERS+=("$FILE_USER")
|
||||
fi
|
||||
fi
|
||||
|
||||
# compare GID
|
||||
if $GROUP_EXISTS then
|
||||
if [[ "$FILE_GID" != "$EXPECTED_GID" ]]; then
|
||||
echo "Fixing GID for $filepath: $FILE_GID -> $EXPECTED_GID" >> "$LOGFILE"
|
||||
chgrp "$EXPECTED_GID" "$filepath"
|
||||
else
|
||||
# mark group as unchanged
|
||||
UNCHANGED_GROUPS+=("$FILE_GROUP")
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
# Display missing users
|
||||
if [[ ${#uid_missing[@]} -gt 0 ]]; then
|
||||
echo "Missing Users"
|
||||
for uid in "${!uid_missing[@]}"; do
|
||||
echo "${uid_missing[$uid]} (UID: $uid) (GID: ${passwd_gid_rollback[${uid_missing[$uid]}]})"
|
||||
done
|
||||
else
|
||||
echo "No missing user found"
|
||||
fi
|
||||
|
||||
export -f process_file
|
||||
export LOGFILE
|
||||
export UNCHANGED_USERS
|
||||
export UNCHANGED_GROUPS
|
||||
if [[ ${#uid_mismatch[@]} -gt 0 ]]; then
|
||||
echo "UID mismatches found:"
|
||||
for rollback_uid in "${!uid_mismatch[@]}"; do
|
||||
booted_uid="${uid_mismatch[$rollback_uid]}"
|
||||
booted_user=$(get_username_by_uid "$booted_uid" "booted")
|
||||
echo "$booted_user : (Rollback UID: $rollback_uid) (Booted UID: $booted_uid)"
|
||||
done
|
||||
else
|
||||
echo "No UID mismatches found."
|
||||
fi
|
||||
|
||||
# Parallelized processing with find and xargs
|
||||
find / -path /sysroot -prune -o -print 2>/dev/null | xargs -P "$(nproc)" -I {} bash -c 'process_file "$@"' _ {}
|
||||
echo "ownership chnage process completed on $(date)" >> "$LOGFILE"
|
||||
|
||||
# Read rollback_group file and store groupname, gid, and subgroup in arrays
|
||||
while IFS=: read -r groupname password gid subgroup; do
|
||||
group_rollback["$groupname"]="$gid"
|
||||
if [[ -n "$subgroup" ]]; then
|
||||
subgroup_mapping["$groupname"]="$subgroup"
|
||||
fi
|
||||
done < $ROLLBACK_GROUP_PATH
|
||||
|
||||
# Array to store booted groupname and GID
|
||||
|
||||
|
||||
# Read booted_group file and store groupname and gid in an associative array
|
||||
while IFS=: read -r groupname password gid subgroup; do
|
||||
group_booted["$groupname"]="$gid"
|
||||
if [[ ${subgroup_mapping["$groupname"]} == $subgroup ]]; then
|
||||
unset "subgroup_mapping[$groupname]"
|
||||
fi
|
||||
done < $BOOTED_GROUP_PATH
|
||||
|
||||
# Check for users in rollback_group but not in booted_group
|
||||
for groupname in "${!group_rollback[@]}"; do
|
||||
if [[ -z "${group_booted[$groupname]}" ]]; then
|
||||
# Add group with details from rollback_group
|
||||
missing_groups["${group_rollback[$groupname]}"]="$groupname"
|
||||
elif [[ "${group_rollback[$groupname]}" != "${group_booted[$groupname]}" ]]; then
|
||||
# GID mismatch - store groupname and mismatched GIDs
|
||||
gid_mismatch["${group_rollback[$groupname]}"]="${group_booted[$groupname]}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Display missing groups
|
||||
if [[ ${#missing_groups[@]} -gt 0 ]]; then
|
||||
echo "Missing groups:"
|
||||
for gid in "${!missing_groups[@]}"; do
|
||||
echo "${missing_groups[$gid]} (GID: ${gid})"
|
||||
done
|
||||
else
|
||||
echo "No missing groups found."
|
||||
fi
|
||||
|
||||
# Display GID mismatches
|
||||
if [[ ${#gid_mismatch[@]} -gt 0 ]]; then
|
||||
echo "GID mismatches found:"
|
||||
for rollback_gid in "${!gid_mismatch[@]}"; do
|
||||
booted_gid="${gid_mismatch[$rollback_gid]}"
|
||||
rollback_group=$(get_groupname_by_gid "$rollback_gid" "rollback")
|
||||
echo "$rollback_group : (Rollback GID: $rollback_gid) (Booted GID: $booted_gid)"
|
||||
done
|
||||
else
|
||||
echo "No GID mismatches found."
|
||||
fi
|
||||
|
||||
# Display remaining groups with subgroups
|
||||
if [[ ${#subgroup_mapping[@]} -gt 0 ]]; then
|
||||
echo "Groups with subgroups:"
|
||||
for groupname in "${!subgroup_mapping[@]}"; do
|
||||
echo "Group: $groupname, Subgroup: ${subgroup_mapping[$groupname]}"
|
||||
done
|
||||
else
|
||||
echo "No groups with subgroups found."
|
||||
fi
|
||||
|
||||
|
||||
# Output of the above script when ran on system switched form rpm-ostree to bootc:
|
||||
# Missing Users
|
||||
# core (UID: 1000) (GID: 1000)
|
||||
# dnsmasq (UID: 994) (GID: 991)
|
||||
# clevis (UID: 998) (GID: 996)
|
||||
# UID mismatches found:
|
||||
# nobody : (Rollback UID: 65534) (Booted UID: 99)
|
||||
# chrony : (Rollback UID: 995) (Booted UID: 994)
|
||||
# polkitd : (Rollback UID: 997) (Booted UID: 999)
|
||||
# sssd : (Rollback UID: 996) (Booted UID: 995)
|
||||
# systemd-coredump : (Rollback UID: 999) (Booted UID: 987)
|
||||
# Missing groups:
|
||||
# core (GID: 1000)
|
||||
# dnsmasq (GID: 991)
|
||||
# clevis (GID: 996)
|
||||
# GID mismatches found:
|
||||
# ssh_keys : (Rollback GID: 101) (Booted GID: 999)
|
||||
# nobody : (Rollback GID: 65534) (Booted GID: 99)
|
||||
# polkitd : (Rollback GID: 995) (Booted GID: 998)
|
||||
# printadmin : (Rollback GID: 994) (Booted GID: 983)
|
||||
# systemd-coredump : (Rollback GID: 997) (Booted GID: 984)
|
||||
# input : (Rollback GID: 999) (Booted GID: 104)
|
||||
# render : (Rollback GID: 998) (Booted GID: 985)
|
||||
# Groups with subgroups:
|
||||
# Group: tss, Subgroup: clevis
|
||||
# Group: wheel, Subgroup: core
|
||||
# END
|
||||
|
||||
# Narrow down the search to UIDs and GIDs missing/mismatch found above instead of the whole file system.
|
||||
# Use find with -uid and -gid flag, and prarllel processing to speed up the process.
|
||||
# Some initial checks to prevent the need for processing to save execution time.
|
||||
|
||||
# Need to process the files based the following 3 cases.
|
||||
# 1. uid or gid = UNKNOWN as seen below which is due to the shift in ids and the old ID does not exist
|
||||
# [root@vm-1 ~]# stat /etc/ssh/ssh_host_ecdsa_key
|
||||
# File: /etc/ssh/ssh_host_ecdsa_key
|
||||
# Size: 492 Blocks: 8 IO Block: 4096 regular file
|
||||
# Device: fc03h/64515d Inode: 33879037 Links: 1
|
||||
# Access: (0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 101/ UNKNOWN)
|
||||
# Context: system_u:object_r:sshd_key_t:s0
|
||||
# Access: 2024-11-29 11:52:32.042510648 +0000
|
||||
# Modify: 2024-11-28 14:16:01.651000000 +0000
|
||||
# Change: 2024-11-29 11:52:07.833734902 +0000
|
||||
# Birth: 2024-11-29 11:52:07.833734902 +0000
|
||||
|
||||
# 2.Some files like below have different user probaly due to the shift in gid
|
||||
# example: dsnmasq which has gid in 991 in rollback_passwd is now missing
|
||||
# and the new bootc system has systemd-timesync assigned to 991
|
||||
# [root@localhost ~]# stat /var/lib/dnsmasq
|
||||
# File: /var/lib/dnsmasq
|
||||
# Size: 6 Blocks: 0 IO Block: 4096 dir
|
||||
# ectory
|
||||
# Device: fc03h/64515d Inode: 33735167 Links: 2
|
||||
# Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 991/
|
||||
# systemd-timesync)
|
||||
# Context: system_u:object_r:dnsmasq_lease_t:s0
|
||||
# Access: 2024-12-01 18:39:07.618331912 +0000
|
||||
# Modify: 2024-11-29 20:38:37.992367043 +0000
|
||||
# Change: 2024-11-29 23:03:57.297643273 +0000
|
||||
# Birth: 2024-11-29 20:38:37.992367043 +0000
|
||||
|
||||
# 3.Missing user(core) when upgrading from rpm-ostree system in bootc,its
|
||||
# kind of same behavior as rpm-ostree but do we want to change it, restore
|
||||
# the user.
|
||||
# [root@localhost etc]# stat /home/core/
|
||||
# File: /home/core/
|
||||
# Size: 53 Blocks: 0 IO Block: 4096 dir
|
||||
# ectory
|
||||
# Device: fc03h/64515d Inode: 33735133 Links: 3
|
||||
# Access: (0700/drwx------) Uid: ( 1000/ UNKNOWN) Gid: ( 1000/
|
||||
# UNKNOWN)
|
||||
# Context: unconfined_u:object_r:user_home_dir_t:s0
|
||||
# Access: 2024-12-01 18:01:09.363246718 +0000
|
||||
# Modify: 2024-11-30 08:42:18.323172433 +0000
|
||||
# Change: 2024-11-30 08:42:18.323172433 +0000
|
||||
# Birth: 2024-11-29 20:34:36.496949664 +0000
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@
|
|||
Description=Bootc system migration file ownership sync
|
||||
# This helps verify that we're running in a bootc/ostree based target.
|
||||
ConditionPathIsMountPoint=/sysroot
|
||||
RequiresMountsFor=/boot
|
||||
After=network.target
|
||||
Requires=local-fs.target
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/libexec/bootc-file-ownership
|
||||
# So we can temporarily remount the sysroot writable
|
||||
MountFlags=slave
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ postprocess:
|
|||
- |
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
mkdir -p /usr/lib/systemd/system/ostree-finalized-stage.service.requires
|
||||
ln -s ../bootc-file-ownership.service /usr/lib/systemd/system/ostree-finalized-stage.service.requires/bootc-file-ownership.service
|
||||
mkdir -p /usr/lib/systemd/system/ostree-finalized-staged.service.requires
|
||||
ln -s ../bootc-file-ownership.service /usr/lib/systemd/system/ostree-finalized-staged.service.requires/bootc-file-ownership.service
|
||||
Loading…
Reference in New Issue