diff --git a/ChangeLog b/ChangeLog index f270cad13..2a08051f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-12-16 Werner Koch + + * configure.ac: Check for funopen and fopencookie as part of the + jnlib checks. + 2003-12-09 Werner Koch * configure.ac: Add a min_automake_version. diff --git a/NEWS b/NEWS index 8aff1add1..ebc65a27d 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,13 @@ Noteworthy changes in version 1.9.3 (unreleased) ------------------------------------------------ * New options --{enable,disable}-ocsp to validate keys using OCSP - This requires at least DirMngr 0.5.1 to work. Default is disabled. + This requires a not yet released DirMngr 0.5.1. Default is + disabled. + + * The --log-file may now be used to print logs to a socket. Prefix + the socket name with "socket://" to enable this. This does not + work on all systems and falls back to stderr if there is a problem + with the socket. Noteworthy changes in version 1.9.2 (2003-11-17) diff --git a/configure.ac b/configure.ac index 7bca11986..a0cf391a4 100644 --- a/configure.ac +++ b/configure.ac @@ -698,7 +698,7 @@ AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include ]) # These are needed by libjnlib - fixme: we should have macros for them AC_CHECK_FUNCS(memicmp stpcpy strlwr strtoul memmove stricmp strtol) AC_CHECK_FUNCS(getrusage setrlimit stat setlocale) -AC_CHECK_FUNCS(flockfile funlockfile) +AC_CHECK_FUNCS(flockfile funlockfile fopencookie funopen) AC_REPLACE_FUNCS(vasprintf) AC_REPLACE_FUNCS(fopencookie) @@ -709,6 +709,7 @@ AC_REPLACE_FUNCS(putc_unlocked) + # # check for gethrtime and run a testprogram to see whether # it is broken. It has been reported that some Solaris and HP UX systems diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index e12dd8e00..e6b7dc3fb 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,8 @@ +2003-12-16 Werner Koch + + * logging.c (writen, fun_writer, fun_closer): New. + (log_set_file): Add feature to log to a socket. + 2003-11-13 Werner Koch * strlist.c (strlist_copy): New. diff --git a/jnlib/logging.c b/jnlib/logging.c index 913d01b6f..b019fb76c 100644 --- a/jnlib/logging.c +++ b/jnlib/logging.c @@ -29,12 +29,15 @@ #include #include #include +#include #include #include #include +#include +#include #include #ifdef __MINGW32__ - #include +# include #endif #define JNLIB_NEED_LOG_LOGV 1 @@ -84,23 +87,174 @@ log_inc_errorcount (void) errorcount++; } -void -log_set_file( const char *name ) -{ - FILE *fp = (name && strcmp(name,"-"))? fopen(name, "a") : stderr; - if( !fp ) { - fprintf(stderr, "failed to open log file `%s': %s\n", - name, strerror(errno)); - return; - } - setvbuf( fp, NULL, _IOLBF, 0 ); - if (logstream && logstream != stderr && logstream != stdout) - fclose( logstream ); - logstream = fp; - missing_lf = 0; +/* The follwing 3 functions are used by funopen to write logs to a + socket. */ +#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN) +struct fun_cookie_s { + int fd; + int quiet; + char name[1]; +}; + +/* Write NBYTES of BUF to file descriptor FD. */ +static int +writen (int fd, const unsigned char *buf, size_t nbytes) +{ + size_t nleft = nbytes; + int nwritten; + + while (nleft > 0) + { + nwritten = write (fd, buf, nleft); + if (nwritten < 0 && errno == EINTR) + continue; + if (nwritten < 0) + return -1; + nleft -= nwritten; + buf = buf + nwritten; + } + + return 0; } + +static int +fun_writer (void *cookie_arg, const char *buffer, size_t size) +{ + struct fun_cookie_s *cookie = cookie_arg; + + /* Note that we always try to reconnect to the socket but print error + messages only the first time an error occured. */ + if (cookie->fd == -1 ) + { + /* Note yet open or meanwhile closed due to an error. */ + struct sockaddr_un addr; + size_t addrlen; + + cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0); + if (cookie->fd == -1) + { + if (!cookie->quiet) + fprintf (stderr, "failed to create socket for logging: %s\n", + strerror(errno)); + goto failure; + } + + memset (&addr, 0, sizeof addr); + addr.sun_family = PF_LOCAL; + strncpy (addr.sun_path, cookie->name, sizeof (addr.sun_path)-1); + addr.sun_path[sizeof (addr.sun_path)-1] = 0; + addrlen = (offsetof (struct sockaddr_un, sun_path) + + strlen (addr.sun_path) + 1); + + if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1) + { + if (!cookie->quiet) + fprintf (stderr, "can't connect to `%s': %s\n", + cookie->name, strerror(errno)); + close (cookie->fd); + cookie->fd = -1; + goto failure; + } + /* Connection established. */ + cookie->quiet = 0; + } + + if (!writen (cookie->fd, buffer, size)) + return size; /* Okay. */ + + fprintf (stderr, "error writing to `%s': %s\n", + cookie->name, strerror(errno)); + close (cookie->fd); + cookie->fd = -1; + + failure: + if (!cookie->quiet) + { + fputs ("switching logging to stderr\n", stderr); + cookie->quiet = 1; + } + + fwrite (buffer, size, 1, stderr); + return size; +} + +static int +fun_closer (void *cookie_arg) +{ + struct fun_cookie_s *cookie = cookie_arg; + + if (cookie->fd != -1) + close (cookie->fd); + jnlib_free (cookie); + return 0; +} +#endif /* HAVE_FOPENCOOKIE || HAVE_FUNOPEN */ + + + + +/* Set the file to write log to. The sepcial names NULL and "_" may + be used to select stderr and names formatted like + "socket:///home/foo/mylogs" may be used to write the logging to the + socket "/home/foo/mylogs". If the connection to the socket fails + or a write error is detected, the function writes to stderr and + tries the next time again to connect the socket. + */ +void +log_set_file (const char *name) +{ + FILE *fp; + + if (name && !strncmp (name, "socket://", 9) && name[9]) + { +#if defined (HAVE_FOPENCOOKIE)|| defined (HAVE_FUNOPEN) + struct fun_cookie_s *cookie; + + cookie = jnlib_xmalloc (sizeof *cookie + strlen (name+9)); + cookie->fd = -1; + cookie->quiet = 0; + strcpy (cookie->name, name+9); + +#ifdef HAVE_FOPENCOOKIE + { + cookie_io_functions_t io = { NULL }; + io.write = fun_writer; + io.close = fun_closer; + + fp = fopencookie (cookie, "w", io); + } +#else /*!HAVE_FOPENCOOKIE*/ + { + fp = funopen (cookie, NULL, fun_writer, NULL, fun_closer); + } +#endif /*!HAVE_FOPENCOOKIE*/ +#else /* Neither fopencookie nor funopen. */ + { + fprintf (stderr, "system does not support logging to a socket - " + "using stderr\n"); + fp = stderr; + } +#endif /* Neither fopencookie nor funopen. */ + } + else + fp = (name && strcmp(name,"-"))? fopen (name, "a") : stderr; + if (!fp) + { + fprintf (stderr, "failed to open log file `%s': %s\n", + name? name:"[stderr]", strerror(errno)); + return; + } + setvbuf (fp, NULL, _IOLBF, 0); + + if (logstream && logstream != stderr && logstream != stdout) + fclose (logstream); + logstream = fp; + missing_lf = 0; +} + + void log_set_fd (int fd) { @@ -221,6 +375,7 @@ do_logv( int level, const char *fmt, va_list arg_ptr ) default: fprintf(logstream,"[Unknown log level %d]: ", level ); break; } + if (fmt) { vfprintf(logstream,fmt,arg_ptr) ;