Membuat daemon di Linux

110

Di Linux saya ingin menambahkan daemon yang tidak dapat dihentikan dan yang memantau perubahan sistem file. Jika ada perubahan yang terdeteksi, itu harus menulis jalur ke konsol tempat dimulainya ditambah baris baru.

Saya sudah memiliki kode untuk mengubah sistem file hampir siap tetapi saya tidak tahu cara membuat daemon.

Kode saya berasal dari sini: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

Apa yang harus dilakukan setelah bercabang?

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;
}
chrisMe
sumber
1
Kemungkinan duplikat: stackoverflow.com/q/5384168/1076451
Chimera
1
kemungkinan duplikat dari: stackoverflow.com/questions/5384168/… untuk bagian daemonize, stackoverflow.com/questions/931093/… untuk sistem file jam tangan
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Jika Anda tidak membutuhkan kepatuhan POSIX, Anda mungkin tertarik dengan inotifyAPI. Lihat: inotify_init, inotify_add_watch, inotify_rm_watch.
patryk.beza

Jawaban:

216

Di Linux saya ingin menambahkan daemon yang tidak dapat dihentikan dan yang memantau perubahan sistem file. Jika ada perubahan yang terdeteksi, itu harus menulis jalur ke konsol tempat dimulainya + baris baru.

Daemon bekerja di latar belakang dan (biasanya ...) bukan milik TTY, itulah mengapa Anda tidak dapat menggunakan stdout / stderr dengan cara yang Anda inginkan. Biasanya daemon syslog ( syslogd ) digunakan untuk mencatat pesan ke file (debug, error, ...).

Selain itu, ada beberapa langkah yang diperlukan untuk membuat daemonisasi suatu proses.


Jika saya ingat dengan benar langkah-langkah ini adalah:

  • lepas proses induk & biarkan berhenti jika garpu berhasil. -> Karena proses induk telah dihentikan, proses anak sekarang berjalan di latar belakang.
  • setsid - Buat sesi baru. Proses panggilan menjadi pemimpin sesi baru dan pemimpin grup proses dari grup proses baru. Proses tersebut sekarang terlepas dari terminal pengendali (CTTY).
  • Menangkap sinyal - Abaikan dan / atau tangani sinyal.
  • bercabang lagi & biarkan proses induk berakhir untuk memastikan bahwa Anda menyingkirkan proses memimpin sesi. (Hanya pemimpin sesi yang bisa mendapatkan TTY lagi.)
  • chdir - Mengubah direktori kerja daemon.
  • umask - Mengubah file mode mask sesuai dengan kebutuhan daemon.
  • close - Tutup semua deskriptor file terbuka yang mungkin diwarisi dari proses induk.

Untuk memberi Anda titik awal: Lihatlah kode kerangka ini yang menunjukkan langkah-langkah dasar. Kode ini sekarang juga dapat bercabang di GitHub: Kerangka dasar daemon 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;
}


  • Kompilasi kode: gcc -o firstdaemon daemonize.c
  • Mulai daemon: ./firstdaemon
  • Periksa apakah semuanya berfungsi dengan baik: ps -xj | grep firstdaemon

  • Outputnya harus serupa dengan yang ini:

+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| PPID | PID | PGID | SID | TTY | TPGID | STAT | UID | WAKTU | CMD |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +
| 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ |
+ ------ + ------ + ------ + ------ + ----- + ------- + ------ + ------ + ------ + ----- +

Yang harus Anda lihat di sini adalah:

  • Daemon tidak memiliki terminal pengontrol ( TTY =? )
  • ID proses induk ( PPID ) adalah 1 (Proses init)
  • The PID! = SID yang berarti bahwa proses kami TIDAK pemimpin sesi
    (karena garpu kedua ())
  • Karena PID! = SID, proses kami tidak dapat mengontrol TTY lagi

Membaca syslog:

  • Temukan file syslog Anda. Punyaku ada di sini:/var/log/syslog
  • Lakukan: grep firstdaemon /var/log/syslog

  • Outputnya harus serupa dengan yang ini:

  firstdaemon [3387]: Daemon pertama dimulai.
  firstdaemon [3387]: Daemon pertama diakhiri.


Catatan: Pada kenyataannya Anda juga ingin menerapkan penangan sinyal dan mengatur logging dengan benar (File, level log ...).

Bacaan lebih lanjut:

Pascal Werkl
sumber
Wow terima kasih! Itu hebat. Jadi saya harus memasukkan kode saya ke while Loop dan hanya itu?
chrisMe
Pada dasarnya, ya. Tetapi kode ini hanyalah sebuah contoh. Ini sepenuhnya tergantung pada apa yang ingin Anda capai menggunakan proses daemon. Pastikan untuk membaca jawaban ini juga: @Edwin
Pascal Werkl
1
Dari pada yang kedua fork(), mengapa tidak digunakan saja setsid()?
Chimera
1
Perhatikan bahwa The sigaction()fungsi menyediakan mekanisme yang lebih komprehensif dan dapat diandalkan untuk mengendalikan sinyal; aplikasi baru harus digunakan sigaction()daripada signal().
patryk.beza
4
Perlu diperhatikan bagi pemirsa bahwa metode ini adalah cara "lama". Cara baru yang disarankan untuk membuat daemon adalah dengan "daemon gaya baru" yang ditemukan di sini: 0pointer.de/public/systemd-man/daemon.html#New-Style%20Daemons atau
Starlord
30

man 7 daemonmenjelaskan cara membuat daemon dengan sangat detail. Jawaban saya hanyalah kutipan dari manual ini.

Setidaknya ada dua jenis daemon:

  1. daemon SysV tradisional ( gaya lama ),
  2. daemon systemd ( gaya baru ).

SysV Daemons

Jika Anda tertarik dengan daemon SysV tradisional , Anda harus menerapkan langkah-langkah berikut :

  1. Tutup semua deskriptor file yang terbuka kecuali input standar , output , dan kesalahan (yaitu, tiga deskriptor file pertama 0, 1, 2). Ini memastikan bahwa tidak ada deskriptor file yang diteruskan secara tidak sengaja tetap ada dalam proses daemon. Di Linux, ini paling baik diterapkan dengan melakukan iterasi /proc/self/fd, dengan fallback iterasi dari deskriptor file 3 ke nilai yang dikembalikan oleh getrlimit()for RLIMIT_NOFILE.
  2. Setel ulang semua penangan sinyal ke defaultnya. Ini paling baik dilakukan dengan melakukan iterasi melalui sinyal yang tersedia hingga batasnya _NSIGdan menyetel ulang ke SIG_DFL.
  3. Setel ulang topeng sinyal menggunakan sigprocmask().
  4. Bersihkan blok lingkungan, hapus atau setel ulang variabel lingkungan yang mungkin berdampak negatif pada runtime daemon.
  5. Panggil fork(), untuk membuat proses latar belakang.
  6. Pada anak, panggil setsid()untuk melepaskan dari terminal mana pun dan buat sesi independen .
  7. Pada anak, panggil fork()lagi, untuk memastikan bahwa daemon tidak akan pernah bisa mendapatkan kembali terminal lagi.
  8. Panggil exit()anak pertama, sehingga hanya anak kedua (proses daemon sebenarnya) yang tetap ada. Ini memastikan bahwa proses daemon dipasangkan kembali ke init / PID 1, sebagaimana seharusnya semua daemon.
  9. Dalam proses daemon, sambungkan /dev/nullke input , output , dan kesalahan standar .
  10. Dalam proses daemon, atur ulang umaskke 0, sehingga mode file diteruskan ke open(), mkdir()dan seperti mengontrol langsung mode akses dari file dan direktori yang dibuat.
  11. Dalam proses daemon, ubah direktori saat ini ke direktori root ( /), untuk menghindari daemon secara tidak sengaja memblokir titik mount agar tidak dilepas.
  12. Dalam proses daemon, tulis PID daemon (seperti yang dikembalikan oleh getpid()) ke file PID, misalnya /run/foobar.pid(untuk daemon hipotetis "foobar") untuk memastikan bahwa daemon tidak dapat dijalankan lebih dari sekali. Ini harus diterapkan dengan gaya bebas balapan sehingga file PID hanya diperbarui ketika diverifikasi pada saat yang sama dengan PID yang sebelumnya disimpan dalam file PID tidak lagi ada atau milik proses asing.
  13. Dalam proses daemon, lepaskan hak istimewa, jika memungkinkan dan dapat diterapkan.
  14. Dari proses daemon, beri tahu proses asli yang dimulai bahwa inisialisasi telah selesai. Ini dapat diimplementasikan melalui pipa tanpa nama atau saluran komunikasi serupa yang dibuat sebelum yang pertama fork()dan karenanya tersedia baik dalam proses asli dan daemon.
  15. Panggil exit()dalam proses aslinya. Proses yang memanggil daemon harus dapat diandalkan bahwa ini exit()terjadi setelah inisialisasi selesai dan semua saluran komunikasi eksternal dibuat dan dapat diakses.

Perhatikan peringatan ini:

BSD daemon()fungsi seharusnya tidak digunakan, karena menerapkan hanya bagian dari langkah-langkah ini.

Daemon yang perlu menyediakan kompatibilitas dengan sistem SysV harus mengimplementasikan skema yang disebutkan di atas. Namun, disarankan untuk membuat perilaku ini opsional dan dapat dikonfigurasi melalui argumen baris perintah untuk memudahkan debugging serta untuk menyederhanakan integrasi ke dalam sistem menggunakan systemd.

Perhatikan bahwa daemon()tidak sesuai dengan POSIX .


Daemon Gaya Baru

Untuk daemon gaya baru, langkah - langkah berikut disarankan:

  1. Jika SIGTERMditerima, matikan daemon dan keluar dengan bersih.
  2. Jika SIGHUPditerima, muat ulang file konfigurasi, jika ini berlaku.
  3. Berikan kode keluar yang benar dari proses daemon utama, karena ini digunakan oleh sistem init untuk mendeteksi kesalahan dan masalah layanan. Direkomendasikan untuk mengikuti skema kode keluar sebagaimana ditentukan dalam rekomendasi LSB untuk skrip init SysV .
  4. Jika memungkinkan dan dapat diterapkan, buka antarmuka kontrol daemon melalui sistem D-Bus IPC dan ambil nama bus sebagai langkah terakhir inisialisasi.
  5. Untuk integrasi dalam systemd, sediakan file unit .service yang membawa informasi tentang memulai, menghentikan, dan sebaliknya memelihara daemon. Lihat detailnya.systemd.service(5)
  6. Sebisa mungkin, andalkan fungsionalitas sistem init untuk membatasi akses daemon ke file, layanan, dan sumber daya lainnya, yaitu dalam kasus systemd, andalkan kontrol batas sumber daya systemd daripada mengimplementasikan milik Anda sendiri, andalkan hak istimewa systemd untuk melepaskan kode alih-alih menerapkannya di daemon, dan sejenisnya. Lihat systemd.exec(5)kontrol yang tersedia.
  7. Jika D-Bus digunakan, jadikan bus daemon Anda dapat diaktifkan dengan menyediakan file konfigurasi aktivasi layanan D-Bus . Ini memiliki beberapa keuntungan: daemon Anda mungkin dijalankan dengan malas sesuai permintaan; itu mungkin dimulai secara paralel dengan daemon lain yang membutuhkannya - yang memaksimalkan paralelisasi dan kecepatan boot-up ; daemon Anda dapat dimulai ulang jika gagal tanpa kehilangan permintaan bus apa pun, karena antrian bus meminta layanan yang dapat diaktifkan. Lihat detailnya di bawah .
  8. Jika daemon Anda menyediakan layanan ke proses lokal lain atau klien jarak jauh melalui soket, itu harus dibuat dapat diaktifkan dengan soket mengikuti skema yang ditunjukkan di bawah ini . Seperti aktivasi D-Bus, ini memungkinkan dimulainya layanan sesuai permintaan serta memungkinkan peningkatan paralelisasi start-up layanan. Selain itu, untuk protokol tanpa status (seperti syslog, DNS), daemon yang mengimplementasikan aktivasi berbasis soket dapat dimulai ulang tanpa kehilangan satu permintaan pun. Lihat detailnya di bawah .
  9. Jika berlaku, daemon harus memberi tahu sistem init tentang penyelesaian startup atau pembaruan status melalui sd_notify(3)antarmuka.
  10. Alih-alih menggunakan syslog()panggilan untuk masuk langsung ke layanan syslog sistem, daemon gaya baru dapat memilih untuk masuk ke kesalahan standar melalui fprintf(), yang kemudian diteruskan ke syslog oleh sistem init. Jika level log diperlukan, ini dapat dikodekan dengan mengawali baris log individual dengan string seperti "<4>" (untuk log level 4 "PERINGATAN" dalam skema prioritas syslog), mengikuti gaya yang mirip dengan sistem printk()level kernel Linux . Untuk detailnya, lihat sd-daemon(3)dan systemd.exec(5).

Untuk mempelajari lebih lanjut baca utuh man 7 daemon.

patryk.beza
sumber
11

Anda tidak dapat membuat proses di linux yang tidak dapat dimatikan. Pengguna root (uid = 0) dapat mengirim sinyal ke suatu proses, dan ada dua sinyal yang tidak dapat ditangkap, SIGKILL = 9, SIGSTOP = 19. Dan sinyal lain (jika tidak tertangkap) juga dapat mengakibatkan penghentian proses.

Anda mungkin menginginkan fungsi daemonize yang lebih umum, di mana Anda dapat menentukan nama untuk program / daemon Anda, dan jalur untuk menjalankan program Anda (mungkin "/" atau "/ tmp"). Anda mungkin juga ingin menyediakan file untuk stderr dan stdout (dan mungkin jalur kontrol menggunakan stdin).

Berikut ini yang perlu di antaranya:

#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)

Dan inilah fungsi yang lebih umum,

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);
}

Berikut adalah contoh program, yang menjadi daemon, hang sekitar, dan kemudian pergi.

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);
}

Perhatikan bahwa SIG_IGN menunjukkan untuk menangkap dan mengabaikan sinyal. Anda bisa membuat penangan sinyal yang bisa mencatat tanda terima sinyal, dan menyetel tanda (seperti tanda untuk menunjukkan pematian yang lancar).

ChuckCottrill
sumber
8

Coba gunakan daemonfungsinya:

#include <unistd.h>

int daemon(int nochdir, int noclose);

Dari halaman manual :

Fungsi daemon () adalah untuk program yang ingin melepaskan dirinya dari terminal pengendali dan berjalan di latar belakang sebagai daemon sistem.

Jika nochdir adalah nol, daemon () mengubah direktori kerja saat ini dari proses pemanggilan ke direktori root ("/"); jika tidak, direktori kerja saat ini dibiarkan tidak berubah.

Jika noclose nol, daemon () mengalihkan input standar, output standar dan kesalahan standar ke / dev / null; jika tidak, tidak ada perubahan yang dilakukan pada deskriptor file ini.

weiyin
sumber
2
Perhatikan bahwa daemon(7)manual menyebutkan langkah-langkah untuk membuat daemon dan memperingatkan bahwa: Fungsi BSD daemon()tidak boleh digunakan, karena hanya mengimplementasikan sebagian dari langkah-langkah ini. daemonFungsi pertama kali muncul di 4.4BSD dan tidak sesuai dengan POSIX .
patryk.beza
2
Perhatikan juga bahwa peringatan tentang penggunaan daemon () ada di bagian SysV gaya lama dari halaman manual daemon (7) . Penggunaan daemon () tidak disarankan untuk systemd.
Greg McPherran
7

Saya dapat berhenti pada persyaratan pertama "Sebuah daemon yang tidak dapat dihentikan ..."

Tidak mungkin teman saya; namun, Anda dapat mencapai hal yang sama dengan alat yang jauh lebih baik, modul kernel.

http://www.infoq.com/articles/inotify-linux-file-system-event-monitoring

Semua daemon bisa dihentikan. Beberapa lebih mudah dihentikan daripada yang lain. Bahkan pasangan daemon dengan pasangan yang ditahan, menghidupkan kembali pasangan jika hilang, dapat dihentikan. Anda hanya perlu bekerja sedikit lebih keras untuk itu.

Edwin Buck
sumber
7
Saya pikir dengan mengatakan "Sebuah daemon yang tidak dapat dihentikan", sebenarnya penulis bermaksud bahwa daemon selalu berjalan di latar belakang ketika sesi dihentikan.
FaceBro
6

Jika aplikasi Anda adalah salah satu dari:

{
  ".sh": "bash",
  ".py": "python",
  ".rb": "ruby",
  ".coffee" : "coffee",
  ".php": "php",
  ".pl" : "perl",
  ".js" : "node"
}

dan Anda tidak keberatan dengan dependensi NodeJS lalu instal NodeJS lalu:

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

Agar semua aplikasi tetap berjalan saat reboot (dan membuat daemonise pm2):

pm2 startup

pm2 save

Sekarang kamu bisa:

service pm2 stop|restart|start|status

(juga memungkinkan Anda dengan mudah untuk melihat perubahan kode di direktori aplikasi Anda dan otomatis memulai ulang proses aplikasi saat terjadi perubahan kode)

danday74
sumber
2
Ini tidak ada hubungannya dengan C.
melpomene
4
Saya menghargai ada tag C. Namun, OP tidak menyebutkan persyaratan tentang C yang dimaksud. Judulnya membuat setan di linux. Jawaban ini memuaskan itu.
danday74
1
Oh, kamu benar. Itu ditandai C, tetapi persyaratan sebenarnya adalah C ++ (sebagaimana dibuktikan oleh kode OP dan artikel yang ditautkan).
melpomene
3

Dengan memanggil fork () Anda telah membuat proses anak. Jika garpu berhasil (garpu mengembalikan PID bukan nol) eksekusi akan dilanjutkan dari titik ini dari dalam proses anak. Dalam hal ini kami ingin keluar dari proses induk dengan anggun dan kemudian melanjutkan pekerjaan kami dalam proses anak.

Mungkin ini akan membantu: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html

Doug Morrow
sumber
2

Daemon hanyalah sebuah proses di latar belakang. Jika Anda ingin memulai program Anda ketika OS melakukan boot, di linux, Anda menambahkan perintah start Anda ke /etc/rc.d/rc.local (jalankan setelah semua skrip lain) atau /etc/startup.sh

Di windows, Anda membuat layanan, mendaftarkan layanan, dan kemudian mengaturnya untuk memulai secara otomatis saat boot di administrasi -> panel layanan.

Magn3s1um
sumber
1
Terima kasih. Jadi, apakah tidak ada perbedaan antara "daemon" dan hanya Program biasa? Saya tidak ingin itu ditutup dengan mudah.
chrisMe
1
Tidak, daemon hanyalah proses latar belakang. Lebih khusus lagi, Anda bercabang dari induk, menjalankan proses anak dan menghentikan induk (sehingga tidak ada akses terminal ke program). itu tidak terlalu diperlukan meskipun untuk menjadi "daemon": en.wikipedia.org/wiki/Daemon_(computing)
Magn3s1um
1

Template Daemon

Saya menulis template daemon mengikuti daemon gaya baru: link

Anda dapat menemukan seluruh kode template di GitHub: di sini

Main.cpp

// This function will be called when the daemon receive a SIGHUP signal.
void reload() {
    LOG_INFO("Reload function called.");
}

int main(int argc, char **argv) {
    // The Daemon class is a singleton to avoid be instantiate more than once
    Daemon& daemon = Daemon::instance();
    // Set the reload function to be called in case of receiving a SIGHUP signal
    daemon.setReloadFunction(reload);
    // Daemon main loop
    int count = 0;
    while(daemon.IsRunning()) {
        LOG_DEBUG("Count: ", count++);
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    LOG_INFO("The daemon process ended gracefully.");
}

Daemon.hpp

class Daemon {
    public:

    static Daemon& instance() {
        static Daemon instance;
        return instance;
    }

    void setReloadFunction(std::function<void()> func);

    bool IsRunning();

    private:

    std::function<void()> m_reloadFunc;
    bool m_isRunning;
    bool m_reload;

    Daemon();
    Daemon(Daemon const&) = delete;
    void operator=(Daemon const&) = delete;

    void Reload();

    static void signalHandler(int signal);
};

Daemon.cpp

Daemon::Daemon() {
    m_isRunning = true;
    m_reload = false;
    signal(SIGINT, Daemon::signalHandler);
    signal(SIGTERM, Daemon::signalHandler);
    signal(SIGHUP, Daemon::signalHandler);
}

void Daemon::setReloadFunction(std::function<void()> func) {
    m_reloadFunc = func;
}

bool Daemon::IsRunning() {
    if (m_reload) {
        m_reload = false;
        m_reloadFunc();
    }
    return m_isRunning;
}

void Daemon::signalHandler(int signal) {
    LOG_INFO("Interrup signal number [", signal,"] recived.");
    switch(signal) {
        case SIGINT:
        case SIGTERM: {
            Daemon::instance().m_isRunning = false;
            break;
        }
        case SIGHUP: {
            Daemon::instance().m_reload = true;
            break;
        }
    }
}

daemon-template.service

[Unit]
Description=Simple daemon template
After=network.taget

[Service]
Type=simple
ExecStart=/usr/bin/daemon-template --conf_file /etc/daemon-template/daemon-tenplate.conf
ExecReload=/bin/kill -HUP $MAINPID
User=root
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=daemon-template

[Install]
WantedBy=multi-user.target
Fabiano Traple
sumber