redmine

Unified output facility

Related: https://github.com/xaionaro/clsync/issues/31
bin_PROGRAMS = clsync
clsync_SOURCES = sync.c cluster.c main.c output.c fileutils.c malloc.c glibex.c
clsync_SOURCES = sync.c cluster.c main.c error.c fileutils.c malloc.c glibex.c
clsync_CFLAGS = $(AM_CFLAGS)
if SOCKET
... ... @@ -39,8 +39,8 @@ clsync_include_HEADERS = \
clsync.h \
malloc.h \
indexes.h \
options.h \
output.h \
glob.h \
error.h \
socket.h \
libclsync.h
... ...
... ... @@ -41,9 +41,9 @@ struct api_eventinfo {
};
typedef struct api_eventinfo api_eventinfo_t;
struct options;
struct glob;
struct indexes;
typedef int(*api_funct_init) (struct options *, struct indexes *);
typedef int(*api_funct_init) (struct glob *, struct indexes *);
typedef int(*api_funct_sync) (int n, api_eventinfo_t *);
typedef int(*api_funct_rsync) (const char *inclist, const char *exclist);
typedef int(*api_funct_deinit)();
... ... @@ -80,12 +80,12 @@ extern int clsyncapi_getapiversion();
/**
* @brief clsync's wrapper for function "fork()". Should be used instead of "fork()" directly, to notify clsync about child's pid.
*
* @param[in] options_p Pointer to "options"
* @param[in] glob_p Pointer to "glob"
*
* @retval -1 If error (see "man 2 fork", added error code "ECANCELED" if too many children)
* @retval 0 If child
* @retval pid Pid of child of parent. (see "man 2 fork")
*
*/
extern pid_t clsyncapi_fork(struct options *options_p);
extern pid_t clsyncapi_fork(struct glob *glob_p);
... ...
This diff is collapsed. Click to expand it.
... ... @@ -69,7 +69,7 @@
#endif
#include "clsync.h"
#include "options.h"
#include "glob.h"
#include "indexes.h"
#ifndef MIN
... ... @@ -96,6 +96,23 @@
#define PARANOIDV(...)
#endif
#ifdef _GNU_SOURCE
# ifndef likely
# define likely(x) __builtin_expect(!!(x), 1)
# endif
# ifndef unlikely
# define unlikely(x) __builtin_expect(!!(x), 0)
# endif
#else
# ifndef likely
# define likely(x) (x)
# endif
# ifndef unlikely
# define unlikely(x) (x)
# endif
#endif
#define TOSTR(a) # a
#define XTOSTR(a) TOSTR(a)
... ... @@ -155,7 +172,7 @@ struct eventinfo {
typedef struct eventinfo eventinfo_t;
typedef int (*thread_callbackfunct_t)(options_t *options_p, char **argv);
typedef int (*thread_callbackfunct_t)(glob_t *glob_p, char **argv);
struct threadinfo {
int thread_num;
thread_callbackfunct_t callback;
... ... @@ -164,7 +181,7 @@ struct threadinfo {
int exitcode;
int errcode;
state_t state;
options_t *options_p;
glob_t *glob_p;
time_t starttime;
time_t expiretime;
int child_pid;
... ... @@ -202,7 +219,7 @@ struct dosync_arg {
char excf_path[PATH_MAX+1];
char outf_path[PATH_MAX+1];
FILE *outf;
options_t *options_p;
glob_t *glob_p;
indexes_t *indexes_p;
void *data;
int linescount;
... ... @@ -248,7 +265,7 @@ enum initsync {
typedef enum initsync initsync_t;
struct sighandler_arg {
options_t *options_p;
glob_t *glob_p;
// indexes_t *indexes_p;
pthread_t pthread_parent;
int *exitcode_p;
... ...
... ... @@ -46,6 +46,7 @@
#define DEFAULT_CLUSTERSDLMAX 32
#define DEFAULT_CONFIG_BLOCK "default"
#define DEFAULT_RETRIES 1
#define DEFAULT_VERBOSE 1
#define FANOTIFY_FLAGS (FAN_CLOEXEC|FAN_UNLIMITED_QUEUE|FAN_UNLIMITED_MARKS)
#define FANOTIFY_EVFLAGS (O_LARGEFILE|O_RDONLY|O_CLOEXEC)
... ...
... ... @@ -21,7 +21,7 @@
#include <sys/un.h> // for "struct sockaddr_un"
#include "output.h"
#include "error.h"
#include "sync.h"
#include "control.h"
#include "socket.h"
... ... @@ -30,11 +30,11 @@ static pthread_t pthread_control;
int control_procclsyncsock(socket_sockthreaddata_t *arg, sockcmd_t *sockcmd_p) {
clsyncsock_t *clsyncsock_p = arg->clsyncsock_p;
options_t *options_p = (options_t *)arg->arg;
glob_t *glob_p = (glob_t *)arg->arg;
switch(sockcmd_p->cmd_id) {
case SOCKCMD_REQUEST_INFO: {
socket_send(clsyncsock_p, SOCKCMD_REPLY_INFO, options_p->config_block, options_p->label, options_p->flags, options_p->flags_set);
socket_send(clsyncsock_p, SOCKCMD_REPLY_INFO, glob_p->config_block, glob_p->label, glob_p->flags, glob_p->flags_set);
break;
}
case SOCKCMD_REQUEST_DIE: {
... ... @@ -48,31 +48,31 @@ int control_procclsyncsock(socket_sockthreaddata_t *arg, sockcmd_t *sockcmd_p) {
return 0;
}
static inline void closecontrol(options_t *options_p) {
if(options_p->socket) {
close(options_p->socket);
options_p->socket = 0;
static inline void closecontrol(glob_t *glob_p) {
if(glob_p->socket) {
close(glob_p->socket);
glob_p->socket = 0;
}
}
int control_loop(options_t *options_p) {
int control_loop(glob_t *glob_p) {
// Starting
printf_d("Debug2: control_loop() started (options_p->socket == %u)\n", options_p->socket);
debug(1, "started (glob_p->socket == %u)", glob_p->socket);
int s;
while((s=options_p->socket)) {
while((s=glob_p->socket)) {
// Check if the socket is still alive
if(socket_check_bysock(s)) {
printf_d("Debug: Control socket closed [case 0]: %s\n", strerror(errno));
closecontrol(options_p);
debug(1, "Control socket closed [case 0]: %s", strerror(errno));
closecontrol(glob_p);
continue;
}
// Waiting for event
printf_ddd("Debug3: control_loop(): waiting for events on the socket\n");
debug(3, "waiting for events on the socket");
fd_set rfds;
FD_ZERO(&rfds);
... ... @@ -81,23 +81,23 @@ int control_loop(options_t *options_p) {
int count = select(s+1, &rfds, NULL, NULL, NULL);
// Processing the events
printf_dd("Debug2: control_loop(): got %i events with select()\n", count);
debug(2, "got %i events with select()", count);
// Processing the events: checks
if(count == 0) {
printf_dd("Debug2: control_loop(): select() timed out.\n");
debug(2, "select() timed out.");
continue;
}
if(count < 0) {
printf_d("Debug: control_loop(): Got negative events count. Closing the socket.\n");
closecontrol(options_p);
debug(1, "Got negative events count. Closing the socket.");
closecontrol(glob_p);
continue;
}
if(!FD_ISSET(s, &rfds)) {
printf_e("Error: control_loop(): Got event, but not on the control socket. Closing the socket (cannot use \"select()\").\n");
closecontrol(options_p);
error("Got event, but not on the control socket. Closing the socket (cannot use \"select()\").");
closecontrol(glob_p);
continue;
}
... ... @@ -110,30 +110,30 @@ int control_loop(options_t *options_p) {
continue;
// Got unknown error. Closing control socket just in case.
printf_e("Error: control_loop(): Cannot socket_accept(): %s (errno: %i)\n", strerror(errno), errno);
closecontrol(options_p);
error("Cannot socket_accept()");
closecontrol(glob_p);
continue;
}
printf_dd("Debug2: control_loop(): Starting new thread for new connection.\n");
debug(2, "Starting new thread for new connection.");
socket_sockthreaddata_t *threaddata_p = socket_thread_attach(clsyncsock_p);
if (threaddata_p == NULL) {
printf_e("Error: control_loop(): Cannot create a thread for connection: %s (errno: %i)\n", strerror(errno), errno);
closecontrol(options_p);
error("Cannot create a thread for connection");
closecontrol(glob_p);
continue;
}
threaddata_p->procfunct = control_procclsyncsock;
threaddata_p->clsyncsock_p = clsyncsock_p;
threaddata_p->arg = options_p;
threaddata_p->running = &options_p->socket;
threaddata_p->authtype = options_p->flags[SOCKETAUTH];
threaddata_p->arg = glob_p;
threaddata_p->running = &glob_p->socket;
threaddata_p->authtype = glob_p->flags[SOCKETAUTH];
threaddata_p->flags = 0;
if (socket_thread_start(threaddata_p)) {
printf_e("Error: control_loop(): Cannot start a thread for connection: %s (errno: %i)\n", strerror(errno), errno);
closecontrol(options_p);
error("Cannot start a thread for connection");
closecontrol(glob_p);
continue;
}
#ifdef DEBUG
... ... @@ -144,22 +144,22 @@ int control_loop(options_t *options_p) {
// Cleanup
printf_d("Debug2: control_loop() finished\n");
debug(1, "control_loop() finished");
return 0;
}
int control_run(options_t *options_p) {
if(options_p->socketpath != NULL) {
int control_run(glob_t *glob_p) {
if(glob_p->socketpath != NULL) {
int ret = 0;
int s = -1;
// initializing clsync-socket subsystem
if ((ret = socket_init()))
printf_e("Error: Cannot init clsync-sockets subsystem.\n");
error("Cannot init clsync-sockets subsystem.");
if (!ret) {
clsyncsock_t *clsyncsock = socket_listen_unix(options_p->socketpath);
clsyncsock_t *clsyncsock = socket_listen_unix(glob_p->socketpath);
if (clsyncsock == NULL) {
ret = errno;
} else {
... ... @@ -170,16 +170,16 @@ int control_run(options_t *options_p) {
// fixing privileges
if (!ret) {
if(options_p->flags[SOCKETMOD])
if(chmod(options_p->socketpath, options_p->socketmod)) {
printf_e("Error, Cannot chmod(\"%s\", %o): %s (errno: %i)\n",
options_p->socketpath, options_p->socketmod, strerror(errno), errno);
if(glob_p->flags[SOCKETMOD])
if(chmod(glob_p->socketpath, glob_p->socketmod)) {
error("Error, Cannot chmod(\"%s\", %o)",
glob_p->socketpath, glob_p->socketmod);
ret = errno;
}
if(options_p->flags[SOCKETOWN])
if(chown(options_p->socketpath, options_p->socketuid, options_p->socketgid)) {
printf_e("Error, Cannot chown(\"%s\", %u, %u): %s (errno: %i)\n",
options_p->socketpath, options_p->socketuid, options_p->socketgid, strerror(errno), errno);
if(glob_p->flags[SOCKETOWN])
if(chown(glob_p->socketpath, glob_p->socketuid, glob_p->socketgid)) {
error("Error, Cannot chown(\"%s\", %u, %u)",
glob_p->socketpath, glob_p->socketuid, glob_p->socketgid);
ret = errno;
}
}
... ... @@ -190,20 +190,20 @@ int control_run(options_t *options_p) {
return ret;
}
options_p->socket = s;
glob_p->socket = s;
printf_dd("Debug2: control_run(): options_p->socket = %u\n", options_p->socket);
debug(2, "glob_p->socket = %u", glob_p->socket);
ret = pthread_create(&pthread_control, NULL, (void *(*)(void *))control_loop, options_p);
ret = pthread_create(&pthread_control, NULL, (void *(*)(void *))control_loop, glob_p);
}
return 0;
}
int control_cleanup(options_t *options_p) {
if(options_p->socketpath != NULL) {
unlink(options_p->socketpath);
closecontrol(options_p);
int control_cleanup(glob_t *glob_p) {
if(glob_p->socketpath != NULL) {
unlink(glob_p->socketpath);
closecontrol(glob_p);
// TODO: kill pthread_control and join
// pthread_join(pthread_control, NULL);
socket_deinit();
... ...
... ... @@ -20,8 +20,8 @@
#ifndef __CLSYNC_CONTROL_H
#define __CLSYNC_CONTROL_H
extern int control_run(options_t *options_p);
extern int control_cleanup(options_t *options_p);
extern int control_run(glob_t *glob_p);
extern int control_cleanup(glob_t *glob_p);
#endif
... ...
/*
clsyncmgr - intermediate daemon to aggregate clsync's sockets
Copyright (C) 2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file implements way to output debugging information. It's supposed
* to be slow but convenient functions.
*/
#include <stdlib.h>
#include <execinfo.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <syslog.h>
#include <pthread.h> /* pthread_self() */
#include "error.h"
#include "common.h"
static int zero = 0;
static int one = 1;
static int *outputmethod = &zero;
static int *debug = &zero;
static int *quiet = &zero;
static int *verbose = &one;
static int printf_stderr(const char *fmt, ...) {
va_list args;
int rc;
va_start(args, fmt);
rc = vfprintf(stderr, fmt, args);
va_end(args);
return rc;
}
static int printf_stdout(const char *fmt, ...) {
va_list args;
int rc;
va_start(args, fmt);
rc = vfprintf(stdout, fmt, args);
va_end(args);
return rc;
}
static int vprintf_stderr(const char *fmt, va_list args) {
return vfprintf(stderr, fmt, args);
}
static int vprintf_stdout(const char *fmt, va_list args) {
return vfprintf(stdout, fmt, args);
}
static void flush_stderr(int level) {
fprintf(stderr, "\n");
fflush(stderr);
}
static void flush_stdout(int level) {
fprintf(stdout, "\n");
fflush(stdout);
}
static char _syslog_buffer[BUFSIZ];
size_t _syslog_buffer_filled = 0;
static int syslog_buf(const char *fmt, ...) {
int len;
va_list args;
va_start(args, fmt);
len = vsnprintf (
&_syslog_buffer[_syslog_buffer_filled],
BUFSIZ - _syslog_buffer_filled,
fmt,
args
);
va_end(args);
if (len>0)
_syslog_buffer_filled += len;
return 0;
}
static int vsyslog_buf(const char *fmt, va_list args) {
int len;
len = vsnprintf (
&_syslog_buffer[_syslog_buffer_filled],
BUFSIZ - _syslog_buffer_filled,
fmt,
args
);
if (len>0)
_syslog_buffer_filled += len;
return 0;
}
static void syslog_flush(int level) {
syslog(level, "%s", _syslog_buffer);
}
typedef int *( *outfunct_t)(const char *format, ...);
typedef int *( *voutfunct_t)(const char *format, va_list ap);
typedef void *(*flushfunct_t)(int level);
static outfunct_t outfunct[] = {
[OM_STDERR] = (outfunct_t)printf_stderr,
[OM_STDOUT] = (outfunct_t)printf_stdout,
[OM_SYSLOG] = (outfunct_t)syslog_buf,
};
static voutfunct_t voutfunct[] = {
[OM_STDERR] = (voutfunct_t)vprintf_stderr,
[OM_STDOUT] = (voutfunct_t)vprintf_stdout,
[OM_SYSLOG] = (voutfunct_t)vsyslog_buf,
};
static flushfunct_t flushfunct[] = {
[OM_STDERR] = (flushfunct_t)flush_stderr,
[OM_STDOUT] = (flushfunct_t)flush_stdout,
[OM_SYSLOG] = (flushfunct_t)syslog_flush,
};
void _critical(const char *const function_name, const char *fmt, ...) {
if (*quiet)
return;
outputmethod_t method = *outputmethod;
{
va_list args;
pthread_t thread = pthread_self();
outfunct[method]("Critical (thread %p): %s(): ", thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
outfunct[method](" (current errno %i: %s)", errno, strerror(errno));
flushfunct[method](LOG_CRIT);
}
{
void *buf[BACKTRACE_LENGTH];
char **strings;
int backtrace_len = backtrace((void **)buf, BACKTRACE_LENGTH);
strings = backtrace_symbols(buf, backtrace_len);
if (strings == NULL) {
outfunct[method]("_critical(): Got error, but cannot print the backtrace. Current errno: %u: %s\n",
errno, strerror(errno));
flushfunct[method](LOG_CRIT);
exit(EXIT_FAILURE);
}
for (int j = 1; j < backtrace_len; j++) {
outfunct[method](" %s", strings[j]);
flushfunct[method](LOG_CRIT);
}
}
exit(errno);
return;
}
void _error(const char *const function_name, const char *fmt, ...) {
va_list args;
if (*quiet)
return;
if (*verbose < 1)
return;
pthread_t thread = pthread_self();
outputmethod_t method = *outputmethod;
outfunct[method]("Error (thread %p): %s(): ", thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
outfunct[method](" (%i: %s)", errno, strerror(errno));
flushfunct[method](LOG_ERR);
return;
}
void _info(const char *const function_name, const char *fmt, ...) {
va_list args;
if (*quiet)
return;
if (*verbose < 3)
return;
pthread_t thread = pthread_self();
outputmethod_t method = *outputmethod;
outfunct[method]("Info (thread %p): %s(): ", thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
flushfunct[method](LOG_INFO);
return;
}
void _info_short(const char *fmt, ...) {
va_list args;
if (*quiet)
return;
if (*verbose < 3)
return;
outputmethod_t method = *outputmethod;
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
flushfunct[method](LOG_INFO);
return;
}
void _warning(const char *const function_name, const char *fmt, ...) {
va_list args;
if (*quiet)
return;
if (*verbose < 2)
return;
pthread_t thread = pthread_self();
outputmethod_t method = *outputmethod;
outfunct[method]("Warning (thread %p): %s(): ", thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
flushfunct[method](LOG_WARNING);
return;
}
void _debug(int debug_level, const char *const function_name, const char *fmt, ...) {
va_list args;
if (*quiet)
return;
if (debug_level > *debug)
return;
pthread_t thread = pthread_self();
outputmethod_t method = *outputmethod;
outfunct[method]("Debug%u (thread %p): %s(): ", debug_level, thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
flushfunct[method](LOG_DEBUG);
return;
}
void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug) {
outputmethod = _outputmethod;
quiet = _quiet;
verbose = _verbose;
debug = _debug;
return;
}
... ...
/*
clsyncmgr - intermediate daemon to aggregate clsync's sockets
Copyright (C) 2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define BACKTRACE_LENGTH 256
extern void _critical( const char *const function_name, const char *fmt, ...);
#define critical(...) _critical(__FUNCTION__, __VA_ARGS__)
extern void _error(const char *const function_name, const char *fmt, ...);
#define error(...) _error(__FUNCTION__, __VA_ARGS__)
extern void _warning(const char *const function_name, const char *fmt, ...);
#define warning(...) _warning(__FUNCTION__, __VA_ARGS__)
extern void _info(const char *const function_name, const char *fmt, ...);
#define info(...) _info(__FUNCTION__, __VA_ARGS__)
extern void _info_short(const char *fmt, ...);
#define info_short(...) _info_short(__VA_ARGS__)
extern void _debug(int debug_level, const char *const function_name, const char *fmt, ...);
#define debug(debug_level, ...) _debug(debug_level, __FUNCTION__, __VA_ARGS__)
#define error_or_debug(debug_level, ...) ((debug_level)<0 ? _error(__FUNCTION__, __VA_ARGS__) : _debug(debug_level, __FUNCTION__, __VA_ARGS__))
extern void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug);
enum outputmethod {
OM_STDERR = 0,
OM_STDOUT,
OM_SYSLOG,
OM_MAX
};
typedef enum outputmethod outputmethod_t;
... ...
... ... @@ -7,5 +7,5 @@ cat > rules <<EOF
+*.*
EOF
clsync -K example-simple -M rsyncdirect -L ./testdir/listdir -w2 -p -t5 -W ./testdir/from -S `which rsync` -R rules -D ./testdir/to $@
clsync -K example-simple -M rsyncdirect -L ./testdir/listdir -w2 -p -d4 -t5 -W ./testdir/from -S `which rsync` -R rules -D ./testdir/to $@
... ...
... ... @@ -18,7 +18,7 @@
*/
#include "common.h"
#include "output.h"
#include "error.h"
#include "malloc.h"
... ... @@ -26,7 +26,7 @@ char *fd2fpath_malloc(int fd) {
struct stat64 lstat;
if(fd <= 0) {
printf_e("Error: Invalid file descriptor supplied: fd2fpath_malloc(%i).\n", fd);
error("Invalid file descriptor supplied: fd2fpath_malloc(%i).", fd);
errno = EINVAL;
return NULL;
}
... ... @@ -36,7 +36,7 @@ char *fd2fpath_malloc(int fd) {
sprintf(fpath, "/proc/self/fd/%i", fd);
if(lstat64(fpath, &lstat)) {
printf_e("Error: Cannot lstat(\"%s\", lstat): %s (errno: %i).\n", fpath, strerror(errno), errno);
error("Cannot lstat(\"%s\", lstat).", fpath);
return NULL;
}
... ... @@ -45,12 +45,12 @@ char *fd2fpath_malloc(int fd) {
if(fpathlen > (1<<8))
fpath = xrealloc(fpath, fpathlen+2);
printf_ddd("Debug2: Getting file path from symlink \"%s\". Path length is: %i.\n", fpath, fpathlen);
debug(3, "Getting file path from symlink \"%s\". Path length is: %i.", fpath, fpathlen);
if((fpathlen = readlink(fpath, fpath, fpathlen+1)) < 0) {
printf_e("Error: Cannot readlink(\"%s\", fpath, bufsize).\n", fpath);
error("Cannot readlink(\"%s\", fpath, bufsize).", fpath);
return NULL;
}
printf_ddd("Debug2: The path is: \"%s\"\n", fpath);
debug(3, "The path is: \"%s\"", fpath);
fpath[fpathlen] = 0;
return fpath;
... ... @@ -73,15 +73,15 @@ int fileutils_copy(const char *path_from, const char *path_to) {