デーモン化
任意のコマンドをデーモンプロセスとして実行するようなコマンドが欲しかったので実装してみた。
/*** * ファイル名: daemonize.c * コンパイル: gcc -o daemonize daemonize * * 概要: * 引数で渡したコマンドをデーモンプロセスとして実行する。 * * 使い方: * $ daemonize [-p PID] [--nochdir] [--noclose] cmd arg* * -p PID: cmdのプロセスIDをファイルPIDに書き込む ※ PIDには絶対パスを指定する必要がある * --nochdir: 指定されていない場合は、'/'にカレントディレクトリを移して、cmdを実行する * --noclose: 指定されていない場合は、標準入力/標準出力/標準エラー出力、を/dev/nullにリダイレクトして、cmdを実行する */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> int main(int argc, char** argv) { char* pid=NULL; char** args; int arg_i = 1; int nochdir=0; int noclose=0; // show usage if(argc < 2) { ARG_ERROR: puts("Usage: daemonize [-p PID] [--nochdir] [--noclose] cmd arg*"); return 1; } // parse arguments for(; arg_i < argc && argv[arg_i][0]=='-'; arg_i++) { char* opt = argv[arg_i]; if(strncmp(opt,"-p",2)==0) pid = opt[2]=='\0' ? argv[++arg_i] : argv[arg_i]+2; else if (strcmp(opt, "--nochdir")==0) nochdir = 1; else if (strcmp(opt, "--noclose")==0) noclose = 1; else goto ARG_ERROR; // unknown option } if(arg_i == argc) goto ARG_ERROR; // too few arguments args = argv+arg_i; // daemonize if(daemon(nochdir, noclose)==-1) return errno; // write PID if(pid) { FILE *f = fopen(pid,"w"); if(!f) return 0; fprintf(f, "%d", getpid()); fclose(f); } // exec execvp(args[0], args); // delete PID on error remove(pid); return 0; } /* // daemon関数の自作版 (若干いい加減) // linuxには(?)、デーモンプロセスを作成するための関数(daemon関数)が備わっていたので、そちらを使用するように変更 #include <stdlib.h> int daemon(int nochdir, int noclose) { int ret; ret = fork(); if(ret==-1) return -1; if(ret!= 0) exit(0); setsid(); ret = fork(); if(ret==-1) return -1; if(ret!= 0) exit(0); if(nochdir==0) if(chdir("/")==-1) return -1; umask(0); { int fd; int fd_limit = sysconf(_SC_OPEN_MAX); for(fd=3; fd < fd_limit; fd++) close(fd); if(noclose==0) { freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); freopen("/dev/null", "r", stdin); } } return 0; } */
実行例
適切な例ではないけど、一応動かしてみた結果。
$ echo $PWD /tmp $ ./daemonize sh -c 'echo $PWD' $ ./daemonize --noclose sh -c 'echo $PWD' / $ ./daemonize --nochdir --noclose sh -c 'echo $PWD' /tmp $ ./daemonize -p/tmp/sleep.pid sleep 1000 $ cat sleep.pid 17069 $ ps alx | grep 17069 F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND 0 1000 17069 1 20 0 2868 728 - Ss ? 0:00 sleep 1000
nohup, disown
上記コマンド作成後に、同じようなことを行うためのnohupやdisownというコマンドがあることを知った。
それらを使った方が良さそう...。
daemonizeコマンドの(ささいな)利点は、プロセスIDをファイルに保存できることくらいかな。