handle loss of syslog socket connection
authorRich Felker <dalias@aerifal.cx>
Thu, 9 Jul 2015 18:36:02 +0000 (18:36 +0000)
committerRich Felker <dalias@aerifal.cx>
Thu, 9 Jul 2015 18:47:48 +0000 (18:47 +0000)
when traditional syslogd implementations are restarted, the old server
socket ceases to exist and a new unix socket with the same pathname is
created. when this happens, the default destination address associated
with the client socket via connect is no longer valid, and attempts to
send produce errors. this happens despite the socket being datagram
type, and is in contrast to the behavior that would be seen with an IP
datagram (UDP) socket.

in order to avoid a situation where the application is unable to send
further syslog messages without calling closelog, this patch makes
syslog attempt to reconnect the socket when send returns an error
indicating a lost connection.

additionally, initial failure to connect the socket no longer results
in the socket being closed. this ensures that an application which
calls openlog to reserve the socket file descriptor will not run into
a situation where transient connection failure (e.g. due to syslogd
restart) prevents fd reservation. however, applications which may be
unable to connect the socket later (e.g. due to chroot, restricted
permissions, seccomp, etc.) will still fail to log if the syslog
socket cannot be connected at openlog time or if it has to be
reconnected later.

src/misc/syslog.c

index e026f9b4dbb07ee2596fd75406d3254a5f249797..9dd1ddb5889322ed69099b008e384cee47b89d4d 100644 (file)
@@ -48,12 +48,8 @@ void closelog(void)
 
 static void __openlog()
 {
-       int fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
-       if (fd < 0) return;
-       if (connect(fd, (void *)&log_addr, sizeof log_addr) < 0)
-               close(fd);
-       else
-               log_fd = fd;
+       log_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+       if (log_fd >= 0) connect(log_fd, (void *)&log_addr, sizeof log_addr);
 }
 
 void openlog(const char *ident, int opt, int facility)
@@ -78,6 +74,11 @@ void openlog(const char *ident, int opt, int facility)
        pthread_setcancelstate(cs, 0);
 }
 
+static int is_lost_conn(int e)
+{
+       return e==ECONNREFUSED || e==ECONNRESET || e==ENOTCONN || e==EPIPE;
+}
+
 static void _vsyslog(int priority, const char *message, va_list ap)
 {
        char timebuf[16];
@@ -107,7 +108,10 @@ static void _vsyslog(int priority, const char *message, va_list ap)
                if (l2 >= sizeof buf - l) l = sizeof buf - 1;
                else l += l2;
                if (buf[l-1] != '\n') buf[l++] = '\n';
-               if (send(log_fd, buf, l, 0) < 0 && (log_opt & LOG_CONS)) {
+               if (send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno)
+                   || connect(log_fd, (void *)&log_addr, sizeof log_addr) < 0
+                   || send(log_fd, buf, l, 0) < 0)
+                   && (log_opt & LOG_CONS)) {
                        fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
                        if (fd >= 0) {
                                dprintf(fd, "%.*s", l-hlen, buf+hlen);