Hi Daniel, > When using syslog() directly we are in danger to deadlock > when syslog() is already been called by normal code > and the signal kicks in. With using a socket to "/dev/log" > we are safe even in the signal handler to log messages. > --- > src/log.c | 153 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- > 1 files changed, 143 insertions(+), 10 deletions(-)
so we wanna just use /dev/log from all of our logging calls. Is this to unify things a bit further or is this fixing a real bug as well. I was thinking of keep using syslog() and only open /dev/log from the signal handler. > diff --git a/src/log.c b/src/log.c > index 04e61f3..63f1df3 100644 > --- a/src/log.c > +++ b/src/log.c > @@ -32,12 +32,92 @@ > #include <syslog.h> > #include <execinfo.h> > #include <dlfcn.h> > +#include <sys/socket.h> > +#include <sys/un.h> > +#include <errno.h> > > #include "connman.h" > > static const char *program_exec; > static const char *program_path; > > +static int log_option; Maybe we can a bit smarter in just always have to check the log_option. > +static int syslog_fd; > + > +static char *program_str; > +static char *pid_str; > +static const char * const level_str[] = { "<0>", "<1>", "<2>", "<3>", > + "<4>", "<5>", "<6>", "<7>" }; There is a double const here ;) > + > +#define IOVEC_SET_STRING(i, s) \ > + do { \ > + struct iovec *_i = &(i); \ > + char *_s = (char *)(s); \ > + _i->iov_base = _s; \ > + _i->iov_len = strlen(_s); \ > + } while (0); > + > +static int write_to_syslog(unsigned int level, const char *buffer) > +{ > + struct iovec iovec[4]; > + struct msghdr msghdr; > + > + if (level > LOG_DEBUG) > + level = LOG_DEBUG; > + > + memset(iovec, 0, sizeof(iovec)); > + IOVEC_SET_STRING(iovec[0], level_str[level]); > + IOVEC_SET_STRING(iovec[1], program_str); > + IOVEC_SET_STRING(iovec[2], pid_str); > + IOVEC_SET_STRING(iovec[3], buffer); > + > + memset(&msghdr, 0, sizeof(msghdr)); > + msghdr.msg_iov = iovec; > + msghdr.msg_iovlen = 4; > + > + if (writev(syslog_fd, iovec, 4) < 0) > + return -errno; > + > + return 0; > +} > + > +static int write_to_console(const char *buffer) > +{ > + struct iovec iovec[4]; > + struct msghdr msghdr; > + > + memset(iovec, 0, sizeof(iovec)); > + IOVEC_SET_STRING(iovec[0], program_str); > + IOVEC_SET_STRING(iovec[1], pid_str); > + IOVEC_SET_STRING(iovec[2], buffer); > + IOVEC_SET_STRING(iovec[3], "\n"); > + > + memset(&msghdr, 0, sizeof(msghdr)); > + msghdr.msg_iov = iovec; > + msghdr.msg_iovlen = 4; > + > + if (writev(STDERR_FILENO, iovec, 4) < 0) > + return -errno; > + > + return 0; > +} To optimize this, we might be able to create only one iovec and just call writev with an offset to it. I don't see a need to allocate an iovec twice. > + > +static void log_dispatch(unsigned int level, const char *format, va_list ap) > +{ > + char name[16], pid[16]; > + char *buffer; > + int len; So who is using name, pid and len (and more important why the compiler did not complain loudly). > + > + len = vasprintf(&buffer, format, ap); > + > + write_to_syslog(level, buffer); > + > + if ((log_option & LOG_PERROR) == LOG_PERROR) > + write_to_console(buffer); > + > + free(buffer); > +} > + > /** > * connman_info: > * @format: format string > @@ -51,7 +131,7 @@ void connman_info(const char *format, ...) > > va_start(ap, format); > > - vsyslog(LOG_INFO, format, ap); > + log_dispatch(LOG_INFO, format, ap); > > va_end(ap); > } > @@ -69,7 +149,7 @@ void connman_warn(const char *format, ...) > > va_start(ap, format); > > - vsyslog(LOG_WARNING, format, ap); > + log_dispatch(LOG_WARNING, format, ap); > > va_end(ap); > } > @@ -87,7 +167,7 @@ void connman_error(const char *format, ...) > > va_start(ap, format); > > - vsyslog(LOG_ERR, format, ap); > + log_dispatch(LOG_ERR, format, ap); > > va_end(ap); > } > @@ -105,7 +185,7 @@ void connman_debug(const char *format, ...) > > va_start(ap, format); > > - vsyslog(LOG_DEBUG, format, ap); > + log_dispatch(LOG_DEBUG, format, ap); > > va_end(ap); > } > @@ -238,6 +318,37 @@ static void signal_setup(sighandler_t handler) > sigaction(SIGPIPE, &sa, NULL); > } > > +static int open_syslog(void) > +{ > + union { > + struct sockaddr sa; > + struct sockaddr_un un; > + } sa; Please don't do that. Just cast it in connect() call. > + memset(&sa, 0, sizeof(sa)); > + sa.un.sun_family = AF_UNIX; > + strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); You could just use strcpy since we know how long the string is. > + > + syslog_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); > + if (syslog_fd < 0) > + return -errno; > + > + if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) { > + close(syslog_fd); > + return -errno; > + } > + > + return 0; > +} > + > +static void close_syslog(void) > +{ > + if (syslog_fd <= 0) > + return; > + > + close(syslog_fd); > +} > + For open_syslog and close_syslog we might be better do it directly in init and exit functions of src/log.c here. No need trying to emulate syslog. > extern struct connman_debug_desc __start___debug[]; > extern struct connman_debug_desc __stop___debug[]; > > @@ -320,6 +431,7 @@ int __connman_log_init(const char *program, const char > *debug, > { > static char path[PATH_MAX]; > int option = LOG_NDELAY | LOG_PID; > + int err; > > program_exec = program; > program_path = getcwd(path, sizeof(path)); > @@ -329,25 +441,46 @@ int __connman_log_init(const char *program, const char > *debug, > > __connman_log_enable(__start___debug, __stop___debug); > > + if (asprintf(&program_str, "%s", basename(program_exec)) < 0) { > + err = -errno; > + goto err; > + } > + > + if (asprintf(&pid_str, "[%lu]: ", (unsigned long)getpid()) < 0) { > + err = -errno; > + goto err; > + } > + > + err = open_syslog(); > + if (err < 0) > + goto err; > + > if (detach == FALSE) > - option |= LOG_PERROR; > + log_option |= LOG_PERROR; > > signal_setup(signal_handler); > > - openlog(basename(program), option, LOG_DAEMON); > - > - syslog(LOG_INFO, "Connection Manager version %s", VERSION); > + connman_info("Connection Manager version %s", VERSION); > > return 0; > + > +err: > + g_free(program_str); > + g_free(pid_str); > + > + return err; > } > > void __connman_log_cleanup(void) > { > - syslog(LOG_INFO, "Exit"); > + connman_info("Exit"); > > - closelog(); > + close_syslog(); > > signal_setup(SIG_DFL); > > + g_free(program_str); > + g_free(pid_str); > + We could just have static strings here. We know what the max will be. > g_strfreev(enabled); > } Regards Marcel _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman