Написання демона

Демон (англ. daemon) — в багатозадачних операційних системах, таких, як UNIX — програма, яка працює у фоновому режимі без прямого спілкування з користувачем.

Демони зазвичай запускаються під час завантаження системи, і виконуються від імені користувача root, або ж окремого користувача, створеного спеціально для даного демона (наприклад, apache). Типові завдання демонів: сервери мережевих протоколів (HTTP, FTP, електронна пошта та інші), управління устаткуванням, підтримка черг друку, управління виконанням за розкладом і подібні завдання. Назви таких програм, зазвичай, закінчуються на «d» для підкреслення того що ця програма є демоном, наприклад: sshd, syslogd, httpd та інші.

До демона пред'являються дві загальних вимоги:
1. Він повинен виконуватись, як нащадок процесу ініціалізації;
2. Він не повинен бути з'єднаним із терміналом.

Загалом, для створення демона необхідно виконати наступні кроки:
1. За допомогою функції fork() створити новий процес, який пізніше буде перетворено у демон;
2. Завершити роботу батьківського процесу шляхом виклику функції exit();
3. Виконується функція setsid(), щоб задати демону нову групу процесів та сеанс;
4. Робочий каталог змінюється за допомогою функції chdir();
5. Закриваються усі файлові дескриптори;
6. Відкриваються файлові дескриптори 0, 1 та 2 (стандартний ввід, стандартний вивід та стандартний вивід для помилок), з їхнім перенаправленням у /dev/null.


#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <linux/limits.h>


int main(void)
{
    /* ID нашого процесу */
    pid_t pid, sid;
    /* Форкаємо процес */
    pid = fork();
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }
    /* Завершуємо батьківський процес */
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }
    /* Змінюємо umask */
    umask(0);
    /* Створюємо новий SID для процесу-нащадка */
    sid = setsid();
    if (sid < 0) {
        exit(EXIT_FAILURE);
    }
    /* Змінюємо поточну директорію */
    if ((chdir("/")) < 0) {
        exit(EXIT_FAILURE);
    }
    /* Закриваємо дескриптори усіх відкритих файлів */
    for (int i = 0; i < NR_OPEN; i++) {
        close(i);
    }

    /* Перенаправляємо дескриптори файлів 0, 1 та 2 в /dev/null */
    open("/dev/null", O_RDWR);
    dup(0);
    dup(0);

    /*
    Специфічний для даного демона код...
    */

    return 0;
}
  • +6
  • 15 квітня 2010, 00:44
  • sashko

Коментарі (15)

RSS згорнути / розгорнути
+
+2
нажаль програма не скомпілиться :) містить синтаксичні помилки…
avatar

archer

  • 15 квітня 2010, 10:25
+
0
Дякую, виправив! Під час форматування тексту трішки схибив…

Маєте +1 за уважність та інтерес! :)
avatar

sashko

  • 15 квітня 2010, 11:39
+
0
цікаво
треба якось спробувати
avatar

Syancya

  • 15 квітня 2010, 17:30
+
0
Загалом, досить стандартна річ, яку повинен уміти, або ж принаймні розуміти кожен розробник.
avatar

sashko

  • 15 квітня 2010, 18:10
+
0
угу, розробник системного рівня на сях під лінюх. в прикладному програмуванні і на жава (рабі, пітоні, ліспі і т.д.) — цього не потрібно. а в вінді цього взагалі нема (маю на увазі поняття «демон»).
avatar

archer

  • 15 квітня 2010, 19:51
+
+1
stdio, syslog, string, linux/limits — лишні

та й варта було б на першоджерело послатись :) «Linux system programming» by Robert Love
avatar

archer

  • 15 квітня 2010, 23:00
+
0
linux/limits.h містить оголошення NR_OPEN, а загалом Ви праві, треба спростити.
avatar

sashko

  • 15 квітня 2010, 23:27
+
-1
а, і ще питання забув. а чому результат виклику ф-ції open ніде не зберігається і не обробляється? та й dup(0) 2 рази під ряд — чи не помилка це :) :) шо воно робит?
avatar

archer

  • 15 квітня 2010, 23:14
+
0
Загалом, перевірки, звісно ж, не просто не лишені, а навіть необхідні, та про це знає кожен програміст рівня junior, і вище. Моєю ж метою було дати якомога менший та простіший у розумінні приклад. Але, якщо муляє — я додам перевірку, мені не складно.

# man 2 dup
Перепрошую за прямоту, та після Ваших дитячих насмішок дозволю собі її проявити — я б на Вашому місці помер від сорому, якби мені хтось вказав на те, що я не знаю про мани :(

Cheers! :)
avatar

sashko

  • 15 квітня 2010, 23:24
+
-1
я язвив, якщо не ясно з мого посту :)
ти б дійсно краще детальніше прокоментувавти останніх 3 строки коду, ніж пояснення для chdir чи close в циклі.
avatar

archer

  • 15 квітня 2010, 23:51
+
0
Вони прокоментовані. Проблема виникла через Ваше незнання функції dup та команди man. Вибачте!
avatar

sashko

  • 16 квітня 2010, 00:21
+
0
і ще одне (це вже дійсно важливо). в своєму коді Robert Love підключає linux/fs.h а не linux/limits.h і це суттєво. справа в тому, що NR_OPEN = 1024 в limits.h, і 1024*1024 в linux/fs.h. насправді, процес в лінуксі (не скажу точно про 2.4, але в 2.6 ядрі однозначно) може відкривати значно більше ніж 1024 файлових дескрипторів (fd в лінуксі це все — сокети, файли, пайпи і так далі). тому, якщо цим кодом (до речі не оптимальним) ти хотів закрити всі відкриті файли — юзай значення дефайнуте в linux/fs.h

man ulimit
man sysctl.conf

:D
avatar

archer

  • 16 квітня 2010, 00:03
+
0
Перший нормальний коментар. Це й справді важливо. Дякую!

І прохання на майбутнє — наступного разу або коментарі по темі, або просто ставите мінус, і пишете: «афтар мудаг», бо надалі розважати Вас, приділяючи увагу, якої Вам, схоже сильно бракує, я наміру не маю. Пишіть свої пости по linux development специфічним темах, їх «розробці» бракує.

Цінуймося! І без образ, просто я ненавиджу тролів!
avatar

sashko

  • 16 квітня 2010, 00:27
+
0
:)
avatar

archer

  • 16 квітня 2010, 00:31
+
0
давно не пишу під лінукс, і ще довше — на сях.
avatar

archer

  • 16 квітня 2010, 01:30

Тільки зареєстровані й авторизовані користувачі можуть залишати коментарі.