aboutsummaryrefslogtreecommitdiffstats
path: root/jnlib/logging.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2003-12-16 11:30:16 +0000
committerWerner Koch <[email protected]>2003-12-16 11:30:16 +0000
commitdba63c0a0ceb473909528ec51b5851ec28731218 (patch)
treea68c2499ab81167e61875513e395b7138ea664f7 /jnlib/logging.c
parentKeep those files in CVS too. (diff)
downloadgnupg-dba63c0a0ceb473909528ec51b5851ec28731218.tar.gz
gnupg-dba63c0a0ceb473909528ec51b5851ec28731218.zip
* configure.ac: Check for funopen and fopencookie as part of the
jnlib checks. * logging.c (writen, fun_writer, fun_closer): New. (log_set_file): Add feature to log to a socket.
Diffstat (limited to 'jnlib/logging.c')
-rw-r--r--jnlib/logging.c181
1 files changed, 168 insertions, 13 deletions
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 <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <stddef.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
#ifdef __MINGW32__
- #include <io.h>
+# include <io.h>
#endif
#define JNLIB_NEED_LOG_LOGV 1
@@ -84,22 +87,173 @@ log_inc_errorcount (void)
errorcount++;
}
-void
-log_set_file( const char *name )
+
+/* 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)
{
- 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;
+ 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;
}
- setvbuf( fp, NULL, _IOLBF, 0 );
+
+ 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;
+}
- if (logstream && logstream != stderr && logstream != stdout)
- fclose( logstream );
- logstream = fp;
- missing_lf = 0;
+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) ;