Upstart, fork и daemon

Хороший способ обеспечить проблемы

У есть одна известная ошибка: неверное использование expect fork/expect daemon может подвесить initctl, после чего всякие start/stop/restart/reload <service> просто перестанут работать. Для полноты картины отмечу, что такой подвисший сервис не получится остановить и через /usr/sbin/service или /etc/init.d. Весёлая , но это еще не всё.

Есть еще одна тонкость: если программа использует fork(), то в конфигурационном файле upstart должна присутствовать строка expect fork. По аналогии можно подумать, что если программа использует daemon(), то в конфигурационном файле upstart должна присутствовать строка expect daemon. А вот и нет!

Я всегда полагал, что вызов daemon() — это, грубо говоря, последовательность fork() + setsid() + fork(). Даже неоднократно видел такую реализация daemon() в скриптах autotools.

Но, как оказалось (по крайней мере в eglibc), daemon() выполняет только один вызов fork():

[-]
View Code C
int
daemon(nochdir, noclose)
    int nochdir, noclose;
{
    int fd;

    switch (__fork()) {
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(0);
    }

    if (__setsid() == -1)
        return (-1);

    if (!nochdir)
        (void)__chdir("/");

    if (!noclose) {
        struct stat64 st;

        if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
            && (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0)
            == 0)) {
            if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0
#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
                && (st.st_rdev
                == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))
#endif
                ) {
                (void)__dup2(fd, STDIN_FILENO);
                (void)__dup2(fd, STDOUT_FILENO);
                (void)__dup2(fd, STDERR_FILENO);
                if (fd > 2)
                    (void)__close (fd);
            } else {
                /* We must set an errno value since no
                   function call actually failed.  */

                close_not_cancel_no_status (fd);
                __set_errno (ENODEV);
                return -1;
            }
        } else {
            close_not_cancel_no_status (fd);
            return -1;
        }
    }
    return (0);
}

Таким образом, если программа использует daemon() для демонизации, безопаснее начинать с expect fork. Или смотреть в реализацию daemon(). Другой вариант — не использовать upstart, пока его не допилят до вменяемого состояния.

Мне нравится сама идея upstart, но текущая реализация во многом оставляет желать лучшего. В результате имеем зоопарк: традиционные initrc-скрипты (которые далеко не всегда просто перевести в upstart) и скрипты upstart. Грустно.

Автор: ; опубликовано в: Linux; метки: Upstart, ошибка
24
Апр
2010

RSS Комментарии к статье «Upstart, fork и daemon» (1)  »

  1. [...] This post was mentioned on Twitter by Интернет заработок. Интернет заработок said: V.Kolesnikov: Upstart, fork и daemon [...]

Пожалуйста, не используйте эту форму для комментирования! Данная форма предназначена исключительно для ботов.

Оставить комментарий к записи «Upstart, fork и daemon»

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя

गते गते पारगते पारसंगते बोधि स्वाहा