This is a man page for zogftw 2015-11-21-0a21288.


zogftw — Creates redundant backups on encrypted external ZFS pools


zogftw cmd command-to-execute
zogftw config
zogftw create zpool-name device-to-label
zogftw export [-f] [zpool-to-export]
zogftw help [-v]
zogftw init
zogftw import [zpool-to-import]
zogftw snap[shot] [dataset-to-snapshot-specified-by-name-or-path]
zogftw source
zogftw sync [receiving-zpool]
zogftw zcmd function-without-prefix-to-execute
zogftw zpool subcommand [prefix_args] [postfix_args]


zogftw makes managing backups on multiple external ZFS storage pools on encrypted devices more convenient. Currently most of its subcommands are only expected to work on FreeBSD and FreeBSD-based systems like ElectroBSD.

zogftw is configured through variables that are provided through the environment or the configuration file ZOGFTW_CONFIG_FILE that is sourced as shell script. They are uppercased and prefixed with ZOGFTW_.

zogftw’s behaviour can be further customized by providing hooks, which are shell functions that are called in certain events, or by overwriting any other internal function providing the behaviour expected by the caller isn’t affected.

All of zogftw’s internal functions are lowercased and prefixed with zogftw_, hooks are additionally postfixed with _hook.

zogftw uses sudo for operations that are expected to require root previleges. Running zogftw itself as root is neither necessary nor recommended.


zogftw cmd command-to-execute

Execute the command-to-execute in the context of zogftw. Useful to call zogftw functions that aren’t reachable through their own subcommands. Use zogftw help -v to see which functions are available.

zogftw config

Show the configuration variables and their content. Useful to confirm that the configuration file is interpreted as expected.

zogftw create zpool-name device-to-label

Create a new external ZFS pool that can be managed with zogftw. The device-to-label is labeled zpool-name using glabel, the labeled device is initialized with geli using the optional ZOGFTW_GELI_INIT_FLAGS, afterwards it is attached and used as vdev for the newly created ZFS pool zpool-name.

A geli passphrase and keyfile are read from the locations documented in the zogftw import section. If the files do not exist at the expected locations, no keyfile is used and the passphrase has to be entered manually. If ZOGFTW_CREATE_ENCRYPTED_GELI_PASSPHRASE_FILE is set to 1 and the passphrase file doesn’t exist yet, it will be created.

The ZFS pool is created with the zpool flags specified with ZOGFTW_ZPOOL_CREATE_FLAGS.

The dataset ZOGFTW_DEST_POOL_PREFIX is created to mark the ZFS pool as receiving target for zogftw sync, the dataset’s compression property is set to ZOGFTW_BACKUP_DATASET_COMPRESSION.

Finally the ZFS pool is exported and the geli provider detached.

As the ZFS pool only has a single vdev, there is no redundancy by default. Instead, the recommendation is to use multiple independent devices with the same content on their own ZFS pools, that can be stored in different locations and accessed independently.

zogftw export [-f] [zpool-to-export]

Export either zpool-to-export or all attached ZFS pools that are stored on a encrypted vdev on a label with the same name as the ZFS pool. If the -f flag is specified, pools are exported forcefully.

zogftw help [-v]

Show the available subcommands. If the -v flag is specified, the internal functions and their parameter names are listed as well. They can be accessed through the subcommands cmd or directly from the shell after sourcing zogftw.

zogftw init

Create the directories and configuration files expected by zogftw as shown by zogftw config without second-guessing their locations or the user’s umask settings. Using this subcommand or creating the files manually is optional, but a configuration file has to exist unless ZOGFTW_CONFIG_FILE is set to an empty string through the environment.

zogftw import [zpool-to-import]

Attach the label zpool-to-import with geli and import the ZFS pool on it. If no zpool-to-import is specified, all labeled devices are attached and imported.

If ZOGFTW_GELI_PASSPHRASE_DIR/zpool-to-import.gpg exists, it is decrypted using gpg and the content used as geli passphrase. If gpg-agent is being used, this allows to attach multiple devices without having to enter the passphrase manually for each device.

If ZOGFTW_GELI_KEYFILE_DIR/zpool-to-import.key exists, it is used a geli keyfile.

zogftw nop

This is an alias for zogftw source. Can be used when modifying the subcommand through a hook that implements a custom subcommand to prevent a syntax warning.

zogftw snap[shot] [dataset-to-snapshot-specified-by-name-or-path]

Create a ZFS snapshot on the dataset specified by name or path. A timestamp is used as snapshot name to make sure that ordering the snapshots by name reflects the chronological order as well.

If no dataset is specified, a ZFS snapshot is created on all datasets specified by ZOGFTW_DEFAULT_SNAPSHOT_DATASETS.

zogftw source

Exit after reading the configuration file without executing one of the other subcommands.

Useful to source zogftw in the current shell to directly access its functions later on without having to prefix them with zogftw cmd and rereading the configuration file each time.

Note that not all shells support passing parameters to sourced scripts, though.

zogftw sync [receiving-zpool]

Send the last snapshots on the configured datasets to the receiving-zpool. If no ZFS pool is specified, send to all attached ZFS pools with a layout as created by zogftw create.

mbuffer is used with the flags specified with ZOGFTW_MBUFFER_FLAGS in the pipe between zfs send and zfs receive.

Snapshots are received below receiving-zpool/ZOGFTW_DEST_POOL_PREFIX.

Snapshots on datasets specified with ZOGFTW_REQUIRED_SRC_DATASETS will be sent to the receiving ZFS pool unless they already exist there or the property de.fabiankeil:zogftw:new_datasets is set on receiving-zpool/ZOGFTW_DEST_POOL_PREFIX and does not contain the value yes.

If the dataset doesn’t already exist it is created, otherwise an incremental snapshot is sent. Intermediary snapshots are sent as well, provided the receiving ZFS pool is bigger than ZOGFTW_MAX_SPACE_CONSTRAINED_ZPOOL_SIZE.

Incremental snapshots are received using the zfs flags specified with ZOGFTW_ZFS_INCREMENTAL_RECEIVE_FLAGS, in case of non-incremental snapshots the zfs flags specified with ZOGFTW_ZFS_NON_INCREMENTAL_RECEIVE_FLAGS are used instead. If the system supports it (FreeBSD r289362 or later and pool feature extensible_dataset enabled), adding the -s flag is highly recommended as it allows zogftw to resume failed transfers the next time the sync command is being used.

Datasets specified with ZOGFTW_OPTIONAL_SRC_DATASETS are treated like required datasets, except that they are only sent if the dataset itself already exists on the receiving ZFS pool and contains at least one snapshot.

Datasets specified with ZOGFTW_EXTERNAL_SRC_DATASETS are treated like optional source datasets but do not have to be available on the source at the time the synchronization occurs.

To figure out which snapshots are missing, zogftw by default lets zfs list them sorted in chronological order. If it is known that sorting them by name keeps them in chronological order, ZOGFTW_SORTING_SNAPSHOTS_BY_NAME_KEEPS_CHRONOLOGICAL_ORDER can be set to 1 to significantly speed up the listing on recent FreeBSD-based systems.

In case of syncronization errors, zogftw sync exits right away (without syncing other pools) to increase the chances that the user notices the problem.

zogftw zcmd function-without-prefix-to-execute

Works like zogftw cmd, but the command is prefixed with zogftw_ so the prefix doesn’t need to be typed manually.

zogftw zpool subcommand [prefix_args] [postfix_args]

For each imported ZFS pool that is managed by zogftw, execute zpool with the specified subcommand using the optional arguments before and after the pool name.


Everything but 0 is an error, 0 usually means success.


The documentation is poorly formatted and incomplete. The OPTIONS section should be called SUBCOMMANDS. The system used to build the documentation doesn’t support this without fiddling, though, and as the documentation system will hopefully be replaced in the near future, said fiddling currently doesn’t seem like time well spent.

ZFS permissions aren’t consistently checked when figuring out whether or not a command requires sudo.

zogftw create currently does not put an unencrypted ElectroBSD system on the beginning of the disk that plays a selection of Die Ärzte - 5 6 7 8 Bullenstaat in a loop when booted, to entertain whoever gets hold of it by tricking a judge into signing a search warrant.


gpg2(1), gpg-agent(1), zfs(8), zpool(8)


Fabian Keil <fk@fabiankeil>