redmine

Added support of signal 29 (to dump by signal)

... ... @@ -72,5 +72,5 @@
#define API_PREFIX "clsyncapi_"
#define DUMP_DIRMODE 0700
#define DUMP_DIRMODE 0750
#define DUMP_FILEMODE 0644
... ...
... ... @@ -41,193 +41,17 @@ static inline int control_error(clsyncsock_t *clsyncsock_p, const char *const fu
return socket_send(clsyncsock_p, SOCKCMD_REPLY_ECUSTOM, funct, args, errno, strerror(errno));
}
enum dump_dirfd_obj {
DUMP_DIRFD_ROOT = 0,
DUMP_DIRFD_QUEUE,
DUMP_DIRFD_THREAD,
DUMP_DIRFD_MAX
};
enum dump_ltype {
DUMP_LTYPE_INCLUDE,
DUMP_LTYPE_EXCLUDE,
DUMP_LTYPE_EVINFO,
};
struct control_dump_arg {
clsyncsock_t *clsyncsock_p;
ctx_t *ctx_p;
int dirfd[DUMP_DIRFD_MAX];
int fd_out;
int data;
};
void control_dump_liststep(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp) {
char *fpath = (char *)fpath_gp;
eventinfo_t *evinfo = (eventinfo_t *)evinfo_gp;
struct control_dump_arg *arg = arg_gp;
char act, num;
switch (arg->data) {
case DUMP_LTYPE_INCLUDE:
act = '+';
num = '1';
break;
case DUMP_LTYPE_EXCLUDE:
act = '-';
num = '1';
break;
case DUMP_LTYPE_EVINFO:
act = '+';
num = evinfo->flags&EVIF_RECURSIVELY ? '*' :
(evinfo->flags&EVIF_CONTENTRECURSIVELY ? '/' : '1');
break;
default:
act = '?';
num = '?';
}
dprintf(arg->fd_out, "%c%c\t%s\n", act, num, fpath);
return;
}
int control_dump_thread(threadinfo_t *threadinfo_p, void *_arg) {
struct control_dump_arg *arg = _arg;
char buf[BUFSIZ];
snprintf(buf, BUFSIZ, "%u-%u-%lx", threadinfo_p->iteration, threadinfo_p->thread_num, (long)threadinfo_p->pthread);
arg->fd_out = openat(arg->dirfd[DUMP_DIRFD_THREAD], buf, O_WRONLY|O_CREAT, DUMP_FILEMODE);
if (arg->fd_out == -1) {
control_error(arg->clsyncsock_p, "openat", "buf");
return errno;
}
{
char **argv;
dprintf(arg->fd_out,
"thread:\n\titeration == %u\n\tnum == %u\n\tpthread == %lx\n\tstarttime == %lu\n\texpiretime == %lu\n\tchild_pid == %u\n\ttry_n == %u\nCommand:",
threadinfo_p->iteration,
threadinfo_p->thread_num,
(long)threadinfo_p->pthread,
threadinfo_p->starttime,
threadinfo_p->expiretime,
threadinfo_p->child_pid,
threadinfo_p->try_n
);
argv = threadinfo_p->argv;
while (*argv != NULL)
dprintf(arg->fd_out, " \"%s\"", *(argv++));
dprintf(arg->fd_out, "\n");
}
arg->data = DUMP_LTYPE_EVINFO;
g_hash_table_foreach(threadinfo_p->fpath2ei_ht, control_dump_liststep, arg);
close(arg->fd_out);
return 0;
}
int control_mkdir_open(clsyncsock_t *clsyncsock_p, const char *const dir_path, int dirfd_parent) {
int dirfd;
debug(4, "mkdirat(%u, \"%s\", %o)", dirfd_parent, dir_path, DUMP_DIRMODE);
if (mkdirat(dirfd_parent, dir_path, DUMP_DIRMODE)) {
control_error(clsyncsock_p, "mkdir", dir_path);
return -1;
}
debug(4, "openat(%u, \"%s\", %x)", dirfd_parent, dir_path, O_RDWR|O_DIRECTORY|O_PATH);
dirfd = openat(dirfd_parent, dir_path, O_RDWR|O_DIRECTORY|O_PATH);
if (dirfd == -1) {
control_error(clsyncsock_p, "openat", dir_path);
return -1;
}
return dirfd;
}
int control_dump(ctx_t *ctx_p, clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p) {
indexes_t *indexes_p = ctx_p->indexes_p;
sockcmd_dat_dump_t *dat = sockcmd_p->data;
int rootfd, fd_out;
struct control_dump_arg arg;
enum dump_dirfd_obj dirfd_obj;
debug(3, "%s", dat->dir_path);
static const char *const subdirs[] = {
[DUMP_DIRFD_QUEUE] = "queue",
[DUMP_DIRFD_THREAD] = "threads"
};
rootfd = control_mkdir_open(clsyncsock_p, dat->dir_path, AT_FDCWD);
if (rootfd == -1)
goto l_control_dump_end;
fd_out = openat(rootfd, "instance", O_WRONLY|O_CREAT, DUMP_FILEMODE);
if (fd_out == -1) {
control_error(clsyncsock_p, "openat", "instance");
goto l_control_dump_end;
}
dprintf(fd_out, "status == %s\n", getenv("CLSYNC_STATUS"));
close(fd_out);
arg.dirfd[DUMP_DIRFD_ROOT] = rootfd;
dirfd_obj = DUMP_DIRFD_ROOT+1;
while (dirfd_obj < DUMP_DIRFD_MAX) {
const char *const subdir = subdirs[dirfd_obj];
arg.dirfd[dirfd_obj] = control_mkdir_open(clsyncsock_p, subdir, rootfd);
if (arg.dirfd[dirfd_obj] == -1)
goto l_control_dump_end;
dirfd_obj++;
}
arg.clsyncsock_p = clsyncsock_p;
arg.ctx_p = ctx_p;
int queue_id = 0;
while (queue_id < QUEUE_MAX) {
char buf[BUFSIZ];
snprintf(buf, BUFSIZ, "%u", queue_id);
arg.fd_out = openat(arg.dirfd[DUMP_DIRFD_QUEUE], buf, O_WRONLY|O_CREAT, DUMP_FILEMODE);
arg.data = DUMP_LTYPE_EVINFO;
g_hash_table_foreach(indexes_p->fpath2ei_coll_ht[queue_id], control_dump_liststep, &arg);
if (indexes_p->exc_fpath_coll_ht[queue_id] != NULL) {
arg.data = DUMP_LTYPE_EXCLUDE;
g_hash_table_foreach(indexes_p->exc_fpath_coll_ht[queue_id], control_dump_liststep, &arg);
}
close(arg.fd_out);
queue_id++;
}
threads_foreach(control_dump_thread, STATE_RUNNING, &arg);
l_control_dump_end:
dirfd_obj = DUMP_DIRFD_ROOT;
while (dirfd_obj < DUMP_DIRFD_MAX) {
if (arg.dirfd[dirfd_obj] != -1)
close(arg.dirfd[dirfd_obj]);
dirfd_obj++;
}
debug(3, "%s", dat->dir_path);
return errno ? errno : socket_send(clsyncsock_p, SOCKCMD_REPLY_DUMP);
return (sync_dump(ctx_p, dat->dir_path)) ?
control_error(clsyncsock_p, "sync_dump", dat->dir_path) :
socket_send(clsyncsock_p, SOCKCMD_REPLY_DUMP);
}
int control_procclsyncsock(socket_sockthreaddata_t *arg, sockcmd_t *sockcmd_p) {
int rc;
clsyncsock_t *clsyncsock_p = arg->clsyncsock_p;
... ...
... ... @@ -96,6 +96,8 @@ enum flags_enum {
MAXITERATIONS = 15|OPTION_LONGOPTONLY,
IGNOREFAILURES = 16|OPTION_LONGOPTONLY,
DUMPDIR = 17|OPTION_LONGOPTONLY,
};
typedef enum flags_enum flags_t;
... ... @@ -139,7 +141,8 @@ typedef enum ruleaction_enum ruleaction_t;
enum sigusr_enum {
SIGUSR_THREAD_GC = 10,
SIGUSR_INITSYNC = 12,
SIGUSR_BLOPINT = 16
SIGUSR_BLOPINT = 16,
SIGUSR_DUMP = 29,
};
struct rule {
... ... @@ -191,6 +194,7 @@ struct ctx {
char *destdirwslash;
char *statusfile;
char *socketpath;
char *dump_path;
int socket;
mode_t socketmod;
uid_t socketuid;
... ...
... ... @@ -152,4 +152,29 @@ short int fileutils_calcdirlevel(const char *path) {
return dirlevel;
}
/**
* @brief Combination of mkdirat() and openat()
*
* @param[in] dir_path Path to directory to create and open
@ @param[in] dirfd_parent File descriptor of directory for relative paths
@ @param[in] dir_mode Modes for newly created directory (e.g. 750)
*
* @retval dirfd File descriptor to newly created directory
* @retval NULL On error
*
*/
int mkdirat_open(const char *const dir_path, int dirfd_parent, mode_t dir_mode) {
int dirfd;
debug(5, "mkdirat(%u, \"%s\", %o)", dirfd_parent, dir_path, dir_mode);
if (mkdirat(dirfd_parent, dir_path, dir_mode))
return -1;
debug(5, "openat(%u, \"%s\", %x)", dirfd_parent, dir_path, O_RDWR|O_DIRECTORY|O_PATH);
dirfd = openat(dirfd_parent, dir_path, O_RDWR|O_DIRECTORY|O_PATH);
if (dirfd == -1)
return -1;
return dirfd;
}
... ...
... ... @@ -21,4 +21,5 @@ extern char *fd2fpath_malloc(int fd);
extern int fileutils_copy(const char *path_from, const char *path_to);
extern short int fileutils_calcdirlevel(const char *path);
extern int mkdirat_open(const char *const dir_path, int dirfd_parent, mode_t dir_mode);
... ...
... ... @@ -92,6 +92,7 @@ static const struct option long_options[] =
{"exit-hook", required_argument, NULL, EXITHOOK},
{"verbose", optional_argument, NULL, VERBOSE},
{"debug", optional_argument, NULL, DEBUG},
{"dump-dir", required_argument, NULL, DUMPDIR},
{"quiet", optional_argument, NULL, QUIET},
#ifdef FANOTIFY_SUPPORT
{"fanotify", optional_argument, NULL, FANOTIFY},
... ... @@ -574,6 +575,9 @@ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t pa
case STATUSFILE:
ctx_p->statusfile = arg;
break;
case DUMPDIR:
ctx_p->dump_path = arg;
break;
case MODE: {
char *value;
... ...
... ... @@ -806,6 +806,16 @@ Is not set by default.
.RE
.PP
.B \-\-dump\-dir
.RS 8
Directory to write clsync's instance information by signal 29 (see
.BR SIGNALS ")."
The directory shouldn't exists before dumping.
Is set to "/tmp/clsync-dump-%label%" by default.
.RE
.PP
.B \-q, \-\-quiet
.RS 8
Suppresses error messages.
... ... @@ -1300,6 +1310,9 @@ Syncing /srv/lxc tree (rsync case):
16 \- interrupts sleep()/select() and wait() [for debugging and internal uses]
29 \- dump information to
.IR dump-dir
[for debugging]
.SH DIAGNOSTICS
... ...
... ... @@ -3258,11 +3258,183 @@ l_sync_parent_interrupt_end:
return thread_info_unlock(0);
}
/* === DUMP === */
enum dump_dirfd_obj {
DUMP_DIRFD_ROOT = 0,
DUMP_DIRFD_QUEUE,
DUMP_DIRFD_THREAD,
DUMP_DIRFD_MAX
};
enum dump_ltype {
DUMP_LTYPE_INCLUDE,
DUMP_LTYPE_EXCLUDE,
DUMP_LTYPE_EVINFO,
};
struct sync_dump_arg {
ctx_t *ctx_p;
int dirfd[DUMP_DIRFD_MAX];
int fd_out;
int data;
};
void sync_dump_liststep(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp) {
char *fpath = (char *)fpath_gp;
eventinfo_t *evinfo = (eventinfo_t *)evinfo_gp;
struct sync_dump_arg *arg = arg_gp;
char act, num;
switch (arg->data) {
case DUMP_LTYPE_INCLUDE:
act = '+';
num = '1';
break;
case DUMP_LTYPE_EXCLUDE:
act = '-';
num = '1';
break;
case DUMP_LTYPE_EVINFO:
act = '+';
num = evinfo->flags&EVIF_RECURSIVELY ? '*' :
(evinfo->flags&EVIF_CONTENTRECURSIVELY ? '/' : '1');
break;
default:
act = '?';
num = '?';
}
dprintf(arg->fd_out, "%c%c\t%s\n", act, num, fpath);
return;
}
int sync_dump_thread(threadinfo_t *threadinfo_p, void *_arg) {
struct sync_dump_arg *arg = _arg;
char buf[BUFSIZ];
snprintf(buf, BUFSIZ, "%u-%u-%lx", threadinfo_p->iteration, threadinfo_p->thread_num, (long)threadinfo_p->pthread);
arg->fd_out = openat(arg->dirfd[DUMP_DIRFD_THREAD], buf, O_WRONLY|O_CREAT, DUMP_FILEMODE);
if (arg->fd_out == -1)
return errno;
{
char **argv;
dprintf(arg->fd_out,
"thread:\n\titeration == %u\n\tnum == %u\n\tpthread == %lx\n\tstarttime == %lu\n\texpiretime == %lu\n\tchild_pid == %u\n\ttry_n == %u\nCommand:",
threadinfo_p->iteration,
threadinfo_p->thread_num,
(long)threadinfo_p->pthread,
threadinfo_p->starttime,
threadinfo_p->expiretime,
threadinfo_p->child_pid,
threadinfo_p->try_n
);
argv = threadinfo_p->argv;
while (*argv != NULL)
dprintf(arg->fd_out, " \"%s\"", *(argv++));
dprintf(arg->fd_out, "\n");
}
arg->data = DUMP_LTYPE_EVINFO;
g_hash_table_foreach(threadinfo_p->fpath2ei_ht, sync_dump_liststep, arg);
close(arg->fd_out);
return 0;
}
int sync_dump(ctx_t *ctx_p, const char *const dir_path) {
indexes_t *indexes_p = ctx_p->indexes_p;
int rootfd, fd_out;
struct sync_dump_arg arg;
enum dump_dirfd_obj dirfd_obj;
debug(3, "%s", dir_path);
if (dir_path == NULL)
return EINVAL;
static const char *const subdirs[] = {
[DUMP_DIRFD_QUEUE] = "queue",
[DUMP_DIRFD_THREAD] = "threads"
};
rootfd = mkdirat_open(dir_path, AT_FDCWD, DUMP_DIRMODE);
if (rootfd == -1)
goto l_sync_dump_end;
fd_out = openat(rootfd, "instance", O_WRONLY|O_CREAT, DUMP_FILEMODE);
if (fd_out == -1)
goto l_sync_dump_end;
dprintf(fd_out, "status == %s\n", getenv("CLSYNC_STATUS")); // TODO: remove getenv() from here
close(fd_out);
arg.dirfd[DUMP_DIRFD_ROOT] = rootfd;
dirfd_obj = DUMP_DIRFD_ROOT+1;
while (dirfd_obj < DUMP_DIRFD_MAX) {
const char *const subdir = subdirs[dirfd_obj];
arg.dirfd[dirfd_obj] = mkdirat_open(subdir, rootfd, DUMP_DIRMODE);
if (arg.dirfd[dirfd_obj] == -1)
goto l_sync_dump_end;
dirfd_obj++;
}
arg.ctx_p = ctx_p;
int queue_id = 0;
while (queue_id < QUEUE_MAX) {
char buf[BUFSIZ];
snprintf(buf, BUFSIZ, "%u", queue_id);
arg.fd_out = openat(arg.dirfd[DUMP_DIRFD_QUEUE], buf, O_WRONLY|O_CREAT, DUMP_FILEMODE);
arg.data = DUMP_LTYPE_EVINFO;
g_hash_table_foreach(indexes_p->fpath2ei_coll_ht[queue_id], sync_dump_liststep, &arg);
if (indexes_p->exc_fpath_coll_ht[queue_id] != NULL) {
arg.data = DUMP_LTYPE_EXCLUDE;
g_hash_table_foreach(indexes_p->exc_fpath_coll_ht[queue_id], sync_dump_liststep, &arg);
}
close(arg.fd_out);
queue_id++;
}
threads_foreach(sync_dump_thread, STATE_RUNNING, &arg);
l_sync_dump_end:
dirfd_obj = DUMP_DIRFD_ROOT;
while (dirfd_obj < DUMP_DIRFD_MAX) {
if (arg.dirfd[dirfd_obj] != -1)
close(arg.dirfd[dirfd_obj]);
dirfd_obj++;
}
if (errno)
error("Cannot create the dump to \"%s\"", dir_path);
return errno;
}
/* === /DUMP === */
int *sync_sighandler_exitcode_p = NULL;
int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
int signal, ret;
ctx_t *ctx_p = sighandler_arg_p->ctx_p;
// indexes_t *indexes_p = sighandler_arg_p->indexes_p;
ctx_t *ctx_p = sighandler_arg_p->ctx_p;
// indexes_t *indexes_p = sighandler_arg_p->indexes_p;
pthread_t pthread_parent = sighandler_arg_p->pthread_parent;
sigset_t *sigset_p = sighandler_arg_p->sigset_p;
int *exitcode_p = sighandler_arg_p->exitcode_p;
... ... @@ -3335,6 +3507,9 @@ int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
case SIGUSR_INITSYNC:
sync_switch_state(pthread_parent, STATE_INITSYNC);
break;
case SIGUSR_DUMP:
sync_dump(ctx_p, ctx_p->dump_path);
break;
default:
error("Unknown signal: %i. Exit.", signal);
sync_switch_state(pthread_parent, STATE_TERM);
... ... @@ -3368,6 +3543,7 @@ int sync_run(ctx_t *ctx_p) {
sigaddset(&sigset_sighandler, SIGINT);
sigaddset(&sigset_sighandler, SIGUSR_THREAD_GC);
sigaddset(&sigset_sighandler, SIGUSR_INITSYNC);
sigaddset(&sigset_sighandler, SIGUSR_DUMP);
ret = pthread_sigmask(SIG_BLOCK, &sigset_sighandler, NULL);
if (ret) return ret;
... ...
... ... @@ -18,6 +18,7 @@
*/
extern int sync_run(struct ctx *ctx);
extern int sync_dump(struct ctx *ctx, const char *const dest_dir);
extern int sync_term(int exitcode);
extern int threads_foreach(int (*funct)(threadinfo_t *, void *), state_t state, void *arg);
... ...