Hi,
Unable to output messages in syslog function immediately after restarting the log daemon.
Caused by ECONNREFUSED on errno in the following __vsyslog function.
(libc/misc/syslog/syslog.c)
void
__vsyslog(int pri, const char *fmt, va_list ap)
{
.
.
.
retry:
if (LogFile >= 0) {
do {
/* can't just use write, it can result in SIGPIPE */
rc = send(LogFile, p, last_chr + 1 - p, MSG_NOSIGNAL);
if (rc < 0) {
switch (errno) {
case EINTR:
break;
case ECONNRESET:
/* syslogd restarted, reopen log */
closelog_intern(1);
openlog_intern();
goto retry;
case EAGAIN:
/* syslogd stalled, noting we can do */
default:
closelog_intern(1); /* 1: do not reset LogXXX globals to default */
goto write_err;
}
rc = 0;
}
p += rc;
} while (p <= last_chr);
goto getout;
}
.
.
.
You can check it with the following sample.
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/signal.h>
#include <sys/syslog.h>
static const struct sockaddr SyslogAddr = {
.sa_family = AF_UNIX,
.sa_data = "/dev/log"
};
static int LogFile;
static int OpenLogSocket(void);
int main(void)
{
char tbuf[1024];
char strbuf[1024];
time_t now;
int rc, count = 0;
printf("\nSyslog loop start!\n\n");
if (0 == OpenLogSocket() ) {
return 1;
}
while (fgets(strbuf, 1024, stdin)) {
if ((char)'e' == strbuf[0]) {
printf("Syslog loop end\n");
break;
}
(void)time(&now);
sprintf(tbuf, "<%d>%.15s Test %u", LOG_USER | LOG_NOTICE,
ctime(&now) + 4, count++);
retry:
rc = send(LogFile, tbuf, strlen(tbuf), MSG_NOSIGNAL);
if (rc < 0) {
switch (errno) {
case EINTR:
printf("Syslog send error EINTR\n");
break;
case ECONNRESET:
// case ECONNREFUSED:
close(LogFile);
if (0 == OpenLogSocket() ) {
return 1;
}
goto retry;
case EAGAIN:
printf("Syslog send error EAGAIN\n");
break;
default:
printf("Syslog send error default (%d)\n", errno);
break;
}
}
}
close(LogFile);
return 0;
}
int OpenLogSocket(void)
{
int FdFlag;
const struct timeval tv = { 1, 0 };
LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
if (-1 == LogFile) {
printf("Syslog open error\n");
return 0;
}
fcntl(LogFile, F_SETFD, FD_CLOEXEC);
FdFlag = fcntl(LogFile, F_GETFL);
fcntl(LogFile, F_SETFL, O_NONBLOCK | FdFlag);
if (-1 != connect(LogFile, &SyslogAddr, sizeof(SyslogAddr))) {
fcntl(LogFile, F_SETFL, ~O_NONBLOCK & fcntl(LogFile, F_GETFL));
setsockopt(LogFile, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
}
else {
printf("Syslog connect error\n");
close(LogFile);
return 0;
}
return 1;
}
When you run the sample, you can send the syslog by return input.
If the log daemon is restarted without exiting the sample, the syslog cannot be sent.
If you delete the comment (//) in the sample, you can send the syslog.
OS:OpenWrt Chaos Calmer 15.05.1 Linux-3.14.77 uClibc-ng-1.0.14
I think it needs to be at least ECONNREFUSED.
Thanks,
--
Takeru Fukushima