diff --git a/tier-1/bootc-file-ownership b/tier-1/bootc-file-ownership new file mode 100755 index 0000000..ef36701 --- /dev/null +++ b/tier-1/bootc-file-ownership @@ -0,0 +1,83 @@ +#!/bin/bash + +# Log file for tracking changes +LOGFILE="/var/log/fix-ownership.log" +echo "Starting ownership change process on $(date)" > "$LOGFILE" + +# Cache to track unchanged users and groups +UNCHANGED_USERS=() +UNCHANGED_GROUPS=() +USER_EXISTS=false +GROUP_EXISTS=false + +# function to check if a user is unchanged +is_user_unchanged() { + local user="$1" + [[ " ${UNCHANGED_USERS[@]} " =~ " ${user} " ]] +} + +# function to check if a group is unchanged +is_group_unchanged() { + local group="$1" + [[ " ${UNCHANGED_GROUPS[@]} " =~ " ${group} " ]] +} + +# function to process a single file +process_file() { + local filepath="$1" + + # 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 + + # 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 + + # 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 + +} + +export -f process_file +export LOGFILE +export UNCHANGED_USERS +export UNCHANGED_GROUPS + +# 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" diff --git a/tier-1/bootc-file-ownership.service b/tier-1/bootc-file-ownership.service new file mode 100644 index 0000000..138db7b --- /dev/null +++ b/tier-1/bootc-file-ownership.service @@ -0,0 +1,15 @@ +[Unit] +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 + +[Service] +ExecStart=/usr/libexec/bootc-file-ownership +# So we can temporarily remount the sysroot writable +MountFlags=slave +# Just to auto-cleanup our temporary files +PrivateTmp=yes + + diff --git a/tier-1/manifest.yaml b/tier-1/manifest.yaml index 2242b17..934605c 100644 --- a/tier-1/manifest.yaml +++ b/tier-1/manifest.yaml @@ -13,6 +13,7 @@ include: - persistent-journal.yaml - initramfs-full.yaml - generic-growfs.yaml + - ownership-sync.yaml packages: # Include and set the default editor diff --git a/tier-1/ownership-sync.yaml b/tier-1/ownership-sync.yaml new file mode 100644 index 0000000..e6aeebb --- /dev/null +++ b/tier-1/ownership-sync.yaml @@ -0,0 +1,12 @@ +add-files: + - - bootc-file-ownership + - /usr/libexec/bootc-file-ownership + - - bootc-file-ownership.service + - /usr/lib/systemd/system/bootc-file-ownership.service + +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 \ No newline at end of file