X-Git-Url: http://git.tuebingen.mpg.de/?p=dss.git;a=blobdiff_plain;f=dss.c;h=8f632cbea50ce34ef91c041e944f17c77db6b8cd;hp=366f6e222ed4880e8fcde7752eac2bea5ffa9927;hb=bdeadb123f2930a6a927e2941f5314d3fda7268f;hpb=f38f86c1d4695a7016d5002e979c4f68ed12fb69 diff --git a/dss.c b/dss.c index 366f6e2..8f632cb 100644 --- a/dss.c +++ b/dss.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2008-2011 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include @@ -63,6 +59,8 @@ static struct lls_parse_result *cmdline_lpr, *lpr; /** Parsed subcommand options. */ static struct lls_parse_result *cmdline_sublpr, *sublpr; +/* The executing subcommand (NULL at startup). */ +static const struct lls_command *subcmd; /** Wether daemon_init() was called. */ static bool daemonized; /** Non-NULL if we log to a file. */ @@ -160,7 +158,7 @@ static void dump_dss_config(const char *msg) fprintf(log, "\n*** internal state ***\n\n"); fprintf(log, "pid: %d\n" - "logile: %s\n" + "logfile: %s\n" "snapshot_currently_being_removed: %s\n" "path_to_last_complete_snapshot: %s\n" "reference_snapshot: %s\n" @@ -242,16 +240,19 @@ __printf_1_2 void dss_log(const char* fmt,...) if (loglevel < lpr_ll) return; outfd = logfile? logfile : stderr; - time(&t1); - tm = localtime(&t1); - strftime(str, sizeof(str), "%b %d %H:%M:%S", tm); - fprintf(outfd, "%s ", str); - if (lpr_ll <= INFO) - fprintf(outfd, "%i: ", loglevel); + if (subcmd == CMD_PTR(RUN)) { + time(&t1); + tm = localtime(&t1); + strftime(str, sizeof(str), "%b %d %H:%M:%S", tm); + fprintf(outfd, "%s ", str); + if (lpr_ll <= INFO) + fprintf(outfd, "%i: ", loglevel); + } + if (subcmd == CMD_PTR(RUN)) #ifdef DSS_NO_FUNC_NAMES - fprintf(outfd, "%s:%d: ", location_file, location_line); + fprintf(outfd, "%s:%d: ", location_file, location_line); #else - fprintf(outfd, "%s: ", location_func); + fprintf(outfd, "%s: ", location_func); #endif va_start(argp, fmt); vfprintf(outfd, fmt, argp); @@ -282,11 +283,13 @@ static char *get_config_file_name(void) return config_file; } -static int send_signal(int sig) +static int send_signal(int sig, bool wait) { pid_t pid; char *config_file = get_config_file_name(); int ret = get_dss_pid(config_file, &pid); + unsigned ms = 32; + struct timespec ts; free(config_file); if (ret < 0) @@ -295,10 +298,27 @@ static int send_signal(int sig) dss_msg("%d\n", (int)pid); return 0; } + DSS_NOTICE_LOG(("sending signal %d to pid %d\n", sig, (int)pid)); ret = kill(pid, sig); if (ret < 0) return -ERRNO_TO_DSS_ERROR(errno); - return 1; + if (!wait) + return 1; + while (ms < 5000) { + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000 * 1000; + ret = nanosleep(&ts, NULL); + if (ret < 0) + return -ERRNO_TO_DSS_ERROR(errno); + ret = kill(pid, 0); + if (ret < 0) { + if (errno != ESRCH) + return -ERRNO_TO_DSS_ERROR(errno); + return 1; + } + ms *= 2; + } + return -E_KILL_TIMEOUT; } struct signal_info { @@ -357,6 +377,7 @@ static const struct signal_info signal_table[] = { static int com_kill(void) { + bool w_given = OPT_GIVEN(KILL, WAIT); const char *arg = OPT_STRING_VAL(KILL, SIGNAL); int ret, i; @@ -367,17 +388,17 @@ static int com_kill(void) return ret; if (val < 0 || val > SIGRTMAX) return -ERRNO_TO_DSS_ERROR(EINVAL); - return send_signal(val); + return send_signal(val, w_given); } if (strncasecmp(arg, "sig", 3) == 0) arg += 3; if (strcasecmp(arg, "CLD") == 0) - return send_signal(SIGCHLD); + return send_signal(SIGCHLD, w_given); if (strcasecmp(arg, "IOT") == 0) - return send_signal(SIGABRT); + return send_signal(SIGABRT, w_given); for (i = 0; i < SIGNAL_TABLE_SIZE; i++) if (strcasecmp(arg, signal_table[i].name) == 0) - return send_signal(signal_table[i].num); + return send_signal(signal_table[i].num, w_given); DSS_ERROR_LOG(("invalid sigspec: %s\n", arg)); return -ERRNO_TO_DSS_ERROR(EINVAL); } @@ -392,7 +413,8 @@ static void dss_get_snapshot_list(struct snapshot_list *sl) static int64_t compute_next_snapshot_time(void) { int64_t x = 0, now = get_current_time(), unit_interval - = 24 * 3600 * OPT_UINT32_VAL(DSS, UNIT_INTERVAL), ret; + = 24 * 3600 * OPT_UINT32_VAL(DSS, UNIT_INTERVAL), ret, + last_completion_time; unsigned wanted = desired_number_of_snapshots(0, OPT_UINT32_VAL(DSS, NUM_INTERVALS)), num_complete = 0; @@ -406,6 +428,7 @@ static int64_t compute_next_snapshot_time(void) continue; num_complete++; x += s->completion_time - s->creation_time; + last_completion_time = s->completion_time; } assert(x >= 0); @@ -415,7 +438,7 @@ static int64_t compute_next_snapshot_time(void) x /= num_complete; /* avg time to create one snapshot */ if (unit_interval < x * wanted) /* oops, no sleep at all */ goto out; - ret = s->completion_time + unit_interval / wanted - x; + ret = last_completion_time + unit_interval / wanted - x; out: free_snapshot_list(&sl); return ret; @@ -515,7 +538,7 @@ static struct snapshot *find_orphaned_snapshot(struct snapshot_list *sl) struct snapshot *s; int i; - DSS_DEBUG_LOG(("looking for orphaned snapshots\n")); + DSS_DEBUG_LOG(("looking for old incomplete snapshots\n")); FOR_EACH_SNAPSHOT(s, i, sl) { if (snapshot_is_being_created(s)) continue; @@ -729,6 +752,7 @@ static int try_to_free_disk_space(void) if (!low_disk_space) goto out; DSS_WARNING_LOG(("disk space low and nothing obvious to remove\n")); + why = "oldest"; victim = find_oldest_removable_snapshot(&sl); if (victim) goto remove; @@ -1053,20 +1077,39 @@ static int handle_sigchld(void) return -E_BUG; } +/* also checks if . is a mountpoint, if --mountpoint was given */ static int change_to_dest_dir(void) { int ret; const char *dd = OPT_STRING_VAL(DSS, DEST_DIR); + struct stat dot, dotdot; DSS_INFO_LOG(("changing cwd to %s\n", dd)); - if (chdir(dd) >= 0) - return 1; - ret = -ERRNO_TO_DSS_ERROR(errno); - DSS_ERROR_LOG(("could not change cwd to %s\n", dd)); - return ret; + if (chdir(dd) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + DSS_ERROR_LOG(("could not change cwd to %s\n", dd)); + return ret; + } + if (!OPT_GIVEN(DSS, MOUNTPOINT)) + return 0; + if (stat(".", &dot) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + DSS_ERROR_LOG(("could not stat .\n")); + return ret; + } + if (stat("..", &dotdot) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + DSS_ERROR_LOG(("could not stat ..\n")); + return ret; + } + if (dot.st_dev == dotdot.st_dev && dot.st_ino != dotdot.st_ino) { + DSS_ERROR_LOG(("mountpoint check failed for %s\n", dd)); + return -E_MOUNTPOINT; + } + return 1; } -static int check_config(const struct lls_command *cmd) +static int check_config(void) { int ret; uint32_t unit_interval = OPT_UINT32_VAL(DSS, UNIT_INTERVAL); @@ -1082,13 +1125,13 @@ static int check_config(const struct lls_command *cmd) DSS_ERROR_LOG(("bad number of intervals: %i\n", num_intervals)); return -E_INVALID_NUMBER; } - if (cmd == CMD_PTR(RUN) || cmd == CMD_PTR(CREATE)) + if (subcmd == CMD_PTR(RUN) || subcmd == CMD_PTR(CREATE)) if (!OPT_GIVEN(DSS, SOURCE_DIR)) { DSS_ERROR_LOG(("--source-dir required\n")); return -E_SYNTAX; } - if (cmd == CMD_PTR(RUN) || cmd == CMD_PTR(CREATE) - || cmd == CMD_PTR(LS) || cmd == CMD_PTR(PRUNE)) { + if (subcmd == CMD_PTR(RUN) || subcmd == CMD_PTR(CREATE) + || subcmd == CMD_PTR(LS) || subcmd == CMD_PTR(PRUNE)) { if (!OPT_GIVEN(DSS, DEST_DIR)) { DSS_ERROR_LOG(("--dest-dir required\n")); return -E_SYNTAX; @@ -1226,7 +1269,7 @@ static int handle_sighup(void) ret = parse_config_file(true /* SIGHUP */, CMD_PTR(RUN)); if (ret < 0) return ret; - ret = check_config(CMD_PTR(RUN)); + ret = check_config(); if (ret < 0) return ret; close_log(logfile); @@ -1258,9 +1301,7 @@ static int handle_signal(void) switch (sig) { case SIGINT: case SIGTERM: - kill_children(); - ret = -E_SIGNAL; - break; + return -E_SIGNAL; case SIGHUP: ret = handle_sighup(); break; @@ -1407,6 +1448,7 @@ static int create_snapshot(char **argv) { int ret; + assert(argv); ret = rename_resume_snap(current_snapshot_creation_time); if (ret < 0) return ret; @@ -1500,15 +1542,18 @@ out: static void exit_hook(int exit_code) { - const char *argv[3]; pid_t pid; - - argv[0] = OPT_STRING_VAL(DSS, EXIT_HOOK); - argv[1] = dss_strerror(-exit_code); - argv[2] = NULL; - - DSS_NOTICE_LOG(("executing %s %s\n", argv[0], argv[1])); - dss_exec(&pid, argv[0], (char **)argv); + char **argv, *tmp = dss_strdup(OPT_STRING_VAL(DSS, EXIT_HOOK)); + unsigned n = split_args(tmp, &argv, " \t"); + + n++; + argv = dss_realloc(argv, (n + 1) * sizeof(char *)); + argv[n - 1] = dss_strdup(dss_strerror(-exit_code)); + argv[n] = NULL; + dss_exec(&pid, argv[0], argv); + free(argv[n - 1]); + free(argv); + free(tmp); } static void lock_dss_or_die(void) @@ -1565,6 +1610,8 @@ static int com_run(void) ret = -E_BUG; kill_children(); exit_hook(ret); + while (wait(NULL) >= 0 || errno != ECHILD) + ; /* still have children to wait for */ return ret; } EXPORT_CMD_HANDLER(run); @@ -1683,19 +1730,30 @@ static int com_ls(void) int i; struct snapshot_list sl; struct snapshot *s; + int64_t now = get_current_time(); dss_get_snapshot_list(&sl); FOR_EACH_SNAPSHOT(s, i, &sl) { - int64_t d = 0; + int64_t d; 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); + else + d = (now - 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; } EXPORT_CMD_HANDLER(ls); +static int com_configtest(void) +{ + printf("Syntax Ok\n"); + return 0; +} +EXPORT_CMD_HANDLER(configtest); + static int setup_signal_handling(void) { int ret; @@ -1720,7 +1778,7 @@ static void handle_version_and_help(void) else if (OPT_GIVEN(DSS, HELP)) txt = lls_short_help(CMD_PTR(DSS)); else if (OPT_GIVEN(DSS, VERSION)) - txt = dss_strdup(VERSION_STRING); + txt = make_message("%s\n", VERSION_STRING); else return; printf("%s", txt); @@ -1737,7 +1795,7 @@ static void show_subcommand_summary(void) for (i = 1; (cmd = lls_cmd(i, dss_suite)); i++) { const char *name = lls_command_name(cmd); const char *purpose = lls_purpose(cmd); - printf("%-10s%s\n", name, purpose); + printf("%-11s%s\n", name, purpose); } exit(EXIT_SUCCESS); } @@ -1745,18 +1803,17 @@ static void show_subcommand_summary(void) int main(int argc, char **argv) { int ret; - const struct lls_command *cmd = CMD_PTR(DSS); char *errctx = NULL; unsigned num_inputs; const struct dss_user_data *ud; - ret = lls_parse(argc, argv, cmd, &cmdline_lpr, &errctx); + ret = lls_parse(argc, argv, CMD_PTR(DSS), &cmdline_lpr, &errctx); if (ret < 0) { ret = lopsub_error(ret, &errctx); goto out; } lpr = cmdline_lpr; - ret = parse_config_file(false /* no SIGHUP */, cmd); + ret = parse_config_file(false /* no SIGHUP */, CMD_PTR(DSS)); if (ret < 0) goto out; handle_version_and_help(); @@ -1768,24 +1825,24 @@ int main(int argc, char **argv) ret = lopsub_error(ret, &errctx); goto out; } - cmd = lls_cmd(ret, dss_suite); - ret = lls_parse(num_inputs, argv + argc - num_inputs, cmd, + subcmd = lls_cmd(ret, dss_suite); + ret = lls_parse(num_inputs, argv + argc - num_inputs, subcmd, &cmdline_sublpr, &errctx); if (ret < 0) { ret = lopsub_error(ret, &errctx); goto out; } sublpr = cmdline_sublpr; - ret = parse_config_file(false /* no SIGHUP */, cmd); + ret = parse_config_file(false /* no SIGHUP */, subcmd); if (ret < 0) goto out; - ret = check_config(cmd); + ret = check_config(); if (ret < 0) goto out; ret = setup_signal_handling(); if (ret < 0) goto out; - ud = lls_user_data(cmd); + ud = lls_user_data(subcmd); ret = ud->handler(); signal_shutdown(); out: @@ -1798,8 +1855,8 @@ out: lls_free_parse_result(lpr, CMD_PTR(DSS)); if (lpr != cmdline_lpr) lls_free_parse_result(cmdline_lpr, CMD_PTR(DSS)); - lls_free_parse_result(sublpr, cmd); + lls_free_parse_result(sublpr, subcmd); if (sublpr != cmdline_sublpr) - lls_free_parse_result(cmdline_sublpr, cmd); + lls_free_parse_result(cmdline_sublpr, subcmd); exit(ret >= 0? EXIT_SUCCESS : EXIT_FAILURE); }