-Makefile.deps
Makefile.local
-*.o
*.swp
-dss.lsg.*
+build/*
dss
-dss.1
-dss.1.html
-index.html
+dss.1.gz
+++ /dev/null
-dss is known to compile on Linux, FreeBSD and NetBSD. However, it is
-run-tested only on Linux.
-
-Note that [lopsub](http://people.tuebingen.mpg.de/maan/lopsub)
-is required to compile dss.
-
-Type
-
- make
-
-in the dss source directory to build the dss executable and the man
-page. If lopsub is installed in a non-standard path, you may need to
-run `make` as follows:
-
- make CPPFLAGS=-I$HOME/lopsub/include LDFLAGS=-L$HOME/lopsub/lib
-
-Then type
-
- sudo make install
-
-to install in /usr/local, or
-
- make install PREFIX=/somewhere/else
-
-to install in /somewhere/else.
-
-Also make sure that [rsync](https://rsync.samba.org/) is installed on
-your system. Version 2.6.1 or newer is required.
-
-Examples:
----------
-
-Suppose you'd like to create snapshots of the existing directory
-
- /foo/bar
-
-in the directory
-
- /baz/qux.
-
-Create the config file
-
- ~/.dssrc
-
-that contains the values for the source and the destination directories
-as follows:
-
- echo 'source-dir "/foo/bar"' > ~/.dssrc
- echo 'dest-dir "/baz/qux"' >> ~/.dssrc
-
-Then execute the commands
-
- mkdir /baz/qux
- dss run
-
-In order to print the list of all snapshots created so far, use
-
- dss ls
-
-Yes, it's really that easy.
-
-The second example involves a slightly more sophisticated config file.
-It instructs dss to exclude everything which matches at least one
-pattern of the given exclude file, prevents rsync from crossing file
-system boundaries and increases the number of snapshots.
-
- source-dir "/foo/bar"
- dest-dir "/baz/qux"
- # exclude files matching patterns in /etc/dss.exclude
- rsync-option "--exclude-from=/etc/dss.exclude"
- # don't cross filesystem boundaries
- rsync-option "--one-file-system"
- # maintain 2^6 - 1 = 63 snapshots
- num-intervals "6"
-
-The /etc/dss.exclude file could look like this (see rsync(1) for
-more examples)
-
-
- - /proc
- - /**/tmp/
-
-Note that dss supports many more features and config options such
-as taking snapshots from remote hosts and several hooks that are
-executed on certain events, for example whenever a snapshot was
-created successfully. Try
-
- dss -h
-
-for an overview of all supported command line options or
-
- dss --detailed-help
-
-for the full help text.
# SPDX-License-Identifier: GPL-2.0
+
+PACKAGE := dss
PREFIX ?= /usr/local
INSTALL ?= install
INSTALL_PROGRAM ?= $(INSTALL)
INSTALL_DATA ?= $(INSTALL) -m 644
MKDIR_P := mkdir -p
+B := build
+VERSION := $(shell $(MKDIR_P) $(B) && ./version-gen.sh $(PACKAGE) $(B)/version.c)
+RM := rm -f
+LSG := lopsubgen
+GROFF := groff -m man -t -Thtml -P -l -P -r -P -I -P image
+GZIP := gzip -cfn9
+GIT := git
+M4 := m4 -D "PACKAGE=$(PACKAGE)" defs.m4
+c_source := $(PACKAGE) str file exec sig daemon df tv snap ipc
+c_generated := $(B)/$(PACKAGE).lsg $(B)/version
+objs := $(addsuffix .o, $(c_generated) $(addprefix $(B)/, $(c_source)))
+deps := $(objs:.o=.d)
+all := $(PACKAGE) $(PACKAGE).1.gz
+www := $(B)/index.html $(B)/$(PACKAGE).1.html $(B)/$(PACKAGE)
-VERSION_STRING = 1.0.1
-
-dss_objects := dss.o str.o file.o exec.o sig.o daemon.o df.o tv.o snap.o ipc.o dss.lsg.o
-all: dss dss.1
-man: dss.1
+all: $(all)
+www: $(www)
+man: $(PACKAGE).1.gz
+$(objs): $(B)/$(PACKAGE).lsg.h Makefile
+-include $(deps)
-DSS_CPPFLAGS := -DVERSION_STRING='"$(VERSION_STRING)"'
DSS_CPPFLAGS += -Wunused-macros
+DSS_CPPFLAGS += -I$(B)
DSS_CFLAGS := -Wno-sign-compare -g -Wunused -Wundef
DSS_CFLAGS += -Wredundant-decls
DSS_CFLAGS += -Wbad-function-cast
DSS_CFLAGS += -Wshadow
-Makefile.deps: $(wildcard *.c *.h)
- $(CC) -MM -MG $(DSS_CPPFLAGS) $(CPPFLAGS) $(DSS_CFLAGS) $(CFLAGS) *.c > $@
-
--include Makefile.deps
-
-dss: $(dss_objects)
- $(CC) -o $@ $(dss_objects) $(LDFLAGS) -llopsub
+CC_CMD = $(CC) -c -o $@ $(DSS_CPPFLAGS) $(CPPFLAGS) $(DSS_CFLAGS) $(CFLAGS) \
+ -MMD -MF $(B)/$(*F).d -MT $@ $<
+LD_CMD = $(CC) -o $@ $(objs) $(LDFLAGS) -llopsub
-%.o: %.c Makefile
- $(CC) -c $(DSS_CPPFLAGS) $(CPPFLAGS) $(DSS_CFLAGS) $(CFLAGS) $<
-
-%.lsg.h: %.suite
- lopsubgen --gen-h=$@ < $<
-%.lsg.c: %.suite
- lopsubgen --gen-c=$@ < $<
-%.1: %.suite
- lopsubgen --gen-man=$@ --version-string=$(VERSION_STRING) < $<
-
-%.1.html: %.1
- groff -m man -Thtml -P -l -P -r $< | sed -e '1,/^<body>/d; /^<\/body>/,$$d' > $@
+.ONESHELL:
+.SHELLFLAGS := -ec
+ifeq ("$(origin V)", "command line")
+ SAY =
+else
+ SAY = @printf '%s\n' '$(strip $(1))'
+endif
+$(B)/version.c:
+ $(call SAY, VG $@)
+ ./version-gen.sh $(PACKAGE) version.c > /dev/null
+$(PACKAGE): $(objs)
+ $(call SAY, LD $@)
+ $(LD_CMD)
+$(B)/$(PACKAGE): $(objs)
+ $(call SAY, LD $@)
+ $(LD_CMD) -static
+ strip $@
+$(B)/%.o: $(B)/%.c
+ $(call SAY, CC $<)
+ $(CC_CMD)
+$(B)/%.o: %.c
+ $(call SAY, CC $<)
+ $(CC_CMD)
+.PHONY: all www clean distclean maintainer-clean install README
+.PRECIOUS: $(B)/%.lsg.c $(B)/%.lsg.h $(B)/%.suite $(B)/%.1
+$(B)/$(PACKAGE).suite: $(PACKAGE).suite.m4 defs.m4 Makefile
+ $(call SAY, M4 $<)
+ $(M4) $< > $@
+$(B)/%.lsg.h: $(B)/%.suite
+ $(call SAY, LSGH $<)
+ $(LSG) --gen-h=$@ < $<
+$(B)/%.lsg.c: $(B)/%.suite
+ $(call SAY, LSGC $<)
+ $(LSG) --gen-c=$@ < $<
+$(B)/%.1: $(B)/%.suite
+ $(call SAY, LSGM $<)
+ $(LSG) --gen-man=$@ --version-string=$(VERSION) < $<
+%.1.gz: $(B)/%.1
+ $(call SAY, GZIP $<)
+ $(GZIP) < $< > $@
+$(B)/%.1.html: $(B)/%.1
+ $(call SAY, GROFF $<)
+ cd $(B)
+ $(GROFF) ../$< > ../$@
+$(B)/index.html: index.html.m4 Makefile defs.m4 dss.svg
+ $(call SAY, M4 $@)
+ $(M4) $< > $@
clean:
- rm -f *.o dss dss.1 dss.1.html Makefile.deps *~ index.html dss.lsg.h dss.lsg.c
+ $(call SAY, CLEAN)
+ $(RM) $(B)/*.o $(B)/*.d $(all) $(www)
+distclean: clean
+ $(call SAY, DISTCLEAN)
+ $(RM) -r $(B)
+maintainer-clean: distclean
+ $(call SAY, MAINTANER-CLEAN)
+ $(GIT) clean -dfqxe Makefile.local
ifneq ($(findstring strip, $(MAKECMDGOALS)),)
strip_option := -s
mandir := $(DESTDIR)$(PREFIX)/share/man/man1
install install-strip: all
$(MKDIR_P) $(bindir) $(mandir)
- $(INSTALL_PROGRAM) $(strip_option) dss $(bindir)
- $(INSTALL_DATA) dss.1 $(mandir)
+ $(INSTALL_PROGRAM) $(strip_option) $(PACKAGE) $(bindir)
+ $(INSTALL_DATA) $(PACKAGE).1.gz $(mandir)
-index.html: dss.1.html index.html.in INSTALL README NEWS
- sed -e '/@README@/,$$d' index.html.in > $@
- markdown README >> $@
- sed -e '1,/@README@/d' -e '/@NEWS@/,$$d' index.html.in >> $@
- markdown NEWS >> $@
- sed -e '1,/@NEWS@/d' -e '/@INSTALL@/,$$d' index.html.in >> $@
- markdown INSTALL >> $@
- sed -e '1,/@INSTALL@/d' -e '/@MAN_PAGE@/,$$d' index.html.in >> $@
- cat dss.1.html >> $@
- sed -e '1,/@MAN_PAGE@/d' index.html.in >> $@
+README:
+ @$(M4) README.m4
-include Makefile.local
+++ /dev/null
-dss creates hardlink-based snapshots of a given directory on a remote
-or local host using rsync's link-dest feature.
-
-dss is admin friendly: It is easy to configure and needs little
-attention once configured to run in daemon mode. It keeps track of
-the available disk space and removes snapshots if disk space becomes
-sparse or snapshots become older than the specified time. Also, due
-to the hardlink-based approach, there is only one type of backup.
-Hence no full, incremental or differential backups need to be
-configured, and there is no database to maintain.
-
-dss is also user-friendly because users can browse the snapshot
-directories without admin intervention and see the contents of the file
-system at the various times a snapshot was taken. Each snapshot looks
-like a full backup, so users can easily restore accidentally removed
-files by using their favorite file browser to simply copy files from
-the snapshot directory back to the live system.
-
-dss gives your data an additional level of security besides the usual
-tape-based backups: If the file server goes down and all data is lost
-you can simply use the most recent snapshot as an immediate replacement
--- no need for a restore from tape that takes days to complete.
-
-Snapshot pruning takes place in a dyadic fashion: Many recent snapshots
-are available, but the number of snapshots per time interval decreases
-exponentially. For example, one can configure dss so that it keeps
-16 snapshots not older than one week, 8 snapshots between one and
-two weeks old, 4 snapshots between two and three weeks old, and so on.
--- /dev/null
+dnl Run "make README" to see this with variables expanded.
+PACKAGE() - SLOGAN()
+
+DESCRIPTION1()
+
+DESCRIPTION2()
+
+DESCRIPTION3()
+
+Resources
+~~~~~~~~~
+project web page: PACKAGE_HOMEPAGE()
+git clone CLONE_URL()
+gitweb: GITWEB_URL()
+author home page: HOME_URL()
+report bugs to: AUTHOR() <EMAIL()>
--- /dev/null
+divert(-1)
+changequote(`«', `»')
+
+define(«SLOGAN», «the dyadic snapshot scheduler»)
+define(«AUTHOR», «Andre Noll»)
+define(«EMAIL», «maan@tuebingen.mpg.de»)
+define(«URL», «https://people.tuebingen.mpg.de/maan/PACKAGE()/»)
+define(«CLONE_URL», «https://git.tuebingen.mpg.de/PACKAGE()»)
+define(«GITWEB_URL», «https://git.tuebingen.mpg.de/PACKAGE().git»)
+define(«PACKAGE_HOMEPAGE», «https://people.tuebingen.mpg.de/maan/PACKAGE()/»)
+define(«HOME_URL», «https://people.tuebingen.mpg.de/maan/»)
+define(«LICENSE», «GPL-2.0»)
+define(«LICENSE_URL», «https://www.gnu.org/licenses»)
+
+define(«DESCRIPTION1», «dnl
+PACKAGE() maintains hardlink-based snapshots of a given directory on
+a remote or local host using rsync's link-dest feature. The snapshots
+are organized so that any snapshot can directly be deployed as an
+(emergency) replacement for the primary system.»)
+
+define(«DESCRIPTION2», «dnl
+PACKAGE() is admin friendly: It is easy to configure and needs
+little attention after the initial setup. In particular, no full,
+incremental or differential backups need to be configured, and there is
+no database to maintain. PACKAGE() is also user-friendly: Assuming the
+snapshot server allows read-only user access over the network, users
+can restore accidentically removed files without admin intervention,
+using their favorite file browser to copy files from the snapshot
+directory back to the primary system.»)
+
+define(«DESCRIPTION3», «dnl
+PACKAGE() keeps track of the age and the state of existing snapshots and
+triggers snapshot creation and removal according to the configuration
+settings. It tries to maintain a scheme where many recent snapshots
+and few old snapshots exist, for example 16 snapshots newer than a
+week, 8 snapshots between one and two weeks old, 4 snapshots between
+two and three weeks old, and so on.»)
+
+divert(0)
return install_sighandler(SIGCHLD);
}
+const char *dss_version(void);
static void handle_version_and_help(void)
{
char *txt;
+ if (OPT_GIVEN(DSS, VERSION)) {
+ printf("%s\n", dss_version());
+ exit(EXIT_SUCCESS);
+ }
if (OPT_GIVEN(DSS, DETAILED_HELP))
txt = lls_long_help(CMD_PTR(DSS));
else if (OPT_GIVEN(DSS, HELP))
txt = lls_short_help(CMD_PTR(DSS));
- else if (OPT_GIVEN(DSS, VERSION))
- txt = make_message("%s\n", VERSION_STRING);
else
return;
printf("%s", txt);
+ printf("\nRun dss help for help on subcommands.\n");
free(txt);
exit(EXIT_SUCCESS);
}
const char *purpose = lls_purpose(cmd);
printf("%-11s%s\n", name, purpose);
}
- exit(EXIT_SUCCESS);
+ printf("\nRun dss help <subcmd> for help on <subcmd>.\n");
+}
+
+static int com_help(void)
+{
+ int ret;
+ char *errctx, *help;
+ const char *arg;
+ const struct lls_command *cmd;
+
+ ret = lls_check_arg_count(sublpr, 0, 1, &errctx);
+ if (ret < 0)
+ return lopsub_error(ret, &errctx);
+ if (lls_num_inputs(sublpr) == 0) {
+ show_subcommand_summary();
+ return 0;
+ }
+ arg = lls_input(0, sublpr);
+ ret = lls_lookup_subcmd(arg, dss_suite, &errctx);
+ if (ret < 0)
+ return lopsub_error(ret, &errctx);
+ cmd = lls_cmd(ret, dss_suite);
+ if (OPT_GIVEN(HELP, LONG))
+ help = lls_long_help(cmd);
+ else
+ help = lls_short_help(cmd);
+ printf("%s", help);
+ free(help);
+ if (!OPT_GIVEN(HELP, LONG))
+ printf("\nRun dss -- help -l %s for long help.\n", arg);
+ return 0;
}
+EXPORT_CMD_HANDLER(help);
int main(int argc, char **argv)
{
goto out;
handle_version_and_help();
num_inputs = lls_num_inputs(lpr);
- if (num_inputs == 0)
+ if (num_inputs == 0) {
show_subcommand_summary();
+ ret = 0;
+ goto out;
+ }
ret = lls_lookup_subcmd(argv[argc - num_inputs], dss_suite, &errctx);
if (ret < 0) {
ret = lopsub_error(ret, &errctx);
+++ /dev/null
-BODY,TD {
- background-color: #ffffff;
- color: #333333;
-}
-
-HR {
- background-color: #ffff00;
-}
-
-A {
- color: #4444ff;
-}
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0
-
-[suite dss]
-caption = Subcommands
-
-[supercommand dss]
- [description]
- dss creates hardlink-based snapshots of a given directory on a remote
- or local host using rsync's link-dest feature.
- [/description]
- purpose = the dyadic snapshot scheduler
- synopsis = [global-options...] [--] [<subcommand> [subcommand-options...]]
-
- [option general-options-section]
- summary = General options
- flag ignored
- [option help]
- summary = print help and exit
- short_opt = h
- [option detailed-help]
- summary = print help, including all details, and exit
- [option version]
- summary = print version and exit
- short_opt = V
- [option config-file]
- short_opt = c
- summary = use alternative config file (default: ~/.dssrc)
- typestr = path
- arg_info = required_arg
- arg_type = string
- [help]
- Options may be given at the command line or in the configuration
- file. As usual, if an option is given both at the command line and
- in the configuration file, the command line option takes precedence.
-
- However, there is one exception to this rule: The run subcommand
- re-reads the configuration file when it receives the HUP signal. In
- this case the options in the config file override any options that
- were previously given at the command line. This allows changing the
- configuration of a running dss process by sending SIGHUP.
- [/help]
- [option loglevel]
- short_opt = l
- summary = set loglevel (0-6)
- typestr = level
- arg_info = required_arg
- arg_type = uint32
- default_val = 4
- [help]
- Lower values mean more verbose logging.
- [/help]
- [option dry-run]
- short_opt = n
- summary = only print what would be done
- [help]
- This flag does not make sense for all subcommands. The run subcommand
- refuses to start if this option was given while the ls subcommand
- silently ignores the flag.
- [/help]
- [option source-dir]
- summary = the remote directory to snapshot
- typestr = dirname
- arg_info = required_arg
- arg_type = string
- flag multiple
- [help]
- The directory on the remote host from which snapshots are taken.
- Of course, the user specified as --remote-user must have read access
- to this directory.
-
- This option is mandatory for the create and run subcommands: It may
- be given multiple times to specify more than one source directory.
- However, all source directories must reside on the same server.
- [/help]
- [option dest-dir]
- summary = where snapshots are stored
- typestr = dirname
- arg_info = required_arg
- arg_type = string
- [help]
- The destination directory on the local host where snapshots will be
- written. This must be writable by the user who runs dss.
-
- This option is mandatory for all subcommands except kill.
- Unlike --source-dir, this option may only be given once.
- [/help]
- [option mountpoint]
- summary = abort if destination directory is not a mountpoint
- [help]
- This option checks whether a file system is mounted on the directory
- specified as the argument to --dest-dir. Operation proceeds only
- if this is the case. Otherwise dss exits unsuccessfully without
- performing any action. Use this option to prevent snapshot creation
- if the snapshot file system is not mounted.
-
- This option is silently ignored for subcommands which do not depend
- on the destination directory.
- [/help]
- [option Rsync-options]
- summary = Controlling how rsync is run
- flag ignored
- [help]
- These options are only relevant to the run and the create subcommands.
- [/help]
- [option remote-host]
- short_opt = H
- summary = host to take snapshots from
- typestr = hostname
- arg_info = required_arg
- arg_type = string
- default_val = localhost
- [help]
- If this option is given and its value differs from the local
- host, then rsync uses ssh. Make sure there is no password
- needed for the ssh connection. To achieve that, use public key
- authentication for ssh and, if needed, set the remote user name
- by using the --remote-user option.
- [/help]
- [option remote-user]
- short_opt = U
- summary = Remote user name (default: current user)
- arg_info = required_arg
- typestr = username
- arg_type = string
- [help]
- Set this if the user that runs dss is different from the user on the
- remote host.
- [/help]
- [option checksum]
- summary = run rsync with --checksum occasionally
- typestr = permille
- arg_info = required_arg
- arg_type = uint32
- default_val = 0
- [help]
- If a file on the backup becomes corrupt in a way that file size
- and modification time still match the original file, rsync will not
- consider the file for transfer ("quick check"). Hence the corruption
- stays on the backup until the file is modified on the source.
- The --checksum option of rsync disables the quick check and compares
- the contents of each file, fixing such corruptions. Since computing
- the checksums adds a significant slowdown due to a lot of disk I/O,
- the option is not enabled by default.
-
- The argument to the --checksum option of dss is a number between 0
- and 1000, inclusively, which determines the probability of adding
- --checksum to the rsync options each time a snapshot is created. The
- default value zero means to never add the option. The value 100 will
- create every tenth snapshot (on average) using checksums, and the
- value 1000 will always pass --checksum to rsync.
- [/help]
- [option rsync-option]
- short_opt = O
- summary = further rsync options
- typestr = option
- arg_info = required_arg
- arg_type = string
- flag multiple
- [help]
- This option may be given multiple times. The given argument is
- passed verbatim to the rsync command. Note that in order to use
- rsync options that require an argument, you have to specify the
- option and its argument as separate --rsync-options, like this:
-
- --rsync-option --exclude --rsync-option /proc
- [/help]
- [option intervals]
- summary = Fine tuning the number of snapshots per time unit
- flag ignored
- [help]
- Snapshot aging is implemented in terms of intervals. There are two
- command line options related to intervals: the duration u of a unit
- interval and the number of unit intervals, denoted n below.
-
- dss removes snapshots older than n times u and tries to keep 2^(n -
- k - 1) snapshots in interval k, where the interval number k counts
- from zero to n - 1, with zero being the most recent unit interval.
-
- Hence the oldest snapshot will at most be u * n days old (4 days *
- 5 intervals = 20 days, if default values are used). Moreover, there
- are at most 2^n - 1 snapshots in total (2^5 - 1 = 31 by default). Note
- that for this to work out your system must be fast enough to create at
- least 2^(n - 1) snapshots per unit interval (16 snapshots in 4 days =
- one snapshot in 6 hours), because this is the number of snapshots in
- interval zero.
- [/help]
- [option unit-interval]
- short_opt = u
- summary = the duration of a unit interval
- typestr = days
- arg_info = required_arg
- arg_type = uint32
- default_val = 4
- [help]
- Increasing this number instructs dss to create fewer snapshots per
- time unit while the number of snapshots to keep stays the same.
- [/help]
- [option num-intervals]
- short_opt = n
- summary = the number of unit intervals
- typestr = num
- arg_info = required_arg
- arg_type = uint32
- default_val = 5
- [help]
- Increasing this number by one doubles the total number of
- snapshots.
- [/help]
- [option hooks]
- summary = Commands to be run on certain events
- flag ignored
- [help]
- All hooks default to "true". That is, the true(1) utility (which
- always returns with exit code zero) is executed if the hook command
- is not specified.
- [/help]
- [option pre-create-hook]
- short_opt = r
- summary = executed before a snapshot is created
- typestr = command
- arg_info = required_arg
- arg_type = string
- default_val = true
- [help]
- This command is executed before dss runs rsync to create a new
- snapshot. If the command returns with a non-zero exit status, no
- snapshot will be created and the operation is retried later.
-
- For example, the command could execute a script that checks whether
- all snapshot-related file systems are mounted.
-
- Another possible application of the pre-create hook is to return
- non-zero during office hours in order to not slow down the file
- systems by taking snapshots.
- [/help]
- [option post-create-hook]
- summary = executed after a snapshot has been created
- typestr = command
- arg_info = required_arg
- arg_type = string
- default_val = true
- [help]
- This is only executed if a snapshot has successfully been created. The
- full path of the newly created snapshot is passed to the hook as the
- first argument. The exit code of this hook is ignored.
-
- For instance this hook could count the number of files per user
- and/or compute disk usage patterns to be stored in a database for
- further analysis.
- [/help]
- [option pre-remove-hook]
- summary = executed before a snapshot is removed
- typestr = command
- arg_info = required_arg
- arg_type = string
- default_val = true
- [help]
- The full path to the snapshot which is about to be removed is passed
- to the command as the first argument. If the command returns with
- a non-zero exit status, the snapshot is not going to be removed and
- the operation is retried later.
-
- For example, one could execute a script that checks whether the
- snapshot to be deleted is currently used by another process, e.g. by
- a tape-based backup system that runs concurrently to dss.
-
- Another possible application of this is to record disk-usage
- patterns before and after snapshot removal.
- [/help]
- [option post-remove-hook]
- summary = executed after snapshot removal
- typestr = command
- arg_info = required_arg
- arg_type = string
- default_val = true
- [help]
- As for the pre-remove hook, the full path of the removed snapshot is
- passed to the hook as the first argument. The exit code of this hook
- is ignored.
- [/help]
- [option exit-hook]
- summary = executed before the run command exits
- typestr = command
- arg_info = required_arg
- arg_type = string
- default_val = true
- [help]
- This hook is only relevant to the run subcommand. It is executed just
- before dss terminates. The reason for termination is passed as the
- first argument.
-
- One possible application for this hook is to send email to the system
- administrator to let her know that no more snapshots are going to
- be created.
- [/help]
-
- [option disk-space-monitoring]
- summary = Disk space monitoring
- flag ignored
- [help]
- The options of this section control the aggressiveness of snapshot
- removal. That is, they define under which circumstances existing
- snapshots are removed. These options are only relevant to the run
- and the prune subcommands.
- [/help]
- [option min-free-mb]
- short_opt = m
- summary = minimal amount of free disk space
- arg_info = required_arg
- arg_type = uint32
- typestr = megabytes
- default_val = 100
- [help]
- If disk space on the file system containing the destination
- directory gets low, the run subcommand suspends the currently
- running rsync process and starts to remove snapshots in order to
- free disk space. This option specifies the minimal amount of free
- disk space. If less than the given number of megabytes is available,
- snapshots are being deleted. See also the --min_free_percent and the
- min-free-percent-inodes options below.
-
- A value of zero deactivates this check.
- [/help]
- [option min-free-percent]
- short_opt = p
- summary = minimal percentage of free disk space
- arg_info = required_arg
- arg_type = uint32
- typestr = percent
- default_val = 2
- [help]
- This is like --min-free-mb but the amount of free disk space
- is specified as a percentage. It is not recommended to set both
- --min-free-mb and --min-free-percent to zero as this will cause your
- file system to fill up quickly.
- [/help]
- [option min-free-percent-inodes]
- short_opt = i
- summary = minimal percent of free inodes
- arg_info = required_arg
- arg_type = uint32
- typestr = percent
- default_val = 0
- [help]
- The minimum amount of free inodes on the file system containing the
- destination dir. If the percentage of free inodes drops below the
- given value, snapshot removal kicks in like in case of low disk space.
-
- The number of free inodes is determined from the f_ffree field of
- the statvfs structure. However, some file systems set this field to
- zero, indicating that the number of inodes is basically unlimited.
- Moreover it is not possible to reliably detect whether this is the
- case. Therefore this feature is disabled by default. It's safe to
- enable it for ext2/ext3/ext4 file systems on linux though.
-
- A value of zero (the default) deactivates this check.
- [/help]
- [option keep-redundant]
- short_opt = k
- summary = prune by disk space only
- [help]
- By default, redundant and outdated snapshots are removed automatically
- to keep the number of snapshots in harmony with the configured
- policy. If this flag is given, dss removes such snapshots only if
- disk space or number of free inodes becomes low.
- [/help]
- [option min-complete]
- summary = minimal number of complete snapshots to keep
- arg_info = optional_arg
- arg_type = uint32
- typestr = num
- default_val = 1
- [help]
- This option is only relevant if snapshots must be deleted because
- disk space gets low.
-
- dss refuses to remove old snapshots if there are fewer complete
- snapshots left than the given number. The default value of one
- guarantees that at least one complete snapshot is available at
- all times.
-
- If only <num> complete snapshots are left, and there is not enough
- disk space available for another snapshot, the program terminates
- with a "No space left on device" error.
- [/help]
-
-[introduction]
- dss supports the subcommands described below. If no subcommand is
- given, the list of available subcommands is shown and the program
- terminates successfully without performing any further action.
-[/introduction]
-
-[subcommand run]
- purpose = start creating and pruning snapshots
- [description]
- This is the main mode of operation. Snapshots are created in an endless
- loop as needed and pruned automatically. The loop only terminates on
- fatal errors or if a terminating signal was received. See also the
- --exit-hook option.
- [/description]
- [option daemon]
- short_opt = d
- summary = run as background daemon
- [help]
- If this option is given, the dss command detaches from the console
- and continues to run in the background. It is not possible to let
- a daemonized process re-attach to the console by editing the config
- file and sending SIGHUP. However, log output may be redirected to a
- different file in this way.
-
- See --logfile.
- [/help]
- [option logfile]
- short_opt = l
- summary = where to write log output
- arg_info = required_arg
- arg_type = string
- typestr = path
- default_val = /dev/null
- [help]
- This option is only honored if --daemon is given, in which case
- log messages go to the given file. Otherwise the option is silently
- ignored and log output is written to stderr.
- [/help]
- [option max-rsync-errors]
- summary = terminate after this many rsync failures
- typestr = count
- arg_info = required_arg
- arg_type = uint32
- default_val = 10
- [help]
- If the rsync process exits with a fatal error, dss restarts the command
- in the hope that the problem is transient and subsequent rsync runs
- succeed. After the given number of consecutive rsync error exits,
- however, dss gives up, executes the exit hook and terminates. Set
- this to zero if dss should exit immediately on the first rsync error.
-
- The only non-fatal error is when rsync exits with code 24. This
- indicates a partial transfer due to vanished source files and happens
- frequently when snapshotting a directory which is concurrently being
- modified.
- [/help]
-[subcommand create]
- purpose = execute rsync once to create a new snapshot
- [description]
- This command does not check the amount free disk space. The pre-create
- and post-create hooks are honored, however.
-
- Specify --dry-run to see the rsync command which is executed to create
- snapshots.
- [/description]
-[subcommand prune]
- purpose = remove snapshots
- [description]
- A snapshot is said to be (a) outdated if its interval number is greater
- or equal than the specified number of unit intervals, (b) redundant if
- the interval it belongs to contains more than the configured number of
- snapshots, and (c) orphaned if it is incomplete and not being created
- or deleted. All other snapshots are called regular.
-
- Unless --dry-run is given, which just prints the snapshot that would be
- removed, this subcommand gets rid of non-regular snapshots. At most
- one snapshot is removed per invocation. If no such snapshot exists
- and disk space is low, the subcommand also removes regular snapshots,
- always picking the oldest one.
-
- The subcommand fails if there is another dss "run" process.
- [/description]
- [option disk-space]
- summary = act as if free disk space was high/low
- arg_info = required_arg
- arg_type = string
- typestr = mode
- values = {
- FDS_CHECK = "check",
- FDS_HIGH = "high",
- FDS_LOW = "low"
- }
- default_val = check
- [help]
- By default, free disk space is checked and even regular snapshots
- become candidates for removal if disk space is low. This option
- overrides the result of the check.
- [/help]
-[subcommand ls]
- purpose = print the list of all snapshots
- [description]
- The list contains all existing snapshots, no matter of their state.
- Incomplete snapshots and snapshots being deleted will also be listed.
- [/description]
-[subcommand kill]
- purpose = send a signal to a running dss process
- [description]
- This sends a signal to the dss process that corresponds to the given
- config file. If --dry-run is given, the PID of the dss process is
- written to stdout, but no signal is sent.
- [/description]
- [option signal]
- short_opt = s
- summary = send the given signal rather than SIGTERM
- typestr = signal
- arg_info = required_arg
- arg_type = string
- default_val = SIGTERM
- [help]
- Like for kill(1), alternate signals may be specified in three ways: as
- a signal number (e.g., 9), the signal name (e.g., KILL), or the signal
- name prefixed with "SIG" (e.g., SIGKILL). In the latter two forms,
- the signal name and the prefix are case insensitive, so "sigkill"
- works as well.
-
- Sending SIGHUP causes the running dss process to reload its config file.
- [/help]
- [option wait]
- short_opt = w
- summary = wait until the signalled process has terminated
- [help]
- This option is handy for system shutdown scripts which would like
- to terminate the dss daemon process.
-
- Without --wait the dss process which executes the kill subcommand
- exits right after the kill(2) system call returns. At this point the
- signalled process might still be alive (even if SIGKILL was sent).
- If --wait is given, the process waits until the signalled process
- has terminated or the timeout expires.
-
- If --wait is not given, the kill subcommand exits successfully if
- and only if the signal was sent (i.e., if there exists another dss
- process to receive the signal). With --wait it exits successfully
- if, additionally, the signalled process has terminated before the
- timeout expires.
-
- It makes only sense to use the option for signals which terminate dss.
- [/help]
-[subcommand configtest]
- purpose = run a configuration file syntax test
- [description]
- This command checks the command line options and the configuration
- file for syntactic correctness. It either reports "Syntax Ok" and
- exits successfully or prints information about the first syntax error
- detected and terminates with exit code 1.
- [/description]
-
-[section copyright]
- Written by Andre Noll
- .br
- Copyright (C) 2008 - present Andre Noll
- .br
- License: GNU GPL version 2
- .br
- This is free software: you are free to change and redistribute it.
- .br
- There is NO WARRANTY, to the extent permitted by law.
- .br
- Report bugs to
- .MT <maan@tuebingen.mpg.de>
- Andre Noll
- .ME
-[/section]
-
-[section see also]
- .BR ssh (1) ,
- .BR rsync (1)
-[/section]
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0
+
+[suite dss]
+caption = Subcommands
+
+[supercommand dss]
+ [description]
+ DESCRIPTION1()
+
+ DESCRIPTION2()
+
+ DESCRIPTION3()
+ [/description]
+ purpose = SLOGAN()
+ synopsis = [global-options...] [--] [<subcommand> [subcommand-options...]]
+
+ [option general-options-section]
+ summary = General options
+ flag ignored
+ [option help]
+ summary = print help and exit
+ short_opt = h
+ [option detailed-help]
+ summary = print help, including all details, and exit
+ [option version]
+ summary = print version and exit
+ short_opt = V
+ [option config-file]
+ short_opt = c
+ summary = use alternative config file (default: ~/.dssrc)
+ typestr = path
+ arg_info = required_arg
+ arg_type = string
+ [help]
+ Options may be given at the command line or in the configuration
+ file. As usual, if an option is given both at the command line and
+ in the configuration file, the command line option takes precedence.
+
+ However, there is one exception to this rule: The run subcommand
+ re-reads the configuration file when it receives the HUP signal. In
+ this case the options in the config file override any options that
+ were previously given at the command line. This allows changing the
+ configuration of a running dss process by sending SIGHUP.
+ [/help]
+ [option loglevel]
+ short_opt = l
+ summary = set loglevel (0-6)
+ typestr = level
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 4
+ [help]
+ Lower values mean more verbose logging.
+ [/help]
+ [option dry-run]
+ short_opt = n
+ summary = only print what would be done
+ [help]
+ This flag does not make sense for all subcommands. The run subcommand
+ refuses to start if this option was given while the ls subcommand
+ silently ignores the flag.
+ [/help]
+ [option source-dir]
+ summary = the remote directory to snapshot
+ typestr = dirname
+ arg_info = required_arg
+ arg_type = string
+ flag multiple
+ [help]
+ The directory on the remote host from which snapshots are taken.
+ Of course, the user specified as --remote-user must have read access
+ to this directory.
+
+ This option is mandatory for the create and run subcommands: It may
+ be given multiple times to specify more than one source directory.
+ However, all source directories must reside on the same server.
+ [/help]
+ [option dest-dir]
+ summary = where snapshots are stored
+ typestr = dirname
+ arg_info = required_arg
+ arg_type = string
+ [help]
+ The destination directory on the local host where snapshots will be
+ written. This must be writable by the user who runs dss.
+
+ This option is mandatory for all subcommands except kill.
+ Unlike --source-dir, this option may only be given once.
+ [/help]
+ [option mountpoint]
+ summary = abort if destination directory is not a mountpoint
+ [help]
+ This option checks whether a file system is mounted on the directory
+ specified as the argument to --dest-dir. Operation proceeds only
+ if this is the case. Otherwise dss exits unsuccessfully without
+ performing any action. Use this option to prevent snapshot creation
+ if the snapshot file system is not mounted.
+
+ This option is silently ignored for subcommands which do not depend
+ on the destination directory.
+ [/help]
+ [option Rsync-options]
+ summary = Controlling how rsync is run
+ flag ignored
+ [help]
+ These options are only relevant to the run and the create subcommands.
+ [/help]
+ [option remote-host]
+ short_opt = H
+ summary = host to take snapshots from
+ typestr = hostname
+ arg_info = required_arg
+ arg_type = string
+ default_val = localhost
+ [help]
+ If this option is given and its value differs from the local
+ host, then rsync uses ssh. Make sure there is no password
+ needed for the ssh connection. To achieve that, use public key
+ authentication for ssh and, if needed, set the remote user name
+ by using the --remote-user option.
+ [/help]
+ [option remote-user]
+ short_opt = U
+ summary = Remote user name (default: current user)
+ arg_info = required_arg
+ typestr = username
+ arg_type = string
+ [help]
+ Set this if the user that runs dss is different from the user on the
+ remote host.
+ [/help]
+ [option checksum]
+ summary = run rsync with --checksum occasionally
+ typestr = permille
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 0
+ [help]
+ If a file on the backup becomes corrupt in a way that file size
+ and modification time still match the original file, rsync will not
+ consider the file for transfer ("quick check"). Hence the corruption
+ stays on the backup until the file is modified on the source.
+ The --checksum option of rsync disables the quick check and compares
+ the contents of each file, fixing such corruptions. Since computing
+ the checksums adds a significant slowdown due to a lot of disk I/O,
+ the option is not enabled by default.
+
+ The argument to the --checksum option of dss is a number between 0
+ and 1000, inclusively, which determines the probability of adding
+ --checksum to the rsync options each time a snapshot is created. The
+ default value zero means to never add the option. The value 100 will
+ create every tenth snapshot (on average) using checksums, and the
+ value 1000 will always pass --checksum to rsync.
+ [/help]
+ [option rsync-option]
+ short_opt = O
+ summary = further rsync options
+ typestr = option
+ arg_info = required_arg
+ arg_type = string
+ flag multiple
+ [help]
+ This option may be given multiple times. The given argument is
+ passed verbatim to the rsync command. Note that in order to use
+ rsync options that require an argument, you have to specify the
+ option and its argument as separate --rsync-options, like this:
+
+ --rsync-option --exclude --rsync-option /proc
+ [/help]
+ [option intervals]
+ summary = Fine tuning the number of snapshots per time unit
+ flag ignored
+ [option unit-interval]
+ short_opt = u
+ summary = the duration of a unit interval
+ typestr = days
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 4
+ [help]
+ Increasing this number instructs dss to create fewer snapshots per
+ time unit while the number of snapshots to keep stays the same.
+ [/help]
+ [option num-intervals]
+ short_opt = n
+ summary = the number of unit intervals
+ typestr = num
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 5
+ [help]
+ Increasing this number by one doubles the total number of
+ snapshots.
+ [/help]
+ [option hooks]
+ summary = Commands to be run on certain events
+ flag ignored
+ [help]
+ All hooks default to "true". That is, the true(1) utility (which
+ always returns with exit code zero) is executed if the hook command
+ is not specified.
+ [/help]
+ [option pre-create-hook]
+ short_opt = r
+ summary = executed before a snapshot is created
+ typestr = command
+ arg_info = required_arg
+ arg_type = string
+ default_val = true
+ [help]
+ This command is executed before dss runs rsync to create a new
+ snapshot. If the command returns with a non-zero exit status, no
+ snapshot will be created and the operation is retried later.
+
+ For example, the command could execute a script that checks whether
+ all snapshot-related file systems are mounted.
+
+ Another possible application of the pre-create hook is to return
+ non-zero during office hours in order to not slow down the file
+ systems by taking snapshots.
+ [/help]
+ [option post-create-hook]
+ summary = executed after a snapshot has been created
+ typestr = command
+ arg_info = required_arg
+ arg_type = string
+ default_val = true
+ [help]
+ This is only executed if a snapshot has successfully been created. The
+ full path of the newly created snapshot is passed to the hook as the
+ first argument. The exit code of this hook is ignored.
+
+ For instance this hook could count the number of files per user
+ and/or compute disk usage patterns to be stored in a database for
+ further analysis.
+ [/help]
+ [option pre-remove-hook]
+ summary = executed before a snapshot is removed
+ typestr = command
+ arg_info = required_arg
+ arg_type = string
+ default_val = true
+ [help]
+ The full path to the snapshot which is about to be removed is passed
+ to the command as the first argument. If the command returns with
+ a non-zero exit status, the snapshot is not going to be removed and
+ the operation is retried later.
+
+ For example, one could execute a script that checks whether the
+ snapshot to be deleted is currently used by another process, e.g. by
+ a tape-based backup system that runs concurrently to dss.
+
+ Another possible application of this is to record disk-usage
+ patterns before and after snapshot removal.
+ [/help]
+ [option post-remove-hook]
+ summary = executed after snapshot removal
+ typestr = command
+ arg_info = required_arg
+ arg_type = string
+ default_val = true
+ [help]
+ As for the pre-remove hook, the full path of the removed snapshot is
+ passed to the hook as the first argument. The exit code of this hook
+ is ignored.
+ [/help]
+ [option exit-hook]
+ summary = executed before the run command exits
+ typestr = command
+ arg_info = required_arg
+ arg_type = string
+ default_val = true
+ [help]
+ This hook is only relevant to the run subcommand. It is executed just
+ before dss terminates. The reason for termination is passed as the
+ first argument.
+
+ One possible application for this hook is to send email to the system
+ administrator to let her know that no more snapshots are going to
+ be created.
+ [/help]
+
+ [option disk-space-monitoring]
+ summary = Disk space monitoring
+ flag ignored
+ [help]
+ The options of this section control the aggressiveness of snapshot
+ removal. That is, they define under which circumstances existing
+ snapshots are removed. These options are only relevant to the run
+ and the prune subcommands.
+ [/help]
+ [option min-free-mb]
+ short_opt = m
+ summary = minimal amount of free disk space
+ arg_info = required_arg
+ arg_type = uint32
+ typestr = megabytes
+ default_val = 100
+ [help]
+ If disk space on the file system containing the destination
+ directory gets low, the run subcommand suspends the currently
+ running rsync process and starts to remove snapshots in order to
+ free disk space. This option specifies the minimal amount of free
+ disk space. If less than the given number of megabytes is available,
+ snapshots are being deleted. See also the --min_free_percent and the
+ min-free-percent-inodes options below.
+
+ A value of zero deactivates this check.
+ [/help]
+ [option min-free-percent]
+ short_opt = p
+ summary = minimal percentage of free disk space
+ arg_info = required_arg
+ arg_type = uint32
+ typestr = percent
+ default_val = 2
+ [help]
+ This is like --min-free-mb but the amount of free disk space
+ is specified as a percentage. It is not recommended to set both
+ --min-free-mb and --min-free-percent to zero as this will cause your
+ file system to fill up quickly.
+ [/help]
+ [option min-free-percent-inodes]
+ short_opt = i
+ summary = minimal percent of free inodes
+ arg_info = required_arg
+ arg_type = uint32
+ typestr = percent
+ default_val = 0
+ [help]
+ The minimum amount of free inodes on the file system containing the
+ destination dir. If the percentage of free inodes drops below the
+ given value, snapshot removal kicks in like in case of low disk space.
+
+ The number of free inodes is determined from the f_ffree field of
+ the statvfs structure. However, some file systems set this field to
+ zero, indicating that the number of inodes is basically unlimited.
+ Moreover it is not possible to reliably detect whether this is the
+ case. Therefore this feature is disabled by default. It's safe to
+ enable it for ext2/ext3/ext4 file systems on linux though.
+
+ A value of zero (the default) deactivates this check.
+ [/help]
+ [option keep-redundant]
+ short_opt = k
+ summary = prune by disk space only
+ [help]
+ By default, redundant and outdated snapshots are removed automatically
+ to keep the number of snapshots in harmony with the configured
+ policy. If this flag is given, dss removes such snapshots only if
+ disk space or number of free inodes becomes low.
+ [/help]
+ [option min-complete]
+ summary = minimal number of complete snapshots to keep
+ arg_info = optional_arg
+ arg_type = uint32
+ typestr = num
+ default_val = 1
+ [help]
+ This option is only relevant if snapshots must be deleted because
+ disk space gets low.
+
+ dss refuses to remove old snapshots if there are fewer complete
+ snapshots left than the given number. The default value of one
+ guarantees that at least one complete snapshot is available at
+ all times.
+
+ If only <num> complete snapshots are left, and there is not enough
+ disk space available for another snapshot, the program terminates
+ with a "No space left on device" error.
+ [/help]
+
+[introduction]
+ dss supports the subcommands described below. If no subcommand is
+ given, the list of available subcommands is shown and the program
+ terminates successfully without performing any further action.
+[/introduction]
+
+[subcommand run]
+ purpose = start creating and pruning snapshots
+ [description]
+ This is the main mode of operation. Snapshots are created in an endless
+ loop as needed and pruned automatically. The loop only terminates on
+ fatal errors or if a terminating signal was received. See also the
+ --exit-hook option.
+ [/description]
+ [option daemon]
+ short_opt = d
+ summary = run as background daemon
+ [help]
+ If this option is given, the dss command detaches from the console
+ and continues to run in the background. It is not possible to let
+ a daemonized process re-attach to the console by editing the config
+ file and sending SIGHUP. However, log output may be redirected to a
+ different file in this way.
+
+ See --logfile.
+ [/help]
+ [option logfile]
+ short_opt = l
+ summary = where to write log output
+ arg_info = required_arg
+ arg_type = string
+ typestr = path
+ default_val = /dev/null
+ [help]
+ This option is only honored if --daemon is given, in which case
+ log messages go to the given file. Otherwise the option is silently
+ ignored and log output is written to stderr.
+ [/help]
+ [option max-rsync-errors]
+ summary = terminate after this many rsync failures
+ typestr = count
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 10
+ [help]
+ If the rsync process exits with a fatal error, dss restarts the command
+ in the hope that the problem is transient and subsequent rsync runs
+ succeed. After the given number of consecutive rsync error exits,
+ however, dss gives up, executes the exit hook and terminates. Set
+ this to zero if dss should exit immediately on the first rsync error.
+
+ The only non-fatal error is when rsync exits with code 24. This
+ indicates a partial transfer due to vanished source files and happens
+ frequently when snapshotting a directory which is concurrently being
+ modified.
+ [/help]
+[subcommand create]
+ purpose = execute rsync once to create a new snapshot
+ [description]
+ This command does not check the amount free disk space. The pre-create
+ and post-create hooks are honored, however.
+
+ Specify --dry-run to see the rsync command which is executed to create
+ snapshots.
+ [/description]
+[subcommand prune]
+ purpose = remove snapshots
+ [description]
+ A snapshot is said to be (a) outdated if its interval number is greater
+ or equal than the specified number of unit intervals, (b) redundant if
+ the interval it belongs to contains more than the configured number of
+ snapshots, and (c) orphaned if it is incomplete and not being created
+ or deleted. All other snapshots are called regular.
+
+ Unless --dry-run is given, which just prints the snapshot that would be
+ removed, this subcommand gets rid of non-regular snapshots. At most
+ one snapshot is removed per invocation. If no such snapshot exists
+ and disk space is low, the subcommand also removes regular snapshots,
+ always picking the oldest one.
+
+ The subcommand fails if there is another dss "run" process.
+ [/description]
+ [option disk-space]
+ summary = act as if free disk space was high/low
+ arg_info = required_arg
+ arg_type = string
+ typestr = mode
+ values = {
+ FDS_CHECK = "check",
+ FDS_HIGH = "high",
+ FDS_LOW = "low"
+ }
+ default_val = check
+ [help]
+ By default, free disk space is checked and even regular snapshots
+ become candidates for removal if disk space is low. This option
+ overrides the result of the check.
+ [/help]
+[subcommand ls]
+ purpose = print the list of all snapshots
+ [description]
+ The list contains all existing snapshots, no matter of their state.
+ Incomplete snapshots and snapshots being deleted will also be listed.
+ [/description]
+[subcommand kill]
+ purpose = send a signal to a running dss process
+ [description]
+ This sends a signal to the dss process that corresponds to the given
+ config file. If --dry-run is given, the PID of the dss process is
+ written to stdout, but no signal is sent.
+ [/description]
+ [option signal]
+ short_opt = s
+ summary = send the given signal rather than SIGTERM
+ typestr = signal
+ arg_info = required_arg
+ arg_type = string
+ default_val = SIGTERM
+ [help]
+ Like for kill(1), alternate signals may be specified in three ways: as
+ a signal number (e.g., 9), the signal name (e.g., KILL), or the signal
+ name prefixed with "SIG" (e.g., SIGKILL). In the latter two forms,
+ the signal name and the prefix are case insensitive, so "sigkill"
+ works as well.
+
+ Sending SIGHUP causes the running dss process to reload its config file.
+ [/help]
+ [option wait]
+ short_opt = w
+ summary = wait until the signalled process has terminated
+ [help]
+ This option is handy for system shutdown scripts which would like
+ to terminate the dss daemon process.
+
+ Without --wait the dss process which executes the kill subcommand
+ exits right after the kill(2) system call returns. At this point the
+ signalled process might still be alive (even if SIGKILL was sent).
+ If --wait is given, the process waits until the signalled process
+ has terminated or the timeout expires.
+
+ If --wait is not given, the kill subcommand exits successfully if
+ and only if the signal was sent (i.e., if there exists another dss
+ process to receive the signal). With --wait it exits successfully
+ if, additionally, the signalled process has terminated before the
+ timeout expires.
+
+ It makes only sense to use the option for signals which terminate dss.
+ [/help]
+[subcommand configtest]
+ purpose = run a configuration file syntax test
+ [description]
+ This command checks the command line options and the configuration
+ file for syntactic correctness. It either reports "Syntax Ok" and
+ exits successfully or prints information about the first syntax error
+ detected and terminates with exit code 1.
+ [/description]
+[subcommand help]
+ purpose = list available subcommands or print subcommand-specific help
+ non-opts-name = [subcommand]
+ [description]
+ If the optional subcommand argument is given, the help text of that
+ subcommand is shown. Without the argument the available subcommands
+ are listed instead.
+ [/description]
+ [option long]
+ short_opt = l
+ summary = show the long help text of a subcommand
+ [help]
+ If this option is given, the command also shows the description of
+ the subcommand and the help text of each option, Otherwise only the
+ purpose, the synopsis and the option list of the subcommand is shown.
+ If no subcommand is supplied, the option has no effect.
+ [/help]
+
+[section examples]
+ Suppose you'd like to create snapshots of the existing directory
+ .I /foo/bar
+ in the directory
+ .IR /baz/qux .
+ Create the config file
+ .I ~/.dssrc
+ containing
+ the values for the source and the destination directories
+ as follows:
+
+ .RS 6
+ .EX
+ echo 'source-dir "/foo/bar"' > ~/.dssrc
+ echo 'dest-dir "/baz/qux"' >> ~/.dssrc
+ .EE
+ .RE
+
+ Then execute the commands
+
+ .RS 6
+ .EX
+ mkdir /baz/qux
+ dss run
+ .EE
+ .RE
+
+ To print the list of all snapshots created so far, run
+ .IR dss\~ls .
+
+ The second example involves a slightly more sophisticated config
+ file. It instructs dss to exclude everything which matches at least
+ one pattern of the given exclude file, prevents rsync from crossing
+ file system boundaries and increases the number of snapshots.
+
+ .RS 6
+ .EX
+ source-dir "/foo/bar"
+ dest-dir "/baz/qux"
+ # exclude files matching patterns in /etc/dss.exclude
+ rsync-option \-\-exclude\-from=/etc/dss.exclude
+ # don't cross filesystem boundaries
+ rsync-option \-\-one\-file\-system
+ # maintain 2^6 - 1 = 63 snapshots
+ num-intervals "6"
+ .EE
+ .RE
+
+ The
+ .I /etc/dss.exclude
+ file could look like this (see rsync(1) for more examples)
+
+ .RS 6
+ .EX
+ - /proc
+ - /**/tmp/
+ .EE
+ .RE
+[/section]
+
+[section snapshot distribution]
+ The age of a snapshot is measured in terms of unit
+ intervals. Given
+ the duration
+ .I u
+ of a unit
+ interval and the number
+ .I n
+ of unit intervals to consider, dss tries to keep
+ .I 2^(n-k-1)
+ snapshots in interval
+ .IR k ,
+ where the interval number
+ .I k
+ counts
+ from zero to
+ .IR n-1 ,
+ with zero being the most recent unit interval. Snapshots older than
+ .I n
+ unit intervals are regarded as outdated and are removed. There are
+ .I 2^n-1
+ snapshots in total.
+
+ For example, with four unit intervals, the 2^4 - 1 = 15 snapshots
+ are distributed as follows.
+
+ .TS
+ allbox;
+ lb r r r r
+ lb r r r r.
+ Interval 3 2 1 0
+ Snapshots \~\~\~\~*\~\~\~ \~\~*\~\~*\~\~ \~*\~*\~*\~* ********
+ .TE
+
+ Note that for this to work out the system must be fast enough to
+ create at least
+ .I 2^(n-1)
+ snapshots per unit interval because this is the number of snapshots
+ in interval zero.
+[/section]
+
+[section copyright]
+ Written by AUTHOR()
+ .br
+ Copyright (C) 2008 - present AUTHOR()
+ .br
+ License: LICENSE()
+ .br
+ This is free software: you are free to change and redistribute it.
+ .br
+ There is NO WARRANTY, to the extent permitted by law.
+ .P
+ Project web page:
+ .UR URL()
+ .UE
+ .br
+ Git clone «URL»:
+ .UR CLONE_URL()
+ .UE
+ .br
+ Gitweb:
+ .UR GITWEB_URL()
+ .UE
+ .br
+ Author's home page:
+ .UR HOME_URL()
+ .UE
+ .br
+ Report bugs to
+ .MT EMAIL()
+ AUTHOR()
+ .ME
+[/section]
+
+[section see also]
+ .BR ssh (1) ,
+ .BR rsync (1)
+[/section]
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
- <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
- <title>DSS - The dyadic snapshot scheduler</title>
- <LINK href="dss.css" REL="stylesheet" TYPE="text/css">
- <link rel="shortcut icon" href="dss.ico">
-</head>
-
-<body>
- <table>
- <tr>
- <td>
- <img src="dss.svg" alt="dss">
- </td>
- <td>
- <h1>The dyadic snapshot scheduler</h1>
- </td>
- </tr>
- </table>
-
- <hr>
-
- [<a href="#readme">README</a>]
- [<a href="#news">NEWS</a>]
- [<a href="#download">Download</a>]
- [<a href="#install">INSTALL</a>]
- [<a href="#license">License</a>]
- [<a href="#contact">Contact</a>]
- [<a href="#manpage">Man page</a>]
-
- <hr>
-
- <center>
- <h2>
- <a name="readme">README</a>
- </h2>
- </center>
-
- @README@
-
- <hr>
-
- <center>
- <h2>
- <a name="news">NEWS</a>
- </h2>
- </center>
-
- @NEWS@
-
- <hr>
-
- <center>
- <h2>
- <a name="download">Download</a>
- </h2>
- </center>
-
- <p>Only the source code is available for download. Use
-
- <a href="http://www.kernel.org/pub/software/scm/git/docs/">git</a>
-
- to clone the dss repository by executing</p>
-
- <center>
-
- <tt>git clone git://git.tuebingen.mpg.de/dss</tt>
-
- </center>
-
- <p> or grab the
-
- <a href="http://git.tuebingen.mpg.de/cgi-bin/gitweb.cgi?p=dss.git;a=snapshot;h=HEAD;sf=tgz">tarball</a>
-
- of the current master branch. If you prefer to download the tarball of
- the latest release, select the corresponding <em>snapshot</em>
- link on the
-
- <a href="http://git.tuebingen.mpg.de/dss.git">dss gitweb page</a>
-
- </p>
-
- <hr>
-
- <center>
- <h2>
- <a name="install">INSTALL</a>
- </h2>
- </center>
-
- @INSTALL@
-
- <hr>
-
- <center>
- <h2>
- <a name="license">License</a>
- </h2>
- </center>
-
- <p>dss is open source software, licensed under the
-
- <a
- href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU
- General Public License, Version 2</a>.</p>
-
- <hr>
-
- <center>
- <h2>
- <a name="contact">Contact</a>
- </h2>
- </center>
-
- <p> Email: André Noll, <a
- href="mailto:maan@tuebingen.mpg.de">maan@tuebingen.mpg.de</a>,
- Homepage: <a
- href="http://people.tuebingen.mpg.de/maan/">http://people.tuebingen.mpg.de/maan/</a>
- </p>
-
- Comments and bug reports are welcome. Please provide
- enough info such as the version of dss you are using and
- relevant parts of the logs. Including the string [dss] in
- the subject line is also a good idea.
-
- <hr>
-
- <center>
- <h2>
- <a name="manpage">Man page</a>
- </h2>
- </center>
-
- @MAN_PAGE@
-
-</body> </html>
-
--- /dev/null
+dnl SPDX-License-Identifier: GPL-2.0
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
+ <title>PACKAGE() - SLOGAN()</title>
+ <style type='text/css'>
+ body {
+ text-align: justify;
+ background-color: #ffffff;
+ color: #333333;
+ padding: 0px 30px 0px 30px;
+ }
+ a {
+ color: #4444ff;
+ }
+ pre,code {
+ font-size: 110%;
+ }
+ </style>
+ <link rel="shortcut icon" href="dss.ico">
+</head>
+
+<body>
+ <table>
+ <tr>
+ <td> include(«dss.svg») </td>
+ <td> <h1>SLOGAN()</h1> </td>
+ </tr>
+ </table>
+
+ <p> DESCRIPTION1() </p>
+ <p> DESCRIPTION2() </p>
+ <p> DESCRIPTION3() </p>
+
+ <h2> <a name="installation">Installation</a> </h2>
+
+ <p> The easiest way to install PACKAGE() is to download and run
+ this pre-compiled <a href="PACKAGE()">static binary</a> for x86. It
+ should work fine on all Linux distributions but it won't work on arm
+ systems. </p>
+
+ <p> To install from source, you first need to install the dependencies:
+ <code>apt-get install gcc rsync liblopsub-dev m4</code>. </p>
+
+ <p> To download the source code, run <code>git clone
+ CLONE_URL()</code>, or grab a current tarball from the <a
+ href="GITWEB_URL()">gitweb page</a> and unpack it. </p>
+
+ <p> To build the PACKAGE() executable and the man page, enter the
+ PACKAGE() source directory and type <code>make</code>. To install
+ both files run <code>sudo make install</code>. </p>
+
+ <p> Try <code>dss -h</code> for an overview of all supported command
+ line options, <code>dss --detailed-help</code> for the long help text,
+ or <code>man dss</code> to see the man page which contains example
+ configurations. </p>
+
+ <h2> <a name="resources">Resources</a> </h2>
+ <ul>
+ <li> <a href="PACKAGE_HOMEPAGE()">PACKAGE() home page</a> </li>
+ <li> <code>git clone CLONE_URL()</code> </li>
+ <li> <a href="GITWEB_URL()">Gitweb</a> </li>
+ <li> <a href="HOME_URL()">Author home page</a> </li>
+ <li> <a href="PACKAGE().1.html">manual page</a> </li>
+ <li> Contact: <a href="mailto:EMAIL()">AUTHOR() <EMAIL()></a> </li>
+ <li> License: <a href="LICENSE_URL()">LICENSE()</a> </li>
+ </ul>
+
+</body> </html>
/** last message before exit */
#define EMERG 7
-/** Log messages with lower priority than that will not be compiled in. */
-#define COMPILE_TIME_LOGLEVEL 0
-
/** Not all compilers support __func__ or an equivalent. */
#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(__GNUC__)
# if defined(_MSC_VER) && _MSC_VER >= 1300
# endif
#endif
-/** \cond */
-#if DEBUG > COMPILE_TIME_LOGLEVEL
#define DSS_DEBUG_LOG(args) \
do { \
dss_log_set_params(DEBUG, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_DEBUG_LOG(args) do {;} while (0)
-#endif
-#if INFO > COMPILE_TIME_LOGLEVEL
#define DSS_INFO_LOG(args) \
do { \
dss_log_set_params(INFO, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_INFO_LOG(args) do {;} while (0)
-#endif
-#if NOTICE > COMPILE_TIME_LOGLEVEL
#define DSS_NOTICE_LOG(args) \
do { \
dss_log_set_params(NOTICE, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_NOTICE_LOG(args) do {;} while (0)
-#endif
-#if WARNING > COMPILE_TIME_LOGLEVEL
#define DSS_WARNING_LOG(args) \
do { \
dss_log_set_params(WARNING, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_WARNING_LOG(args) do {;} while (0)
-#endif
-#if ERROR > COMPILE_TIME_LOGLEVEL
#define DSS_ERROR_LOG(args) \
do { \
dss_log_set_params(ERROR, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_ERROR_LOG(args) do {;} while (0)
-#endif
-#if CRIT > COMPILE_TIME_LOGLEVEL
#define DSS_CRIT_LOG(args) \
do { \
dss_log_set_params(CRIT, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_CRIT_LOG(args) do {;} while (0)
-#endif
-#if EMERG > COMPILE_TIME_LOGLEVEL
#define DSS_EMERG_LOG(args) \
do { \
dss_log_set_params(EMERG, __FILE__, __LINE__, __func__); \
dss_log args ; \
} while (0)
-#else
-#define DSS_EMERG_LOG(args)
-#endif
}
}
-/**
+/*
* Get the home directory of the current user.
*
- * \return A dynamically allocated string that must be freed by the caller. If
- * the home directory could not be found, this function returns "/tmp".
+ * Returns a dynamically allocated string that must be freed by the caller. If
+ * the HOME environment variable is unset or empty, the function aborts.
*/
__must_check __malloc char *get_homedir(void)
{
- struct passwd *pw = getpwuid(getuid());
- return dss_strdup(pw? pw->pw_dir : "/tmp");
+ const char *home = getenv("HOME");
+ if (home && *home)
+ return dss_strdup(home);
+ DSS_EMERG_LOG(("fatal: HOME is unset or empty\n"));
+ exit(EXIT_FAILURE);
}
/**
return 1;
}
-/**
+/*
* Get the logname of the current user.
*
- * \return A dynamically allocated string that must be freed by the caller. On
- * errors, the string "unknown user" is returned, i.e. this function never
- * returns \p NULL.
- *
- * \sa getpwuid(3).
+ * Returns a dynamically allocated string that must be freed by the caller. On
+ * errors, the string "unknown" is returned. This function never returns NULL.
*/
__must_check __malloc char *dss_logname(void)
{
- struct passwd *pw = getpwuid(getuid());
- return dss_strdup(pw? pw->pw_name : "unknown_user");
+ const char *logname = getenv("LOGNAME");
+ if (!logname && !*logname)
+ logname = "unknown";
+ return dss_strdup(logname);
}
/**
--- /dev/null
+#!/bin/sh
+
+# SPDX-License-Identifier: GPL-3.0-only
+
+package="$1"
+version_file="$2"
+
+ver='unnamed_version'
+# First try git, then gitweb, then default.
+if [ -e '.git' -o -e '../.git' ]; then
+ git_ver=$(git describe --abbrev=4 --always HEAD 2>/dev/null)
+ [ -z "$git_ver" ] && git_ver="$ver"
+ # update stat information in index to match working tree
+ git update-index -q --refresh > /dev/null
+ # if there are differences (exit code 1), the working tree is dirty
+ git diff-index --quiet HEAD || git_ver=$git_ver-dirty
+ ver=$git_ver
+elif [ "${PWD%%-*}" = $package- ]; then
+ ver=${PWD##*/$package-}
+fi
+ver=${ver#v}
+
+echo "$ver"
+[ -z "${version_file}" ] && exit 0
+# update version file if necessary
+content="const char *${package}_version(void) {return \"$ver\";};"
+[ -r "$version_file" ] && echo "$content" | cmp -s - $version_file && exit 0
+[ "$version_file" = "${version_file%/*}" ] || mkdir -p ${version_file%/*}
+printf '%s\n' "$content" > $version_file