Escrevendo o próprio daemon. erro systemd: Falha ao ler PID do arquivo: argumento inválido

3

Estou tentando escrever o próprio daemon com um MPD muito simples (é um trabalho de laboratório de sistemas operacionais). Eu fiz isso funcionar: começa como um daemon (saída de ps):

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

toca, recebe sinais.

O problema é que não posso executá-lo com o systemd. Eu escrevi um arquivo de serviço muito simples:

[Unit]
Description=Operating systems lab 1 daemon

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

[Install]
WantedBy=multi-user.target

Mas quando eu executo o daemon com systemctl start , ele fica pendurado por 0.5 min e, em logs, vejo:

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

Mas aconteceu! Eu verifiquei:

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

O que eu fiz de errado?

PS: Eu até tentei a função daemon verificar, que eu fiz daemonizing corretamente. Mas eu tenho os mesmos resultados. Código fonte mínimo (58 LOC, movido do 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);
}
    
por rominf 04.03.2014 / 21:41

2 respostas

4

Da documentação do systemd, acredito que o problema é o formato incorreto do seu arquivo PID. Em vez de escrever "PPID: yourpid ". Você deve apenas escrever " yourpid ". A propósito, PID significa Process ID e PPID para Parent Process ID. Você não pode usá-los de forma intercambiável.

Então, em vez de

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

Você deve fazer

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

Também seria uma boa prática desbloquear o arquivo como @samiam diz em sua resposta.

    
por 04.03.2014 / 22:28
2

Eu não acho que o systemd possa ler um arquivo que está bloqueado. Tente algo assim:

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

Como o pastebin tem anúncios faladores desagradáveis, aqui está o código fonte inteiro do pôster original:

#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);
}
    
por 04.03.2014 / 22:14