From 41ee6c7df1bb1c332710b2f8a56db51fdc425d7f Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Sat, 23 Jul 2016 14:52:04 -0700 Subject: [PATCH] reports/project-fsck-status: new project fsck report Runs git fsck --strict on all projects (using nice and ionice) and reports any non-dangling results for non-empty projects. Signed-off-by: Kyle J. McKay --- cron/girocco | 3 + toolbox/reports/project-fsck-status.sh | 152 +++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100755 toolbox/reports/project-fsck-status.sh diff --git a/cron/girocco b/cron/girocco index 4b3aa06..e7ce679 100644 --- a/cron/girocco +++ b/cron/girocco @@ -57,6 +57,9 @@ # Report project disk space usage once a week with an email to admin #23 7 * * 3 repo "$HOME/repomgr/toolbox/reports/project-disk-use.sh" -m 100 +# Report project fsck status once a month with an email to admin +#37 19 17 * * repo "$HOME/repomgr/toolbox/reports/project-fsck-status.sh" -m + # The job daemon and task daemon are run in a screen # The ../screen/screenrc file needs to be installed to # ~repo/.screenrc to support the SCREENCOMMAND functionality. diff --git a/toolbox/reports/project-fsck-status.sh b/toolbox/reports/project-fsck-status.sh new file mode 100755 index 0000000..2611eee --- /dev/null +++ b/toolbox/reports/project-fsck-status.sh @@ -0,0 +1,152 @@ +#!/bin/sh + +# Report on project fsck status. +# Output can be sent as email to admin with -m +# Automatically runs with nice and ionice (if available) + +# Usage: project-fsck-status [-m] + +# With -m mail the report to $cfg_admin instead of sending it to stdout + +# Shows fsck status for all projects with details for any issues + +# Note that only projects listed in $cfg_chroot/etc/group are checked + +set -e + +datefmt='%Y-%m-%d %H:%M:%S %z' +startdate="$(date "+$datefmt")" + +. @basedir@/shlib.sh + +mailresult= +if [ "$1" = "-m" ]; then + shift + mailresult=1 +fi + +hasnice= +command -v nice > /dev/null && hasnice=1 +hasionice= +command -v ionice > /dev/null && hasionice=1 + +nl="$(printf '\n*')" +nl="${nl%?}" + +projlist="$(cut -d : -f 1 < "$cfg_chroot/etc/group")" + +is_listed_proj() { + echo "$projlist" | grep -q -e "^$1$" +} + +is_empty_proj() { + # if packed-refs is empty and no files in refs then empty + # we do NOT want to run any git command in case the repo is bad + _pd="$cfg_reporoot/$1.git" + if [ -f "$_pd/packed-refs" -a -s "$_pd/packed-refs" ]; then + if [ $(LC_ALL=C sed -n '/^#/!p' <"$_pd/packed-refs" | LC_ALL=C wc -l) -gt 0 ]; then + return 1 + fi + fi + test $(find "$_pd/refs" -type f -print 2>/dev/null | head -n 1 | LC_ALL=C wc -l) -eq 0 +} + +get_fsck_proj() ( + cd "$cfg_reporoot/$1.git" || { + echo "no such directory: $cfg_reporoot/$1.git" + return 1 + } + # using --strict changes "zero-padded file modes" from a warning into an error + # which we do NOT want so we do NOT use --strict + cmd="git fsck" + [ -z "$var_have_git_1710" ] || cmd="$cmd --no-dangling" + # no need for --no-progress (v1.7.9+) since stderr will not be a tty + cmd="$cmd 2>&1" + [ -n "$hasionice" ] && cmd="ionice -c 3 $cmd" + [ -n "$hasnice" ] && cmd="nice -n 19 $cmd" + fsckresult=0 + fsckoutput="$(eval "$cmd")" || fsckresult=$? + if [ -z "$var_have_git_1710" ]; then + # strip lines starting with "dangling" since --no-dangling is not supported + # note that "dangling" is NOT translated + fsckoutput="$(printf '%s\n' "$fsckoutput" | LC_ALL=C sed -n '/^dangling/!p')" + fi + [ -z "$fsckoutput" ] || printf '%s\n' "$fsckoutput" + return $fsckresult +) + +cd "$cfg_reporoot" +# howmany is how many fsck was run on plus how many were empty +howmany=0 +# mtcount is how many were empty +mtcount=0 +# okcount is how many fsck returned 0 status for +okcount=0 +# warncount is how many fsck returned 0 status but non-empty output +warncount=0 +# errresults are results from fsck non-0 status fsck runs +errresults= +# warnresults are non-empty results from 0 status fsck runs +warnresults= +while IFS='' read -r proj; do + proj="${proj#./}" + proj="${proj%.git}" + is_listed_proj "$proj" && is_git_dir "$cfg_reporoot/$proj.git" || continue + [ -d "$proj.git/objects" ] || continue + howmany="$(( $howmany + 1 ))" + if is_empty_proj "$proj"; then + mtcount="$(( $mtcount + 1 ))" + continue + fi + ok=1 + output="$(get_fsck_proj "$proj")" || ok= + [ -z "$ok" ] || okcount="$(( $okcount + 1 ))" + [ -n "$ok" -o -n "$output" ] || output="git fsck failed with no output" + if [ -n "$output" ]; then + output="$(printf '%s\n' "$output" | LC_ALL=C sed 's/^/ /')$nl" + if [ -n "$ok" ]; then + # warning + warncount="$(( $warncount + 1 ))" + [ -z "$warnresults" ] || warnresults="$warnresults$nl" + warnresults="$warnresults$proj: (warnings only)$nl$output" + else + [ -z "$errresults" ] || errresults="$errresults$nl" + errresults="$errresults$proj: (errors found)$nl$output" + fi + fi +done </dev/null) +EOT + +enddate="$(date "+$datefmt")" +domail=cat +[ -n "$mailresult" ] && domail='mail -s "[$cfg_name] Project Fsck Status Report" "$cfg_admin"' +{ + cat <