ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 08.11.2023
Просмотров: 16
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
МИНИСТЕРСТВО ОБРАЗОВАНИЯ РЕСПУБЛИКИ БЕЛАРУСЬ
Белорусский национальный технический университет
Международный институт дистанционного образования
Курсовой проект
«Компьютерные системы и сети»
Системные службы (демоны) Linux
Выполнил: Студент 2 курса, группы 41702121
Тарасик Никита Олегович
Руководитель: Русак Л.В.
Минск 2023
Содержание:
Цель работы 2
Задание 3
1.Краткие теоретические сведения 3
1.1.Системные службы (демоны) в Linux 3
2.Практическая часть 12
2.1.Листинг программы 12
2.2.Результат работы программы 16
3.Заключение 18
4.Список литературы 19
Цель работы
Получить навыки создания и журналирования работы программ-демонов на языке Си в операционных системах семейства Linux.
Задание
Проект может быть реализован в виде консольного приложения в среде ОС Ubuntu, Fedora, CentOS или других средствами компилятора gcc версии не ниже 4.
Проект является модификацией программ связанных с формированием серверных реализаций (при условии, что проект выполнялся с применением каналов FIFO).
Проект должен предусматривать обработку исключительных ситуаций (отсутствие или неверное количество входных параметров, ошибки открытия входного и/или выходного файла, ошибки чтения и записи)
Цель работы 2
Задание 3
1.Краткие теоретические сведения 3
1.1.Системные службы (демоны) в Linux 3
2.Практическая часть 12
2.1.Листинг программы 12
2.2.Результат работы программы 16
3.Заключение 18
4.Список литературы 19
Номер варианта | Задание | Параметры командной Строки |
10 | Заменить пробелы первым символом текста | 1. Имя входного файла 2. Количество замен |
-
Краткие теоретические сведения
-
Системные службы (демоны) в Linux
Демон (англ. daemon) – это процесс, обладающий следующим свойствами.
- Имеет длинный жизненный цикл. Часто демоны создаются во время загрузки системы и работают до момента ее выключения.
- Выполняется в фоновом режиме и не имеет контролирующего терминала.
Последняя особенность гарантирует, что ядро не сможет генерировать для такого процесса никаких сигналов, связанных с терминалом или управлением заданиями (таких, как SIGINT, SIGHUP).
Демоны создаются для выполнения специфических задач. Например:
- cron – демон, который выполняет команды в запланированное время;
- sshd – демон защищенной командной оболочки, который позволяет входить в систему с удаленных компьютеров, используя безопасный протокол;
- httpd – демон HTTP-сервера (Apache), который обслуживает веб-страницы;
Многие стандартные демоны работают в качестве привилегированных процессов (то есть их действующий пользовательский идентификатор равен 0), поэтому при их написании следует руководствоваться рекомендациями по написанию безопасных программ с повышенными привилегиями.
Создание демона
Для того чтобы стать демоном, программа должна выполнить следующие шаги.
1. Сделать вызов fork(), после которого родитель завершается, а потомок продолжает работать (в результате этого демон становится потомком процесса init). Этот шаг делается по двум следующим причинам.
- Исходя из того, что демон был запущен в командной строке, за вершение родителя будет обнаружено командной оболочкой, которая вслед за этим выведет новое приглашение и позволит потомку выполняться в фоновом режиме.
- Потомок гарантированно не станет лидером группы процессов, поскольку он наследует идентификатор группы программ PGID от своего родителя и получает свой уникальный идентификатор, который отличается от унаследованного PGID. Это необходимо для успешного выполнения следующего шага.
2. Дочерний процесс вызывает setsid(), чтобы начать новую сессию и разорвать любые связи с контролирующим терминалом.
Контролирующий терминал – это тот, который устанавливается при первом открытии устройства терминала лидером сессии. Любой
контролирующий терминал может быть связан не более чем с одной сессией. Сессия – это набор групп процессов. Членство процесса в сессии определяется идентификатором SID (session identifier – идентификатор сессии), который по аналогии с PGID (process group identifier – идентификатор группы процессов) является числом типа pid_t. Лидером сессии является процесс, который ее создал и чей идентификатор используется в качестве SID. Новый процесс наследует идентификатор SID своего родителя. Этот вызов возвращает идентификатор новой сессии или –1, если случилась ошибка:
#include
pid_t setsid(void);
Создание новой сессии системным вызовом setsid() происходит следующим образом:
- вызывающий процесс становится лидером новой сессии и новой группы процессов внутри нее. Идентификаторы PGID и SID нового процесса получают то же значение, что и сам процесс;
- вызывающий процесс не имеет контролирующего терминала.
Любое соединение с контролирующим терминалом, установленное ранее, разрывается.
3. Если после этого демон больше не открывает никаких терминальных устройств, мы можем не волноваться о том, что он восстановит соединение с контролирующим терминалом. В противном случае нам необходимо сделать так, чтобы терминальное устройство не стало контролирующим. Это можно сделать двумя нижеописанными способами.
- указывать флаг 0_NOCTTY для любых вызовов open(), которые могут открыть терминальное устройство.
- более простой вариант: после setsid() можно еще раз сделать вызов fork(), опять позволив родителю завершиться, а потомку (правнуку) – продолжить работу. Это гарантирует, что потомок не станет лидером сессии, что делает невозможным повторное соединение с контролирующим терминалом (это соответствует процедуре получения контролирующего терминала, принятой в System V).
4. Очистить атрибут umask процесса, чтобы файлы и каталоги, созданные демоном, имели запрашиваемые права доступа.
5. Поменять текущий рабочий каталог процесса (обычно на корневой – /). Это необходимо, поскольку демон обычно выполняется вплоть до выключения системы. Если файловая система, на которой находится его текущий рабочий каталог, не является корневой, она не может быть отключена. Как вариант, в качестве рабочего каталога демон может задействовать то место, где он выполняет свою работу, или воспользоваться значением в конфигурационном файле; главное, чтобы файловая система, в которой находится этот каталог, никогда не нуждалась в отключении. Например, cron применяет для этого
/var/spool/cron.
6. Закрыть все открытые файловые дескрипторы, которые демон унаследовал от своего родителя (возможно, некоторые из них необходимо оставить открытыми, поэтому данный шаг является необязательным и может быть откорректирован). Это делается по целому ряду причин. Поскольку демон потерял свой контролирующий терминал и работает в фоновом режиме, ему больше не нужно хранить дескрипторы с номерами 0, 1 и 2 (они ссылаются на терминал). Кроме того, мы не можем отключить файловую систему, на которой долгоживущий демон удерживает открытыми какие-либо файлы. И, следуя обычным правилам, мы должны закрывать неиспользуемые файловые дескрипторы, поскольку их число ограниченно.
Функция daemon( )
Библиотека GNU С предоставляет нестандартную функцию daemon(), которая превращает вызывающий процесс в демона. Функция daemon() необходима для того, чтобы отключить программу от управляющего терминала и запустить ее в фоновом режиме подобно тому, как выполняются системные службы.
#include
int daemon(int nochdir, int noclose);
Если аргумент nochdir равен нулю, то daemon() изменяет текущий рабочий каталог процесса на корневой («/»); в противном случае текущий рабочий каталог не изменяется.
Если аргумент noclose равен нулю, то daemon() перенаправляет стандартный поток ввода, вывода и ошибок в /dev/null; в противном случае данные файловые дескрипторы не изменяются.
Эта функция порождает новый процесс и, если fork() завершается без ошибок, родительский процесс вызывает _exit(), чтобы дальнейшие ошибки воспринимались только дочерним процессом. В случае успешного выполнения daemon() возвращает ноль. Если возникла ошибка, то daemon() возвращает –1 и присваивает глобальной переменной errno одно из значений, указанных для fork() и setsid().
Для библиотеки GNU C реализация этой функции была взята из BSD, и в ней не применяется техника двойного fork (т. е. fork(), setsid(), fork()), поэтому необходимо проверить, что полученный процесс службы не является лидером сеанса. Вместо этого полученная служба является лидером сеанса. В системах, следующих семантике System V (например, Linux), это означает, что если служба открывает терминал, который пока не является управляющим для другого сеанса, то этот терминал непреднамеренно станет управляющим терминалом для службы.
Запись в журнал сообщений и ошибок с помощью системы syslog
При написании демона одной из проблем является вывод сообщений об ошибках. Поскольку демон выполняется в фоновом режиме, он не может выводить информацию в терминале, как это делают другие программы. В качестве альтернативы сообщения можно записывать в отдельный журнальный файл программы.
Для записи сообщений в журнал любой процесс может воспользоваться библиотечной функцией syslog(). На основе переданных ей аргументов она создает сообщение стандартного вида и помещает его в сокет /dev/log, где оно будет доступно для syslogd.
Программный интерфейс syslog состоит из трех основных функций.
1. Функция openlog() устанавливает настройки, которые по умолчанию применяются ко всем последующим вызовам syslog().
Она не является обязательной. Если ею не воспользоваться, соединение с системой ведения журнала устанавливается при первом вызове syslog() на основе стандартных настроек.
2. Функция syslog() записывает сообщения в журнал.
3. Функция closelog() вызывается после окончания записи сообщений, чтобы разорвать соединение с журналом.
Ни одна из этих функций не возвращает значение статуса. Частично это продиктовано тем, что системное журналирование должно быть всегда доступным (если оно перестанет работать, системный администратор должен быстро это заметить). Кроме того, если при ведении журнала произошла ошибка, приложение обычно мало что может сделать, чтобы об этом сообщить.
Функция closelog() закрывает описатель, используемый для записи данных в журнал. Использование closelog() необязательно.
Функция openlog() при необходимости устанавливает соединение с системным средством ведения журнала и задает настройки, которые будут применяться по умолчанию ко всем последующим вызовам syslog().
#include
void openlog (const char *ident, int log_options,
int facility);
Аргумент ident является указателем на строку, которая добавляется в каждое сообщение, записываемое с помощью syslog(); обычно это название программы. Стоит отметить, что openlog() всего лишь копирует значение этого указателя. Продолжая использовать вызовы syslog(), приложение должно следить за тем, чтобы строка, на которую ссылается данный аргумент, не изменилась.
Если в качестве аргумента ident указать NULL, интерфейс syslog из состава glibc, как и некоторые другие реализации, будет автоматически подставлять вместо него название программы. Однако такое поведение не предусмотрено стандартом SUSv3 и не выполняется в некоторых системах, поэтому переносимые приложения не должны на него полагаться.
Аргумент log_options для вызова openlog() представляет собой битовую маску, состоящую из любых комбинаций следующих констант, к которым применяется побитовое ИЛИ.
- LOG_CONS – если в системный журнал приходит ошибка, она записывается в системную консоль (/dev/console).
- LOG_NDELAY – соединение с системой ведения журнала (то есть с сокетом домена UNIX, /dev/log) устанавливается немедленно. По умолчанию (LOG_ODELAY) это происходит, только когда (и если) первое сообщение попадает в журнал с помощью вызова syslog(). Флаг LOG_NDELAY может пригодиться в программах, которым нужно контролировать момент выделения файлового дескриптора для /dev/log. Например, это может быть приложение, которое вызывает chroot(); после этого вызова путь /dev/log перестает быть доступным, поэтому, если вы вызываете функцию openlog() с флагом LOG_NDELAY, это нужно делать до chroot(). Примером программы, которая использует флаг LOG_NDELAY таким образом, может служить демон tftpd (Trivial File Transfer).
- LOG_NOWAIT – вызов syslog() не ждет дочерний процесс, который мог быть создан для записи сообщения в журнал. Этот флаг нужен в приложениях, в которых для записи сообщений используются отдельные дочерние процессы. Он позволяет вызову syslog() избежать ожидания потомков, уже утилизированных родителем, который тоже их ожидал. В Linux флаг LOG_NOWAIT ни на что не влияет, так как в этой системе при записи сообщений в журнал дочерние процессы не создаются.
- LOG_ODELAY – противоположность флагу LOG_NDELAY. Соединение с системой ведения журнала откладывается до тех пор, пока не будет записано первое сообщение. Этот флаг используется по умолчанию, и его не нужно указывать отдельно.
- LOG_PID – включать PID в каждое сообщение.
Аргумент facility устаналивает значение по умолчанию, если не указываются соответствующие параметры при вызовах syslog().
Аргумент facility используется для указания типа программы, записывающей сообщения. Это позволяет файлу конфигурации указывать, что сообщения от различных программ будут по-разному обрабатываться.
- LOG_AUTH – сообщения о безопасности/авторизации (рекомендуется использовать вместо него LOG_AUTHPRIV);
- LOG_AUTHPRIV – сообщения о безопасности/авторизации (частные);
- LOG_CRON – демон часов (cron и at);
- LOG_DAEMON – другие системные демоны;
- LOG_KERN – сообщения ядра;
- LOG_LOCAL0 до LOG_LOCAL7 – зарезервированы для определения пользователем;
- LOG_LPR – подсистема принтера;
- LOG_MAIL – почтовая подсистема;
- LOG_NEWS – подсистема новостей USENET;
- LOG_SYSLOG – сообщения, генерируемые syslogd;
- LOG_USER (по умолчанию) – общие сообщения на уровне пользователя;
- LOG_UUCP – подсистема UUCP.
Функция syslog() изначально разрабатывалась для BSD, в настоящее время она предоставляется большинством производителей систем UNIX.
void syslog(int priority, const char *format, ...);
syslog() создает сообщение для журнала, которое передается демону syslogd. priority получается при логическом сложении facility, описанном выше, и level, описанном ниже. Аргументы format такие же, как и в printf(), кроме того, что сочетание %m будет заменено сообщением об ошибке strerror(errno) и будет добавлен завершающий символ новой строки.
Параметр level определяет степень важности сообщения. Далее значения приводятся по понижению степени их важности:
- LOG_EMERG – система остановлена;
- LOG_ALERT – требуется немедленное вмешательство;
- LOG_CRIT – критические условия;
- LOG_ERR – ошибки;
- LOG_WARNING – предупреждения;
- LOG_NOTICE – важные рабочие условия;
- LOG_INFO – информационные сообщения;
- LOG_DEBUG – сообщения об отладке.
Функция setlogmask() может использоваться для ограничения доступа на указанные уровни.
Назначение аргументов facility и level в том, чтобы все сообщения, которые посылаются процессами определенного типа (то есть с одним значением аргумента facility), могли обрабатываться одинаково в файле /etc/syslog.conf или чтобы все сообщения одного уровня (с одинаковым значением аргумента level) обрабатывались одинаково. Например, демон может сделать следующий вызов, когда вызов функции rename неожиданно оказывается неудачным:
syslog(LOG_INFO|LOG_LOCAL2, "rename(%s, %s): %m",
file1, file2);
Конфигурационный файл /etc/syslog.conf определяет поведение демона syslogd . Он состоит из правил и комментариев (последние начинаются с символа #). Правила в общем случае имеют следующий вид:
категория.приоритет действие
Сочетание категории и приоритета называют селектором, поскольку они позволяют выбрать сообщения, к которым применяется правило. Виды категорий (facility) и приоритетов (level) описаны выше, но в файле конфигурации применяются без префикса LOG_.
Под действием подразумевается место назначения сообщений, которые соответствуют селектору. Селектор и действие разделены пробельными символами. Ниже показан пример нескольких правил:
*.err /dev/tty10
auth.notice root
*.debug;mail.none;news.none -/var/log/messages
Согласно первому правилу сообщения всех категорий (*) с приоритетом err (LOG_ERR) или выше должны передаваться консольному устройству /dev/tty10. Второе правило делает так, что сообщения, связанные с авторизацией (LOG_AUTH) и имеющие приоритет notice (LOG_NOTICE) или выше, должны отправляться во все консоли или терминалы, в которых работает пользователь root. Это, например, позволит администратору немедленно получать все сообщения о неудачных попытках повышения привилегий (вызове команды su).
В последней строчке демонстрируются некоторые продвинутые аспекты синтаксиса для описания правил. В ней перечислено сразу несколько селекторов, разделенных точкой с запятой. Первый селектор относится к сообщениям любой категории (*) с приоритетом debug (самым низким) и выше, т. е. это затрагивает все сообщения. В Linux, как и в большинстве других UNIX-систем, вместо debug можно указать символ *, который будет иметь то же значение, однако данная возможность поддерживается не всеми реализациями syslog. Если правило содержит несколько селекторов, оно обычно охватывает сообщения, соответствующие любому из них. Но если в качестве приоритета указать значение none, то сообщения, принадлежащие к заданной категории, будут отбрасываться. Таким образом, это правило передает все сообщения (кроме тех, которые имеют категории mail и news) в файл /var/log/messages. Символ «тильда» () перед именем этого файла говорит о том, что сбрасывание данных на диск будет происходить не при каждой передаче сообщения. Это приводит к увеличению скорости записи, но в случае сбоя системы сообщения, пришедшие недавно, могут быть утеряны.
При каждом изменении файла syslog.conf демону следует отправлять сигнал, чтобы он смог заново себя инициализировать:
$killall -HUP syslogd //Отправляем сигнал SIGHUP
демону syslogd
Синтаксис файла syslog.conf позволяет создавать куда более сложные правила, чем те, что были показаны.
-
Практическая часть
-
Листинг программы
#include
#include
#include
#include
#include
void func(int argc, char** argv)
{
while(1)
{
openlog("dem",LOG_PID|LOG_CONS,LOG_USER);
FILE *f;
char ch;
int size=0;
char *buffer;
int count=0;
if((f=fopen(argv[1], "rt"))==NULL)
{
syslog(LOG_INFO, "ERROR: Can't open File");
exit(1);
}
else
{
while((ch=fgetc(f))!=EOF)
{
size++;
}
buffer=(char*)malloc(size+1);
fseek(f,0,SEEK_SET);
int i=0;
while((ch=fgetc(f))!=EOF)
{
buffer[i]=ch;
i++;
}
fclose(f);
ch=buffer[0];
for(int k=0;k
{
if(buffer[k]==' ')
{
buffer[k]=ch;
count++;
}
int c=atoi(argv[2]);
if(count>=c) break;
}
}
buffer[size]='\0';
if((f=fopen(argv[1],"wt"))==NULL)
{
syslog(LOG_INFO,"can't open file");
exit(1);
}
else
{
fprintf(f,"%s",buffer);
fclose(f);
syslog(LOG_INFO,"file update");
}
free(buffer);
closelog();
sleep(10);
}
}
int main(int argc, char** argv)
{
if(argc<2)
{
printf("Not enough arguments\n");
return -1;
}
if((atoi(argv[2])==0)
{
printf("second argument must not be ‘0’!\n or has not number!");
return -1;
}
int pid=fork();
switch(pid){
case 0:
setsid();
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
func(argc, argv);
case -1:
printf("fail");
break;
default:
printf("create pid=%d\n",pid);
break;
}
return 0;
}
-
Результат работы программы
Предусмотрены обработчик ошибок ввода аргументов в терминале, таких как проверка числового поля в виде второго аргумента( количество изменений за один цикл), а также ограничение в виде нуля итераций; обработчик ошибок количества аргуменотов.
-
Заключение
В ходе выполнения курсовой работы были получены базовые знания по структуре операционной системы Linux(Ubuntu 20.04) и её эксплуатации. Как работать с терминалом. Особенности файловой системы Linux и работы с потоками и процессами. Ознакомились с особенностями создания Daemon и журнала сообщений и ошибок на языке Си в операционной системе Linux. Ознакомился с работой процесса демонизации в Linux, стандартными потоками ввода, вывода и ошибок, особенностями работы fork(). В ходе работы ознакомился со спецификой использования демонов, использования журнала сообщений и ошибок.
-
Список литературы
-
Электронный источник - https://ubuntu.com/; -
Unix и Linux: руководство системного администратора - Бэн Уэйли, Гарт Снайдер, Эви Немет, Трент Р Хейн, - 2012г. , 1314 с. -
Внутреннее устройство Linux – Уорд Брайан, -2018, 384 с. -
Электронный источник C/Linux - https://www.youtube.com/watch?v= kP02t8NOqJQ&list=PLdI4_a4AZXjHAHG4qqhIovDQnirO7rWAL