私は非常に単純なMPD(オペレーティングシステムの実験室での作業)で独自のデーモンを作成しようとしています。私はそれを機能させました:それはデーモンのように始まります(psの出力):
1 14877 14877 14877 ? -1 Ss 0 0:00 lab1_daemon
再生し、信号を受け取ります。
問題は、systemdでは実行できないことです。私は非常に単純な.serviceファイルを書きました:
[Unit]
Description=Operating systems lab 1 daemon
[Service]
Type=forking
PIDFile=/run/lab1_daemon.pid
ExecStart=/path/lab1_daemon
[Install]
WantedBy=multi-user.target
しかし、systemctl start
を指定してデーモンを実行すると、0.5分間ハングし、ログに次のように表示されます。
Failed to read PID from file /run/lab1_daemon.pid: Invalid argument
lab1_daemon.service never wrote its PID file. Failing.
しかし、それはしました!私はそれをチェックしました:
-rw-r--r-- 1 root root 13 Mar 5 00:13 /run/lab1_daemon.pid
私は何を間違えましたか?
PS:daemon
関数を試して、デーモン化が正しく行われたことを確認しました。しかし、私は同じ結果を得ました。最小限のソースコード(58 LOC、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);
}
Systemdのドキュメントから、問題はPIDファイルの形式が正しくないことが原因だと思います。 「PPID:yourpid "」と書く代わりに。 「yourpid "」と書くだけです。ちなみに、PIDはプロセスID、PPIDは親プロセスIDの略です。それらを同じ意味で使用することはできません。
だから代わりに
char buf[16];
sprintf(buf, "PPID: %ld\n", (long)getpid());
write(lock_file, buf, strlen(buf) + 1);
やったほうがいい
fprintf(lock_file, "%ld\n", (long) getpid());
@samiamが彼の答えで言っているように、ファイルのロックを解除することも良い習慣です。
Systemdがロックされたファイルを読み取ることができないと思います。次のようなものを試してください。
void unlockfile() {
struct flock fl;
fl.l_type = F_UNLCK;
/* etc. */
return fcntl(fd, F_SETLK, &fl);
}
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);
}