Sous Linux, je souhaite ajouter un démon qui ne peut pas être arrêté et qui surveille les modifications du système de fichiers. Si des modifications sont détectées, il convient d'écrire le chemin d'accès à la console où elle a été démarrée, ainsi qu'une nouvelle ligne.
Le système de fichiers est déjà prêt à changer de code, mais je ne sais pas comment créer un démon.
Mon code vient d'ici: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
Que faire après la fourchette?
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;
}
Sous Linux, je veux ajouter un démon qui ne peut pas être arrêté et qui surveille les modifications du système de fichiers. Si des modifications sont détectées, le chemin d'accès à la console où elle a été démarrée doit être écrit + une nouvelle ligne.
Les démons fonctionnent en arrière-plan et (généralement ...) n'appartiennent pas à un téléscripteur. C'est pourquoi vous ne pouvez pas utiliser stdout/stderr comme vous le souhaitez probablement. Généralement, un démon syslog ( syslogd ) est utilisé pour consigner les messages dans des fichiers (débogage, erreur, ...).
En plus de cela, il y a quelques étapes requises pour démoniser un processus.
Si je me souviens bien, ces étapes sont les suivantes:
Pour vous donner un point de départ: Regardez ce code squelette qui montre les étapes de base. Ce code peut maintenant aussi être créé dans GitHub: squelette de base d’un démon 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
Vérifiez si tout fonctionne correctement: ps -xj | grep firstdaemon
Le résultat devrait ressembler à celui-ci:
+ ------ + ------ + ------ + ------ + ----- + ------- + - ---- + ------ + ------ + ----- + | PPID | PID | PGID | SID | ATS | TPGID | STAT | UID | TEMPS | CMD | + ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- + | 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ | + ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
Ce que vous devriez voir ici est:
Lecture du journal système:
/var/log/syslog
Faites un: grep firstdaemon /var/log/syslog
Le résultat devrait ressembler à celui-ci:
firstdaemon [3387]: premier démon démarré. firstdaemon [3387]: premier démon terminé.
Remarque: En réalité, vous voudriez également implémenter un gestionnaire de signal et configurer correctement la journalisation (fichiers, niveaux de journalisation). .).
Lectures supplémentaires:
Vous ne pouvez pas créer un processus sous Linux qui ne puisse pas être tué. L'utilisateur root (uid = 0) peut envoyer un signal à un processus. Deux signaux ne peuvent pas être capturés, SIGKILL = 9, SIGSTOP = 19. Et d'autres signaux (non capturés) peuvent également entraîner la fin du processus.
Vous voudrez peut-être une fonction de démonisation plus générale, dans laquelle vous pourrez spécifier un nom pour votre programme/démon et un chemin pour l’exécuter (par exemple "/" ou "/ tmp"). Vous pouvez également vouloir fournir des fichiers pour stderr et stdout (et éventuellement un chemin de contrôle utilisant stdin).
Voici le nécessaire comprend:
#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)
Et voici une fonction plus générale,
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);
}
Voici un exemple de programme qui devient un démon, qui traîne, puis s'en va.
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);
}
Notez que SIG_IGN indique d'attraper et d'ignorer le signal. Vous pouvez créer un gestionnaire de signal pouvant enregistrer la réception du signal et définir des indicateurs (tels qu'un indicateur indiquant un arrêt progressif).
Je peux m'arrêter à la première condition "Un démon qui ne peut pas être arrêté ..."
Pas possible mon ami; Cependant, vous pouvez réaliser la même chose avec un outil bien meilleur, un module de noyau.
http://www.infoq.com/articles/inotify-linux-file-system-evyst-monitoring
Tous les démons peuvent être arrêtés. Certains sont plus facilement arrêtés que d'autres. Même une paire de démons avec le partenaire en attente, permettant de rétablir le partenaire s'il est perdu, peut être arrêtée. Vous devez juste travailler un peu plus fort à ce sujet.
Essayez d’utiliser la fonction daemon
:
#include <unistd.h>
int daemon(int nochdir, int noclose);
De la page de manuel :
La fonction daemon () est destinée aux programmes souhaitant se détacher du terminal de contrôle et s'exécuter en arrière-plan en tant que démons système.
Si nochdir est à zéro, daemon () modifie le répertoire de travail actuel du processus appelant dans le répertoire racine ("/"); sinon, le répertoire de travail actuel reste inchangé.
Si noclose vaut zéro, daemon () redirige l'entrée standard, la sortie standard et l'erreur standard vers/dev/null; sinon, aucune modification n'est apportée à ces descripteurs de fichier.
Si votre application est l'une des suivantes:
{
".sh": "bash",
".py": "python",
".rb": "Ruby",
".coffee" : "coffee",
".php": "php",
".pl" : "Perl",
".js" : "node"
}
et vous ne craignez pas une dépendance NodeJS, puis installez NodeJS puis:
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
Pour que toutes les applications continuent de s'exécuter au redémarrage (et à démoniser pm2):
pm2 startup
pm2 save
Maintenant vous pouvez:
service pm2 stop|restart|start|status
(vous permet également de surveiller facilement les modifications de code dans votre répertoire d'applications et de redémarrer automatiquement le processus d'application lorsqu'une modification de code se produit)
En appelant fork (), vous avez créé un processus enfant. Si le fork a réussi (le fork a retourné un PID différent de zéro), l'exécution se poursuivra à partir de ce point depuis le processus enfant. Dans ce cas, nous voulons quitter le processus parent de façon élégante, puis poursuivre notre travail dans le processus enfant.
Peut-être que cela aidera: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html
Un démon est juste un processus en arrière-plan. Si vous souhaitez démarrer votre programme au démarrage du système d’exploitation, sous Linux, vous ajoutez votre commande de démarrage à /etc/rc.d/rc.local (exécuté après tous les autres scripts) ou à /etc/startup.sh.
Sous Windows, vous créez un service, enregistrez-le, puis vous le configurez pour qu'il démarre automatiquement au démarrage dans le volet administration -> services.