+ if (snapshot_removal_status == HS_PRE_RUNNING) {
+ ret = wait_for_remove_process();
+ if (ret < 0)
+ goto out;
+ if (snapshot_removal_status != HS_PRE_SUCCESS)
+ goto out;
+ }
+ ret = exec_rm();
+ if (ret < 0)
+ goto out;
+ ret = wait_for_remove_process();
+ if (ret < 0)
+ goto out;
+ if (snapshot_removal_status != HS_SUCCESS)
+ goto out;
+ ret = post_remove_hook();
+ if (ret < 0)
+ goto out;
+ if (snapshot_removal_status != HS_POST_RUNNING)
+ goto out;
+ ret = wait_for_remove_process();
+ if (ret < 0)
+ goto out;
+ ret = 1;
+out:
+ free_snapshot_list(&sl);
+ return ret;
+}
+
+static int com_create(void)
+{
+ int ret, status;
+ char **rsync_argv;
+
+ if (conf.dry_run_given) {
+ int i;
+ char *msg = NULL;
+ create_rsync_argv(&rsync_argv, ¤t_snapshot_creation_time);
+ for (i = 0; rsync_argv[i]; i++) {
+ char *tmp = msg;
+ msg = make_message("%s%s%s", tmp? tmp : "",
+ tmp? " " : "", rsync_argv[i]);
+ free(tmp);
+ }
+ free_rsync_argv(rsync_argv);
+ dss_msg("%s\n", msg);
+ free(msg);
+ return 1;
+ }
+ ret = pre_create_hook();
+ if (ret < 0)
+ return ret;
+ if (create_pid) {
+ ret = wait_for_process(create_pid, &status);
+ if (ret < 0)
+ return ret;
+ ret = handle_pre_create_hook_exit(status);
+ if (ret <= 0) /* error, or pre-create failed */
+ return ret;
+ }
+ create_rsync_argv(&rsync_argv, ¤t_snapshot_creation_time);
+ ret = create_snapshot(rsync_argv);
+ if (ret < 0)
+ goto out;
+ ret = wait_for_process(create_pid, &status);
+ if (ret < 0)
+ goto out;
+ ret = handle_rsync_exit(status);
+ if (ret < 0)
+ goto out;
+ post_create_hook();
+ if (create_pid)
+ ret = wait_for_process(create_pid, &status);
+out:
+ free_rsync_argv(rsync_argv);
+ return ret;
+}
+
+static int com_ls(void)
+{
+ int i;
+ struct snapshot_list sl;
+ struct snapshot *s;
+
+ dss_get_snapshot_list(&sl);
+ FOR_EACH_SNAPSHOT(s, i, &sl) {
+ int64_t d = 0;
+ if (s->flags & SS_COMPLETE)
+ d = (s->completion_time - s->creation_time) / 60;
+ dss_msg("%u\t%s\t%3" PRId64 ":%02" PRId64 "\n", s->interval, s->name, d/60, d%60);
+ };
+ free_snapshot_list(&sl);
+ return 1;
+}
+
+static int setup_signal_handling(void)
+{
+ int ret;
+
+ DSS_INFO_LOG("setting up signal handlers\n");
+ signal_pipe = signal_init(); /* always successful */
+ ret = install_sighandler(SIGINT);
+ if (ret < 0)
+ return ret;
+ ret = install_sighandler(SIGTERM);
+ if (ret < 0)
+ return ret;
+ return install_sighandler(SIGCHLD);
+}
+
+/**
+ * The main function of dss.
+ *
+ * \param argc Usual argument count.
+ * \param argv Usual argument vector.
+ */
+int main(int argc, char **argv)
+{
+ int ret;
+ struct cmdline_parser_params params = {
+ .override = 0,
+ .initialize = 1,
+ .check_required = 0,
+ .check_ambiguity = 0,
+ .print_errors = 1
+ };
+
+ cmdline_parser_ext(argc, argv, &conf, ¶ms); /* aborts on errors */
+ ret = parse_config_file(0);
+ if (ret < 0)
+ goto out;
+ if (ret == 0) { /* no config file given */
+ /*
+ * Parse the command line options again, but this time check
+ * that all required options are given.
+ */
+ params = (struct cmdline_parser_params) {
+ .override = 1,
+ .initialize = 1,
+ .check_required = 1,
+ .check_ambiguity = 1,
+ .print_errors = 1
+ };
+ cmdline_parser_ext(argc, argv, &conf, ¶ms); /* aborts on errors */
+ }
+ if (conf.daemon_given)
+ daemon_init();
+ ret = change_to_dest_dir();