+ if (conf.min_free_mb_arg)
+ if (ds.free_mb < conf.min_free_mb_arg)
+ return 1;
+ if (conf.min_free_percent_arg)
+ if (ds.percent_free < conf.min_free_percent_arg)
+ return 1;
+ return 0;
+}
+
+int try_to_free_disk_space(int low_disk_space)
+{
+ int ret;
+ struct snapshot_list sl;
+
+ get_snapshot_list(&sl);
+ ret = remove_outdated_snapshot(&sl);
+ if (ret) /* error, or we are removing something */
+ goto out;
+ /* no outdated snapshot */
+ ret = remove_redundant_snapshot(&sl);
+ if (ret)
+ goto out;
+ ret = 0;
+ if (!low_disk_space)
+ goto out;
+ DSS_WARNING_LOG("disk space low and nothing obvious to remove\n");
+ ret = remove_oldest_snapshot();
+ if (ret)
+ goto out;
+ make_err_msg("uhuhu: not enough disk space for a single snapshot");
+ ret= -ENOSPC;
+out:
+ free_snapshot_list(&sl);
+ return ret;
+}
+
+int select_loop(void)
+{
+ int ret;
+ struct timeval tv = {.tv_sec = 0, .tv_usec = 0};
+
+ for (;;) {
+ fd_set rfds;
+ int low_disk_space;
+ char **rsync_argv;
+ struct timeval now, *tvp = &tv;
+
+ if (rsync_pid)
+ tv.tv_sec = 60; /* check every 60 seconds for free disk space */
+ else if (rm_pid)
+ tvp = NULL; /* sleep until rm process dies */
+ FD_ZERO(&rfds);
+ FD_SET(signal_pipe, &rfds);
+ DSS_DEBUG_LOG("tvp: %p, tv_sec: %lu\n", tvp, (long unsigned) tv.tv_sec);
+ ret = dss_select(signal_pipe + 1, &rfds, NULL, tvp);
+ if (ret < 0)
+ return ret;
+ if (FD_ISSET(signal_pipe, &rfds))
+ handle_signal();
+ if (rm_pid)
+ continue;
+ ret = disk_space_low();
+ if (ret < 0)
+ break;
+ low_disk_space = ret;
+ if (low_disk_space)
+ stop_rsync_process();
+ ret = try_to_free_disk_space(low_disk_space);
+ if (ret < 0)
+ break;
+ if (rm_pid)
+ continue;
+ restart_rsync_process();
+ gettimeofday(&now, NULL);
+ if (tv_diff(&next_snapshot_time, &now, &tv) > 0)
+ continue;
+ switch (snapshot_creation_status) {
+ case SCS_READY:
+ ret = pre_create_hook();
+ if (ret < 0)
+ goto out;
+ continue;
+ case SCS_PRE_HOOK_RUNNING:
+ continue;
+ case SCS_PRE_HOOK_SUCCESS:
+ create_rsync_argv(&rsync_argv, ¤t_snapshot_creation_time);
+ ret = create_snapshot(rsync_argv);
+ free_rsync_argv(rsync_argv);
+ if (ret < 0)
+ goto out;
+ continue;
+ case SCS_RSYNC_RUNNING:
+ continue;
+ case SCS_RSYNC_SUCCESS:
+ ret = post_create_hook();
+ if (ret < 0)
+ goto out;
+ continue;
+ case SCS_POST_HOOK_RUNNING:
+ continue;
+ }
+ }
+out:
+ return ret;
+}
+
+int com_run(void)
+{
+ int ret;
+
+ if (conf.dry_run_given) {
+ make_err_msg("dry_run not supported by this command");
+ return -E_SYNTAX;
+ }
+ ret = install_sighandler(SIGHUP);
+ if (ret < 0)
+ return ret;
+ compute_next_snapshot_time();
+ return select_loop();
+}
+
+void log_disk_space(struct disk_space *ds)
+{
+ DSS_INFO_LOG("free: %uM/%uM (%u%%), %u%% inodes unused\n",
+ ds->free_mb, ds->total_mb, ds->percent_free,
+ ds->percent_free_inodes);
+}
+
+int com_prune(void)
+{
+ int ret;
+ struct snapshot_list sl;
+ struct disk_space ds;
+
+ ret = get_disk_space(".", &ds);
+ if (ret < 0)
+ return ret;
+ log_disk_space(&ds);
+ for (;;) {
+ get_snapshot_list(&sl);
+ ret = remove_outdated_snapshot(&sl);
+ free_snapshot_list(&sl);
+ if (ret < 0)
+ return ret;
+ if (!ret)
+ break;
+ ret = wait_for_rm_process();
+ if (ret < 0)
+ goto out;
+ }
+ for (;;) {
+ get_snapshot_list(&sl);
+ ret = remove_redundant_snapshot(&sl);
+ free_snapshot_list(&sl);
+ if (ret < 0)
+ return ret;
+ if (!ret)
+ break;
+ ret = wait_for_rm_process();
+ if (ret < 0)
+ goto out;
+ }
+ return 1;
+out: