Tworzenie demona w Linuksie
W Linuksie chcę dodać demona, którego nie można zatrzymać i który monitoruje zmiany systemu plików. Jeśli zostaną wykryte jakiekolwiek zmiany, powinien napisać ścieżkę do konsoli, w której został uruchomiony, oraz znak nowej linii.
Mam już prawie gotowy kod zmieniający system plików, ale nie mogę wymyślić, jak utworzyć demona.
Mój kod pochodzi stąd: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
Co zrobić po widelcu?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;
}
8 answers
W Linuksie chcę dodać demona, którego nie można zatrzymać i który monitoruje zmiany systemu plików. Jeśli zostaną wykryte jakiekolwiek zmiany, powinien napisać ścieżkę do konsoli, w której został uruchomiony + znak nowej linii.
Demony działają w tle i (zazwyczaj...) nie należy do TTY, dlatego nie możesz używać stdout/stderr w sposób, w jaki prawdopodobnie chcesz. Zazwyczaj Demon syslog (syslogd) jest używany do rejestrowania Wiadomości do plików (debug, błąd,...).
Poza tym istnieje kilka wymaganych kroków , aby daemonizować proces.
Jeśli dobrze pamiętam te kroki to:
- fork wyłącz proces macierzysty i pozwól mu zakończyć się, jeśli rozwidlenie się powiedzie. - >Ponieważ proces macierzysty został zakończony, proces potomny działa teraz w tle.
- setsid - Utwórz nową sesję. Proces wywołujący staje się liderem nowej sesji i procesu lider grupy nowych procesów. Proces jest teraz oddzielony od swojego terminala sterującego (CTTY).
- Catch signals - ignorować i / lub obsługiwać sygnały.
- fork again & pozwól procesowi nadrzędnemu zakończyć się, aby upewnić się, że pozbędziesz się wiodącego procesu sesji. (Tylko liderzy sesji mogą ponownie uzyskać TTY.)
- chdir - Zmiana katalogu roboczego demona.
- umask - Zmiana maski trybu Pliku według potrzeby demona.
- close - zamyka wszystkie otwarte deskryptory plików, które mogą być dziedziczone po procesie nadrzędnym.
Aby dać ci punkt wyjścia: spójrz na ten szkielet kodu, który pokazuje podstawowe kroki:
/*
* 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;
}
- Skompiluj kod:
gcc -o firstdaemon daemonize.c
- Uruchom demona:
./firstdaemon
Sprawdź, czy wszystko działa poprawnie:
ps -xj | grep firstdaemon
-
Wyjście powinno być podobne do tego jeden:
+------+------+------+------+-----+-------+------+------+------+-----+ | PPID | PID | PGID | SID | TTY | TPGID | STAT | UID | TIME | CMD | +------+------+------+------+-----+-------+------+------+------+-----+ | 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ | +------+------+------+------+-----+-------+------+------+------+-----+
To co powinieneś zobaczyć to:
- demon nie ma kontrolującego terminala ( TTY = ?)
- identyfikator procesu nadrzędnego (PPID) jest 1 (proces init)
- PID ! Oznacza to, że nasz proces nie jest liderem sesji.]} (z powodu drugiego widelca ())
- ponieważ PID != SID nasz proces nie może przejąć kontroli nad TTY again
Czytanie sysloga:
- Zlokalizuj swój plik syslog. Mój jest tutaj:
/var/log/syslog
Do a:
grep firstdaemon /var/log/syslog
-
Wyjście powinno być podobne do tego:
firstdaemon[3387]: First daemon started. firstdaemon[3387]: First daemon terminated.
uwaga:
W rzeczywistości chciałbyś również zaimplementować obsługę sygnału i poprawnie skonfigurować rejestrowanie (pliki, poziomy dziennika...).
Czytaj dalej:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-29 06:49:55
man 7 daemon
opisuje szczegółowo, jak tworzyć demona. Moja odpowiedź to tylko fragment tego podręcznika.
Istnieją co najmniej dwa rodzaje demonów:
Demony SysV
Jeśli interesuje Cię tradycyjnyDemon SysV , powinieneś zaimplementować następujący kroki :
- Zamknij wszystkie otwarte deskryptory plików z wyjątkiem standardowego wejścia , wyjście i błąd (tj. pierwsze trzy deskryptory plików 0, 1, 2). Gwarantuje to, że żaden przypadkowo przekazany deskryptor pliku nie pozostanie w procesie demona. W Linuksie najlepiej jest to zaimplementować poprzez iterację przez
/proc/self/fd
, z powrotem iteracji z deskryptora pliku 3 do wartości zwracanej przezgetrlimit()
dlaRLIMIT_NOFILE
.- Reset wszystkie obsługa sygnałów do ich domyślnych. Najlepiej jest to zrobić poprzez iterację dostępnych sygnałów do limitu
_NSIG
i zresetowanie ich doSIG_DFL
.- Zresetuj maskę sygnału za pomocą
sigprocmask()
.- wyczyścić blok środowiska, usuwając lub resetując zmienne środowiskowe, które mogą negatywnie wpłynąć na środowisko uruchomieniowe demona.
- Call
fork()
, aby utworzyć proces w tle.- u dziecka wywołanie
setsid()
aby odłączyć się od dowolnego terminala i Utwórz niezależną sesję .- u dziecka wywołanie
fork()
ponownie, aby upewnić się, że demon nie może ponownie zdobyć terminala.- Call
exit()
W pierwszym potomku, tak, że tylko drugie dziecko (rzeczywisty proces demona) pozostaje w pobliżu. Gwarantuje to, że proces daemona zostanie przekierowany do init / PID 1, tak jak powinny być wszystkie demony.- w procesie demona połącz
/dev/null
do standardowego wejścia , wyjście i błąd .- w procesie demona zresetuj
umask
do 0, tak aby tryby pliku przeszły doopen()
,mkdir()
i takjak bezpośrednio kontrolować tryb dostępu do utworzonych plików i katalogów.- w procesie demona, Zmień bieżący katalog na katalog główny (
/
), aby uniknąć tego, że Demon mimowolnie blokuje punkty montowania przed odmontowaniem.- W proces demona, napisz demona PID (jako zwracane przez
getpid()
) do pliku PID, na przykład/run/foobar.pid
(dla hipotetycznego demona "foobar"), aby upewnić się, że demon nie może być uruchomiony więcej niż jeden raz. Musi to być realizowane w sposób wolny od rasy tak, że plik PID jest aktualizowany tylko wtedy, gdy jest zweryfikowane w tym samym czasie, że PID wcześniej zapisane w pliku PID nie istnieje lub należy do zagranicznego procesu.- w procesie demona, upuść uprawnienia, jeśli możliwe i stosowne.
- Z procesu demona, powiadom rozpoczęty oryginalny proces o zakończeniu inicjalizacji. Można to zaimplementować za pomocą nienazwanego potoku lub podobnego kanału komunikacyjnego, który jest tworzony przed pierwszym
fork()
i stąd dostępne zarówno w oryginale, jak i w procesie demona.- Call
exit()
w pierwotnym procesie. Proces, który wywołał demona, musi być w stanie polegać na tym, że toexit()
happens po inicjalizacja jest zakończona i wszystkie zewnętrzne kanały komunikacji są ustanowione i dostępne.
Zwróć uwagę na to Ostrzeżenie:
BSD
daemon()
funkcja nie powinna być używana, ponieważ implementuje tylko podzbiór tych kroków.Demon, który musi zapewnić kompatybilność z systemami SysV powinien zaimplementować schemat wskazany powyżej. Jednak zaleca się, aby to zachowanie opcjonalne i konfigurowalne za pomocą argumentu wiersza poleceń w celu ułatwienia debugowania, jak również w celu uproszczenia integracji z systemami przy użyciu systemd.
Zauważ, że daemon()
nie jest zgodny z POSIX .
Demony W Nowym Stylu
Dla demonów nowego stylu zaleca się następujące kroki: ]}
- jeśli odebrano
SIGTERM
, wyłącz demona i zakończ go czysto.- If
SIGHUP
is received, reload the pliki konfiguracyjne, jeśli ma to zastosowanie.- podaj poprawny kod wyjścia z głównego procesu demona, ponieważ jest on używany przez system init do wykrywania błędów i problemów z usługą. Zaleca się stosowanie schematu kodu wyjścia zdefiniowanego w zaleceniach LSB dla skryptów init SysV .
- jeśli to możliwe i stosowne, wystaw interfejs sterowania demona za pomocą systemu D-Bus IPC i pobierz nazwę magistrali jako ostatni krok inicjalizacji.
- Dla integracja w systemd, podaj .serwis unit plik, który zawiera informacje o uruchamianiu, zatrzymywaniu i utrzymywaniu demona w inny sposób. Zobacz też
systemd.service(5)
Po szczegóły.- w miarę możliwości, polegaj na funkcjonalności systemu init, aby ograniczyć dostęp demona do plików, usług i innych zasobów, tj. w przypadku systemd, polegaj na kontroli limitu zasobów systemd zamiast implementować własne, polegaj na systemd upuszczanie kodu zamiast implementowania go w Demonie i tym podobne. Zobacz też
systemd.exec(5)
Dla dostępnych elementów sterujących.- jeśli D-Busjest używany, Uaktywnij magistralę demona, dostarczając plik konfiguracyjny aktywacji usługi D-Bus . Ma to wiele zalet: Demon może być uruchamiany leniwie na żądanie; może być uruchamiany równolegle do innych demonów, które go wymagają - co maksymalizuje równoległość i prędkość rozruchu ; Twój Demon może zostać uruchomiony ponownie w przypadku awarii bez utraty żądań autobusowych, ponieważ kolejki autobusowe żądają aktywowanych usług. Zobacz poniżej Po szczegóły.
- jeśli twój Demon świadczy usługi innym lokalnym procesom lub zdalnym klientom za pośrednictwem gniazda, powinien on być aktywowany zgodnie ze schematem wskazanym poniżej . Podobnie jak aktywacja D-Bus, umożliwia to uruchamianie usług na żądanie, a także umożliwia lepszą równoległość usług start-up. Ponadto, w przypadku protokołów bez stanu (takich jak syslog, DNS), Demon implementujący aktywację opartą na gniazdach może zostać ponownie uruchomiony bez utraty ani jednego żądania. Zobacz poniżej Po szczegóły.
- jeśli ma to zastosowanie, Demon powinien powiadomić system init o zakończeniu uruchamiania lub aktualizacji statusu za pomocą
sd_notify(3)
interfejs.- zamiast używać
syslog()
wywołanie logowania bezpośrednio do usługi syslog systemu, daemon w Nowym Stylu może wybrać po prostu logowanie do błąd standardowy poprzezfprintf()
, który jest następnie przekazywany do syslog przez system init. Jeśli konieczne są poziomy logów, mogą one być zakodowane przez prefiks pojedynczych linii logów z łańcuchami takimi jak " "(dla poziomu log 4 "WARNING" w schemacie priorytetu syslog), zgodnie z podobnym stylem jak jądro Linuksaprintk()
system poziomów. Szczegółowe informacje można znaleźć na stroniesd-daemon(3)
orazsystemd.exec(5)
.
Aby dowiedzieć się więcej czytaj całość man 7 daemon
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-08 10:09:22
I can stop at the first requirement " a daemon which cannot be stopped ..."
Nie jest to możliwe mój przyjacielu; jednak możesz osiągnąć to samo za pomocą znacznie lepszego narzędzia, modułu jądra.
Http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring
Wszystkie demony można zatrzymać. Niektóre są łatwiejsze do powstrzymania niż inne. Nawet para demonów z partnerem w przytrzymaniu, odradzanie partnera w przypadku utraty, może zostać zatrzymana. Po prostu musisz trochę ciężej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 19:20:24
Nie można utworzyć procesu w Linuksie, którego nie można zabić. Użytkownik root (UID=0) może wysłać sygnał do procesu i są dwa sygnały, których nie można przechwycić, SIGKILL=9, SIGSTOP=19. I inne sygnały (gdy nie są przesyłane) mogą również powodować zakończenie procesu.
Możesz potrzebować bardziej ogólnej funkcji demonizacji, w której możesz podać nazwę swojego programu / demona oraz ścieżkę do uruchomienia programu (być może "/" lub "/tmp"). Możesz również podać pliki dla stderr i stdout (i ewentualnie ścieżka kontrolna przy użyciu standardowego wejścia).
Oto niezbędne elementy:
#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)
A oto bardziej ogólna Funkcja,
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);
}
Oto przykładowy program, który staje się demonem, wisi wokół, a następnie odchodzi.
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);
}
Zauważ, że SIG_IGN oznacza przechwytywanie i ignorowanie sygnału. Można zbudować funkcję obsługi sygnału, która może rejestrować odbiór sygnału i ustawiać flagi(takie jak flaga wskazująca wdzięczne zamknięcie).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-15 19:43:11
Spróbuj użyć funkcji daemon
:
#include <unistd.h>
int daemon(int nochdir, int noclose);
Funkcja daemon() jest przeznaczona dla programów, które chcą się odłączyć z terminala sterującego i uruchom w tle jako system demony.
Jeśli nochdir jest równy zero, daemon () zmienia bieżący proces wywołujący working directory to the root directory ( " / " ); w przeciwnym razie, bieżący katalog roboczy pozostaje bez zmian.
Jeśli noclose jest równe zero, DAEMON () przekierowuje standardowe wejście, standardowe wyjście i standardowy błąd do /dev / null; w przeciwnym razie żadne zmiany nie są do tych deskryptorów plików.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-13 00:13:29
Jeśli Twoja aplikacja jest jedną z:
{
".sh": "bash",
".py": "python",
".rb": "ruby",
".coffee" : "coffee",
".php": "php",
".pl" : "perl",
".js" : "node"
}
I nie masz nic przeciwko zależności od NodeJS to zainstaluj NodeJS a potem:
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
Aby wszystkie aplikacje były uruchomione przy ponownym uruchomieniu (i demonizowaniu pm2):
pm2 startup
pm2 save
Teraz możesz:
service pm2 stop|restart|start|status
Pozwala również łatwo obserwować zmiany kodu w katalogu aplikacji i automatycznie restartować proces aplikacji, gdy nastąpi zmiana kodu)Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-29 03:17:57
Wywołując fork() utworzyłeś proces potomny. Jeśli fork powiedzie się (Fork zwrócił niezerowy PID) wykonywanie będzie kontynuowane od tego momentu z wewnątrz procesu potomnego. W tym przypadku chcemy z wdziękiem wyjść z procesu rodzica, a następnie kontynuować naszą pracę w procesie dziecka.
Może to pomoże: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 18:32:54
Demon jest tylko procesem w tle. Jeśli chcesz uruchomić program po uruchomieniu systemu operacyjnego, na Linuksie Dodaj swoje polecenie start do /etc / rc.d / rc.local (Uruchom po wszystkich innych skryptach) lub /etc/startup.sh
W systemie windows tworzysz usługę, rejestrujesz usługę, a następnie ustawiasz ją tak, aby uruchamiała się automatycznie przy starcie w panelu Administracja - > Usługi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 18:22:57