Linux에서는 중지 할 수없고 파일 시스템 변경을 모니터링하는 데몬을 추가하고 싶습니다. 변경 사항이 감지되면 시작된 콘솔 경로와 개행 문자를 기록해야합니다.
이미 파일 시스템 변경 코드가 거의 준비되어 있지만 데몬을 만드는 방법을 알 수 없습니다.
내 코드는 여기에 있습니다 : http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
포크 후에 무엇을해야합니까?
int main (int argc, char **argv) {
pid_t pID = fork();
if (pID == 0) { // child
// Code only executed by child process
sIdentifier = "Child Process: ";
}
else if (pID < 0) {
cerr << "Failed to fork" << endl;
exit(1);
// Throw exception
}
else // parent
{
// Code only executed by parent process
sIdentifier = "Parent Process:";
}
return 0;
}
답변
Linux에서 중지 할 수없고 파일 시스템 변경을 모니터링하는 데몬을 추가하고 싶습니다. 변경 사항이 감지되면 시작된 콘솔 경로 + 개행 문자를 작성해야합니다.
데몬은 백그라운드에서 작동하며 (보통 …) TTY에 속하지 않기 때문에 원하는 방식으로 stdout / stderr를 사용할 수 없습니다. 일반적으로 syslog 데몬 ( syslogd )은 파일 (디버그, 오류 등)에 메시지를 기록하는 데 사용됩니다.
그 외에도 프로세스를 데몬 화하는 데 필요한 몇 가지 단계 가 있습니다.
올바르게 기억하는 경우 다음 단계는 다음과 같습니다.
- 부모 프로세스를 포크 하고 포크가 성공하면 종료합니다. -> 상위 프로세스가 종료되었으므로 이제 하위 프로세스가 백그라운드에서 실행됩니다.
- setsid- 새 세션을 만듭니다. 호출 프로세스는 새 세션의 리더가되고 새 프로세스 그룹의 프로세스 그룹 리더가됩니다. 이제 프로세스가 제어 터미널 (CTTY)에서 분리됩니다.
- 신호 포착 – 신호를 무시 및 / 또는 처리합니다.
- 다시 포크 하고 부모 프로세스를 종료하여 세션 선행 프로세스를 제거하십시오. (세션 리더 만이 TTY를 다시받을 수 있습니다.)
- chdir- 데몬의 작업 디렉토리를 변경합니다.
- umask- 데몬의 필요에 따라 파일 모드 마스크를 변경합니다.
- close- 상위 프로세스에서 상속 될 수있는 모든 열린 파일 설명자를 닫 습니다 .
시작점을 제공하려면 : 기본 단계를 보여주는 스켈레톤 코드를보십시오. 이 코드는 이제 GitHub : Linux 데몬의 기본 골격 에서도 분기 할 수 있습니다.
/*
* daemonize.c
* This example daemonizes a process, writes a few log messages,
* sleeps 20 seconds and terminates afterwards.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
static void skeleton_daemon()
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}
/* Open the log file */
openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
skeleton_daemon();
while (1)
{
//TODO: Insert daemon code here.
syslog (LOG_NOTICE, "First daemon started.");
sleep (20);
break;
}
syslog (LOG_NOTICE, "First daemon terminated.");
closelog();
return EXIT_SUCCESS;
}
- 코드를 컴파일합니다.
gcc -o firstdaemon daemonize.c
- 데몬을 시작합니다.
./firstdaemon
-
모든 것이 제대로 작동하는지 확인하십시오.
ps -xj | grep firstdaemon
-
출력은 다음과 유사해야합니다.
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- + | PPID | PID | PGID | SID | TTY | TPGID | 통계 | UID | 시간 | CMD | + ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- + | 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ | + ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
여기서 확인해야 할 것은 다음과 같습니다.
- 데몬에는 제어 터미널이 없습니다 ( TTY =? )
- 상위 프로세스 ID ( PPID )는 1 (초기 프로세스)입니다.
- PID! = SID 우리의 프로세스가 세션 리더되지 않음을 의미합니다
(때문에 두 번째 포크 ()) - PID! = SID 때문에 우리 프로세스 는 TTY를 다시 제어 할 수 없습니다.
syslog 읽기 :
- syslog 파일을 찾습니다. 내 위치 :
/var/log/syslog
-
다음을 수행하십시오.
grep firstdaemon /var/log/syslog
-
출력은 다음과 유사해야합니다.
firstdaemon [3387] : 첫 번째 데몬이 시작되었습니다. firstdaemon [3387] : 첫 번째 데몬이 종료되었습니다.
참고 :
실제로 신호 처리기를 구현하고 로깅을 적절하게 설정해야합니다 (파일, 로그 수준 …).
추가 읽기 :
답변
man 7 daemon
데몬을 만드는 방법을 자세히 설명합니다. 내 대답은이 설명서에서 발췌 한 것입니다.
데몬에는 최소한 두 가지 유형이 있습니다.
SysV 데몬
기존 SysV 데몬에 관심이있는 경우 다음 단계를 구현해야 합니다 .
- 표준 입력 , 출력 및 오류 (즉, 처음 세 개의 파일 설명자 0, 1, 2)를 제외한 모든 열린 파일 설명자를 닫습니다 . 이는 실수로 전달 된 파일 설명자가 데몬 프로세스에 남아 있지 않도록합니다. Linux에서는
/proc/self/fd
파일 설명자 3에서getrlimit()
for에서 반환 한 값으로의 반복을 대체 하여를 반복하여 구현하는 것이 가장 좋습니다RLIMIT_NOFILE
.- 모든 신호 처리기를 기본값으로 재설정 합니다. 사용 가능한 신호를 최대 한도까지 반복
_NSIG
하고로 재설정하는 것이 가장 좋습니다SIG_DFL
.- 를 사용하여 신호 마스크를 재설정합니다
sigprocmask()
.- 데몬 런타임에 부정적인 영향을 미칠 수있는 환경 변수를 제거하거나 재설정하여 환경 블록을 삭제합니다.
- 를 호출
fork()
하여 백그라운드 프로세스를 만듭니다.- 자식
setsid()
에서 모든 터미널에서 분리하고 독립적 인 세션을 만들기 위해 호출 합니다 .- 자식에서
fork()
다시 호출 하여 데몬이 터미널을 다시 획득 할 수 없도록합니다.exit()
첫 번째 자식을 호출 하여 두 번째 자식 (실제 데몬 프로세스) 만 유지되도록합니다. 이렇게하면 모든 데몬이 그래야하는 것처럼 데몬 프로세스가 init / PID 1의 상위가됩니다.- 데몬 프로세스에서
/dev/null
표준 input , output 및 error에 연결 합니다 .- 데몬 과정에서,를 다시
umask
파일 모드가 통과 그래서, 0open()
,mkdir()
직접 만든 파일과 디렉토리의 액세스 모드를 제어 그와 같은.- 데몬 프로세스 에서 현재 디렉토리를 루트 디렉토리 ( ) 로 변경
/
하여 데몬이 마운트 지점이 마운트 해제되는 것을 무의식적으로 차단하지 않도록합니다.- 데몬 프로세스에서 데몬 PID (에서 반환 된대로
getpid()
)를 PID 파일/run/foobar.pid
( 예 : 가상 데몬 “foobar”의 경우)에 기록하여 데몬이 두 번 이상 시작되지 않도록합니다. PID 파일에 이전에 저장된 PID가 더 이상 존재하지 않거나 외부 프로세스에 속함과 동시에 PID 파일이 확인 될 때만 PID 파일이 업데이트되도록 경쟁없는 방식으로 구현해야합니다.- 데몬 프로세스에서 가능하고 적용 가능한 경우 권한을 삭제합니다.
- 데몬 프로세스에서 초기화가 완료되었음을 시작된 원래 프로세스에 알립니다. 이것은 이름이 지정되지 않은 파이프 또는 첫 번째 이전에 생성 된 유사한 통신 채널을 통해 구현 될 수 있으므로
fork()
원본 및 데몬 프로세스 모두에서 사용할 수 있습니다.exit()
원래 프로세스를 호출 하십시오. 데몬을 호출 한 프로세스는 초기화가 완료되고 모든 외부 통신 채널이 설정되고 액세스 가능한 후에exit()
발생 한다는 사실에 의존 할 수 있어야합니다 .
다음 경고에 유의하십시오.
BSD
daemon()
함수 는 이러한 단계 의 하위 집합 만 구현하므로 사용 해서는 안됩니다 .SysV 시스템과의 호환성 을 제공해야하는 데몬은 위에서 언급 한 체계를 구현해야합니다. 그러나 디버깅을 용이하게하고 systemd를 사용하여 시스템으로의 통합을 단순화하기 위해이 동작을 선택 사항으로 만들고 명령 줄 인수를 통해 구성 할 수 있도록하는 것이 좋습니다.
새로운 스타일의 데몬
새로운 스타일의 데몬의 경우 다음 단계 를 권장합니다.
- 경우
SIGTERM
수신 깨끗하게 데몬 종료를 종료합니다.SIGHUP
수신 된 경우 구성 파일을 다시로드하십시오 (적용되는 경우).- 서비스 오류 및 문제를 감지하기 위해 init 시스템에서 사용하므로 기본 데몬 프로세스에서 올바른 종료 코드를 제공하십시오. SysV init 스크립트 에 대한 LSB 권장 사항에 정의 된 종료 코드 체계를 따르는 것이 좋습니다 .
- 가능하고 적용 가능한 경우 D-Bus IPC 시스템을 통해 데몬의 제어 인터페이스를 노출하고 초기화의 마지막 단계로 버스 이름을 가져옵니다.
- systemd에서 통합 하려면 데몬 시작, 중지 및 유지 관리에 대한 정보를 전달 하는 .service unit 파일을 제공 하십시오. 자세한 내용은
systemd.service(5)
을 참조하십시오.- 가능한 한 init 시스템의 기능에 의존하여 파일, 서비스 및 기타 리소스에 대한 데몬 액세스를 제한합니다. 즉, systemd의 경우 자체 구현 대신 systemd의 리소스 제한 제어 에 의존하고 systemd의 권한 삭제 에 의존합니다. 데몬에서 구현하는 대신 코드와 유사합니다.
systemd.exec(5)
사용 가능한 컨트롤 은 을 참조하십시오 .- 경우 D-버스가 사용하는 D-버스 서비스 활성화에 공급하여 데몬 버스 – 기동하게 구성 파일을 . 여기에는 여러 가지 장점이 있습니다. 데몬이 요청시 느리게 시작될 수 있습니다. 필요한 다른 데몬과 병렬로 시작될 수 있습니다. 이는 병렬화 및 부팅 속도 를 최대화 합니다 . 버스가 활성화 가능한 서비스에 대한 요청을 대기열에 추가하므로 버스 요청을 잃지 않고 실패시 데몬을 다시 시작할 수 있습니다. 자세한 내용은 아래 를 참조하십시오.
- 데몬이 소켓을 통해 다른 로컬 프로세스 나 원격 클라이언트에 서비스를 제공하는 경우 아래에 설명 된 체계에 따라 소켓 활성화 가 가능해야 합니다 . D-Bus 활성화와 마찬가지로 이것은 서비스 시작의 병렬화를 개선 할뿐만 아니라 주문형 서비스 시작을 가능하게합니다. 또한 상태 비 저장 프로토콜 (예 : syslog, DNS)의 경우 단일 요청 손실없이 소켓 기반 활성화를 구현하는 데몬을 다시 시작할 수 있습니다. 자세한 내용은 아래 를 참조하십시오.
- 해당되는 경우 데몬은
sd_notify(3)
인터페이스 를 통해 시작 완료 또는 상태 업데이트에 대해 init 시스템에 알려야합니다 .syslog()
호출을 사용하여 시스템 syslog 서비스에 직접 기록 하는 대신 새로운 스타일의 데몬은를 통해 단순히 표준 오류에 기록하도록 선택할 수 있습니다.fprintf()
그런 다음 init 시스템에 의해 syslog로 전달됩니다. 로그 수준이 필요한 경우 Linux 커널printk()
수준 시스템 과 유사한 스타일에 따라 “<4>”(syslog 우선 순위 체계의 로그 수준 4 “WARNING”)와 같은 문자열로 개별 로그 행을 접두사로 지정하여 이러한 수준을 인코딩 할 수 있습니다 . 자세한 내용은sd-daemon(3)
및을 참조하십시오systemd.exec(5)
.
자세한 내용은 전체를 읽으십시오 man 7 daemon
.
답변
리눅스에서는 죽일 수없는 프로세스를 만들 수 없습니다. 루트 사용자 (uid = 0)는 프로세스에 신호를 보낼 수 있으며 잡을 수없는 신호는 SIGKILL = 9, SIGSTOP = 19입니다. 그리고 다른 신호 (잡히지 않은 경우)도 프로세스를 종료 할 수 있습니다.
프로그램 / 데몬의 이름과 프로그램을 실행할 경로 (예 : “/”또는 “/ tmp”)를 지정할 수있는보다 일반적인 데몬 화 기능이 필요할 수 있습니다. stderr 및 stdout (및 stdin을 사용하는 제어 경로)에 대한 파일을 제공 할 수도 있습니다.
필요한 것은 다음과 같습니다.
#include <stdio.h> //printf(3)
#include <stdlib.h> //exit(3)
#include <unistd.h> //fork(3), chdir(3), sysconf(3)
#include <signal.h> //signal(3)
#include <sys/stat.h> //umask(3)
#include <syslog.h> //syslog(3), openlog(3), closelog(3)
여기 더 일반적인 기능이 있습니다.
int
daemonize(char* name, char* path, char* outfile, char* errfile, char* infile )
{
if(!path) { path="/"; }
if(!name) { name="medaemon"; }
if(!infile) { infile="/dev/null"; }
if(!outfile) { outfile="/dev/null"; }
if(!errfile) { errfile="/dev/null"; }
//printf("%s %s %s %s\n",name,path,outfile,infile);
pid_t child;
//fork, detach from process group leader
if( (child=fork())<0 ) { //failed fork
fprintf(stderr,"error: failed fork\n");
exit(EXIT_FAILURE);
}
if (child>0) { //parent
exit(EXIT_SUCCESS);
}
if( setsid()<0 ) { //failed to become session leader
fprintf(stderr,"error: failed setsid\n");
exit(EXIT_FAILURE);
}
//catch/ignore signals
signal(SIGCHLD,SIG_IGN);
signal(SIGHUP,SIG_IGN);
//fork second time
if ( (child=fork())<0) { //failed fork
fprintf(stderr,"error: failed fork\n");
exit(EXIT_FAILURE);
}
if( child>0 ) { //parent
exit(EXIT_SUCCESS);
}
//new file permissions
umask(0);
//change to path directory
chdir(path);
//Close all open file descriptors
int fd;
for( fd=sysconf(_SC_OPEN_MAX); fd>0; --fd )
{
close(fd);
}
//reopen stdin, stdout, stderr
stdin=fopen(infile,"r"); //fd=0
stdout=fopen(outfile,"w+"); //fd=1
stderr=fopen(errfile,"w+"); //fd=2
//open syslog
openlog(name,LOG_PID,LOG_DAEMON);
return(0);
}
다음은 데몬이되어 주위를 맴돌다가 떠나는 샘플 프로그램입니다.
int
main()
{
int res;
int ttl=120;
int delay=5;
if( (res=daemonize("mydaemon","/tmp",NULL,NULL,NULL)) != 0 ) {
fprintf(stderr,"error: daemonize failed\n");
exit(EXIT_FAILURE);
}
while( ttl>0 ) {
//daemon code here
syslog(LOG_NOTICE,"daemon ttl %d",ttl);
sleep(delay);
ttl-=delay;
}
syslog(LOG_NOTICE,"daemon ttl expired");
closelog();
return(EXIT_SUCCESS);
}
SIG_IGN은 신호를 포착하고 무시 함을 나타냅니다. 신호 수신을 기록 할 수있는 신호 처리기를 빌드하고 플래그 (예 : 정상 종료를 나타내는 플래그)를 설정할 수 있습니다.
답변
daemon
기능을 사용해보십시오 :
#include <unistd.h>
int daemon(int nochdir, int noclose);
로부터 man 페이지 :
daemon () 함수는 제어 터미널에서 자신을 분리하고 시스템 데몬으로 백그라운드에서 실행하려는 프로그램을위한 것입니다.
nochdir이 0이면 daemon ()은 호출 프로세스의 현재 작업 디렉토리를 루트 디렉토리 ( “/”)로 변경합니다. 그렇지 않으면 현재 작업 디렉토리가 변경되지 않습니다.
noclose가 0이면 daemon ()은 표준 입력, 표준 출력 및 표준 오류를 / dev / null로 리디렉션합니다. 그렇지 않으면 이러한 파일 설명자가 변경되지 않습니다.
답변
” 멈출 수없는 데몬 …” 이라는 첫 번째 요구 사항에서 멈출 수 있습니다 .
내 친구는 불가능합니다. 그러나 훨씬 더 나은 도구 인 커널 모듈을 사용하여 동일한 결과를 얻을 수 있습니다.
http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring
모든 데몬을 중지 할 수 있습니다. 일부는 다른 것보다 더 쉽게 중지됩니다. 보류중인 파트너와의 데몬 쌍도 잃어버린 경우 파트너를 리스폰하는 것을 중지 할 수 있습니다. 당신은 그것에 대해 조금 더 열심히 일해야합니다.
답변
앱이 다음 중 하나 인 경우 :
{
".sh": "bash",
".py": "python",
".rb": "ruby",
".coffee" : "coffee",
".php": "php",
".pl" : "perl",
".js" : "node"
}
NodeJS 종속성에 신경 쓰지 않고 NodeJS를 설치하고 다음을 수행하십시오.
npm install -g pm2
pm2 start yourapp.yourext --name "fred" # where .yourext is one of the above
pm2 start yourapp.yourext -i 0 --name "fred" # run your app on all cores
pm2 list
재부팅시 모든 앱을 계속 실행하려면 (및 pm2 데몬 화) :
pm2 startup
pm2 save
이제 다음을 수행 할 수 있습니다.
service pm2 stop|restart|start|status
(또한 쉽게 앱 디렉토리에서 코드 변경을 감시하고 코드 변경이 발생하면 앱 프로세스를 자동으로 다시 시작할 수 있습니다)
답변
fork ()를 호출하여 자식 프로세스를 만들었습니다. 포크가 성공하면 (포크가 0이 아닌 PID를 반환 함) 자식 프로세스 내에서이 지점부터 실행이 계속됩니다. 이 경우 부모 프로세스를 정상적으로 종료 한 다음 자식 프로세스에서 작업을 계속하려고합니다.
아마도 이것이 도움이 될 것입니다 :
http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html