Écrire son propre démon. Erreur systemd: Impossible de lire le file PID du file: argument invalide

J'essaye d'écrire propre démon à la MPD très simple (c'est le travail de laboratoire de systèmes d'exploitation). Je l'ai fait fonctionner: il commence comme un démon (sortie de ps):

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

ça joue, ça reçoit des signaux.

Le problème est que je ne peux pas l'exécuter avec systemd. J'ai écrit un file .service très simple:

 [Unit] Description=Operating systems lab 1 daemon [Service] Type=forking PIDFile=/run/lab1_daemon.pid ExecStart=/path/lab1_daemon [Install] WantedBy=multi-user.target 

Mais quand je lance daemon avec systemctl start il se bloque pendant 0,5 min et puis dans les journaux je vois:

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

Mais ça l'a fait! Je l'ai vérifié:

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

Qu'est ce que j'ai mal fait?

PS: J'ai même essayé la fonction daemon pour vérifier, que j'ai fait la démonisation correctement. Mais j'ai eu les mêmes résultats. Code source minimal (58 LOC, déplacé de 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 <ssortingng.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); } 

De la documentation de systemd, je suppose que le problème est le format incorrect de votre file PID. Au lieu d'écrire "PPID: yourpid ". Vous devriez juste écrire " yourpid ". Par ailleurs, PID signifie Process ID et PPID pour Parent Process ID. Vous ne pouvez pas les utiliser de manière interchangeable.

Donc au lieu de

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

Tu devrais faire

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

Ce serait aussi une bonne pratique de débloquer le file que @samiam dit dans sa réponse.

Je ne pense pas que systemd puisse lire un file qui est verrouillé. Essayez quelque chose comme ceci:

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

Depuis que pastebin a des publicités parlantes désagréables, voici le code source complet de l'affiche originale:

 #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 <ssortingng.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); }