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);
}
  • And what is the content of /run/lab1_daemon.pid̀ when it's written? (just in case, to be sure) – lgeorget Mar 4 '14 at 20:53
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.

  • 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 '14 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);
}
  • Sorry for pastebin. I didn't know that it has ads :) (Adblock). – rominf Mar 5 '14 at 5:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.