1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
#!/bin/sh
set -e
# Filters out UNKNOWN users and groups, prints a warning on stderr.
filter_unknown() {
CMD=$1
while read line; do
# if the first n chars of $line equal "$CMD UNKNOWN "...
if [ "$(printf %.$((9+${#CMD}))s "$line")" = "$CMD UNKNOWN " ]; then
echo Bad "$2" for "$line" >&2
else
echo "$line"
fi
done
}
filter_ignore() {
if [ "$VCS" = darcs ]; then
ignorefile=.darcsignore
fi
if [ "$VCS" = darcs ] && [ -e "$ignorefile" ]; then
# Spaces embedded into patterns would break it.
# But really, why would anyone want to use ' ' instead of '\s' ?
#patterns=$( grep -v '^[[:space:]]*\(#\|$\)' "$ignorefile" | xargs -n 1 printf " -e %s" )
#grep -Ev $patterns
#unset patterns
# Alternative using a temp file
patternsfile="$( mktemp -t etckeeper-$VCS.XXXXXXXXXX )"
grep -v '^[[:space:]]*\(#\|$\)' "$ignorefile" > "$patternsfile" || true
grep -Evf "$patternsfile"
rm -f "$patternsfile"
unset patternsfile
else
cat -
fi
}
generate_metadata() {
# This function generates the script commands to fix any files
# that aren't owner=root, group=root, or mode=0644 or 0755.
# The script is produced on stdout. Errors go to stderr.
#
# The script can use a 'maybe' function, which only runs a command
# if the file in its last argument exists.
# We maintain the permissions on the directory containing VCS data
# but we want find to ignore the VCS files themselves.
#
# (Note that when using this, the find expression must end with
# -print or -exec, else the excluded directories will actually be
# printed!)
NOVCS='. -wholename ./.git -prune -o -wholename ./.bzr -prune -o -wholename ./.hg -prune -o -wholename ./_darcs -prune -o'
# Keep the sort order the same at all times.
LC_COLLATE=C
export LC_COLLATE
if [ "$VCS" = git ] || [ "$VCS" = hg ]; then
# These version control systems do not track directories,
# so empty directories must be stored specially.
find $NOVCS -type d -empty -print |
sort | sed -e "s/^/mkdir -p '/" -e "s/\$/'/"
fi
if [ "$VCS" = darcs ]; then
# This version control system does not track symlinks,
# so they must be stored specially.
find $NOVCS -type l -print | sort | filter_ignore | while read link; do
dest=$( readlink "$link" )
printf "ln -sf '%s' '%s'\n" "$dest" "$link"
done
fi
# Find all files and directories that don't have the current user as the owner
find $NOVCS \! -user "$(id -u)" -exec stat --format="maybe chown %U '{}'" {} \; \
| sort | filter_unknown 'maybe chown' owner
# Find all files and directories that don't have root as the group
find $NOVCS \! -group $(id -g) -exec stat --format="maybe chgrp %G '{}'" {} \; \
| sort | filter_unknown 'maybe chgrp' group
# Find all directories that aren't 0755
find $NOVCS -type d \! -perm 0755 \
-exec stat --format="maybe chmod %a '{}'" {} \; | sort
if [ "$VCS" = darcs ]; then
# Find all files that aren't 0644 (darcs doesn't maintain
# the executable bit).
find $NOVCS -type f \! -perm 0644 \
-exec stat --format="maybe chmod %a '{}'" {} \; | sort
else
# Find all files that aren't 0644 or 0755 (we can assume the VCS will
# maintain the executable bit).
find $NOVCS -type f \! -perm 0644 \! -perm 0755 \
-exec stat --format="maybe chmod %a '{}'" {} \; | sort
fi
# We don't handle xattrs.
# Maybe check for getfattr/setfattr and use them if they're available?
}
if [ "$VCS" = git ] || [ "$VCS" = hg ] || [ "$VCS" = bzr ] || [ "$VCS" = darcs ]; then
if [ -f .metadata ]; then
# remove obsolete .metadata file
# git allows fully deleting it at this point, other VCS
# may not (the repo is locked for hg).
if [ "$VCS" = git ]; then
$VCS rm .metadata
else
rm -f .metadata
fi
fi
echo "# Generated by etckeeper. Do not edit." > .etckeeper
echo >> .etckeeper
# Make sure the file is not readable by others, since it can leak
# information about contents of non-readable directories in /etc.
chmod 700 .etckeeper
generate_metadata >> .etckeeper
# stage the file as part of the current commit
if [ "$VCS" = git ]; then
# this will do nothing if the metadata file is unchanged.
git add .etckeeper
fi
# hg, bzr and darcs add not done, they will automatically
# include the file in the current commit
fi
|