+ return next_snapshot_time != 0;
+}
+
+static int next_snapshot_is_due(void)
+{
+ int64_t now = get_current_time();
+
+ if (!next_snapshot_time_is_valid())
+ next_snapshot_time = compute_next_snapshot_time();
+ if (next_snapshot_time <= now) {
+ DSS_DEBUG_LOG("next snapshot: now\n");
+ return 1;
+ }
+ DSS_DEBUG_LOG("next snapshot due in %" PRId64 " seconds\n",
+ next_snapshot_time - now);
+ return 0;
+}
+
+static int pre_create_hook(void)
+{
+ int ret, fds[3] = {0, 0, 0};
+
+ assert(snapshot_creation_status == HS_READY);
+ /* make sure that the next snapshot time will be recomputed */
+ invalidate_next_snapshot_time();
+ if (!conf.pre_create_hook_given) {
+ snapshot_creation_status = HS_PRE_SUCCESS;
+ return 0;
+ }
+ DSS_DEBUG_LOG("executing %s\n", conf.pre_create_hook_arg);
+ ret = dss_exec_cmdline_pid(&create_pid,
+ conf.pre_create_hook_arg, fds);
+ if (ret < 0)
+ return ret;
+ snapshot_creation_status = HS_PRE_RUNNING;
+ return ret;
+}
+
+static int pre_remove_hook(struct snapshot *s, const char *why)
+{
+ int ret, fds[3] = {0, 0, 0};
+ char *cmd;
+
+ if (!s)
+ return 0;
+ DSS_DEBUG_LOG("%s snapshot %s\n", why, s->name);
+ assert(snapshot_removal_status == HS_READY);
+ assert(remove_pid == 0);
+ assert(!snapshot_currently_being_removed);
+
+ snapshot_currently_being_removed = dss_malloc(sizeof(struct snapshot));
+ *snapshot_currently_being_removed = *s;
+ snapshot_currently_being_removed->name = dss_strdup(s->name);
+
+ if (!conf.pre_remove_hook_given) {
+ snapshot_removal_status = HS_PRE_SUCCESS;
+ return 0;
+ }
+ cmd = make_message("%s %s/%s", conf.pre_remove_hook_arg,
+ conf.dest_dir_arg, s->name);
+ DSS_DEBUG_LOG("executing %s\n", cmd);
+ ret = dss_exec_cmdline_pid(&remove_pid, cmd, fds);
+ free(cmd);
+ if (ret < 0)
+ return ret;
+ snapshot_removal_status = HS_PRE_RUNNING;
+ return ret;
+}
+
+static int exec_rm(void)
+{
+ struct snapshot *s = snapshot_currently_being_removed;