Linux как сделать демона

Что такое демоны в Linux

Демоны много работают, для того, чтобы вы могли сосредоточится на своем деле. Представьте, что вы пишите статью или книгу. Вы заинтересованны в том, чтобы писать. Удобно, что вам не нужно вручную запускать принтер и сетевые службы, а потом следить за ними весь день для того чтобы убедится, что всё работает нормально.

За это можно благодарить демонов, они делают эту работу за нас. В сегодняшней статье мы рассмотрим что такое демоны в Linux, а также зачем они нужны.

Что такое демоны в понятии Linux

Демон Linux — это программа, у которой есть определённая уникальная цель. Обычно, это служебные программы, которые незаметно работают в фоновом режиме для того чтобы отслеживать состояние и обслуживать определённые подсистемы и гарантировать правильную работу всей операционной системы в целом. Например, демон принтера, отслеживает состояние служб печати, а сетевой демон управляет сетевыми подключениями и следит за их состоянием.

Многие люди, перешедшие в Linux из Windows знают демонов как службы или сервисы. В MacOS термин «Служба» имеет другое значение. Так как MacOS это тоже Unix, в ней испольуются демоны. А службами называются программы, которые находятся в меню Службы.

Демоны выполняют определённые действия в запланированное время или в зависимости от определённых событий. В системе Linux работает множество демонов, и каждый из них предназначен для того чтобы следить за своей небольшой частью операционной системы. Поскольку они не находятся под непосредственным контролем пользователя, они фактически невидимы, но тем не менее необходимы. Поскольку демоны выполняют большую часть своей работы в фоновом режиме, они могут казаться загадочными.

Какие демоны работают на вашем компьютере

Обычно имена процессов демонов заканчиваются на букву d. В Linux принято называть демоны именно так. Есть много способов увидеть работающих демонов. Они попадаются в списке процессов, выводимом утилитами ps, top или htop. Но больше всего для поиска демонов подходит утилита pstree. Эта утилита показывает все процессы, запущенные в вашей системе в виде дерева. Откройте терминал и выполните такую команду:

Вы увидите полный список всех запущенных процессов. Вы можете не знать за что отвечают эти процессы, но они все будут здесь перечислены. Вывод pstree — отличная иллюстрация того, что происходит с вашей машиной. Здесь удобно найти запущенные демоны Linux.

Вот демоны Linux, которых вы можете здесь увидеть: udisksd, gvfsd, systemd, logind и много других. Список процессов довольно длинный, поэтому он не поместится в одном окне терминала, но вы можете его листать.

Запуск демонов в Linux

Давайте разберемся как запустить демона Linux. Ещё раз. Демон — это процесс, работающий в фоновом режиме и находится вне контроля пользователя. Это значит, что демон не связан с терминалом, с помощью которого можно было бы им управлять. Процесс — это запущенная программа. В каждый момент времени он может быть запущенным, спящим или зомби (процесс выполнивший свою задачу, но ожидающий пока родительский процесс примет результат).

В Linux существует три типа процессов: интерактивные, пакетные и демоны. Интерактивные процессы пользователь запускает из командной строки. Пакетные процессы обычно тоже не связанны с терминалом. Они запускаются обычно во время когда на систему минимальная нагрузка и делают свою работу. Это могут быть, например, скрипты резервного копирования или другие подобные обслуживающие сценарии.

Интерактивные и пакетные процессы нельзя считать демонами, хотя их можно запускать в фоновом режиме и они делают определённую работу. Ключевое отличие в том, что оба вида процессов требуют участия человека. Демонам не нужен человек для того чтобы их запускать.

Когда загрузка системы завершается, система инициализации, например, systemd, начинает создавать демонов. Этот процесс называется forking (разветвление). Программа запускается как обычный интерактивный процесс с привязкой к терминалу, но в определённый момент она делится на два идентичных потока. Первый процесс, привязанный к терминалу может выполнятся дальше или завершится, а второй, уже ни к чему не привязанный продолжает работать в фоновом режиме.

Существуют и другие способы ветвления программ в Linux, но традиционно для создания дочерних процессов создается копия текущего. Термин forking появился не из ниоткуда. Его название походит от функции языка программирования Си. Стандартная библиотека Си содержит методы для управления службами, и один из них называется fork. Используется он для создания новых процессов. После создания процесса, процесс, на основе которого был создан демон считается для него родительским процессом.

Когда система инициализации запускает демонов, она просто разделяется на две части. В таком случае система инициализации будет считаться родительским процессом. Однако в Linux есть ещё один метод запуска демонов. Когда процесс создает дочерний процесс демона, а затем завершается. Тогда демон остается без родителя и его родителем становится система инициализации. Важно не путать такие процессы с зомби. Зомби, это процессы, завершившие свою работу и ожидающие пока родительский процесс примет их код выхода.

Примеры демонов в Linux

Самый простой способ определить демона — это буква d в конце его названия. Вот небольшой список демонов, которые работают в вашей системе. Каждый демон создан для выполнения определённой задачи.

  • systemd — основная задача этого демона унифицировать конфигурацию и поведение других демонов в разных дистрибутивах Linux.
  • udisksd — обрабатывает такие операции как: монтирование, размонтирование, форматирование, подключение и отключение устройств хранения данных, таких как жесткие диски, USB флешки и т д.
  • logind — небольшой демон, управляющий авторизацией пользователей.
  • httpd — демон веб-сервера, позволяет размешать на компьютере или сервере веб-сайты.
  • sshd — позволяет подключаться к серверу или компьютеру удалённо, по протоколу SSH.
  • ftpd — организует доступ к компьютеру по протоколу FTP для передачи файлов.
  • crond — демон планировщика, позволяющий выполнять нужные задачи в определённое время.

Как появился термин демон в Linux

Так откуда же взялся этот термин? На первый взгляд может показаться, что у создателей операционной системы просто было искаженное чувство юмора. Но это не совсем так. Это слово появилось в вычислительной технике ещё до появления Unix. А история самого слова ещё более древняя.

Читайте также:  Нет изображения после установки windows

Изначально это слово писалось как daimon и означало ангелов хранителей или духов помощников, которые помогали формировать характеры людей. Сократ утверждал, что у него был демон, который ему помогал. Демон Сократа говорил ему когда следует держать язык за зубами. Он рассказал о своем демоне во время суда в 399 году до нашей эры. Так что вера в демонов существует довольно давно. Иногда слово daimon пишется как daemon. Это одно и то же.

В то время как daemon — помощник, demon — это злой персонаж из библии. Различия в написании не случайны и видимо так было решено где-то в 16-том веке. Тогда решили, что daemons — хорошие парни, а demons — плохие.

Использовать слово демон (daemon) в вычислительной технике начали в 1963 году. Проект Project MAC (Project on Mathematics and Computation) был разработан в Массачусетском технологическом институте. И именно в этом проекте начали использовать слово демон для обозначения любых программ, которые работают в фоновом режиме, следят за состоянием других процессов и выполняют действия в зависимости от ситуации. Эти программы были названы в честь демона Максвелла.

Демон Максвелла — это результат мысленного эксперимента. В 1871 году Джеймс Клер Максвелл представил себе существо, способное наблюдать и направлять движение отдельных молекул. Целью мысленного эксперимента было показать противоречия во втором законе термодинамики.

Однако есть и другие варианты значения этого слова. Например это может быть аббревиатура от Disk And Executive MONitor. Хотя первоначальные пользователи термина демон не использовали его для этих целей, так что вариант с аббревиатурой, скорее всего неверный.

Теперь вы знаете что такое демоны в понятии Linux. На завершение, обратите внимание, что талисман BSD — демон. Он выбран в честь программных демонов (daemons) но выглядит как злой демон (demon). Имя этого демона Beastie. Точно неизвестно откуда взялось это имя, но есть предположения, оно походит от фразы: BSD. Try it; I did. Если произнести это на английском быстро, получится звук похожий на Beastie. А ещё тризуб Beastie символизирует разветвление (forking) процессов в Linux.

Источник

Создание демонов в Linux

Демон или (от анг. daemon) это программа в системах класса UNIX, запускается самой ОС и работает в фоновом режиме без взаимодействия с пользователем. Демоны обычно запускаются во время загрузки системы.
Для создания демона необходимо выполнить установку ПО и настроить его автозагрузку при старте системы. Обычно если
устанавливаемая программа предназначена для использования в качестве демона, то соответствующие инструкции выполняются в автоматическом режиме и не требуют вмешательства.
Имеется несколько вариантов автоматического запуска демонов в Unix подобных системах. Например, для сервера Ubuntu без графического интерфейса используется классический вариант помещения системных файлов в папку /etc/init.d.

Соответственно в папках:

/etc/rc0.d, размещаются файлы, которые выполняются автоматически при запуске

/etc/rc1.d, размещаются файлы, которые выполняются автоматически при остановке системы

Такие файлы запуска принято называть с символа S (от анг. Start), а останова — с символа K (от анг. Kill); после этого символа указывается число, определяющее порядковый номер запуска и остановки). Для запуска службы в эти папки просто помещают ссылки
на командный файл запуска в папке /etc/init.d.
Такие ссылки создать можно и вручную, но правильней использовать команду update-rc.d. Эта утилита автоматически создает ссылки при установке демона или удаляет их в противном случае. Для создания демона достаточно выполнить:

update-rc.d файл_запуска defaults

С ключом remove эта команда удаляет соответствующие ссылки. Следующий пример показывает отключение демона apache:

sudo update-rc.d -f apache2 remove

Источник

Как создать демона в linux

Демон — это программа не имеющая стандартного ввода и вывода, и при этом работающая в фоновом режиме.

Исходный код простейшего демона:

В первую очередь вызывается функция fork , которая создает копию процесса. В родительском-процессе функция вернет PID порожденного дочернего процесса, а в дочернем процессе fork вернет 0.

Вызов setsid создает новую сессию. Создание новой сессии обеспечит нас следующими преимуществами: процесс становится лидером новой сессии, процесс становится лидером новой группы процессов и у процесса нет управляющего терминала.

chdir(«/») изменяет текущий каталог процесса на корневой, что бы освободить файловую систему с которой был запущен демон.

Ну и вызов close(stdin), close(stdout), close(stderr) закрывают файловые дескрипторы стандартного ввода и вывода.

Реализация функции mainloop зависит от от назначения демона, поэтому код этой функции здесь не приведен.

8 комментариев: Как создать демона в linux

Скажите пож. как мне чтобы каждые 5 минут на сервере выполнялась проверка, существует ли процесс ts3server_linux и если его не существует, то выполнялась бы команда
/home/teamspeak3-server_linux-x86/ts3server_startscript.sh start
от имени пользователя tssrv

Можно написать скрипт, который проверяет запущен ли процесс (например так: ps -C ts3server_linux || /home/teamspeak3-server_linux-x86/ts3server_startscript.sh start ). И прописать запуск этого скрипта в crontab.

А еще посоветую посмотреть в сторону специально заточенных для этих целей утилит, daemontools или runit.

Если нужна более подробная информация — пишите, может смогу помочь.

Куда будет писать функция:
printf(«Fail: unable to fork\n»);
если мы закрыли stdout?

Затупил… Закрыли мы для дочернего процесса, а вывод для родителя

«Демоны проклятые…» 🙂 В Windows — сервис. Почему в Linux — демоны?

Чёрная магия 🙂 Работа программиста и шамана имеет много общего — оба бормочут непонятные слова, совершают непонятные действия и не могут объяснить, как оно работает…

<
setsid();
chdir(«/»);
fclose(stdin);
//оставим вывод в консоль наш демон будет периодически выводить дату и время
// fclose(stdout);
fclose(stderr);
demon();
>

как создать демон для эл почты почта уже создана

Источник

Русские Блоги

Процесс системного программирования Linux (восемь): подробное объяснение и создание процесса демона, использование daemon ()

1. Обзор Daemon

Linux Daemon (демон) — это специальный процесс, работающий в фоновом режиме. Он не зависит от терминала управления и периодически выполняет определенные задачи или ожидает определенных событий. Он может работать без ввода данных пользователем и предоставлять услуги как для всей системы, так и для пользовательской программы. Большинство серверов в системе Linux реализованы с помощью демонов. К распространенным процессам демона относятся системный журнал syslogd, веб-сервер httpd, почтовый сервер sendmail и сервер базы данных mysqld.

Читайте также:  Цифровой активатор для windows 10

Демоны, как правило, начинают работать при запуске системы, и если их не принудительно завершить, в противном случае продолжайте работу, пока система не будет выключена. Демоны часто запускаются с привилегиями суперпользователя (root), потому что они используют специальные порты (1-1024) или получают доступ к определенным специальным ресурсам.

Родительский процесс демона — это процесс init, потому что его реальный родительский процесс завершается до выхода из дочернего процесса после разветвления дочернего процесса, поэтому он является потерянным процессом, унаследованным init. Демон является неинтерактивной программой без управляющего терминала, поэтому любой вывод, будь то стандартный вывод устройства stdout или стандартный вывод ошибки устройства stderr, требует специальной обработки.

Имя демона обычно заканчивается на d, например sshd, xinetd, crond и т. Д.

Во-вторых, шаги для создания демона

Сначала мы должны понять некоторые основные понятия:

  • Каждый процесс также принадлежит к группе процессов
  • У каждого владельца процесса есть номер группы процессов, который равен номеру PID лидера группы процессов.
  • Процесс может установить только идентификационный номер группы процессов для себя или подпроцесса

Сеанс — это набор из одной или нескольких групп процессов.

Функция setsid () может установить период диалога:

Если процесс, вызывающий setsid, не является лидером группы процессов, эта функция создает новый сеанс 。

(1) Этот процесс становится первым процессом периода диалога

(2) Этот процесс становится лидером процесса новой группы процессов.

(3) В этом процессе нет управляющего терминала. Если у процесса есть управляющий терминал до вызова setsid, контакт с терминалом освобождается. Если процесс является лидером группы процессов, эта функция возвращает ошибку.

(4) Чтобы убедиться в этом, мы сначала вызываем fork (), а затем exit (), в это время работает только дочерний процесс.

Теперь давайте рассмотрим шаги, необходимые для создания демона:

Общие шаги для написания демона:

(1) Выполнить форк и выйти из родительского процесса;

(2) вызовите функцию setsid в дочернем процессе, чтобы создать новый сеанс;

(3) вызовите функцию chdir в дочернем процессе, чтобы сделать корневой каталог «/» рабочим каталогом дочернего процесса;

(4) Вызовите функцию umask в подпроцессе и установите для umask процесса значение 0;

(5) Закройте все ненужные файловые дескрипторы в дочернем процессе

1. Запустите в фоновом режиме.
Чтобы избежать приостановки управляющего терминала, поместите Daemon в фоновый режим для выполнения. Метод заключается в вызове fork процесса, чтобы завершить родительский процесс и позволить Daemon выполняться в фоновом режиме в дочернем процессе.
if(pid=fork())
exit (0); // Это родительский процесс, завершить родительский процесс, дочерний процесс продолжается
2. Выйдите из терминала управления и войдите в сеанс и группу процессов.
Необходимо сначала представить взаимосвязь между процессом и управляющим терминалом в Linux, сеансом входа в систему и группой процессов: процесс принадлежит группе процессов, а номер группы процессов (GID) является лидером группы процессов Идентификатор процесса (PID). Сеанс входа может содержать несколько групп процессов. Эти группы процессов имеют общий управляющий терминал. Этот управляющий терминал обычно является терминалом входа в систему, который создает процесс.
Терминал управления, сеанс входа в систему и группа процессов обычно наследуются от родительского процесса. Наша цель — избавиться от них и сделать их невосприимчивыми к их влиянию. Метод заключается в вызове setsid () на основе пункта 1, чтобы сделать процесс лидером сеанса:
setsid();
Объяснение: Когда процесс является лидером сеанса, вызовы setsid () не выполняются. Но первый пункт гарантировал, что процесс не является лидером сессии. После успешного вызова setsid () процесс становится новым лидером сеанса и новым лидером процесса и отделяется от исходного сеанса входа в систему и группы процессов. Вследствие исключительности процесса разговора с управляющим терминалом процесс отделяется от управляющего терминала одновременно.
3. Запретить процессу повторное открытие терминала управления
Теперь процесс стал лидером терминала в сеансе без терминала. Но он может повторно открыть контрольный терминал. Вы можете запретить процессу повторное открытие терминала управления, сделав процесс больше не лидером сеанса:
if(pid=fork())
exit (0); // Завершаем первый дочерний процесс, второй дочерний процесс продолжается (второй дочерний процесс больше не является лидером сеанса)
4. Закройте дескриптор открытого файла
Процесс наследует дескриптор открытого файла от родительского процесса, который его создал. Если он не закрыт, системные ресурсы будут потрачены впустую, что приведет к размонтированию файловой системы, в которой расположен процесс, и к непредсказуемым ошибкам. Закройте их следующим образом:
для (i = 0; я закрываю дескриптор открытого файла close (i);>
5. Изменить текущий рабочий каталог
Когда процесс активен, файловая система, в которой находится его рабочий каталог, не может быть размонтирована. Как правило, вам нужно изменить рабочий каталог на корневой каталог. Для дампов ядра процесс записи рабочего журнала меняет рабочий каталог на определенный каталог, такой как / tmpchdir («/»)
6. Сбросьте маску создания файла
Процесс наследует маску создания файла от родительского процесса, который ее создал. Это может изменить бит доступа к файлу, созданному демоном. Чтобы предотвратить это, очистите маску создания файла: umask (0);
7. Обработка сигнала SIGCHLD
Нет необходимости обрабатывать сигналы SIGCHLD. Но для некоторых процессов, особенно для процесса сервера, он часто генерирует подпроцессы для обработки запроса при поступлении запроса. Если родительский процесс не ожидает завершения дочернего процесса, дочерний процесс станет процессом зомби (zombie) и займет системные ресурсы. Если родительский процесс ожидает завершения дочернего процесса, это увеличит нагрузку на родительский процесс и повлияет на одновременную производительность серверного процесса. В Linux вы можете просто установить действие сигнала SIGCHLD на SIG_IGN.
signal(SIGCHLD,SIG_IGN);
Таким образом, ядро ​​не будет генерировать процесс зомби в конце дочернего процесса. Это отличается от BSD4, который должен явно дождаться завершения дочернего процесса, прежде чем выпускать процесс зомби.

Три, создайте демон

Перед созданием давайте разберемся с использованием setsid ():

DESCRIPTION
setsid() creates a new session if the calling process is not a process
group leader . The calling process is the leader of the new session ,
the process group leader of the new process group, and has no control-
ling tty . The process group ID and session ID of the calling process
are set to the PID of the calling process . The calling process will be
the only process in this new process group and in this new session .

Читайте также:  Список символов windows 10

// Вызывающий процесс должен быть не текущим лидером группы процессов. После вызова генерируется новый период сеанса, и в период сеанса существует только одна группа процессов, и лидер группы процессов является вызывающим процессом без управляющего терминала. И идентификатор сеанса установлен на PID вызывающего процесса

RETURN VALUE
On success, the (new) session ID of the calling process is returned.
On error, (pid_t) -1 is returned, and errno is set to indicate the
error.

Теперь создайте демон согласно приведенным выше шагам:

Следующая программа предназначена для создания демона, а затем с помощью этого демона каждую минуту записывает текущее время в файл daemon.log

Результаты показывают, что когда я выполняю a.out как обычный пользователь, вновь созданный демон не появляется в таблице процессов, но когда я выполняю как пользователь root, он успешно выполняется, и файл daemon.log создается в каталоге /, После просмотра кошки это действительно пишется раз в минуту. Почему он может выполняться только пользователем root, потому что когда мы создали процесс демона, мы переключили текущий каталог на каталог my /, поэтому, когда я позже создаю файл daemon.log, он фактически находится в каталоге /. Разрешения, может быть, вы спросите, почему это не так? На самом деле, есть ошибка, но мы закрыли стандартный ввод и перенаправили на / dev / null при создании демона, поэтому мы не можем увидеть сообщение об ошибке.

В-четвертых, используйте библиотечную функцию daemon () для создания демона

Фактически, мы можем использовать функцию daemon () для создания процесса-демона, прототип функции:

int daemon(int nochdir, int noclose);

DESCRIPTION
The daemon() function is for programs wishing to detach themselves from
the controlling terminal and run in the background as system daemons.

If nochdir is zero, daemon() changes the process’s current working
directory to the root directory («/»); otherwise,

If noclose is zero, daemon() redirects standard input, standard output
and standard error to /dev/null; otherwise, no changes are made to
these file descriptors.

Функция: Создать демон

nochdir: = 0 меняет текущий каталог на «/»

noclose: = 0 перенаправить стандартный ввод, стандартный вывод, стандартную ошибку в «/ dev / null»

Теперь мы используем daemon (), чтобы переписать программу прямо сейчас:

Результат такой же, как и раньше, только root может преуспеть, обычные пользователи не могут видеть сообщение об ошибке при выполнении

Теперь позвольте daemon (0,1), только не закрывайте стандартные результаты ввода и вывода:

Вы можете увидеть сообщение об ошибке

Теперь давайте daemon (1,0), он не перенаправлен, результат выглядит следующим образом:

На этот раз обычный пользователь преуспел, думая, что он не переключился в каталог / и имеет разрешения

Фактически, мы можем использовать daemon () по умолчанию, который мы только что создали, для создания программы процесса демона:

Код выглядит следующим образом:

Демон — это особый процесс, работающий в фоновом режиме. Он не зависит от терминала управления и периодически выполняет определенные задачи или ожидает определенных событий. Демон очень полезный процесс.

1. Самая важная особенность демона — запуск в фоновом режиме.
2. Демон должен быть изолирован от среды перед запуском. Эти среды включают в себя открытые дескрипторы файлов, управляющие терминалы, сеансы и группы процессов, рабочие каталоги и маски создания файлов. Эти среды обычно наследуются демоном от его родительского процесса (особенно оболочки).
3. Способ запуска демона особенный. Он может быть запущен из сценария запуска /etc/rc.d при запуске системы Linux, может быть запущен crond процесса планирования работы или может быть выполнен пользовательским терминалом (оболочкой).

Короче говоря, кроме этих специальностей, процесс-демон практически не отличается от обычного процесса. Поэтому написание демона фактически превращает обычный процесс в демон в соответствии с характеристиками демона, описанными выше. Если у вас есть более глубокое понимание процесса, его легче понять и запрограммировать.

Правила программирования демонов
(1) Первое, что нужно сделать, это вызвать umask, чтобы установить для слова маски создания режима файла значение 0.
Маска прав доступа к файлу: означает блокировку соответствующего бита в праве доступа к файлу. Например, существует маска прав доступа к файлу 050, которая блокирует права на чтение и выполнение для владельца группы файлов (соответствует двоичному, rwx, 101). Поскольку дочерний процесс, созданный функцией fork, наследует маску разрешений файла родительского процесса, это вызывает большие проблемы для дочернего процесса при использовании файла. Таким образом, установка маски прав доступа к файлу на 0 (то есть не блокирование каких-либо разрешений) может повысить гибкость демона. Функция установки маски прав доступа к файлам — umask. Обычное использование — это umask (0).

(2) Вызовите fork, а затем завершите родительский процесс (выход). if(pid=fork()) exit(0);

(3) Вызовите setsid для создания нового сеанса и выхода из управляющего терминала и группы процессов. Роль функции setsid: используется для создания нового разговора и выступает в качестве лидера группы разговоров.

Вызов setsid имеет три функции: (a) позволить процессу избавиться от исходного управления сеансом, (b) позволить процессу избавиться от исходного управления группой процессов, (c) позволить процессу избавиться от исходного управления терминалом управления setsid()
Цель использования функции setsid: поскольку первым шагом создания процесса-демона является вызов функции fork для создания дочернего процесса, а затем выход из родительского процесса. Когда вызывается функция fork, дочерний процесс копирует период сеанса, группу процессов, управляющий терминал и т. Д. Родительского процесса. Хотя родительский процесс завершается, период сеанса, группа процессов, управляющий терминал и т. Д. Не изменились, поэтому это не так Независимость открылась в смысле. После использования функции setsid процесс может быть полностью независимым, чтобы избавиться от контроля над другими процессами.

(4) Измените текущий рабочий каталог на корневой каталог. #define NOFILE 256 for(i=0;i

(5) Закройте файловые дескрипторы, которые больше не нужны. Это приводит к тому, что демон больше не содержит определенные файловые дескрипторы, унаследованные от его родительского процесса (родительский процесс может быть процессом оболочки или каким-либо другим процессом).

(6) Некоторые демоны открывают / dev / null, чтобы иметь файловые дескрипторы 0, 1 и 2, так что любая библиотечная процедура, которая пытается прочитать стандартный ввод, записать стандартный вывод и стандартную ошибку, не будет иметь никакого эффекта. Поскольку демон не связан с терминальным устройством, его выходные данные не могут быть отображены на терминальном устройстве, и некуда принимать входные данные от интерактивных пользователей.

Источник

Оцените статью