saving uncommitted changes in /etc prior to emerge run

This commit is contained in:
2015-02-27 01:58:55 +01:00
committed by root
commit b3cea8d893
2385 changed files with 507432 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
# The VCS to use.
#VCS="hg"
VCS="git"
#VCS="bzr"
#VCS="darcs"
# Options passed to git commit when run by etckeeper.
GIT_COMMIT_OPTIONS=""
# Options passed to hg commit when run by etckeeper.
HG_COMMIT_OPTIONS=""
# Options passed to bzr commit when run by etckeeper.
BZR_COMMIT_OPTIONS=""
# Options passed to darcs record when run by etckeeper.
DARCS_COMMIT_OPTIONS="-a"
# Uncomment to avoid etckeeper committing existing changes
# to /etc automatically once per day.
#AVOID_DAILY_AUTOCOMMITS=1
# Uncomment the following to avoid special file warning
# (the option is enabled automatically by cronjob regardless).
#AVOID_SPECIAL_FILE_WARNING=1
# Uncomment to avoid etckeeper committing existing changes to
# /etc before installation. It will cancel the installation,
# so you can commit the changes by hand.
#AVOID_COMMIT_BEFORE_INSTALL=1
# The high-level package manager that's being used.
# (apt, pacman-g2, yum, zypper etc)
#HIGHLEVEL_PACKAGE_MANAGER=apt
# Gentoo specific:
# For portage this is emerge
# For paludis this is cave
HIGHLEVEL_PACKAGE_MANAGER=emerge
# The low-level package manager that's being used.
# (dpkg, rpm, pacman, pacman-g2, etc)
#LOWLEVEL_PACKAGE_MANAGER=dpkg
# Gentoo specific:
# For portage this is qlist
# For paludis this is cave
LOWLEVEL_PACKAGE_MANAGER=qlist
# To push each commit to a remote, put the name of the remote here.
# (eg, "origin" for git). Space-separated lists of multiple remotes
# also work (eg, "origin gitlab github" for git).
PUSH_REMOTE=""

17
etckeeper/commit.d/10vcs-test Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
set -e
not_enabled_warning() {
echo "etckeeper warning: etckeeper is not yet enabled for $(pwd)" >&2
echo "etckeeper warning: run etckeeper init to enable it" >&2
}
if [ "$VCS" = git ] && [ ! -d .git ]; then
not_enabled_warning
elif [ "$VCS" = hg ] && [ ! -d .hg ]; then
not_enabled_warning
elif [ "$VCS" = bzr ] && [ ! -d .bzr ]; then
not_enabled_warning
elif [ "$VCS" = darcs ] && [ ! -d _darcs ]; then
not_enabled_warning
fi

8
etckeeper/commit.d/30bzr-add Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
set -e
if [ "$VCS" = bzr ] && [ -d .bzr ]; then
if ! bzr add -q .; then
echo "etckeeper warning: bzr add failed" >&2
fi
fi

14
etckeeper/commit.d/30darcs-add Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
set -e
if [ "$VCS" = darcs ] && [ -d _darcs ]; then
rc=0
res=$( darcs add -qr . 2>&1 ) || rc=$?
if test $rc -ne 0; then
if ! test $rc -eq 2 -a "${res%No files were added}" != "$res"; then
printf "%s" "$res"
echo "etckeeper warning: darcs add failed" >&2
fi
fi
unset rc res
fi

8
etckeeper/commit.d/30git-add Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
set -e
if [ "$VCS" = git ] && [ -d .git ]; then
if ! git add --all; then
echo "etckeeper warning: git add --all" >&2
fi
fi

View File

@@ -0,0 +1,8 @@
#!/bin/sh
set -e
if [ "$VCS" = hg ] && [ -d .hg ]; then
if ! hg addremove .; then
echo "etckeeper warning: hg addremove failed" >&2
fi
fi

113
etckeeper/commit.d/50vcs-commit Executable file
View File

@@ -0,0 +1,113 @@
#!/bin/sh
set -e
cleanup () {
if [ -n "$logfile" ]; then
rm -f "$logfile"
fi
}
if [ -n "$1" ]; then
trap cleanup EXIT
logfile="$(mktemp -t etckeeper-$VCS.XXXXXXXXXX)"
if [ "x$1" = "x--stdin" ]; then
cat > "$logfile"
else
if [ "x$1" = "x-m" ]; then
shift 1
fi
echo "$1" > "$logfile"
fi
else
logfile=""
fi
hostname=`hostname`
hostname="${hostname%%.*}"
dnsdomainname=`dnsdomainname 2>/dev/null || true`
if [ -n "$dnsdomainname" ]; then
hostname="$hostname.$dnsdomainname"
fi
USER=
if [ -n "$SUDO_USER" ]; then
USER="$SUDO_USER"
else
# try to check tty ownership, in case user su'd to root
TTY="$(tty 2>/dev/null || true)"
if [ -n "$TTY" ] && [ -c "$TTY" ]; then
USER="$(find "$TTY" -printf "%u")"
fi
fi
if [ "$VCS" = git ] && [ -d .git ]; then
if [ -n "$USER" ]; then
# Use user.name and user.email from the gitconfig belonging
# to the user who became root.
USER_HOME="$(perl -e 'print ((getpwnam(shift()))[7])' "$USER")"
if [ -n "$USER_HOME" ] && [ -e "$USER_HOME/.gitconfig" ]; then
if [ -z "$GIT_AUTHOR_NAME" ]; then
GIT_AUTHOR_NAME="$(git config -f "$USER_HOME/.gitconfig" user.name)" || true
export GIT_AUTHOR_NAME
fi
if [ -z "$GIT_AUTHOR_EMAIL" ]; then
GIT_AUTHOR_EMAIL="$(git config -f "$USER_HOME/.gitconfig" user.email)" || true
export GIT_AUTHOR_EMAIL
fi
fi
if [ -z "$GIT_COMMITTER_EMAIL" ]; then
GIT_COMMITER_EMAIL="$(git config --global user.email)" || true
export GIT_COMMITER_EMAIL
fi
if [ -z "$GIT_AUTHOR_NAME" ]; then
GIT_AUTHOR_NAME="$USER"
export GIT_AUTHOR_NAME
fi
if [ -z "$GIT_AUTHOR_EMAIL" ]; then
GIT_AUTHOR_EMAIL="$USER@$hostname"
export GIT_AUTHOR_EMAIL
fi
if [ -z "$GIT_COMMITTER_EMAIL" ]; then
GIT_COMMITTER_EMAIL=`whoami`"@$hostname"
export GIT_COMMITTER_EMAIL
fi
fi
if [ -n "$logfile" ]; then
git commit $GIT_COMMIT_OPTIONS -F "$logfile"
else
git commit $GIT_COMMIT_OPTIONS
fi
elif [ "$VCS" = hg ] && [ -d .hg ]; then
if [ -n "$USER" ]; then
LOGNAME="$USER"
export LOGNAME
fi
if [ -z "$HGUSER" ]; then
HGUSER="$USER@$hostname"
export HGUSER
fi
if [ -n "$logfile" ]; then
hg commit $HG_COMMIT_OPTIONS -l "$logfile"
else
hg commit $HG_COMMIT_OPTIONS
fi
elif [ "$VCS" = bzr ] && [ -d .bzr ]; then
if [ -z "$EMAIL" ] && [ -n "$USER" ]; then
EMAIL="$USER <$USER@$hostname>"
export EMAIL
fi
if [ -n "$logfile" ]; then
bzr commit $BZR_COMMIT_OPTIONS -F "$logfile"
else
bzr commit $BZR_COMMIT_OPTIONS
fi
elif [ "$VCS" = darcs ] && [ -d _darcs ]; then
if [ -z "$USER" ]; then
USER=root
fi
if [ -n "$logfile" ]; then
darcs record --author="$USER" $DARCS_COMMIT_OPTIONS --logfile="$logfile"
else
darcs record --author="$USER" $DARCS_COMMIT_OPTIONS
fi
fi

14
etckeeper/commit.d/99push Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
if [ -n "$PUSH_REMOTE" ]; then
if [ "$VCS" = git ] && [ -d .git ]; then
for REMOTE in $PUSH_REMOTE; do
git push "$REMOTE" master || true
done
elif [ "$VCS" = hg ] && [ -d .hg ]; then
for REMOTE in $PUSH_REMOTE; do
hg push "$REMOTE" || true
done
else
echo "PUSH_REMOTE not yet supported for $VCS" >&2
fi
fi

View File

@@ -0,0 +1,3 @@
Files in this directory are run when there might be changes to commit.
(Before and after packages are installed, upgraded, etc.)
They should commit changes and new files in /etc to repository.

49
etckeeper/etckeeper.conf Normal file
View File

@@ -0,0 +1,49 @@
# The VCS to use.
#VCS="hg"
VCS="git"
#VCS="bzr"
#VCS="darcs"
# Options passed to git commit when run by etckeeper.
GIT_COMMIT_OPTIONS=""
# Options passed to hg commit when run by etckeeper.
HG_COMMIT_OPTIONS=""
# Options passed to bzr commit when run by etckeeper.
BZR_COMMIT_OPTIONS=""
# Options passed to darcs record when run by etckeeper.
DARCS_COMMIT_OPTIONS="-a"
# Uncomment to avoid etckeeper committing existing changes
# to /etc automatically once per day.
#AVOID_DAILY_AUTOCOMMITS=1
# Uncomment the following to avoid special file warning
# (the option is enabled automatically by cronjob regardless).
#AVOID_SPECIAL_FILE_WARNING=1
# Uncomment to avoid etckeeper committing existing changes to
# /etc before installation. It will cancel the installation,
# so you can commit the changes by hand.
#AVOID_COMMIT_BEFORE_INSTALL=1
# The high-level package manager that's being used.
# (apt, pacman-g2, yum, zypper etc)
# Gentoo specific:
# For portage this is emerge
# For paludis this is cave
HIGHLEVEL_PACKAGE_MANAGER=emerge
# The low-level package manager that's being used.
# (dpkg, rpm, pacman, pacman-g2, etc)
# Gentoo specific:
# For portage this is qlist
# For paludis this is cave
LOWLEVEL_PACKAGE_MANAGER=qlist
# To push each commit to a remote, put the name of the remote here.
# (eg, "origin" for git). Space-separated lists of multiple remotes
# also work (eg, "origin gitlab github" for git).
PUSH_REMOTE=""

View File

@@ -0,0 +1,14 @@
#!/bin/sh
set -e
# Note that metastore doesn't check that the .metastore file only changes
# perms of files in the current directory. It's ok to trust the .metastore
# file won't do anything shady, because, as documented, etckeeper-init
# should only be run on repositories you trust.
if [ -e .metadata ]; then
if which metastore >/dev/null; then
metastore --apply --mtime
else
echo "etckeeper warning: legacy .metastore file is present but metastore is not installed" >&2
fi
fi

View File

@@ -0,0 +1,22 @@
#!/bin/sh
set -e
# Used by .etckeeper to run a command if the file it acts on
# (the last parameter) exists.
maybe () {
command="$1"
shift 1
if eval [ -e "\"\$$#\"" ]; then
"$command" "$@"
fi
}
# Yes, this runs code from the repository. As documented, etckeeper-init
# should only be run on repositories you trust.
if [ -e .etckeeper ]; then
. ./.etckeeper
else
touch .etckeeper
chmod 600 .etckeeper
fi

17
etckeeper/init.d/40vcs-init Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
set -e
if [ "$VCS" = git ] && [ ! -e .git ]; then
git init
echo "$(hostname) /etc repository" > .git/description
elif [ "$VCS" = hg ] && [ ! -e .hg ]; then
hg init
echo "[web]" > .hg/hgrc
echo "description = $(hostname) /etc repository" >> .hg/hgrc
elif [ "$VCS" = bzr ] && [ ! -e .bzr ]; then
bzr init
bzr nick "$(hostname) /etc repository"
elif [ "$VCS" = darcs ] && [ ! -e _darcs ]; then
darcs initialize
echo "$(hostname) /etc repository" > _darcs/prefs/motd
fi

4
etckeeper/init.d/50vcs-ignore Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
set -e
etckeeper update-ignore -a || true

12
etckeeper/init.d/50vcs-perm Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
chmod 700 .git
elif [ "$VCS" = hg ]; then
chmod 700 .hg
elif [ "$VCS" = bzr ]; then
chmod 700 .bzr
elif [ "$VCS" = darcs ]; then
chmod 700 _darcs
fi

View File

@@ -0,0 +1,49 @@
#!/bin/sh
set -e
case "$VCS" in
git)
if [ -x .git/hooks/pre-commit ]; then
if ! grep -q "etckeeper pre-commit" .git/hooks/pre-commit; then
echo "etckeeper warning: .git/hooks/pre-commit needs to be manually modified to run: etckeeper pre-commit -d `pwd`" >&2
fi
else
cat >.git/hooks/pre-commit <<EOF
#!/bin/sh
# pre-commit hook for etckeeper, to store metadata and do sanity checks
set -e
etckeeper pre-commit -d `pwd`
EOF
chmod +x .git/hooks/pre-commit
fi
;;
hg)
if [ -e .hg/hgrc ] && grep "^\[hooks\]" .hg/hgrc; then
if ! grep "^pre-commit" .hg/hgrc | grep -q "etckeeper pre-commit"; then
echo "etckeeper warning: [hooks] section in .hg/hgrc needs to be manually modified to contain: pre-commit = etckeeper pre-commit -d `pwd`" >&2
fi
else
touch .hg/hgrc
cat >>.hg/hgrc <<EOF
[hooks]
# pre-commit hook for etckeeper, to store metadata and do sanity checks
pre-commit = etckeeper pre-commit -d `pwd`
EOF
fi
;;
darcs)
if [ -e _darcs/prefs/defaults ]; then
if ! ( grep -q "record prehook etckeeper pre-commit" _darcs/prefs/defaults &&
grep -q "whatsnew prehook etckeeper pre-commit" _darcs/prefs/defaults ); then
echo "etckeeper warning: _darcs/prefs/defaults needs to be manually modified to run: etckeeper pre-commit -d `pwd`" >&2
fi
else
cat >_darcs/prefs/defaults <<EOF
record prehook etckeeper pre-commit -d `pwd`
record run-prehook
whatsnew prehook etckeeper pre-commit -d `pwd`
whatsnew run-prehook
EOF
fi
;;
esac

View File

@@ -0,0 +1,48 @@
#!/bin/sh
set -e
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
}
if [ "$VCS" = darcs ];then
NOVCS='. -path ./.git -prune -o -path ./.bzr -prune -o -path ./.hg -prune -o -path ./_darcs -prune -o'
# We assume that if .etckeeper is empty this is the first run
if [ -s .etckeeper ]; then
linksindex="$( mktemp -t etckeeper-$VCS.XXXXXXXXXX )"
grep '^ln -s' .etckeeper | while IFS="'" read n n n link n; do
printf "%s\n" "$link" >> "$linksindex"
done
# Warn about symbolic links that shouldn't exist
if links=$( find $NOVCS -type l -print | filter_ignore | grep -vFf "$linksindex" ); then
printf "%s\n%s\n" \
"The following symbolic links should not exist:" \
"$links" >&2
fi
rm -f "$linksindex"
unset links linksindex
fi
fi

27
etckeeper/init.d/70vcs-add Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
if ! git add .; then
echo "etckeeper warning: git add failed" >&2
fi
elif [ "$VCS" = hg ]; then
if ! hg add .; then
echo "etckeeper warning: hg add failed" >&2
fi
elif [ "$VCS" = bzr ]; then
if ! bzr add .; then
echo "etckeeper warning: bzr add failed" >&2
fi
elif [ "$VCS" = darcs ]; then
# Don't warn if all the files were already added.
rc=0
res=$( darcs add -qr . 2>&1 ) || rc=$?
if test $rc -ne 0; then
if ! test $rc -eq 2 -a "${res%No files were added}" != "$res"; then
printf "%s" "$res"
echo "etckeeper warning: darcs add failed" >&2
fi
fi
unset rc res
fi

13
etckeeper/init.d/README Normal file
View File

@@ -0,0 +1,13 @@
Executable files in this directory are run to initialise the working directory
for use by etckeeper. If the working directory is not already in version
control, that includes setting up the version control, but not actually
committing anything. If the working directory is in version control,
it includes applying stored metadata to the checked out files in the
working directory.
Please be careful to *never* overwrite existing files/directories
in the working directory (or use absolute care when doing so). If a file
you need to write already exists, check if its contents are sane, and
if not, emit a warning on stderr.
If initialisation fails, exit nonzero and no later files will be run.

View File

@@ -0,0 +1,16 @@
#!/bin/sh
# Output to stdout a *sorted* list of all currently installed
# (or removed but still with config-files) packages, in the
# format "package version\n" (or something similar).
if [ "$LOWLEVEL_PACKAGE_MANAGER" = dpkg ]; then
dpkg-query -W -f '${Status}\t${Package} ${Version}\n' | \
egrep '(ok installed|ok config-files)' | cut -f2,3
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = rpm ]; then
rpm -qa --qf "%|epoch?{%{epoch}}:{0}|:%{name}-%{version}-%{release}.%{arch}\n" | sort
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = pacman ]; then
pacman -Q
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = qlist ]; then
qlist -ICv
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = cave ]; then
cave print-packages -r installed
fi

View File

@@ -0,0 +1,30 @@
#!/bin/sh
set -e
pl="/var/cache/etckeeper/packagelist"
if etckeeper unclean; then
message="committing changes in /etc after $HIGHLEVEL_PACKAGE_MANAGER run"
set +e
if [ -e $pl.pre-install ]; then
(
echo "$message"
echo
echo "Package changes:"
etckeeper list-installed | diff -U0 $pl.pre-install - | tail -n+4 | egrep '^[-+]' || true
) | etckeeper commit --stdin
else
etckeeper commit "$(printf "$message")"
fi
status=$?
set -e
if [ "$status" != 0 ]; then
echo "warning: etckeeper failed to commit changes in /etc using $VCS" >&2
fi
fi
if [ -e $pl.pre-install ]; then
rm -f $pl.pre-install
fi

View File

@@ -0,0 +1,23 @@
#!/bin/sh
set -e
pl="/var/cache/etckeeper/packagelist"
if etckeeper unclean; then
message="committing changes in /etc after $HIGHLEVEL_PACKAGE_MANAGER run"
if [ -e $pl.pre-install ]; then
(
echo "$message"
echo
echo "Package changes:"
etckeeper list-installed | diff -U0 $pl.pre-install - | tail -n+4 | egrep '^[-+]' || true
) | etckeeper commit --stdin
else
etckeeper commit "$(printf "$message")"
fi
fi
if [ -e $pl.pre-install ]; then
rm -f $pl.pre-install
fi

View File

@@ -0,0 +1,2 @@
Files in this directory are run after packages are installed, upgraded, etc.
They should commit changes and new files in /etc to repository.

View File

@@ -0,0 +1,30 @@
#!/bin/sh
set -e
exclude_internal () {
egrep -v '(^|/)(.git|.hg|.bzr|_darcs)/'
}
if [ "$VCS" = bzr ] || [ "$VCS" = darcs ]; then
special=$(find . ! -type d ! -type f ! -type l | exclude_internal) || true
hardlinks=$(find . -type f ! -links 1 | exclude_internal ) || true
elif [ "$VCS" = hg ]; then
special=$(find . ! -type d ! -type f ! -type l | exclude_internal) || true
hardlinks=$(find . -type f ! -links 1 -exec hg status {} \; | exclude_internal ) || true
elif [ "$VCS" = git ]; then
special=$(find . ! -type d ! -type f ! -type l -exec git ls-files --exclude-standard --cached --others {} \; | exclude_internal) || true
hardlinks=$(find . -type f ! -links 1 -exec git ls-files --exclude-standard --cached --others {} \; | exclude_internal) || true
else
special=""
fi
if [ -n "$special" ] && [ -z "$AVOID_SPECIAL_FILE_WARNING" ]; then
echo "etckeeper warning: special files could cause problems with $VCS:" >&2
echo "$special" >&2
fi
if [ -n "$hardlinks" ] && [ -z "$AVOID_SPECIAL_FILE_WARNING" ]; then
echo "etckeeper warning: hardlinked files could cause problems with $VCS:" >&2
echo "$hardlinks" >&2
fi
true

View File

@@ -0,0 +1,153 @@
#!/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() {
case "$VCS" in
darcs) ignorefile=.darcsignore ;;
git) ignorefile=.gitignore ;;
esac
if [ -n "$ignorefile" ] && [ -e "$ignorefile" ]; then
listfile="$( mktemp -t etckeeper-$VCS.XXXXXXXXXX )"
case "$VCS" in
darcs)
grep -v '^[[:space:]]*\(#\|$\)' "$ignorefile" > "$listfile" || true
grep -Evf "$listfile"
;;
git)
(git ls-files -oi --exclude-standard; git ls-files -oi --exclude-standard --directory) | sort | uniq > "$listfile" || true
sed 's/^\.\///' | grep -xFvf "$listfile"
;;
esac
rm -f "$listfile"
unset listfile
else
cat -
fi
}
shellquote() {
# Single quotes text, escaping existing single quotes.
sed -e "s/'/'\"'\"'/g" -e "s/^/'/" -e "s/$/'/"
}
generate_metadata() {
# This function generates the script commands to fix any file
# ownerships that aren't owner=root, group=root, as well as to
# store the permissions of files.
# 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 want files in 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='. -path ./.git -prune -o -path ./.bzr -prune -o -path ./.hg -prune -o -path ./_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 | shellquote | sed -e "s/^/mkdir -p /"
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" "$(echo "$dest" | shellquote)" "$(echo "$link" | shellquote)"
done
fi
# Store things that don't have the default user or group.
# Store all file modes, in case the user has an unusual umask.
find $NOVCS \( -type f -or -type d \) -print | filter_ignore | sort | perl -ne '
BEGIN { $q=chr(39) }
sub uidname {
my $want=shift;
if (exists $uidcache{$want}) {
return $uidcache{$want};
}
my $name=scalar getpwuid($want);
return $uidcache{$want}=defined $name ? $name : $want;
}
sub gidname {
my $want=shift;
if (exists $gidcache{$want}) {
return $gidcache{$want};
}
my $name=scalar getgrgid($want);
return $gidcache{$want}=defined $name ? $name : $want;
}
chomp;
my @stat=stat($_);
my $mode = $stat[2];
my $uid = $stat[4];
my $gid = $stat[5];
s/$q/$q"$q"$q/g; # escape single quotes
s/^/$q/;
s/$/$q/;
if ($uid != $>) {
printf "maybe chown $q%s$q %s\n", uidname($uid), $_;
}
if ($gid != $)) {
printf "maybe chgrp $q%s$q %s\n", gidname($gid), $_;
}
printf "maybe chmod %04o %s\n", $mode & 07777, $_;
'
# 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

View File

@@ -0,0 +1,2 @@
This is run by a git pre-commit hook before committing changes to the
repository. This can be used for storing metadata, and for sanity checks.

View File

@@ -0,0 +1,15 @@
#!/bin/sh
set -e
if etckeeper unclean; then
if [ "$AVOID_COMMIT_BEFORE_INSTALL" = 1 ]; then
echo "" >&2
echo "** etckeeper detected uncommitted changes in /etc prior to $HIGHLEVEL_PACKAGE_MANAGER run" >&2
echo "** Aborting $HIGHLEVEL_PACKAGE_MANAGER run. Manually commit and restart." >&2
echo "" >&2
exit 1
fi
if ! etckeeper commit "saving uncommitted changes in /etc prior to $HIGHLEVEL_PACKAGE_MANAGER run"; then
echo "warning: etckeeper failed to commit changes in /etc using $VCS" >&2
fi
fi

View File

@@ -0,0 +1,4 @@
#!/bin/sh
# This list will be later used when committing.
mkdir -p /var/cache/etckeeper/
etckeeper list-installed > /var/cache/etckeeper/packagelist.pre-install

View File

@@ -0,0 +1,29 @@
#!/bin/sh
set -e
if [ "$1" = "fail-debconf" ]; then
. /usr/share/debconf/confmodule
db_subst etckeeper/commit_failed VCS "$VCS"
db_input critical etckeeper/commit_failed || true
db_go || true
db_reset etckeeper/commit_failed || true
exit 0
fi
if etckeeper unclean; then
if [ "$AVOID_COMMIT_BEFORE_INSTALL" = 1 ]; then
echo "" >&2
echo "** etckeeper detected uncommitted changes in /etc prior to $HIGHLEVEL_PACKAGE_MANAGER run" >&2
echo "** Aborting $HIGHLEVEL_PACKAGE_MANAGER run. Manually commit and restart." >&2
echo "" >&2
exit 1
fi
if ! etckeeper commit "saving uncommitted changes in /etc prior to $HIGHLEVEL_PACKAGE_MANAGER run"; then
if [ -e /usr/share/debconf/confmodule ]; then
$0 fail-debconf
else
echo "error: etckeeper failed to commit changes in /etc using $VCS"
exit 1
fi
fi
fi

View File

@@ -0,0 +1,3 @@
Files in this directory are run before packages are installed, upgraded,
etc. This is mostly used for sanity checks, ie, does /etc have any
uncommitted changes?

12
etckeeper/unclean.d/50test Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
[ -d .git ] && [ -n "`git status --porcelain`" ]
elif [ "$VCS" = hg ]; then
[ -d .hg ] && ! hg status 2>&1 | wc -l | grep -q "^0$"
elif [ "$VCS" = bzr ]; then
[ -d .bzr ] && ! bzr version-info --custom --template="{clean}\n" | grep -q "^1$"
elif [ "$VCS" = darcs ]; then
[ -d _darcs ] && darcs whatsnew -l >/dev/null
fi

View File

@@ -0,0 +1,2 @@
Files in this directory are used to test if the working copy has
uncommitted changes.

View File

@@ -0,0 +1,54 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
rm -rf .git
file=.gitignore
elif [ "$VCS" = hg ]; then
rm -rf .hg
file=.hgignore
elif [ "$VCS" = bzr ]; then
rm -rf .bzr
file=.bzrignore
elif [ "$VCS" = darcs ]; then
rm -rf _darcs
file=.darcsignore
fi
managed_by_etckeeper="managed by etckeeper"
if ! grep -q "$managed_by_etckeeper" "$file"; then
exit 0
else
realfile="$file"
if which tempfile >/dev/null 2>&1 || type -p tempfile >/dev/null 2>&1; then
tempfile="tempfile"
elif which mktemp >/dev/null 2>&1 || type -p mktemp >/dev/null 2>&1; then
tempfile="mktemp"
else
echo "etckeeper warning: can't find tempfile or mktemp" >&2
exit 1
fi
file=$($tempfile)
otherentries=
skipping=
while read -r line; do
if echo "$line" | grep -q "$managed_by_etckeeper"; then
if [ ! "$skipping" ]; then
skipping=1
else
skipping=
fi
elif [ ! "$skipping" ]; then
echo "$line" >> "$file"
otherentries=1
fi
done <"$realfile"
if [ "$otherentries" ]; then
mv -f "$file" "$realfile"
else
rm -f "$file"
rm -f "$realfile"
fi
fi

20
etckeeper/uninit.d/01prompt Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
set -e
if [ "$1" != "-f" ]; then
echo "** Warning: This will DESTROY all recorded history for $ETCKEEPER_DIR,"
echo "** including the $VCS repository."
echo ""
printf "Are you sure you want to do this? [yN] "
read answer
case "$answer" in
[Yy]*)
echo "Proceeding.."
exit 0
;;
*)
echo "Aborting etckeeper uninit."
exit 1
;;
esac
fi

View File

@@ -0,0 +1,6 @@
#!/bin/sh
set -e
# Files generated by etckeeper to store metadata the VCS cannot preserve.
rm -f .etckeeper
rm -f .metadata # only generated by old versions

54
etckeeper/uninit.d/50vcs-uninit Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
rm -rf .git
file=.gitignore
elif [ "$VCS" = hg ]; then
rm -rf .hg
file=.hgignore
elif [ "$VCS" = bzr ]; then
rm -rf .bzr
file=.bzrignore
elif [ "$VCS" = darcs ]; then
rm -rf _darcs
file=.darcsignore
fi
managed_by_etckeeper="managed by etckeeper"
if ! grep -q "$managed_by_etckeeper" "$file"; then
exit 0
else
realfile="$file"
if which tempfile >/dev/null 2>&1 || type -p tempfile >/dev/null 2>&1; then
tempfile="tempfile"
elif which mktemp >/dev/null 2>&1 || type -p mktemp >/dev/null 2>&1; then
tempfile="mktemp"
else
echo "etckeeper warning: can't find tempfile or mktemp" >&2
exit 1
fi
file=$($tempfile)
otherentries=
skipping=
while read line; do
if echo "$line" | grep -q "$managed_by_etckeeper"; then
if [ ! "$skipping" ]; then
skipping=1
else
skipping=
fi
elif [ ! "$skipping" ]; then
echo "$line" >> "$file"
otherentries=1
fi
done <"$realfile"
if [ "$otherentries" ]; then
mv -f "$file" "$realfile"
else
rm -f "$file"
rm -f "$realfile"
fi
fi

View File

@@ -0,0 +1,2 @@
Executable files in this directory are run to uninitialise the working
directory, removing files added by `etckeeper init`.

View File

@@ -0,0 +1,209 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
dir=.git
file=.gitignore
elif [ "$VCS" = hg ]; then
dir=.hg
file=.hgignore
elif [ "$VCS" = bzr ]; then
dir=.bzr
file=.bzrignore
elif [ "$VCS" = darcs ]; then
dir=_darcs
file=.darcsignore
else
echo "etckeeper: unsupported VCS $VCS" >&2
exit 1
fi
if [ ! -d "$dir" ]; then
exit 0
fi
managed_by_etckeeper="managed by etckeeper"
nl() {
echo >>"$file"
}
comment() {
comment="$1"
echo "# $comment" >>"$file"
}
ignore() {
glob="$1"
case "$VCS" in
git)
# escape "#" in ignores, as otherwise it may
# be considered a comment
echo "$glob" | sed 's/#/\\#/g' >>"$file"
;;
bzr)
echo "$glob" >>"$file"
;;
hg)
# rather than converting the glob to a regexp, just
# configure hg to use globs
if [ -z "$hg_syntax_printed" ]; then
comment "use glob syntax"
echo "syntax: glob" >>"$file"
nl
hg_syntax_printed=1
fi
echo "$glob" | sed 's/#/\\#/g' >>"$file"
;;
darcs)
# darcs doesn't understand globs, so we need to
# translate them into regexs. Not a complete converter,
# but suitable for given globs.
if [ "${glob%\*}" != "$glob" ]; then
glob="${glob%\*}"
else
glob="$glob"'($|/)'
fi
if [ "${glob#\*}" != "$glob" ]; then
glob="${glob#\*}"
else
glob='(^|/)'"$glob"
fi
glob="$( printf %s $glob | sed -e 's/\./\\./g;s/\*/[^\/]*/g;s/\?/[^\/]/g' )"
echo "$glob" >>"$file"
esac
}
writefile () {
comment "begin section $managed_by_etckeeper (do not edit this section by hand)"
nl
if [ "$VCS" = darcs ]; then
darcs setpref boringfile .darcsignore
fi
if [ "$LOWLEVEL_PACKAGE_MANAGER" = dpkg ]; then
comment "new and old versions of conffiles, stored by dpkg"
ignore "*.dpkg-*"
comment "new and old versions of conffiles, stored by ucf"
ignore "*.ucf-*"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "rpm" ]; then
comment "new and old versions of conffiles, stored by apt/rpm"
ignore "*.rpm*"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "pacman-g2" -o "$LOWLEVEL_PACKAGE_MANAGER" = "pacman" ]; then
comment "new and old versions of conffiles, stored by pacman"
ignore "*.pacnew"
ignore "*.pacorig"
ignore "*.pacsave"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "qlist" -o "$LOWLEVEL_PACKAGE_MANAGER" = "cave" ]; then
comment "new and old versions of conffiles, stored by emerge"
ignore "._cfg*"
nl
fi
comment "old versions of files"
ignore "*.old"
# Not currently ignored as admins tend to rely on these files.
#ignore "passwd-"
#ignore "group-"
#ignore "shadow-"
#ignore "gshadow-"
nl
comment "mount(8) records system state here, no need to store these"
ignore blkid.tab
ignore blkid.tab.old
nl
comment "some other files in /etc that typically do not need to be tracked"
ignore nologin
ignore ld.so.cache
ignore prelink.cache
ignore mtab
ignore mtab.fuselock
ignore .pwd.lock
ignore "*.LOCK"
ignore network/run
ignore adjtime
ignore lvm/cache
ignore lvm/archive
ignore "X11/xdm/authdir/authfiles/*"
ignore ntp.conf.dhcp
ignore .initctl
ignore "webmin/fsdump/*.status"
ignore "webmin/webmin/oscache"
ignore "apparmor.d/cache/*"
ignore "service/*/supervise/*"
ignore "service/*/log/supervise/*"
ignore "sv/*/supervise/*"
ignore "sv/*/log/supervise/*"
ignore "*.elc"
ignore "*.pyc"
ignore "*.pyo"
ignore "init.d/.depend.*"
ignore "openvpn/openvpn-status.log"
ignore "cups/subscriptions.conf"
ignore "cups/subscriptions.conf.O"
ignore "fake-hwclock.data"
ignore "check_mk/logwatch.state"
nl
comment "editor temp files"
ignore "*~"
ignore ".*.sw?"
ignore ".sw?"
ignore "#*#"
ignore DEADJOE
nl
comment "end section $managed_by_etckeeper"
}
if [ -e "$file" ]; then
if ! grep -q "$managed_by_etckeeper" "$file"; then
if [ "$1" != "-a" ]; then
echo "etckeeper: "$file" does not contain \"$managed_by_etckeeper\" comment; not updating"
exit 1
else
echo "etckeeper: "$file" exists but does not contain \"$managed_by_etckeeper\" comment; updating"
writefile
exit 0
fi
fi
realfile="$file"
if which tempfile >/dev/null 2>&1 || type -p tempfile >/dev/null 2>&1; then
tempfile="tempfile"
elif which mktemp >/dev/null 2>&1 || type -p mktemp >/dev/null 2>&1; then
tempfile="mktemp"
else
echo "etckeeper warning: can't find tempfile or mktemp" >&2
fi
file=$($tempfile)
(
skipping=
while read -r line; do
if echo "$line" | grep -q "$managed_by_etckeeper"; then
if [ ! "$skipping" ]; then
skipping=1
else
skipping=
writefile
fi
elif [ ! "$skipping" ]; then
echo "$line" >> "$file"
fi
done
if [ "$skipping" ]; then
# reached end of file w/o ending block
writefile
fi
) <"$realfile"
mv -f "$file" "$realfile"
else
writefile
fi

View File

@@ -0,0 +1,212 @@
#!/bin/sh
set -e
if [ "$VCS" = git ]; then
dir=.git
file=.gitignore
elif [ "$VCS" = hg ]; then
dir=.hg
file=.hgignore
elif [ "$VCS" = bzr ]; then
dir=.bzr
file=.bzrignore
elif [ "$VCS" = darcs ]; then
dir=_darcs
file=.darcsignore
else
echo "etckeeper: unsupported VCS $VCS" >&2
exit 1
fi
if [ ! -d "$dir" ]; then
exit 0
fi
managed_by_etckeeper="managed by etckeeper"
nl() {
echo >>"$file"
}
comment() {
comment="$1"
echo "# $comment" >>"$file"
}
ignore() {
glob="$1"
case "$VCS" in
git)
# escape "#" in ignores, as otherwise it may
# be considered a comment
echo "$glob" | sed 's/#/\\#/g' >>"$file"
;;
bzr)
echo "$glob" >>"$file"
;;
hg)
# rather than converting the glob to a regexp, just
# configure hg to use globs
if [ -z "$hg_syntax_printed" ]; then
comment "use glob syntax"
echo "syntax: glob" >>"$file"
nl
hg_syntax_printed=1
fi
echo "$glob" | sed 's/#/\\#/g' >>"$file"
;;
darcs)
# darcs doesn't understand globs, so we need to
# translate them into regexs. Not a complete converter,
# but suitable for given globs.
if [ "${glob%\*}" != "$glob" ]; then
glob="${glob%\*}"
else
glob="$glob"'($|/)'
fi
if [ "${glob#\*}" != "$glob" ]; then
glob="${glob#\*}"
else
glob='(^|/)'"$glob"
fi
glob="$( printf %s $glob | sed -e 's/\./\\./g;s/\*/[^\/]*/g;s/\?/[^\/]/g' )"
echo "$glob" >>"$file"
esac
}
writefile () {
comment "begin section $managed_by_etckeeper (do not edit this section by hand)"
nl
if [ "$VCS" = darcs ]; then
darcs setpref boringfile .darcsignore
fi
if [ "$LOWLEVEL_PACKAGE_MANAGER" = dpkg ]; then
comment "new and old versions of conffiles, stored by dpkg"
ignore "*.dpkg-*"
comment "new and old versions of conffiles, stored by ucf"
ignore "*.ucf-*"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "rpm" ]; then
comment "new and old versions of conffiles, stored by apt/rpm"
ignore "*.rpm*"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "pacman-g2" -o "$LOWLEVEL_PACKAGE_MANAGER" = "pacman" ]; then
comment "new and old versions of conffiles, stored by pacman"
ignore "*.pacnew"
ignore "*.pacorig"
ignore "*.pacsave"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "qlist" ]; then
comment "new and old versions of conffiles, stored by emerge"
ignore "._cfg*"
nl
elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "cave" ]; then
comment "new and old versions of conffiles, stored by emerge"
ignore "._cfg*"
nl
fi
comment "old versions of files"
ignore "*.old"
# Not currently ignored as admins tend to rely on these files.
#ignore "passwd-"
#ignore "group-"
#ignore "shadow-"
#ignore "gshadow-"
nl
comment "mount(8) records system state here, no need to store these"
ignore blkid.tab
ignore blkid.tab.old
nl
comment "some other files in /etc that typically do not need to be tracked"
ignore nologin
ignore ld.so.cache
ignore prelink.cache
ignore mtab
ignore mtab.fuselock
ignore .pwd.lock
ignore "*.LOCK"
ignore network/run
ignore adjtime
ignore lvm/cache
ignore lvm/archive
ignore "X11/xdm/authdir/authfiles/*"
ignore ntp.conf.dhcp
ignore .initctl
ignore "webmin/fsdump/*.status"
ignore "webmin/webmin/oscache"
ignore "apparmor.d/cache/*"
ignore "service/*/supervise/*"
ignore "service/*/log/supervise/*"
ignore "sv/*/supervise/*"
ignore "sv/*/log/supervise/*"
ignore "*.elc"
ignore "*.pyc"
ignore "*.pyo"
ignore "init.d/.depend.*"
ignore "openvpn/openvpn-status.log"
ignore "cups/subscriptions.conf"
ignore "cups/subscriptions.conf.O"
ignore "fake-hwclock.data"
nl
comment "editor temp files"
ignore "*~"
ignore ".*.sw?"
ignore ".sw?"
ignore "#*#"
ignore DEADJOE
nl
comment "end section $managed_by_etckeeper"
}
if [ -e "$file" ]; then
if ! grep -q "$managed_by_etckeeper" "$file"; then
if [ "$1" != "-a" ]; then
echo "etckeeper: "$file" does not contain \"$managed_by_etckeeper\" comment; not updating"
exit 1
else
echo "etckeeper: "$file" exists but does not contain \"$managed_by_etckeeper\" comment; updating"
writefile
exit 0
fi
fi
realfile="$file"
if which tempfile >/dev/null 2>&1 || type -p tempfile >/dev/null 2>&1; then
tempfile="tempfile"
elif which mktemp >/dev/null 2>&1 || type -p mktemp >/dev/null 2>&1; then
tempfile="mktemp"
else
echo "etckeeper warning: can't find tempfile or mktemp" >&2
fi
file=$($tempfile)
(
skipping=
while read line; do
if echo "$line" | grep -q "$managed_by_etckeeper"; then
if [ ! "$skipping" ]; then
skipping=1
else
skipping=
writefile
fi
elif [ ! "$skipping" ]; then
echo "$line" >> "$file"
fi
done
if [ "$skipping" ]; then
# reached end of file w/o ending block
writefile
fi
) <"$realfile"
mv -f "$file" "$realfile"
else
writefile
fi

View File

@@ -0,0 +1,2 @@
Executable files in this directory are run to update the VCS ignore file,
or create it if it does not exist.

11
etckeeper/vcs.d/50vcs-cmd Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -e
# check whether we can locate the vcs binary
if [ -n "$VCS" ] && which "$VCS" > /dev/null; then
# pass commands to the VCS application
$VCS "$@"
else
echo "error: VCS ($VCS) not set or not in PATH" >&2
exit 1
fi