+void compute_next_snapshot_time(void)
+{
+ struct timeval now, unit_interval = {.tv_sec = 24 * 3600 * conf.unit_interval_arg},
+ tmp, diff;
+ int64_t x = 0;
+ unsigned wanted = num_snapshots(0), num_complete_snapshots = 0;
+ int i, ret;
+ struct snapshot *s = NULL;
+ struct snapshot_list sl;
+
+ assert(snapshot_creation_status == SCS_READY);
+ current_snapshot_creation_time = 0;
+ get_snapshot_list(&sl);
+ FOR_EACH_SNAPSHOT(s, i, &sl) {
+ if (!(s->flags & SS_COMPLETE))
+ continue;
+ num_complete_snapshots++;
+ x += s->completion_time - s->creation_time;
+ }
+ assert(x >= 0);
+ if (num_complete_snapshots)
+ x /= num_complete_snapshots; /* avg time to create one snapshot */
+ x *= wanted; /* time to create all snapshots in interval 0 */
+ tmp.tv_sec = x;
+ tmp.tv_usec = 0;
+ ret = tv_diff(&unit_interval, &tmp, &diff); /* total sleep time per unit interval */
+ gettimeofday(&now, NULL);
+ if (ret < 0 || !s)
+ goto min_sleep;
+ tv_divide(wanted, &diff, &tmp); /* sleep time betweeen two snapshots */
+ diff.tv_sec = s->completion_time;
+ diff.tv_usec = 0;
+ tv_add(&diff, &tmp, &next_snapshot_time);
+ if (tv_diff(&now, &next_snapshot_time, NULL) < 0)
+ goto out;
+min_sleep:
+ next_snapshot_time = now;
+ next_snapshot_time.tv_sec += 60;
+out:
+ free_snapshot_list(&sl);
+}
+
+int handle_rsync_exit(int status)
+{
+ int es, ret;
+
+ if (!WIFEXITED(status)) {
+ make_err_msg("rsync process %d died involuntary", (int)rsync_pid);
+ ret = -E_INVOLUNTARY_EXIT;
+ snapshot_creation_status = SCS_READY;
+ compute_next_snapshot_time();
+ goto out;
+ }
+ es = WEXITSTATUS(status);
+ if (es != 0 && es != 23 && es != 24) {
+ make_err_msg("rsync process %d returned %d", (int)rsync_pid, es);
+ ret = -E_BAD_EXIT_CODE;
+ snapshot_creation_status = SCS_READY;
+ compute_next_snapshot_time();
+ goto out;
+ }
+ ret = rename_incomplete_snapshot(current_snapshot_creation_time);
+ if (ret < 0)
+ goto out;
+ snapshot_creation_status = SCS_RSYNC_SUCCESS;
+out:
+ rsync_pid = 0;
+ rsync_stopped = 0;
+ return ret;
+}