/** Parsed subcommand options. */
static struct lls_parse_result *cmdline_sublpr, *sublpr;
+/* The executing subcommand (NULL at startup). */
+static const struct lls_command *subcmd;
/** Wether daemon_init() was called. */
static bool daemonized;
/** Non-NULL if we log to a file. */
if (loglevel < lpr_ll)
return;
outfd = logfile? logfile : stderr;
- time(&t1);
- tm = localtime(&t1);
- strftime(str, sizeof(str), "%b %d %H:%M:%S", tm);
- fprintf(outfd, "%s ", str);
- if (lpr_ll <= INFO)
- fprintf(outfd, "%i: ", loglevel);
+ if (subcmd == CMD_PTR(RUN)) {
+ time(&t1);
+ tm = localtime(&t1);
+ strftime(str, sizeof(str), "%b %d %H:%M:%S", tm);
+ fprintf(outfd, "%s ", str);
+ if (lpr_ll <= INFO)
+ fprintf(outfd, "%i: ", loglevel);
+ }
+ if (subcmd == CMD_PTR(RUN))
#ifdef DSS_NO_FUNC_NAMES
- fprintf(outfd, "%s:%d: ", location_file, location_line);
+ fprintf(outfd, "%s:%d: ", location_file, location_line);
#else
- fprintf(outfd, "%s: ", location_func);
+ fprintf(outfd, "%s: ", location_func);
#endif
va_start(argp, fmt);
vfprintf(outfd, fmt, argp);
dss_msg("%d\n", (int)pid);
return 0;
}
+ DSS_NOTICE_LOG(("sending signal %d to pid %d\n", sig, (int)pid));
ret = kill(pid, sig);
if (ret < 0)
return -ERRNO_TO_DSS_ERROR(errno);
struct snapshot *s;
int i;
- DSS_DEBUG_LOG(("looking for orphaned snapshots\n"));
+ DSS_DEBUG_LOG(("looking for old incomplete snapshots\n"));
FOR_EACH_SNAPSHOT(s, i, sl) {
if (snapshot_is_being_created(s))
continue;
if (!low_disk_space)
goto out;
DSS_WARNING_LOG(("disk space low and nothing obvious to remove\n"));
+ why = "oldest";
victim = find_oldest_removable_snapshot(&sl);
if (victim)
goto remove;
return -E_BUG;
}
+ /* also checks if . is a mountpoint, if --mountpoint was given */
static int change_to_dest_dir(void)
{
int ret;
const char *dd = OPT_STRING_VAL(DSS, DEST_DIR);
+ struct stat dot, dotdot;
DSS_INFO_LOG(("changing cwd to %s\n", dd));
- if (chdir(dd) >= 0)
- return 1;
- ret = -ERRNO_TO_DSS_ERROR(errno);
- DSS_ERROR_LOG(("could not change cwd to %s\n", dd));
- return ret;
+ if (chdir(dd) < 0) {
+ ret = -ERRNO_TO_DSS_ERROR(errno);
+ DSS_ERROR_LOG(("could not change cwd to %s\n", dd));
+ return ret;
+ }
+ if (!OPT_GIVEN(DSS, MOUNTPOINT))
+ return 0;
+ if (stat(".", &dot) < 0) {
+ ret = -ERRNO_TO_DSS_ERROR(errno);
+ DSS_ERROR_LOG(("could not stat .\n"));
+ return ret;
+ }
+ if (stat("..", &dotdot) < 0) {
+ ret = -ERRNO_TO_DSS_ERROR(errno);
+ DSS_ERROR_LOG(("could not stat ..\n"));
+ return ret;
+ }
+ if (dot.st_dev == dotdot.st_dev && dot.st_ino != dotdot.st_ino) {
+ DSS_ERROR_LOG(("mountpoint check failed for %s\n", dd));
+ return -E_MOUNTPOINT;
+ }
+ return 1;
}
-static int check_config(const struct lls_command *cmd)
+static int check_config(void)
{
int ret;
uint32_t unit_interval = OPT_UINT32_VAL(DSS, UNIT_INTERVAL);
DSS_ERROR_LOG(("bad number of intervals: %i\n", num_intervals));
return -E_INVALID_NUMBER;
}
- if (cmd == CMD_PTR(RUN) || cmd == CMD_PTR(CREATE))
+ if (subcmd == CMD_PTR(RUN) || subcmd == CMD_PTR(CREATE))
if (!OPT_GIVEN(DSS, SOURCE_DIR)) {
DSS_ERROR_LOG(("--source-dir required\n"));
return -E_SYNTAX;
}
- if (cmd == CMD_PTR(RUN) || cmd == CMD_PTR(CREATE)
- || cmd == CMD_PTR(LS) || cmd == CMD_PTR(PRUNE)) {
+ if (subcmd == CMD_PTR(RUN) || subcmd == CMD_PTR(CREATE)
+ || subcmd == CMD_PTR(LS) || subcmd == CMD_PTR(PRUNE)) {
if (!OPT_GIVEN(DSS, DEST_DIR)) {
DSS_ERROR_LOG(("--dest-dir required\n"));
return -E_SYNTAX;
ret = parse_config_file(true /* SIGHUP */, CMD_PTR(RUN));
if (ret < 0)
return ret;
- ret = check_config(CMD_PTR(RUN));
+ ret = check_config();
if (ret < 0)
return ret;
close_log(logfile);
}
EXPORT_CMD_HANDLER(ls);
+static int com_configtest(void)
+{
+ printf("Syntax Ok\n");
+ return 0;
+}
+EXPORT_CMD_HANDLER(configtest);
+
static int setup_signal_handling(void)
{
int ret;
for (i = 1; (cmd = lls_cmd(i, dss_suite)); i++) {
const char *name = lls_command_name(cmd);
const char *purpose = lls_purpose(cmd);
- printf("%-10s%s\n", name, purpose);
+ printf("%-11s%s\n", name, purpose);
}
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
int ret;
- const struct lls_command *cmd = CMD_PTR(DSS);
char *errctx = NULL;
unsigned num_inputs;
- const struct dss_user_data *ud = NULL;
+ const struct dss_user_data *ud;
- ret = lls_parse(argc, argv, cmd, &cmdline_lpr, &errctx);
+ ret = lls_parse(argc, argv, CMD_PTR(DSS), &cmdline_lpr, &errctx);
if (ret < 0) {
ret = lopsub_error(ret, &errctx);
goto out;
}
lpr = cmdline_lpr;
- ret = parse_config_file(false /* no SIGHUP */, cmd);
+ ret = parse_config_file(false /* no SIGHUP */, CMD_PTR(DSS));
if (ret < 0)
goto out;
handle_version_and_help();
ret = lopsub_error(ret, &errctx);
goto out;
}
- cmd = lls_cmd(ret, dss_suite);
- ret = lls_parse(num_inputs, argv + argc - num_inputs, cmd,
+ subcmd = lls_cmd(ret, dss_suite);
+ ret = lls_parse(num_inputs, argv + argc - num_inputs, subcmd,
&cmdline_sublpr, &errctx);
if (ret < 0) {
ret = lopsub_error(ret, &errctx);
goto out;
}
sublpr = cmdline_sublpr;
- ret = parse_config_file(false /* no SIGHUP */, cmd);
+ ret = parse_config_file(false /* no SIGHUP */, subcmd);
if (ret < 0)
goto out;
- ret = check_config(cmd);
+ ret = check_config();
if (ret < 0)
goto out;
ret = setup_signal_handling();
if (ret < 0)
goto out;
- ud = lls_user_data(cmd);
+ ud = lls_user_data(subcmd);
ret = ud->handler();
signal_shutdown();
out:
lls_free_parse_result(lpr, CMD_PTR(DSS));
if (lpr != cmdline_lpr)
lls_free_parse_result(cmdline_lpr, CMD_PTR(DSS));
- lls_free_parse_result(sublpr, cmd);
+ lls_free_parse_result(sublpr, subcmd);
if (sublpr != cmdline_sublpr)
- lls_free_parse_result(cmdline_sublpr, cmd);
+ lls_free_parse_result(cmdline_sublpr, subcmd);
exit(ret >= 0? EXIT_SUCCESS : EXIT_FAILURE);
}
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 to change the
+ were previously given at the command line. This allows changing the
configuration of a running dss process by sending SIGHUP.
[/help]
[option loglevel]
This option is mandatory for all subcommands except kill.
[/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
typestr = percent
default_val = 2
[help]
- This is like --min-free-mb but allows to specify the amount of
- free disk space as a percentage. It is not recommended to set both
+ 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]
Sending SIGHUP causes the running dss process to reload its config file.
[/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