+ why = "redundant";
+ s = find_redundant_snapshot(&sl);
+ if (s)
+ goto out;
+ why = "orphaned";
+ s = find_orphaned_snapshot(&sl);
+out:
+ if (s) {
+ DSS_NOTICE_LOG(("recycling %s snapshot %s\n", why, s->name));
+ ret = dss_rename(s->name, new_name);
+ }
+ if (ret >= 0)
+ DSS_NOTICE_LOG(("creating %s\n", new_name));
+ free(new_name);
+ free_snapshot_list(&sl);
+ return ret;
+}
+
+static void create_rsync_argv(char ***argv, int64_t *num)
+{
+ char *logname;
+ int i = 0, j, N = OPT_GIVEN(DSS, RSYNC_OPTION);
+ struct snapshot_list sl;
+
+ dss_get_snapshot_list(&sl);
+ assert(!name_of_reference_snapshot);
+ name_of_reference_snapshot = name_of_newest_complete_snapshot(&sl);
+ free_snapshot_list(&sl);
+
+ *argv = dss_malloc((15 + N) * sizeof(char *));
+ (*argv)[i++] = dss_strdup("rsync");
+ (*argv)[i++] = dss_strdup("-a");
+ (*argv)[i++] = dss_strdup("--delete");
+ for (j = 0; j < N; j++)
+ (*argv)[i++] = dss_strdup(lls_string_val(j,
+ OPT_RESULT(DSS, RSYNC_OPTION)));
+ if (name_of_reference_snapshot) {
+ DSS_INFO_LOG(("using %s as reference\n", name_of_reference_snapshot));
+ (*argv)[i++] = make_message("--link-dest=../%s",
+ name_of_reference_snapshot);
+ } else
+ DSS_INFO_LOG(("no suitable reference snapshot found\n"));
+ logname = dss_logname();
+ if (use_rsync_locally(logname))
+ (*argv)[i++] = dss_strdup(OPT_STRING_VAL(DSS, SOURCE_DIR));
+ else
+ (*argv)[i++] = make_message("%s@%s:%s/",
+ OPT_GIVEN(DSS, REMOTE_USER)?
+ OPT_STRING_VAL(DSS, REMOTE_USER) : logname,
+ OPT_STRING_VAL(DSS, REMOTE_HOST),
+ OPT_STRING_VAL(DSS, SOURCE_DIR));
+ free(logname);
+ *num = get_current_time();
+ (*argv)[i++] = incomplete_name(*num);
+ (*argv)[i++] = NULL;
+ for (j = 0; j < i; j++)
+ DSS_DEBUG_LOG(("argv[%d] = %s\n", j, (*argv)[j]));
+}
+
+static void free_rsync_argv(char **argv)
+{
+ int i;
+
+ if (!argv)
+ return;
+ for (i = 0; argv[i]; i++)
+ free(argv[i]);
+ free(argv);
+}
+
+static int create_snapshot(char **argv)
+{
+ int ret;
+
+ ret = rename_resume_snap(current_snapshot_creation_time);
+ if (ret < 0)
+ return ret;
+ dss_exec(&create_pid, argv[0], argv);
+ snapshot_creation_status = HS_RUNNING;
+ return ret;
+}
+
+static int select_loop(void)
+{
+ int ret;
+ /* check every 60 seconds for free disk space */
+ struct timeval tv;
+ char **rsync_argv = NULL;
+
+ for (;;) {
+ fd_set rfds;
+ struct timeval *tvp;
+
+ if (remove_pid)
+ tvp = NULL; /* sleep until rm hook/process dies */
+ else { /* sleep one minute */
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+ FD_ZERO(&rfds);
+ FD_SET(signal_pipe, &rfds);
+ ret = dss_select(signal_pipe + 1, &rfds, NULL, tvp);
+ if (ret < 0)
+ goto out;
+ if (FD_ISSET(signal_pipe, &rfds)) {
+ ret = handle_signal();
+ if (ret < 0)
+ goto out;
+ }
+ if (remove_pid)
+ continue;
+ if (snapshot_removal_status == HS_PRE_SUCCESS) {
+ ret = exec_rm();
+ if (ret < 0)
+ goto out;
+ continue;
+ }
+ if (snapshot_removal_status == HS_SUCCESS) {
+ post_remove_hook();
+ continue;
+ }
+ ret = try_to_free_disk_space();
+ if (ret < 0)
+ goto out;
+ if (snapshot_removal_status != HS_READY) {
+ stop_create_process();
+ continue;
+ }
+ restart_create_process();
+ switch (snapshot_creation_status) {
+ case HS_READY:
+ if (!next_snapshot_is_due())
+ continue;
+ pre_create_hook();
+ continue;
+ case HS_PRE_RUNNING:
+ case HS_RUNNING:
+ case HS_POST_RUNNING:
+ continue;
+ case HS_PRE_SUCCESS:
+ if (!name_of_reference_snapshot) {
+ free_rsync_argv(rsync_argv);
+ create_rsync_argv(&rsync_argv, ¤t_snapshot_creation_time);
+ }
+ ret = create_snapshot(rsync_argv);
+ if (ret < 0)
+ goto out;
+ continue;
+ case HS_NEEDS_RESTART:
+ if (!next_snapshot_is_due())
+ continue;
+ ret = create_snapshot(rsync_argv);
+ if (ret < 0)
+ goto out;
+ continue;
+ case HS_SUCCESS:
+ post_create_hook();
+ continue;
+ }