/usr/sbin/simplesnap is in simplesnap 1.0.3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318  | #!/bin/bash
# Simple snapshot manager
# Copyright (c) 2014 John Goerzen
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
set -e
# Log a message
logit () {
   logger -p info -t "`basename $0`[$$]" "$1"
}
# Log stdin with the given code.  Used normally to log stderr.
logstdin () {
   logger -p info -t "`basename $0`[$$/$1]"
}
# Run command, logging stderr and exit code
runcommand () {
   logit "Running $*"
   if "$@" 2> >(logstdin "$1") ; then
      logit "$1 exited successfully"
      return 0
   else
       RETVAL="$?"
       logit "$1 exited with error $RETVAL"
       return "$RETVAL"
   fi
}
exiterror () {
   logit "$1"
   echo "$1" 1>&2
   exit 10
}
syntaxerror () {
   cat <<EOF
Syntax: 
$0 [--sshcmd CMD] [--local] [--wrapcmd CMD] 
   [--backupdataset DATASET [--datasetdest DEST]] 
   --store STORE --setname NAME --host HOST
or
$0 --check TIMEFRAME --store STORE --setname NAME [--host HOST]
Required:
  --store: gives the ZFS dataset name where data will be stored.  Mountpoint
           is inferred.
  --setname: Gives the backup set name.  Can just be a made-up word
             if multiple sets aren not needed; for instance, the hostname
             of the backup server.  This is used in the snapshot name.
  --host: Gives the hostname to back up.
Optional:
  --sshcmd: Gives the SSH command.  Defaults to "ssh".  Example:
            --sshcmd "ssh -i /root/.id_rsa_simplesnap"
  --wrapcmd: Gives the path to simplesnapwrap on the remote
             (or local machine, if --local is present).
             Not usually relevant, since this is set in
             ~/.ssh/authorized_keys.  Default: "simplesnapwrap"
  --local: The host is localhost; do not use remote tool to access it.
  --backupdataset: Back up only the specified dataset instead of all.
  --datasetdest: Valid only with --backupdataset; store the backup in
                 the specified location.
  --check: Do not back up, but check existing backups.  If any are
           older than TIMEFRAME, print an error and exit with a nonzero
           code.  Scans all hosts unless a specific host is given with
           --host.  The parameter is in the format given to date/gdate: 
           for instance, --check "30 days ago".  Remember to enclose it
           in quotes if it contains spaces.
  
EOF
  exiterror "Syntax error: $1"
}
logit "Invoked as: $0 $*"
while [ -n "$1" ]; do
  case "$1" in
    "--sshcmd")
      SSHCMD="$2"
      shift 2
      ;;
    "--wrapcmd")
      WRAPCMD="$2"
      shift 2
      ;;
    "--store")
      STORE="$2"
      shift 2
      ;;
    "--setname")
      SETNAME="$2"
      shift 2
      ;;
    "--host")
      HOST="$2"
      shift 2
      ;;
    "--backupdataset")
      BACKUPDATASET="$2"
      shift 2
      ;;
    "--datasetdest")
      DATASETDEST="$2"
      shift 2
      ;;
    "--check")
      CHECKMODE="$2"
      if [ -z "$CHECKMODE" ] ; then
          syntaxerror "--check requires a paremter"
      fi
      shift 2
      ;;
    "--local")
      LOCALMODE="on"
      shift
      ;;
    *)
      syntaxerror "Unknown option \"$1\""
      ;;
  esac
done
SSHCMD="${SSHCMD:-ssh}"
WRAPCMD="${WRAPCMD:-simplesnapwrap}"
DATE="gdate"
gdate &> /dev/null || DATE="date"
SED="gsed"
gsed &> /dev/null || SED="sed"
GREP="ggrep"
ggrep &> /dev/null || GREP="grep"
# Validating
[ -n "$SSHCMD" ] || syntaxerror "Invalid SSH command: $SSHCMD"
[ -n "$STORE" ] || syntaxerror "Missing --store"
[ -n "$SETNAME" ] || syntaxerror "Missing --setname"
[ -n "$CHECKMODE" -o -n "$HOST" ] || syntaxerror "Missing --host"
echo "_${STORE}" | $GREP -qv " " || syntaxerror "Space in --store: ${STORE}"
TEMPLATEPATTERN="^[a-zA-Z0-9]\+\$"
echo "a${SETNAME}" | $GREP -q "${TEMPLATEPATTERN}" || syntaxerror "Invalid characters in setname \"${SETNAME}\"; pattern is \"${TEMPLATEPATTERN}\""
echo "_${SETNAME}" | $GREP -qv '^_-' || syntaxerror "Set name cannot begin with a dash: \"${SETNAME}\""
TEMPLATE="__simplesnap_${SETNAME}_"
[ -n "$DATASETDEST" -a -z "$BACKUPDATASET" ] && syntaxerror "--datasetdest given without --backupdataset"
MOUNTPOINT="`zfs list -H -o mountpoint -t filesystem \"${STORE}\"`"
logit "Store ${STORE} is mounted at ${MOUNTPOINT}"
cd "${MOUNTPOINT}"
# template - $1
# dataset - $2
listsnaps () {
   runzfs list -t snapshot -r -d 1 -H -o name "$2" | $GREP "@$1" || true
}
CHECKRETVAL=0
runzfs () {
  runcommand /sbin/zfs "$@"
}
checkbackups () {
  CHECKHOST="$1"
  DATASETS="`runzfs list -t filesystem,volume -o name -H -r \"${STORE}/${HOST}\"`"
  CUTOFF="`$DATE -d \"${CHECKMODE}\" +%s`"
  for CHECKDS in ${DATASETS}; do
    # Don't check the top-level host dataset itself.
    if [ "${CHECKDS}" = "${STORE}/${HOST}" ]; then
        continue
    fi
    FOUNDOK=0
    # Extract timestamps
    for TIMESTAMP in `listsnaps "$TEMPLATE" "$CHECKDS" | $SED 's/^.*_\([^_]\+\)__$/\1/'`; do
        TSSEC=`$DATE -d "${TIMESTAMP}" +%s`
        if [ "$TSSEC" -gt "$CUTOFF" ]; 
            then FOUNDOK=1
        fi
    done
    if [ "$FOUNDOK" = "0" ]; then
        echo "${CHECKDS} last back up is too old; created at `$DATE -d \"@${TSSEC}\"` but cutoff is `$DATE -d \"@${CUTOFF}\"`!" 1>&2
        CHECKRETVAL=10
    fi
  done 
}
if [ -n "$CHECKMODE" ]; then
  # Do a check only.
  if [ -n "$HOST" ]; then
    checkbackups "$HOST"
  else
    for HOST in *; do checkbackups "$HOST"; done
  fi
  logit "check: exiting with value $CHECKRETVAL"
  exit $CHECKRETVAL
fi
runwrap () {
  if [ "$LOCALMODE" = "on" ]; then
    runcommand "${WRAPCMD}" reinvoked simplesnapwrap "$@"
  else
    runcommand ${SSHCMD} ${HOST} ${WRAPCMD} "$@"
  fi
}
if [ ! -d "${MOUNTPOINT}/${HOST}" ]; then
  runzfs create "${STORE}/${HOST}"
fi
LOCKFILE="${MOUNTPOINT}/${HOST}/.lock"
if dotlockfile -r 0 -l -p "${LOCKFILE}"; then
  LOCKMETHOD="dotlockfile"
  logit "Lock obtained at ${LOCKFILE} with dotlockfile"
  trap "ECODE=$?; dotlockfile -u \"${LOCKFILE}\"; exit $ECODE" EXIT INT TERM
else
  RETVAL="$?"
  if [ "$RETVAL" = "127" ]; then
    LOCKMETHOD="mkdir"
    mkdir "${LOCKFILE}" || exiterror "Could not obtain lock at ${LOCKFILE}; if $0 is not already running, rmdir that path."
    logit "Lock obtained at ${LOCKFILE} with mkdir"
    trap "ECODE=$?; rmdir \"${LOCKFILE}\"" EXIT INT TERM
  else
    exiterror "Could not obtain lock at ${LOCKFILE}; $0 likely already running."
  fi
fi
reap () {
  DATASET="$1"
       # We always save the most recent.
       SNAPSTOREMOVE="`listsnaps \"${TEMPLATE}\" \"${DATASET}\" | head -n -1`"
       if [ -z "${SNAPSTOREMOVE}" ]; then
         logit "No snapshots to remove."
       else
         for REMOVAL in ${SNAPSTOREMOVE}; do
            logit "Destroying snapshot ${REMOVAL}"
            echo "_${REMOVAL}" | $GREP -q '@' || exiterror "PANIC: snapshot name doesn not contain @"
            runzfs destroy "${REMOVAL}"
         done
       fi
}
  
backupto() {
    DATASET="$1"
    DESTDIR="$2"
    DATASETPATTERN="^[a-zA-Z0-9_/.-]\+\$"
    if echo "a$DATASET" | $GREP -vq "$DATASETPATTERN"; then
        logit "Dataset \"$DATASET\" contains invalid characters; pattern is $DATASETPATTERN"
        return
    fi
    if echo "a$DATASET" | $GREP -q "^[/-]"; then
        exiterror "Dataset \"$DATASET\" begins with a / or a -; something is wrong.  Aborting."
    fi
    if echo "a$DATASET" | $GREP -q '\.\.'; then
        exiterror "Dataset \"$DATASET\" contains ..; something is wrong.  Aborting."
    fi
    if runwrap sendback "${SETNAME}" "${DATASET}" | \
       runzfs receive -F "${DESTDIR}"; then
        logit "Received backup into ${DESTDIR}"
        runwrap reap "${SETNAME}" "${DATASET}"
        reap "${DESTDIR}"
    else
        logit "zfs receive died with error: $?"
        exit 100
    fi        
}
# If the user requested only one dataset to be backed up:
if [ -n "${BACKUPDATASET}" ]; then
    logit "Option --backupdataset ${BACKUPDATASET} requested; not asking remote for dataset list."
    # If the user gave a specified location:
    if [ -n "${DATASETDEST}" ]; then
        backupto "${BACKUPDATASET}" "${DATASETDEST}"
    else
        backupto "${BACKUPDATASET}" "${STORE}/${HOST}/${BACKUPDATASET}"
    fi
else
    logit "Finding remote datasets to back up"
    REMOTEDATASETS="`runwrap listfs`"
    for DATASET in ${REMOTEDATASETS}; do
        backupto "${DATASET}" "${STORE}/${HOST}/${DATASET}"
    done
fi
logit "Exiting successfully."
 |