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

Демон (англ. 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;
}

Коментарі 15

archer - 15 квітня 2010, 10:25

нажаль програма не скомпілиться :) містить синтаксичні помилки…

sashko - 15 квітня 2010, 11:39

Дякую, виправив! Під час форматування тексту трішки схибив…

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

Syancya - 15 квітня 2010, 17:30

цікаво

треба якось спробувати

sashko - 15 квітня 2010, 18:10

Загалом, досить стандартна річ, яку повинен уміти, або ж принаймні розуміти кожен розробник.

archer - 15 квітня 2010, 19:51

угу, розробник системного рівня на сях під лінюх. в прикладному програмуванні і на жава (рабі, пітоні, ліспі і т.д.) — цього не потрібно. а в вінді цього взагалі нема (маю на увазі поняття «демон»).

archer - 15 квітня 2010, 23:00

stdio, syslog, string, linux/limits — лишні

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

sashko - 15 квітня 2010, 23:27

linux/limits.h містить оголошення NR_OPEN, а загалом Ви праві, треба спростити.

archer - 15 квітня 2010, 23:14

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

sashko - 15 квітня 2010, 23:24

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

# man 2 dup

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

Cheers! :)

archer - 15 квітня 2010, 23:51

я язвив, якщо не ясно з мого посту :)

ти б дійсно краще детальніше прокоментувавти останніх 3 строки коду, ніж пояснення для chdir чи close в циклі.

sashko - 16 квітня 2010, 00:21

Вони прокоментовані. Проблема виникла через Ваше незнання функції dup та команди man. Вибачте!

archer - 16 квітня 2010, 00:03

і ще одне (це вже дійсно важливо). в своєму коді 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

sashko - 16 квітня 2010, 00:27

Перший нормальний коментар. Це й справді важливо. Дякую!

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

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

archer - 16 квітня 2010, 00:31

:)

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

давно не пишу під лінукс, і ще довше — на сях.

Коментувати
© 2009 - 2020, Розробка - соціальна ІТ спільнота.
Контакти: info@rozrobka.com
Правила користування