-/*
- * Copyright (C) 2008-2011 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* SPDX-License-Identifier: GPL-2.0 */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
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)
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 {
static int com_kill(void)
{
+ bool w_given = OPT_GIVEN(KILL, WAIT);
const char *arg = OPT_STRING_VAL(KILL, SIGNAL);
int ret, i;
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);
}
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(void)
{
int ret;
+ assert(argv);
ret = rename_resume_snap(current_snapshot_creation_time);
if (ret < 0)
return ret;
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)
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);
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;