In ex1 and the lectures, we learned about strace and some of the things that it can do to help us understand what’s going on in a process. As I understand daemon processes are like background processes but I am not exactly sure what they do.

How do daemon processes work and can strace be used on these processes to figure out what they do?

So-called "daemons" work like any other processes in Linux, with a few notable differences I will describe below. This means they can be investigated via the /proc file system and commands that use it, they can be straced, and you can even attach gdb to them. However, as they are often run either as the root user or under a dedicated account, regular users are prevented from doing so. It requires superuser permissions.

Where daemons differ is that they typically do not have a controlling terminal so they are not subject to terminal management (they do not receive SIGINT for instance if someone types Ctrl-C), etc.

As a brief case study, let's look at the cupsd daemon on a Ubuntu 18.04 machine.

This daemon has process id 32069:

# ps ax | grep cupsd | grep -v grep
32069 ?        Ss     0:00 /usr/sbin/cupsd -l

The ? denotes that it lacks a controlling terminal.

We can examine its file descriptors:

# ls -l /proc/32069/fd
total 0
lr-x------ 1 root root 64 Feb 11 10:08 0 -> /dev/null
lrwx------ 1 root root 64 Feb 11 10:08 1 -> 'socket:[2352462]'
l-wx------ 1 root root 64 Feb 11 10:08 10 -> 'pipe:[2350417]'
lr-x------ 1 root root 64 Feb 11 10:08 11 -> 'pipe:[2350418]'
l-wx------ 1 root root 64 Feb 11 10:08 12 -> 'pipe:[2350418]'
l-wx------ 1 root root 64 Feb 11 10:08 14 -> 'pipe:[2350419]'
lrwx------ 1 root root 64 Feb 11 10:08 15 -> /var/log/cups/access_log
lrwx------ 1 root root 64 Feb 11 10:08 2 -> 'socket:[2352462]'
lrwx------ 1 root root 64 Feb 11 10:08 3 -> 'socket:[2353206]'
lrwx------ 1 root root 64 Feb 11 10:08 4 -> 'anon_inode:[eventpoll]'
lrwx------ 1 root root 64 Feb 11 10:08 5 -> 'socket:[2345942]'
lrwx------ 1 root root 64 Feb 11 10:08 6 -> 'socket:[2350414]'
lrwx------ 1 root root 64 Feb 11 10:08 7 -> 'socket:[2350415]'
lrwx------ 1 root root 64 Feb 11 10:08 8 -> 'socket:[2350416]'
lr-x------ 1 root root 64 Feb 11 10:08 9 -> 'pipe:[2350417]'

Standard output and standard error refer to a socket:[2352462] object, which is a Unix domain socket. A Unix socket works similar to a pipe, except that it is bidirectional and that it is tied to a path in the filesystem that is used to refer to it.

We can use the ss(8) to find out the processes connected to the endpoints of this.

# ss -x | grep 2352462
u_str  ESTAB   0        0                 /run/systemd/journal/stdout 2351222                                            * 2352462                              
u_str  ESTAB   0        0                                           * 2352462                                            * 2351222                              

Here, we learn that cupsd standard output is connected to a Unix socket at /run/systemd/journal/stdout.

systemd-journald reads from this socket and stores the output in its logs. The journalctl command can be used to retrieve what cupsd output to its standard output or error. Here's the last line:

# journalctl  -u cups | tail -1
Feb 11 10:08:02 gback-N501VW systemd[1]: Started CUPS Scheduler.

It is also possible to attach strace to the running cupsd daemon:

# strace -p 32069
strace: Process 32069 attached
epoll_wait(4,

Here, we see cupsd in the BLOCKED state inside a epoll_wait system call referencing file descriptor 4. This file descriptor refers to a so-called epoll set

lrwx------ 1 root root 64 Feb 11 10:08 4 -> 'anon_inode:[eventpoll]'

cupsd maintains multiple file descriptors at once (see the listing above) and it needs to be prepared to read from any of them, but it cannot use read(2) on any individual file descriptor for this purpose. If it used read() on one file descriptor and were blocked it couldn't then read from another file descriptor until after that first file descriptor had data available, which prevented it from reacting to input. Instead, it implements a method to multiplex multiple file descriptors at once. Further investigation would reveal the other processes with which cupsd communicates, such as /usr/lib/cups/notifier/dbus which interacts with the D-Bus.