3

I'm trying to write own daemon a la very simple MPD (it's operating systems laboratory work). I made it work: it starts like a daemon (output of ps):

1 14877 14877 14877 ?           -1 Ss       0   0:00 lab1_daemon

it plays, it gets signals.

The problem is that I can't run it with systemd. I wrote very simple .service file:

[Unit]
Description=Operating systems lab 1 daemon

[Service]
Type=forking
PIDFile=/run/lab1_daemon.pid
ExecStart=/path/lab1_daemon

[Install]
WantedBy=multi-user.target

But when I run daemon with systemctl start it hangs for 0.5 min and then in logs I see:

Failed to read PID from file /run/lab1_daemon.pid: Invalid argument
lab1_daemon.service never wrote its PID file. Failing.

But it did! I checked it:

-rw-r--r-- 1 root root 13 Mar  5 00:13 /run/lab1_daemon.pid

What have I done wrong?

PS: I even tried daemon function to check, that I did daemonizing correctly. But I got same results. Minimal source code (58 LOC, moved from pastebin):

#define _BSD_SOURCE
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 199506L
#define _D_XOPEN_SOURCE 700

#define NAME "lab1_daemon"
#define PID_FILE_NAME "/run/" NAME ".pid"

#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int lockfile(int fd)
{
        struct flock fl;
        fl.l_type = F_WRLCK;
        fl.l_start = 0;
        fl.l_whence = SEEK_SET;
        fl.l_len = 0;
        return fcntl(fd, F_SETLK, &fl);
}

bool is_already_running(char const *lock_file_name)
{
        int lock_file = open(lock_file_name, O_RDWR | O_CREAT,
                             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        if (lock_file < 0)
                exit(1);

        if (lockfile(lock_file) < 0) {
                if (errno == EACCES || errno == EAGAIN) {
                        close(lock_file);
                        return true;
                }
                exit(1);
        }
        ftruncate(lock_file, 0);
        char buf[16];
        sprintf(buf, "PPID: %ld\n", (long)getpid());
        write(lock_file, buf, strlen(buf) + 1);
        return false;
}

int main(void)
{
        if (is_already_running(PID_FILE_NAME))
                exit(EXIT_FAILURE);
        daemon(0, 0);
        sleep(10);
        exit(EXIT_SUCCESS);
}
1
  • And what is the content of /run/lab1_daemon.pid̀ when it's written? (just in case, to be sure)
    – lgeorget
    Mar 4, 2014 at 20:53

2 Answers 2

4

From the documentation of systemd, I guess that the problem is the incorrect format of your PID file. Instead of writing "PPID: yourpid". You should just write "yourpid". By the way, PID stands for Process ID, and PPID for Parent Process ID. You cannot use them interchangeably.

So instead of

char buf[16];
sprintf(buf, "PPID: %ld\n", (long)getpid());
write(lock_file, buf, strlen(buf) + 1);

You should do

fprintf(lock_file, "%ld\n", (long) getpid());

It would also be good practice to unlock the file as @samiam says in his answer.

1
  • Yes, my bad, how can I type PPID? Of course PID != PPID. I changed print line and created separate pid file (without locking) and now it works great. I mixed up with pid and lock files concept.
    – rominf
    Mar 5, 2014 at 10:15
2

I don't think systemd can read a file that is locked. Try something like this:

void unlockfile() {
    struct flock fl;
    fl.l_type = F_UNLCK;
    /* etc. */
    return fcntl(fd, F_SETLK, &fl);
}

Since pastebin has obnoxious talking ads, here is the original poster's entire source code:

#define _BSD_SOURCE
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 199506L
#define _D_XOPEN_SOURCE 700

#define NAME "lab1_daemon"
#define PID_FILE_NAME "/run/" NAME ".pid"

#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int lockfile(int fd)
{
    struct flock fl;
    fl.l_type = F_WRLCK;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    return fcntl(fd, F_SETLK, &fl);
}

bool is_already_running(char const *lock_file_name)
{
    int lock_file = open(lock_file_name, O_RDWR | O_CREAT,
                         S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (lock_file < 0)
            exit(1);

    if (lockfile(lock_file) < 0) {
            if (errno == EACCES || errno == EAGAIN) {
                    close(lock_file);
                    return true;
            }
            exit(1);
    }
    ftruncate(lock_file, 0);
    char buf[16];
    sprintf(buf, "PPID: %ld\n", (long)getpid());
    write(lock_file, buf, strlen(buf) + 1);
    return false;
}

int main(void)
{
    if (is_already_running(PID_FILE_NAME))
            exit(EXIT_FAILURE);
    daemon(0, 0);
    sleep(10);
    exit(EXIT_SUCCESS);
}
1
  • Sorry for pastebin. I didn't know that it has ads :) (Adblock).
    – rominf
    Mar 5, 2014 at 5:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .