1*6a54128fSAndroid Build Coastguard Worker#!/bin/bash 2*6a54128fSAndroid Build Coastguard Worker 3*6a54128fSAndroid Build Coastguard Worker# Copyright (C) 2018 Oracle. All Rights Reserved. 4*6a54128fSAndroid Build Coastguard Worker# 5*6a54128fSAndroid Build Coastguard Worker# Author: Darrick J. Wong <[email protected]> 6*6a54128fSAndroid Build Coastguard Worker# 7*6a54128fSAndroid Build Coastguard Worker# This program is free software; you can redistribute it and/or 8*6a54128fSAndroid Build Coastguard Worker# modify it under the terms of the GNU General Public License 9*6a54128fSAndroid Build Coastguard Worker# as published by the Free Software Foundation; either version 2 10*6a54128fSAndroid Build Coastguard Worker# of the License, or (at your option) any later version. 11*6a54128fSAndroid Build Coastguard Worker# 12*6a54128fSAndroid Build Coastguard Worker# This program is distributed in the hope that it would be useful, 13*6a54128fSAndroid Build Coastguard Worker# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*6a54128fSAndroid Build Coastguard Worker# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*6a54128fSAndroid Build Coastguard Worker# GNU General Public License for more details. 16*6a54128fSAndroid Build Coastguard Worker# 17*6a54128fSAndroid Build Coastguard Worker# You should have received a copy of the GNU General Public License 18*6a54128fSAndroid Build Coastguard Worker# along with this program; if not, write the Free Software Foundation, 19*6a54128fSAndroid Build Coastguard Worker# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 20*6a54128fSAndroid Build Coastguard Worker 21*6a54128fSAndroid Build Coastguard WorkerPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 22*6a54128fSAndroid Build Coastguard Worker 23*6a54128fSAndroid Build Coastguard Workerif (( $EUID != 0 )); then 24*6a54128fSAndroid Build Coastguard Worker echo "e2scrub_all must be run as root" 25*6a54128fSAndroid Build Coastguard Worker exit 1 26*6a54128fSAndroid Build Coastguard Workerfi 27*6a54128fSAndroid Build Coastguard Worker 28*6a54128fSAndroid Build Coastguard Workerperiodic_e2scrub=0 29*6a54128fSAndroid Build Coastguard Workerscrub_all=0 30*6a54128fSAndroid Build Coastguard Workersnap_size_mb=256 31*6a54128fSAndroid Build Coastguard Workerreap=0 32*6a54128fSAndroid Build Coastguard Workerconffile="@root_sysconfdir@/e2scrub.conf" 33*6a54128fSAndroid Build Coastguard Worker 34*6a54128fSAndroid Build Coastguard Workertest -f "${conffile}" && . "${conffile}" 35*6a54128fSAndroid Build Coastguard Worker 36*6a54128fSAndroid Build Coastguard Workerscrub_args="" 37*6a54128fSAndroid Build Coastguard Worker 38*6a54128fSAndroid Build Coastguard Workerprint_help() { 39*6a54128fSAndroid Build Coastguard Worker echo "Usage: $0 [OPTIONS]" 40*6a54128fSAndroid Build Coastguard Worker echo " -n: Show what commands e2scrub_all would execute." 41*6a54128fSAndroid Build Coastguard Worker echo " -r: Remove e2scrub snapshots." 42*6a54128fSAndroid Build Coastguard Worker echo " -A: Scrub all ext[234] filesystems even if not mounted." 43*6a54128fSAndroid Build Coastguard Worker echo " -V: Print version information and exit." 44*6a54128fSAndroid Build Coastguard Worker} 45*6a54128fSAndroid Build Coastguard Worker 46*6a54128fSAndroid Build Coastguard Workerprint_version() { 47*6a54128fSAndroid Build Coastguard Worker echo "e2scrub_all @E2FSPROGS_VERSION@ (@E2FSPROGS_DATE@)" 48*6a54128fSAndroid Build Coastguard Worker} 49*6a54128fSAndroid Build Coastguard Worker 50*6a54128fSAndroid Build Coastguard Workerexitcode() { 51*6a54128fSAndroid Build Coastguard Worker ret="$1" 52*6a54128fSAndroid Build Coastguard Worker 53*6a54128fSAndroid Build Coastguard Worker # If we're being run as a service, the return code must fit the LSB 54*6a54128fSAndroid Build Coastguard Worker # init script action error guidelines, which is to say that we 55*6a54128fSAndroid Build Coastguard Worker # compress all errors to 1 ("generic or unspecified error", LSB 5.0 56*6a54128fSAndroid Build Coastguard Worker # section 22.2) and hope the admin will scan the log for what 57*6a54128fSAndroid Build Coastguard Worker # actually happened. 58*6a54128fSAndroid Build Coastguard Worker 59*6a54128fSAndroid Build Coastguard Worker if [ -n "${SERVICE_MODE}" -a "${ret}" -ne 0 ]; then 60*6a54128fSAndroid Build Coastguard Worker test "${ret}" -ne 0 && ret=1 61*6a54128fSAndroid Build Coastguard Worker fi 62*6a54128fSAndroid Build Coastguard Worker 63*6a54128fSAndroid Build Coastguard Worker exit "${ret}" 64*6a54128fSAndroid Build Coastguard Worker} 65*6a54128fSAndroid Build Coastguard Worker 66*6a54128fSAndroid Build Coastguard Workerwhile getopts "nrAV" opt; do 67*6a54128fSAndroid Build Coastguard Worker case "${opt}" in 68*6a54128fSAndroid Build Coastguard Worker "n") DBG="echo Would execute: " ;; 69*6a54128fSAndroid Build Coastguard Worker "r") scrub_args="${scrub_args} -r"; reap=1;; 70*6a54128fSAndroid Build Coastguard Worker "A") scrub_all=1;; 71*6a54128fSAndroid Build Coastguard Worker "V") print_version; exitcode 0;; 72*6a54128fSAndroid Build Coastguard Worker *) print_help; exitcode 2;; 73*6a54128fSAndroid Build Coastguard Worker esac 74*6a54128fSAndroid Build Coastguard Workerdone 75*6a54128fSAndroid Build Coastguard Workershift "$((OPTIND - 1))" 76*6a54128fSAndroid Build Coastguard Worker 77*6a54128fSAndroid Build Coastguard Worker# If we're in service mode and the service is not enabled via config file... 78*6a54128fSAndroid Build Coastguard Workerif [ -n "${SERVICE_MODE}" -a "${periodic_e2scrub}" -ne 1 ]; then 79*6a54128fSAndroid Build Coastguard Worker # ...don't start e2scrub processes. 80*6a54128fSAndroid Build Coastguard Worker if [ "${reap}" -eq 0 ]; then 81*6a54128fSAndroid Build Coastguard Worker exitcode 0 82*6a54128fSAndroid Build Coastguard Worker fi 83*6a54128fSAndroid Build Coastguard Worker 84*6a54128fSAndroid Build Coastguard Worker # ...and if we don't see any leftover e2scrub snapshots, don't 85*6a54128fSAndroid Build Coastguard Worker # run the reaping process either, because lvs can be slow. 86*6a54128fSAndroid Build Coastguard Worker if ! readlink -q -s -e /dev/mapper/*.e2scrub* > /dev/null; then 87*6a54128fSAndroid Build Coastguard Worker exitcode 0 88*6a54128fSAndroid Build Coastguard Worker fi 89*6a54128fSAndroid Build Coastguard Workerfi 90*6a54128fSAndroid Build Coastguard Worker 91*6a54128fSAndroid Build Coastguard Worker# close file descriptor 3 (from cron) since it causes lvm to kvetch 92*6a54128fSAndroid Build Coastguard Workerexec 3<&- 93*6a54128fSAndroid Build Coastguard Worker 94*6a54128fSAndroid Build Coastguard Worker# If some prerequisite packages are not installed, exit with a code 95*6a54128fSAndroid Build Coastguard Worker# indicating success to avoid spamming the sysadmin with fail messages 96*6a54128fSAndroid Build Coastguard Worker# when e2scrub_all is run out of cron or a systemd timer. 97*6a54128fSAndroid Build Coastguard Worker 98*6a54128fSAndroid Build Coastguard Workerif ! type mapfile >& /dev/null ; then 99*6a54128fSAndroid Build Coastguard Worker test -n "${SERVICE_MODE}" && exitcode 0 100*6a54128fSAndroid Build Coastguard Worker echo "e2scrub_all: can't find mapfile --- is bash 4.xx installed?" 101*6a54128fSAndroid Build Coastguard Worker exitcode 1 102*6a54128fSAndroid Build Coastguard Workerfi 103*6a54128fSAndroid Build Coastguard Worker 104*6a54128fSAndroid Build Coastguard Workerif ! type lsblk >& /dev/null ; then 105*6a54128fSAndroid Build Coastguard Worker test -n "${SERVICE_MODE}" && exitcode 0 106*6a54128fSAndroid Build Coastguard Worker echo "e2scrub_all: can't find lsblk --- is util-linux installed?" 107*6a54128fSAndroid Build Coastguard Worker exitcode 1 108*6a54128fSAndroid Build Coastguard Workerfi 109*6a54128fSAndroid Build Coastguard Worker 110*6a54128fSAndroid Build Coastguard Workerif ! type lvcreate >& /dev/null ; then 111*6a54128fSAndroid Build Coastguard Worker test -n "${SERVICE_MODE}" && exitcode 0 112*6a54128fSAndroid Build Coastguard Worker echo "e2scrub_all: can't find lvcreate --- is lvm2 installed?" 113*6a54128fSAndroid Build Coastguard Worker exitcode 1 114*6a54128fSAndroid Build Coastguard Workerfi 115*6a54128fSAndroid Build Coastguard Worker 116*6a54128fSAndroid Build Coastguard Worker# Find scrub targets, make sure we only do this once. 117*6a54128fSAndroid Build Coastguard Workerls_scan_targets() { 118*6a54128fSAndroid Build Coastguard Worker local devices=$(lvs -o lv_path --noheadings -S "lv_active=active,lv_role=public,lv_role!=snapshot,vg_free>=${snap_size_mb}") 119*6a54128fSAndroid Build Coastguard Worker 120*6a54128fSAndroid Build Coastguard Worker if [ -z "$devices" ]; then 121*6a54128fSAndroid Build Coastguard Worker return 0; 122*6a54128fSAndroid Build Coastguard Worker fi 123*6a54128fSAndroid Build Coastguard Worker lsblk -o NAME,MOUNTPOINT,FSTYPE,TYPE -P -n -p $devices | \ 124*6a54128fSAndroid Build Coastguard Worker grep FSTYPE=\"ext\[234\]\" | grep TYPE=\"lvm\" | \ 125*6a54128fSAndroid Build Coastguard Worker while read vars ; do 126*6a54128fSAndroid Build Coastguard Worker eval "${vars}" 127*6a54128fSAndroid Build Coastguard Worker 128*6a54128fSAndroid Build Coastguard Worker if [ "${scrub_all}" -eq 1 ] || [ -n "${MOUNTPOINT}" ]; then 129*6a54128fSAndroid Build Coastguard Worker echo ${MOUNTPOINT:-${NAME}} 130*6a54128fSAndroid Build Coastguard Worker fi 131*6a54128fSAndroid Build Coastguard Worker done 132*6a54128fSAndroid Build Coastguard Worker} 133*6a54128fSAndroid Build Coastguard Worker 134*6a54128fSAndroid Build Coastguard Worker# Find leftover scrub snapshots 135*6a54128fSAndroid Build Coastguard Workerls_reap_targets() { 136*6a54128fSAndroid Build Coastguard Worker lvs -o lv_path -S lv_role=snapshot -S lv_name=~\(e2scrub$\) \ 137*6a54128fSAndroid Build Coastguard Worker --noheadings | sed -e 's/.e2scrub$//' 138*6a54128fSAndroid Build Coastguard Worker} 139*6a54128fSAndroid Build Coastguard Worker 140*6a54128fSAndroid Build Coastguard Worker# Figure out what we're targeting 141*6a54128fSAndroid Build Coastguard Workerls_targets() { 142*6a54128fSAndroid Build Coastguard Worker if [ "${reap}" -eq 1 ]; then 143*6a54128fSAndroid Build Coastguard Worker ls_reap_targets 144*6a54128fSAndroid Build Coastguard Worker else 145*6a54128fSAndroid Build Coastguard Worker ls_scan_targets 146*6a54128fSAndroid Build Coastguard Worker fi 147*6a54128fSAndroid Build Coastguard Worker} 148*6a54128fSAndroid Build Coastguard Worker 149*6a54128fSAndroid Build Coastguard Worker# systemd doesn't know to do path escaping on the instance variable we pass 150*6a54128fSAndroid Build Coastguard Worker# to the e2scrub service, which breaks things if there is a dash in the path 151*6a54128fSAndroid Build Coastguard Worker# name. Therefore, do the path escaping ourselves if needed. 152*6a54128fSAndroid Build Coastguard Worker# 153*6a54128fSAndroid Build Coastguard Worker# systemd path escaping also drops the initial slash so we add that back in so 154*6a54128fSAndroid Build Coastguard Worker# that log messages from the service units preserve the full path and users can 155*6a54128fSAndroid Build Coastguard Worker# look up log messages using full paths. However, for "/" the escaping rules 156*6a54128fSAndroid Build Coastguard Worker# do /not/ drop the initial slash, so we have to special-case that here. 157*6a54128fSAndroid Build Coastguard Workerescape_path_for_systemd() { 158*6a54128fSAndroid Build Coastguard Worker local path="$1" 159*6a54128fSAndroid Build Coastguard Worker 160*6a54128fSAndroid Build Coastguard Worker if [ "${path}" != "/" ]; then 161*6a54128fSAndroid Build Coastguard Worker echo "-$(systemd-escape --path "${path}")" 162*6a54128fSAndroid Build Coastguard Worker else 163*6a54128fSAndroid Build Coastguard Worker echo "-" 164*6a54128fSAndroid Build Coastguard Worker fi 165*6a54128fSAndroid Build Coastguard Worker} 166*6a54128fSAndroid Build Coastguard Worker 167*6a54128fSAndroid Build Coastguard Worker# Scrub any mounted fs on lvm by creating a snapshot and fscking that. 168*6a54128fSAndroid Build Coastguard Workermapfile -t targets < <(ls_targets) 169*6a54128fSAndroid Build Coastguard Workerfor tgt in "${targets[@]}"; do 170*6a54128fSAndroid Build Coastguard Worker # If we're not reaping and systemd is present, try invoking the 171*6a54128fSAndroid Build Coastguard Worker # systemd service. 172*6a54128fSAndroid Build Coastguard Worker if [ "${reap}" -ne 1 ] && type systemctl > /dev/null 2>&1; then 173*6a54128fSAndroid Build Coastguard Worker tgt_esc="$(escape_path_for_systemd "${tgt}")" 174*6a54128fSAndroid Build Coastguard Worker ${DBG} systemctl start "e2scrub@${tgt_esc}" 2> /dev/null 175*6a54128fSAndroid Build Coastguard Worker res=$? 176*6a54128fSAndroid Build Coastguard Worker if [ "${res}" -eq 0 ] || [ "${res}" -eq 1 ]; then 177*6a54128fSAndroid Build Coastguard Worker continue; 178*6a54128fSAndroid Build Coastguard Worker fi 179*6a54128fSAndroid Build Coastguard Worker fi 180*6a54128fSAndroid Build Coastguard Worker 181*6a54128fSAndroid Build Coastguard Worker # Otherwise use direct invocation 182*6a54128fSAndroid Build Coastguard Worker ${DBG} "@root_sbindir@/e2scrub" ${scrub_args} "${tgt}" 183*6a54128fSAndroid Build Coastguard Workerdone 184*6a54128fSAndroid Build Coastguard Worker 185*6a54128fSAndroid Build Coastguard Workerexitcode 0 186