X-Git-Url: http://git.tuebingen.mpg.de/?p=dss.git;a=blobdiff_plain;f=dss.c;h=db065c689b95dc0274231c9923cb9be6dd852839;hp=0a2f55b9fb02035405c791e2343398eeacb78d44;hb=e60f419875fc41704b9e3df9914c6393e7a7791e;hpb=fd7ab0475e24ec414883bf3772db160869ed2e0c diff --git a/dss.c b/dss.c index 0a2f55b..db065c6 100644 --- a/dss.c +++ b/dss.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Andre Noll + * Copyright (C) 2008-2010 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -64,7 +64,106 @@ enum hook_status snapshot_removal_status; DEFINE_DSS_ERRLIST; +static const char const *hook_status_description[] = {HOOK_STATUS_ARRAY}; +/* may be called with ds == NULL. */ +static int disk_space_low(struct disk_space *ds) +{ + struct disk_space ds_struct; + + if (!ds) { + int ret = get_disk_space(".", &ds_struct); + if (ret < 0) + return ret; + ds = &ds_struct; + } + 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; + if (conf.min_free_percent_inodes_arg) + if (ds->percent_free_inodes < conf.min_free_percent_inodes_arg) + return 1; + return 0; +} + +static void dump_dss_config(const char *msg) +{ + const char dash[] = "-----------------------------"; + int ret; + FILE *log = logfile? logfile : stderr; + struct disk_space ds; + int64_t now = get_current_time(); + + if (conf.loglevel_arg > INFO) + return; + + fprintf(log, "%s <%s config> %s\n", dash, msg, dash); + fprintf(log, "\n*** disk space ***\n\n"); + ret = get_disk_space(".", &ds); + if (ret >= 0) { + DSS_INFO_LOG("disk space low: %s\n", disk_space_low(&ds)? + "yes" : "no"); + log_disk_space(&ds); + } else + DSS_ERROR_LOG("can not get free disk space: %s\n", + dss_strerror(-ret)); + + /* we continue on errors from get_disk_space */ + + fprintf(log, "\n*** command line and config file options ***\n\n"); + cmdline_parser_dump(log, &conf); + fprintf(log, "\n*** internal state ***\n\n"); + fprintf(log, + "pid: %d\n" + "logile: %s\n" + "snapshot_currently_being_removed: %s\n" + "path_to_last_complete_snapshot: %s\n" + "reference_snapshot: %s\n" + "snapshot_creation_status: %s\n" + "snapshot_removal_status: %s\n" + , + (int) getpid(), + logfile? conf.logfile_arg : "stderr", + snapshot_currently_being_removed? + snapshot_currently_being_removed->name : "(none)", + path_to_last_complete_snapshot? + path_to_last_complete_snapshot : "(none)", + name_of_reference_snapshot? + name_of_reference_snapshot : "(none)", + hook_status_description[snapshot_creation_status], + hook_status_description[snapshot_removal_status] + ); + if (create_pid != 0) + fprintf(log, + "create_pid: %" PRId32 "\n" + "create process is %sstopped\n" + , + create_pid, + create_process_stopped? "" : "not " + ); + if (remove_pid != 0) + fprintf(log, "remove_pid: %" PRId32 "\n", remove_pid); + if (next_snapshot_time != 0) + fprintf(log, "next snapshot due in %" PRId64 " seconds\n", + next_snapshot_time - now); + if (current_snapshot_creation_time != 0) + fprintf(log, "current_snapshot_creation_time: %" + PRId64 " (%" PRId64 " seconds ago)\n", + current_snapshot_creation_time, + now - current_snapshot_creation_time + ); + if (next_removal_check.tv_sec != 0) { + fprintf(log, "next removal check: %llu (%llu seconds ago)\n", + (long long unsigned)next_removal_check.tv_sec, + now - (long long unsigned)next_removal_check.tv_sec + ); + + } + fprintf(log, "%s %s\n", dash, msg, dash); +} /* a litte cpp magic helps to DRY */ #define COMMANDS \ @@ -127,25 +226,6 @@ static __printf_1_2 void dss_msg(const char* fmt,...) va_end(argp); } -static int disk_space_low(void) -{ - struct disk_space ds; - int ret = get_disk_space(".", &ds); - - if (ret < 0) - return ret; - 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; - if (conf.min_free_percent_inodes_arg) - if (ds.percent_free_inodes < conf.min_free_percent_inodes_arg) - return 1; - return 0; -} - static void dss_get_snapshot_list(struct snapshot_list *sl) { get_snapshot_list(sl, conf.unit_interval_arg, conf.num_intervals_arg); @@ -161,7 +241,6 @@ static int64_t compute_next_snapshot_time(void) struct snapshot *s = NULL; struct snapshot_list sl; - current_snapshot_creation_time = 0; dss_get_snapshot_list(&sl); FOR_EACH_SNAPSHOT(s, i, &sl) { if (!(s->flags & SS_COMPLETE)) @@ -215,10 +294,6 @@ static int pre_create_hook(void) 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); @@ -244,15 +319,10 @@ static int pre_remove_hook(struct snapshot *s, const char *why) *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, - conf.pre_remove_hook_arg, fds); + ret = dss_exec_cmdline_pid(&remove_pid, cmd, fds); free(cmd); if (ret < 0) return ret; @@ -451,7 +521,7 @@ static int try_to_free_disk_space(void) const char *why; int low_disk_space; - ret = disk_space_low(); + ret = disk_space_low(NULL); if (ret < 0) return ret; low_disk_space = ret; @@ -504,11 +574,6 @@ static int post_create_hook(void) int ret, fds[3] = {0, 0, 0}; char *cmd; - if (!conf.post_create_hook_given) { - create_pid = 0; - snapshot_creation_status = HS_READY; - return 0; - } cmd = make_message("%s %s/%s", conf.post_create_hook_arg, conf.dest_dir_arg, path_to_last_complete_snapshot); DSS_NOTICE_LOG("executing %s\n", cmd); @@ -528,10 +593,6 @@ static int post_remove_hook(void) assert(s); - if (!conf.post_remove_hook_given) { - snapshot_removal_status = HS_READY; - return 0; - } cmd = make_message("%s %s/%s", conf.post_remove_hook_arg, conf.dest_dir_arg, s->name); DSS_NOTICE_LOG("executing %s\n", cmd); @@ -543,27 +604,48 @@ static int post_remove_hook(void) return ret; } -static void kill_process(pid_t pid) +static void dss_kill(pid_t pid, int sig, const char *msg) { - if (!pid) + const char *signame, *process_name; + + if (pid == 0) + return; + switch (sig) { + case SIGTERM: signame = "TERM"; break; + case SIGSTOP: signame = "STOP"; break; + case SIGCONT: signame = "CONT"; break; + default: signame = "????"; + } + + if (pid == create_pid) + process_name = "create"; + else if (pid == remove_pid) + process_name = "remove"; + else process_name = "??????"; + + if (msg) + DSS_INFO_LOG("%s\n", msg); + DSS_DEBUG_LOG("sending signal %d (%s) to pid %d (%s process)\n", + sig, signame, (int)pid, process_name); + if (kill(pid, sig) >= 0) return; - DSS_WARNING_LOG("sending SIGTERM to pid %d\n", (int)pid); - kill(pid, SIGTERM); + DSS_INFO_LOG("failed to send signal %d (%s) to pid %d (%s process)\n", + sig, signame, (int)pid, process_name); } static void stop_create_process(void) { - if (!create_pid || create_process_stopped) + if (create_process_stopped) return; - kill(SIGSTOP, create_pid); + dss_kill(create_pid, SIGSTOP, "suspending create process"); create_process_stopped = 1; } static void restart_create_process(void) { - if (!create_pid || !create_process_stopped) + if (!create_process_stopped) return; - kill (SIGCONT, create_pid); + dss_kill(create_pid, SIGCONT, "resuming create process"); create_process_stopped = 0; } @@ -608,8 +690,7 @@ static int wait_for_process(pid_t pid, int *status) } } /* SIGINT or SIGTERM */ - DSS_WARNING_LOG("sending SIGTERM to pid %d\n", (int)pid); - kill(pid, SIGTERM); + dss_kill(pid, SIGTERM, "killing child process"); } if (ret < 0) DSS_ERROR_LOG("failed to wait for process %d\n", (int)pid); @@ -639,10 +720,7 @@ static int handle_rm_exit(int status) snapshot_removal_status = HS_READY; return -E_BAD_EXIT_CODE; } - if (conf.post_remove_hook_given) - snapshot_removal_status = HS_SUCCESS; - else - snapshot_removal_status = HS_READY; + snapshot_removal_status = HS_SUCCESS; return 1; } @@ -779,18 +857,22 @@ static int handle_sigchld(void) if (pid == create_pid) { switch (snapshot_creation_status) { case HS_PRE_RUNNING: - return handle_pre_create_hook_exit(status); + ret = handle_pre_create_hook_exit(status); + break; case HS_RUNNING: - return handle_rsync_exit(status); + ret = handle_rsync_exit(status); + break; case HS_POST_RUNNING: snapshot_creation_status = HS_READY; - return 1; + ret = 1; + break; default: DSS_EMERG_LOG("BUG: create can't die in status %d\n", snapshot_creation_status); return -E_BUG; } create_pid = 0; + return ret; } if (pid == remove_pid) { ret = handle_remove_exit(status); @@ -901,24 +983,16 @@ static int change_to_dest_dir(void) return dss_chdir(conf.dest_dir_arg); } -static void dump_dss_config(const char *msg) -{ - if (conf.loglevel_arg > INFO) - return; - DSS_INFO_LOG("%s\n", msg); - cmdline_parser_dump(logfile? logfile : stderr, &conf); -} - static int handle_sighup(void) { int ret; DSS_NOTICE_LOG("SIGHUP, re-reading config\n"); - dump_dss_config("current config"); + dump_dss_config("old"); ret = parse_config_file(1); if (ret < 0) return ret; - dump_dss_config("new config"); + dump_dss_config("reloaded"); invalidate_next_snapshot_time(); return change_to_dest_dir(); } @@ -934,8 +1008,8 @@ static int handle_signal(void) case SIGINT: case SIGTERM: restart_create_process(); - kill_process(create_pid); - kill_process(remove_pid); + dss_kill(create_pid, SIGTERM, NULL); + dss_kill(remove_pid, SIGTERM, NULL); ret = -E_SIGNAL; break; case SIGHUP: @@ -1075,7 +1149,6 @@ static int select_loop(void) } 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) goto out; @@ -1119,9 +1192,14 @@ static int select_loop(void) case HS_POST_RUNNING: continue; case HS_PRE_SUCCESS: - free_rsync_argv(rsync_argv); - create_rsync_argv(&rsync_argv, ¤t_snapshot_creation_time); - /* fall through */ + 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; @@ -1146,8 +1224,6 @@ static void exit_hook(int exit_code) char *argv[] = {conf.exit_hook_arg, dss_strerror(-exit_code), NULL}; pid_t pid; - if (!conf.exit_hook_given) - return; DSS_NOTICE_LOG("executing %s %s\n", argv[0], argv[1]); dss_exec(&pid, conf.exit_hook_arg, argv, fds); } @@ -1350,10 +1426,10 @@ int main(int argc, char **argv) } if (conf.daemon_given) daemon_init(); - dump_dss_config("dss configuration"); ret = change_to_dest_dir(); if (ret < 0) goto out; + dump_dss_config("startup"); ret = setup_signal_handling(); if (ret < 0) goto out;