Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

determine syslog file descriptor

782 views
Skip to first unread message

Rainer Weikusat

unread,
Apr 15, 2016, 2:46:02 PM4/15/16
to
In a certain program, I need to determine the file descriptor number
which will be used to log syslog messages.The obvious idea for this
would be (in a single-threaded program)

static int log_fd = -1;

static void open_log(void)
{
log_fd = open("/dev/null", O_RDWR, 0);
close(log_fd);

openlog("clfds", LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);
}

Are there others?


Kaz Kylheku

unread,
Apr 15, 2016, 3:49:33 PM4/15/16
to
On 2016-04-15, Rainer Weikusat <rwei...@talktalk.net> wrote:
> In a certain program, I need to determine the file descriptor number
> which will be used to log syslog messages.The obvious idea for this
> would be (in a single-threaded program)

(Single threaded, and no asynchronous signal handlers going off
that could open/close descriptors.)

Is it required that syslog goes through a file descriptor at all,
or that openlog acquires that descriptor?

Ubuntu:

Nothing upon just opening the logger:

$ strace txr -e '(openlog "foo")'
[ ... ]
readlink("/proc/self/exe", "/usr/local/bin/txr", 4096) = 18
brk(0x8643000) = 0x8643000
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
exit_group(0) = ?

Logging an actual message lazily creates a socket, whether or not
you call openlog first. Before that, it calls time, and accesses time zone
info.

$ strace txr -e '(syslog log-emerg "foo")'
[ ... ]
readlink("/proc/self/exe", "/usr/local/bin/txr", 4096) = 18
brk(0x9cc2000) = 0x9cc2000
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
time(NULL) = 1460748667
open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2875, ...}) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=2875, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x285000
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\0"..., 4096) = 2875
_llseek(3, -24, [2851], SEEK_CUR) = 0
read(3, "\nPST8PDT,M3.2.0,M11.1.0\n", 4096) = 24
close(3) = 0
munmap(0x285000, 4096) = 0
socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_FILE, path="/dev/log"}, 110) = 0
send(3, "<8>Apr 15 12:31:07 txr: foo", 27, MSG_NOSIGNAL) = 27
exit_group(0) = ?

By the way, AF_FILE??? Never heard of it. Ah, synonym for AF_LOCAL, which I
also never heard of, which is some POSIX alias for AF_UNIX. (For
trademark-avoiding paranoics?)

> static int log_fd = -1;
>
> static void open_log(void)
> {
> log_fd = open("/dev/null", O_RDWR, 0);
> close(log_fd);
>
> openlog("clfds", LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);

Here we should probably interrogate log_fd to see whether it is now a
valid descriptor, from which we can infer that openlog opened it for
some purpose, and left it open:

if (fcntl(log_fd, F_GETFD) == -1) && errno == EBADF)
log_fd = -1;

(Of course, we already know that this isn't enough on one
widespread system.)

Barry Margolin

unread,
Apr 15, 2016, 3:57:36 PM4/15/16
to
In article <201604151...@kylheku.com>,
Kaz Kylheku <545-06...@kylheku.com> wrote:

> On 2016-04-15, Rainer Weikusat <rwei...@talktalk.net> wrote:
> > In a certain program, I need to determine the file descriptor number
> > which will be used to log syslog messages.The obvious idea for this
> > would be (in a single-threaded program)
>
> (Single threaded, and no asynchronous signal handlers going off
> that could open/close descriptors.)
>
> Is it required that syslog goes through a file descriptor at all,
> or that openlog acquires that descriptor?

Or that it keeps the descriptor open?

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Casper H.S. Dik

unread,
Apr 16, 2016, 5:51:24 AM4/16/16
to
Not sure this is going to work in a threaded application.

Why do you want to know? Or you trying to close file descriptors
or dup to them when you hadn't been given to you by some system call
(except for 0, 1 & 2)?

Casper

Kaz Kylheku

unread,
Apr 16, 2016, 8:38:59 AM4/16/16
to
On 2016-04-16, Casper H.S Dik <Caspe...@OrSPaMcle.COM> wrote:
> Rainer Weikusat <rwei...@talktalk.net> writes:
>
>>In a certain program, I need to determine the file descriptor number
>>which will be used to log syslog messages.The obvious idea for this
>>would be (in a single-threaded program)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>static int log_fd = -1;

[...]

Rainer Weikusat

unread,
Apr 16, 2016, 10:39:25 AM4/16/16
to
Casper H.S. Dik <Caspe...@OrSPaMcle.COM> writes:
> Rainer Weikusat <rwei...@talktalk.net> writes:
>>In a certain program, I need to determine the file descriptor number
>>which will be used to log syslog messages.

[...]

> Why do you want to know? Or you trying to close file descriptors
> or dup to them when you hadn't been given to you by some system call
> (except for 0, 1 & 2)?

Closing all file descriptors which will be inherited accross an exec
(with the option to keep some of them) and ensuring that 0, 1 and 2 are
occupied before executing another program. The program in question,
lxc-start of the 'Linux container tools', will terminate itself
with an error in case it inherits descriptors beyond 2 and it's called
from a script acting as backend for a simple web application executions
of which are serialized by fcnt-locking a certain file and leaving the
file descriptor open until the kernel closes it when the outermost
process exits.

This is based on Linux /proc/self/fd and thus needs to steer around the
file descriptor of the dirstream used to read the directory and I'd like
to avoid closing the syslog fd, too.

Rainer Weikusat

unread,
Apr 16, 2016, 10:43:47 AM4/16/16
to
Kaz Kylheku <545-06...@kylheku.com> writes:
> On 2016-04-15, Rainer Weikusat <rwei...@talktalk.net> wrote:
>> In a certain program, I need to determine the file descriptor number
>> which will be used to log syslog messages.The obvious idea for this
>> would be (in a single-threaded program)
>
> (Single threaded, and no asynchronous signal handlers going off
> that could open/close descriptors.)
>
> Is it required that syslog goes through a file descriptor at all,
> or that openlog acquires that descriptor?
>
> Ubuntu:
>
> Nothing upon just opening the logger:
>
> $ strace txr -e '(openlog "foo")'
> [ ... ]
> readlink("/proc/self/exe", "/usr/local/bin/txr", 4096) = 18
> brk(0x8643000) = 0x8643000
> ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
> ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
> exit_group(0) = ?
>
> Logging an actual message lazily creates a socket, whether or not
> you call openlog first. Before that, it calls time, and accesses time zone
> info.

If syslogging needs a file descriptor, LOG_NDELAY is supposed to make
openlog 'allocate' that for the benefit of 'programs that need to manage
the order in which file descriptors are allocated.'.

[...]

>> static int log_fd = -1;
>>
>> static void open_log(void)
>> {
>> log_fd = open("/dev/null", O_RDWR, 0);
>> close(log_fd);
>>
>> openlog("clfds", LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);
>
> Here we should probably interrogate log_fd to see whether it is now a
> valid descriptor, from which we can infer that openlog opened it for
> some purpose, and left it open:
>
> if (fcntl(log_fd, F_GETFD) == -1) && errno == EBADF)
> log_fd = -1;
>
> (Of course, we already know that this isn't enough on one
> widespread system.)

Another idea would be to do a second open. If the returned descriptor is
different from the first, the old number was consumed by openlog.

James K. Lowden

unread,
Apr 21, 2016, 2:26:46 PM4/21/16
to
On 16 Apr 2016 09:51:21 GMT
Casper H.S. Dik <Caspe...@OrSPaMcle.COM> wrote:

> Rainer Weikusat <rwei...@talktalk.net> writes:
>
> >In a certain program, I need to determine the file descriptor number
> >which will be used to log syslog messages.
>
> Why do you want to know?

I came across another reason today: backtrace_symbols_fd(3). In severe
circumstances, there might be no better option than to write a
backtrace to the log.

--jkl

Kaz Kylheku

unread,
Apr 21, 2016, 3:07:15 PM4/21/16
to
Silly interface. If you have something like this:

backtrace_symbols_fn(..., void (*put_char_fn)(int, void *context),
void *context);

you can trivially write backtrace_symbols_fd, if you want, and in
addition redirect the backtrace however you want.

I did something similar for the ARM unwind stuff in the Linux kernel
to redirect stack dumps to a particular logging mechanism.

And/or POSIX should provide a "FILE *stdlog" stream for syslogging
using stdio. Then a backgrace_symbols_stdio makes it a no-brainer.

Syslog stream in action:

$ txr
This is the TXR Lisp interactive listener of TXR 138.
Use the :quit command or type Ctrl-D on empty line to exit.
1> (format *stdlog* "foo\n") ;; just print to *stdlog*
t
2> (format *stdlog* "foo\n")
t
3> (sh "tail -2 /var/log/syslog") ;; comes out in syslog
Apr 21 11:58:56 zelenka txr: foo
Apr 21 11:58:57 zelenka txr: foo

Dumping stuff to the raw descriptor isn't necessarily right.
Who says that the format is just raw text?

The meta-data like the time-stamp, identity, facility and severity
likely have to be serialized in some way way that is parsed by whatever
is on the other side that descriptor.

Scott Lurndal

unread,
Apr 21, 2016, 3:57:36 PM4/21/16
to
Kaz Kylheku <545-06...@kylheku.com> writes:
>On 2016-04-21, James K. Lowden <jklo...@speakeasy.net> wrote:
>> On 16 Apr 2016 09:51:21 GMT
>> Casper H.S. Dik <Caspe...@OrSPaMcle.COM> wrote:
>>
>>> Rainer Weikusat <rwei...@talktalk.net> writes:
>>>
>>> >In a certain program, I need to determine the file descriptor number
>>> >which will be used to log syslog messages.
>>>
>>> Why do you want to know?
>>
>> I came across another reason today: backtrace_symbols_fd(3). In severe
>> circumstances, there might be no better option than to write a
>> backtrace to the log.
>
>Silly interface. If you have something like this:
>
> backtrace_symbols_fn(..., void (*put_char_fn)(int, void *context),
> void *context);
>
Which gcc on linux has:

#include <execinfo.h>

void
backtrace(Logger *lp)
{
int num_frames;
void *framelist[100];
char **strings;

num_frames = ::backtrace(framelist, sizeof(framelist)/sizeof(framelist[0]));
strings = ::backtrace_symbols(framelist, num_frames);
if (strings == NULL) {
lp->log("Unable to obtain stack traceback: %s\n",
strerror(errno));
return;
}
for(int frame=0; frame < num_frames; frame++) {
char *name = strchr(strings[frame], '(');
if (name == NULL) {
lp->log("[%2.2d] %s\n", frame, strings[frame]);
} else {
size_t len = strcspn(name, "+)");
int diag = -1;
char save = name[len];
name[len] = '\0';
char *rest=name + len + 1;
char save1 = *name;
*name++ = '\0';
char *dm = abi::__cxa_demangle(name, NULL, NULL, &diag);
if (diag == 0) {
lp->log("[%2.2d] %s(%s+%s)\n", frame, strings[frame], dm, rest);
} else {
*--name = save1;
name[len] = save;
lp->log("[%2.2d] %s\n", frame, strings[frame]);
}
::free(dm);
}
}
::free(strings);
}


Rainer Weikusat

unread,
Apr 21, 2016, 4:46:01 PM4/21/16
to
Kaz Kylheku <545-06...@kylheku.com> writes:
> On 2016-04-21, James K. Lowden <jklo...@speakeasy.net> wrote:
>> On 16 Apr 2016 09:51:21 GMT
>> Casper H.S. Dik <Caspe...@OrSPaMcle.COM> wrote:
>>
>>> Rainer Weikusat <rwei...@talktalk.net> writes:
>>>
>>> >In a certain program, I need to determine the file descriptor number
>>> >which will be used to log syslog messages.
>>>
>>> Why do you want to know?
>>
>> I came across another reason today: backtrace_symbols_fd(3). In severe
>> circumstances, there might be no better option than to write a
>> backtrace to the log.

[...]

> Dumping stuff to the raw descriptor isn't necessarily right.
> Who says that the format is just raw text?
>
> The meta-data like the time-stamp, identity, facility and severity
> likely have to be serialized in some way way that is parsed by whatever
> is on the other side that descriptor.

The protocol is actually documented and fairly simple:

https://www.ietf.org/rfc/rfc3164.txt

Everything except the message is optional. Using 'raw text' should cause
everything to be logged as an emergency message -- maybe a nice idea for
a stracktrace.

------------
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/socket.h>
#include <sys/un.h>

#define LOG "/dev/log"

static unsigned fac = LOG_USER;
static unsigned prio = LOG_INFO;

static void usage(void)
{
fputs("Usage: log-it [-f <fac>] [-p <prio>] <msg>\n", stderr);
exit(1);
}

static char *parse_args(int argc, char **argv)
{
int opt;

while ((opt = getopt(argc, argv, "f:p:")) != -1)
switch (opt) {
case 'f':
fac = atoi(optarg);
break;

case 'p':
prio = atoi(optarg);
if (prio > 7) {
fprintf(stderr, "prio to large (%u)\n", prio);
exit(1);
}

break;

default:
usage();
}

argv += optind;
if (!*argv) usage();

return *argv;
}

static int lconnect(void)
{
struct sockaddr_un sun;
char *sysc;
int sk, rc;

sk = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sk == -1) {
sysc = "socket";
goto err;
}

sun.sun_family = AF_UNIX;
strncpy(sun.sun_path, LOG, sizeof(sun.sun_path));
sun.sun_path[sizeof(sun.sun_path) - 1] = 0;
rc = connect(sk, (struct sockaddr *)&sun, sizeof(sun));
if (rc == -1) {
sysc = "connect";
goto err;
}

return sk;

err:
perror(sysc);
exit(1);
}

int main(int argc, char **argv)
{
char sysl_msg[1024 + 1];
char *msg;
int sk, rc;

msg = parse_args(argc, argv);
sk = lconnect();

rc = snprintf(sysl_msg, sizeof(sysl_msg), "<%u>%s", fac * 8 + prio, msg);

rc = write(sk, sysl_msg, rc);
if (rc == -1) {
perror("write");
exit(1);
}

return 0;
}
0 new messages