From 43092ad1f4f706823b3aa40b836eea3905dac5a6 Mon Sep 17 00:00:00 2001 From: Serafim Date: Thu, 3 Apr 2025 00:23:50 +0300 Subject: [PATCH] style/improve-code-style (#7) Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/7 Reviewed-by: dr-wh0 <79003667309@yandex.ru> Co-authored-by: Serafim Co-committed-by: Serafim --- src/DosAtk.cpp | 487 +++++++++++++++++++++++++++---------------------- src/a.out | Bin 57600 -> 0 bytes 2 files changed, 272 insertions(+), 215 deletions(-) delete mode 100755 src/a.out diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 41825a6..1e9e7cf 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -1,3 +1,5 @@ +// ====== DCL библиотеки ====== // + #include // Для работы с вводом-выводом (cout, cin и др.) #include // Стандартная библиотека C (функции работы с памятью, преобразования типов и др.) #include // Для работы со строками string @@ -8,25 +10,32 @@ #include // Функции для работы с символами (isdigit, isalpha и др.) #include // Библиотека libcurl для HTTP-запросов (отправка в Telegram) -// Глобальные переменные -std::string attack_type; // Тип атаки: scan или syn -std::string domain; // Доменное Имя -std::string ip; // Ip жертвы -std::string port; // Порт -std::string log_file; // Путь к директории для логов -std::string telegram_id; // Telegram ID для уведомлений -std::string telegram_token; // Токен бота -int n_ok_requests; // Количество успешных запросов -int n_fail_requests; // Количество не успешных запросов -std::chrono::system_clock::time_point start_timestamp; // Начальное время работы -std::string log_msg; // Сообщение, которое будет записано в лог-файл -std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю -std::string msg; // Сообщение, которое будет отправлено в телеграм -int status; // Статус работы программы +// ====== DCL глобальные переменные ====== // -// ====== end of DCL ====== // +// Параметры +int argc // Количество аргументов при вызове программы +char **argv // Массив строк с агрументами +std::string attack_type; // Тип атаки: scan или syn +std::string domain; // Доменное Имя +std::string ip; // Ip жертвы +std::string port; // Порт для syn атаки +std::string log_file; // Путь к директории для логов +std::string telegram_id; // Telegram ID для уведомлений +std::string telegram_token; // Токен бота для уведомлений -int my_check_params(int argc, char **argv) +// Статистика +int n_ok_requests; // Количество успешных запросов +int n_fail_requests; // Количество не успешных запросов +std::chrono::system_clock::time_point start_timestamp; // Начальное время работы +// Переменные +std::string log_msg; // Сообщение, которое будет записано в лог-файл +std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю +std::string msg; // Сообщение, которое будет отправлено в телеграм +int status; // Статус работы программы + +// ====== DCL процедуры ====== // + +void my_check_params() { // Данная процедура записывает в глобальные переменные параметры // (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы @@ -41,11 +50,18 @@ int my_check_params(int argc, char **argv) // -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи // -600 - пользователь ввел токен, но не id или наоборот - int status; - int opt; - const char* short_options; - short_options = "a:d:i:p:l:t:b:h"; - const struct option long_options[] = + //Объявление + std::chrono::milliseconds ms; // Количество миллисекунд от целой секунды времени начала выполнения программы + int opt; // Прочитанный параметр + const char* short_options; // Сокращения для параметров + struct option long_options[]; // Структура, описывающая пеобходимые программе параметры + int i; // Счётчик для цикла + + // Инициализация + ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; + opt = -1; + short_options = "a:d:i:p:l:t:b:h"; + long_options = { {"attack", required_argument, NULL, 'a'}, {"domain", required_argument, NULL, 'd'}, @@ -57,14 +73,19 @@ int my_check_params(int argc, char **argv) {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; + i = 0; - std::string debug_msg; - debug_msg = ""; - for (int i = 0; i < argc; i++) { - debug_msg += argv[i]; - debug_msg += " "; - } - printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); // debug + printf("begin my_check_params"); // debug + + // Выводим информацию о времени запуска программы + printf("Starting DosAtk at %04d-%02d-%02d %02d:%02d:%02d.%03ld\n", // Шаблон для вывода + std::localtime(&now_time_t)->tm_year + 1900, // Год (с 1900) + std::localtime(&now_time_t)->tm_mon + 1, // Месяц (0-11) + std::localtime(&now_time_t)->tm_mday, // День месяца + std::localtime(&now_time_t)->tm_hour, // Часы + std::localtime(&now_time_t)->tm_min, // Минуты + std::localtime(&now_time_t)->tm_sec, // Секунды + ms.count()); // Миллисекунды // Обрабатываем аргументы командной строки с помощью getopt_long // Цикл продолжается, пока getopt_long возвращает валидные опции (-1 означает конец опций) @@ -104,34 +125,33 @@ int my_check_params(int argc, char **argv) if (status != 0 && status != -101) { // Проверяем валидность типа атаки - if (attack_type != "flood" && attack_type != "scan") { - status = -1; // Некорректный тип атаки - } - // Для сканирования портов должна быть указана цель (домен или IP) - else if (attack_type == "scan" && domain.empty() && ip.empty()) { - status = -10; // Не указана цель для сканирования - } - // Для флуд-атаки должна быть указана цель (домен или IP) - else if (attack_type == "flood" && domain.empty() && ip.empty()) { - status = -20; // Не указана цель для флуда - } - // Проверяем, что если указан Telegram ID или токен, то должны быть указаны оба - else if ((!telegram_id.empty() && telegram_token.empty()) || - (telegram_id.empty() && !telegram_token.empty())) { - status = -600; // Неполные данные для Telegram - } - // Если все проверки пройдены и тип атаки - сканирование - else if (attack_type == "scan") { - status = 1; // Валидные параметры для сканирования - } - // Если все проверки пройдены и тип атаки - флуд - else if (attack_type == "flood") { - status = 2; // Валидные параметры для флуда - } + if (attack_type != "flood" && attack_type != "scan") { + status = -1; // Некорректный тип атаки + } + // Для сканирования портов должна быть указана цель (домен или IP) + else if (attack_type == "scan" && domain.empty() && ip.empty()) { + status = -10; // Не указана цель для сканирования + } + // Для флуд-атаки должна быть указана цель (домен или IP) + else if (attack_type == "flood" && domain.empty() && ip.empty()) { + status = -20; // Не указана цель для флуда + } + // Проверяем, что если указан Telegram ID или токен, то должны быть указаны оба + else if ((!telegram_id.empty() && telegram_token.empty()) || + (telegram_id.empty() && !telegram_token.empty())) { + status = -600; // Неполные данные для Telegram + } + // Если все проверки пройдены и тип атаки - сканирование + else if (attack_type == "scan") { + status = 1; // Валидные параметры для сканирования + } + // Если все проверки пройдены и тип атаки - флуд + else if (attack_type == "flood") { + status = 2; // Валидные параметры для флуда + } } printf("end my_check_params status: %i\n", status); // debug - return status; } void my_diag() @@ -139,8 +159,8 @@ void my_diag() // Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, // формирует сообщение с описанием произошедшей ошибки - // Отладочный вывод - начало работы функции (можно отключить в релизной версии) printf("begin my_diag, status: %i\n", status); // debug + // Выбор сообщения в зависимости от кода ошибки switch (status) { @@ -181,9 +201,18 @@ void my_diag() // Принимает: const std::string& s - исходная строка для обработки // Возвращает: std::string - строка с экранированными спецсимволами std::string escape_json(const std::string& s) { + // Возвращаем строку с экранированными символами + + // ===== Объявления ===== std::string result; // Результирующая строка с экранированными символами + char c; // Символ в строке + + // ===== Инициализация ===== + result = ""; + c = ''; + // Проходим по каждому символу входной строки - for (char c : s) { + for (c : s) { // Обрабатываем специальные символы JSON switch (c) { case '"': result += "\\\""; break; // Экранирование двойных кавычек @@ -196,17 +225,24 @@ std::string escape_json(const std::string& s) { default: result += c; break; // Все остальные символы добавляем как есть } } + return result; // Возвращаем обработанную строку } bool is_numeric(const std::string& s) { // Проверка, является ли строка числом (включая отрицательные) + // ===== Объявления ===== size_t start; // Индекс, с которого начинать проверку цифр + size_t i; + + // ===== Инициализация ===== + start = 0; + i = 0; + if (s.empty()) return false; // Пустая строка не может быть числом // Проверяем наличие знака минус в начале - start = 0; if (s[0] == '-') { // Строка из одного минуса не является числом if (s.size() == 1) return false; @@ -214,50 +250,46 @@ bool is_numeric(const std::string& s) { start = 1; } // Проверяем все оставшиеся символы на цифры - for (size_t i = start; i < s.size(); ++i) { + for (i = start; i < s.size(); ++i) { // Найден нецифровой символ - строка не число if (!isdigit(s[i])) return false; } + // Все проверки пройдены - строка является числом return true; } -int my_msg() { - // Инициализация локальных переменных для работы с CURL +void my_msg() { + printf("begin my_msg"); // debug + // Объявление + struct curl_slist* headers; // Заголовки HTTP-запроса CURL* curl; // Указатель на CURL-объект std::string escaped_msg; // Экранированное сообщение для JSON - std::cout << msg << std::endl; // Вывод сообщения в консоль (для отладки) std::string chat_id_field; // Поле chat_id для JSON std::string json_data; // Итоговый JSON для отправки - struct curl_slist* headers; // Заголовки HTTP-запроса - headers = nullptr; // Инициализация заголовков long http_code; // HTTP-код ответа CURLcode res; // Код результата CURL-операции - + + // Инициализация + headers = curl_slist_append(nullptr, "Content-Type: application/json"); // Установка заголовка Content-Type + curl = curl_easy_init(); // Инициализация CURL + escaped_msg = escape_json(msg); // Экранирование спецсимволов в сообщении для JSON + chat_id_field = is_numeric(telegram_id) ? "\"chat_id\": " + telegram_id : "\"chat_id\": \"" + telegram_id + "\""; + json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; // Сборка JSON-запроса + http_code = 0; + res = nullptr; + // Проверка наличия обязательных параметров Telegram - if (telegram_token.empty() || telegram_id.empty()) { - return 0; // Интеграция с Telegram не настроена (отсутствует токен или ID) + if (telegram_token.empty() || telegram_id.empty()) + { + status = 0; // Интеграция с Telegram не настроена (отсутствует токен или ID) } - // Инициализация CURL - curl = curl_easy_init(); - if (!curl) return 6; // Ошибка инициализации CURL - - // Экранирование спецсимволов в сообщении для JSON - escaped_msg = escape_json(msg); - - // Формирование поля chat_id в зависимости от типа ID (число или строка) - if (is_numeric(telegram_id)) { - chat_id_field = "\"chat_id\": " + telegram_id; // Числовой ID - } else { - chat_id_field = "\"chat_id\": \"" + telegram_id + "\""; // Строковый ID + if (!curl) + { + status = 6; // Ошибка инициализации CURL } - - // Сборка JSON-запроса - json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; - // Установка заголовка Content-Type - headers = curl_slist_append(headers, "Content-Type: application/json"); // Настройка параметров CURL-запроса curl_easy_setopt(curl, CURLOPT_URL, ("https://api.telegram.org/bot" + telegram_token + "/sendMessage").c_str()); // URL API Telegram @@ -267,15 +299,17 @@ int my_msg() { curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/7.68.0"); // User-Agent // Игнорирование вывода ответа (пустая функция обратного вызова) - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void*, size_t size, size_t nmemb, void*) -> size_t { - return size * nmemb; - }); + curl_easy_setopt( + curl, CURLOPT_WRITEFUNCTION, + [](void*, size_t size, size_t nmemb, void*) -> size_t { + return size * nmemb; + } + ); // Выполнение HTTP-запроса res = curl_easy_perform(curl); // Получение HTTP-кода ответа - http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); // Освобождение ресурсов @@ -283,57 +317,80 @@ int my_msg() { curl_easy_cleanup(curl); // Завершение работы CURL // Обработка ошибок CURL - if (res != CURLE_OK) return 5; // Ошибка выполнения запроса + if (res != CURLE_OK) + { + status = 5; // Ошибка выполнения запроса + } // Обработка HTTP-кодов ответа - switch (http_code) { - case 200: return 0; // Успешный запрос - case 401: return 1; // Ошибка авторизации (неверный токен) - case 400: return 2; // Неверный запрос - case 404: return 3; // Ресурс не найден - default: - if (http_code >= 500) return 4; // Ошибка сервера - return 4; // Прочие ошибки + switch (http_code) + { + case 200: + status = 0; // Успешный запрос + case 401: + status = 1; // Ошибка авторизации (неверный токен) + case 400: + status = 2; // Неверный запрос + case 404: + status = 3; // Ресурс не найден + case 500: + status = 4; // Ошибка сервера } + + printf("end my_msg"); // debug } -int my_log() +void my_log() { // Данная функция записывает в файл лога сообщение - return 0; + printf("start my_log"); // debug + printf("end my_log"); // debug } void my_fin() { - // Данная функция завершает программу и рассчитывает итоговое время выполнения программы + // Данная процедура завершает программу и рассчитывает итоговое время выполнения программы + + // Объявления + time_t end_time_t; // Время завершения выполненя программы + std::chrono::duration duration; // Длительность выполнения программы + std::chrono::hours hours; // Компонента часов времени завершения + std::chrono::minutes minutes; // Компонента минут времени завершения + std::chrono::seconds seconds; // Компонента секунд времени завершения + std::chrono::milliseconds milliseconds; // Компонента миллисекунд времени завершения - // Фиксируем время окончания работы программы - auto end_timestamp = std::chrono::system_clock::now(); - // Преобразуем время окончания в time_t и миллисекунды - auto end_time_t = std::chrono::system_clock::to_time_t(end_timestamp); - auto end_ms = std::chrono::duration_cast(end_timestamp.time_since_epoch()) % 1000; + // Иницаализация + end_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + duration = end_timestamp - start_timestamp; // Вычисляем продолжительность работы программы + hours = std::chrono::duration_cast(duration); // Разбиваем продолжительность на компоненты + minutes = std::chrono::duration_cast(duration % std::chrono::hours(1)); // Разбиваем продолжительность на компоненты + seconds = std::chrono::duration_cast(duration % std::chrono::minutes(1)); // Разбиваем продолжительность на компоненты + milliseconds = std::chrono::duration_cast(duration % std::chrono::seconds(1)); // Разбиваем продолжительность на компоненты + double total_seconds - // Вычисляем продолжительность работы программы - auto duration = end_timestamp - start_timestamp; - // Разбиваем продолжительность на компоненты - auto hours = std::chrono::duration_cast(duration); - auto minutes = std::chrono::duration_cast(duration % std::chrono::hours(1)); - auto seconds = std::chrono::duration_cast(duration % std::chrono::minutes(1)); - auto milliseconds = std::chrono::duration_cast(duration % std::chrono::seconds(1)); + printf("begin my_diag\n"); // debug - // Выводим информацию о времени работы - std::cout << "Worked for "; + std::cout << "Worked for "; // Выводим информацию о времени работы // Для коротких периодов (<2 минут) выводим в секундах с дробной частью - if (duration < std::chrono::minutes(2)) { - double total_seconds = std::chrono::duration(duration).count(); + if (duration < std::chrono::minutes(2)) + { + total_seconds = std::chrono::duration(duration).count(); std::cout << std::fixed << std::setprecision(3) << total_seconds << " seconds"; - } else { - // Для длительных периодов выводим в формате ЧЧ:ММ:СС.мс - if (hours.count() > 0) std::cout << hours.count() << "h "; - if (minutes.count() > 0) std::cout << minutes.count() << "m "; - std::cout << seconds.count() << "s " << milliseconds.count() << "ms"; } - std::cout << std::endl; + else + { + // Для длительных периодов выводим в формате ЧЧ:ММ:СС.мс + if (hours.count() > 0) // Если программа работала хотя бы один час + { + std::cout << hours.count() << "h "; // Выводим часы + } + if (minutes.count() > 0) // Если программа работала хотя бы одину минуту + { + std::cout << minutes.count() << "m "; // Вывовим минуты + } + std::cout << seconds.count() << "s " << milliseconds.count() << "ms"; // Выводим секунды и миллисекунды + } + std::cout << std::endl; // После осуществления вывода переходим на новую строку // Выводим статистику по запросам std::cout << "Sent " << (n_ok_requests + n_fail_requests) << " requests (" @@ -341,171 +398,171 @@ void my_fin() // Выводим точное время завершения работы std::cout << "DosAtk stopped at " << std::put_time(std::localtime(&end_time_t), "%Y-%m-%d %H:%M:%S") - << "." << std::setfill('0') << std::setw(3) << end_ms.count() << std::endl; + << "." << std::setfill('0') << std::setw(3) << milliseconds.count() << std::endl; - // Завершаем программу с кодом 0 (успешное завершение) - std::exit(0); + // Завершаем программу с кодом состояния + std::exit(status); } -int my_dns() +void my_dns() { // Данная процедура сопостовляет доменное имя с IP - return 0; + printf("start my_dns"); // debug + printf("end my_dns"); // debug } -int my_tcp_syn() +void my_tcp_syn() { // Данная процедура выполняет TCP SYN Flood атаку - return 2; + printf("start my_tcp_syn"); // debug + printf("end my_tcp_syn"); // debug } -int my_udp() +void my_udp() { // Данная процедура выполняет UDP Flood (port scanning) атаку - return 2; + printf("start my_udp"); // debug + printf("end my_udp"); // debug } -int main(int argc, char **argv) +int main(int arg_ctr, char **arg_ptr) { - // Главная функция программы - точка входа - - // Объявление переменных для хранения статусов операций - int log_status; // Статус записи в лог - int dns_status; // Статус DNS-разрешения - int udp_status; // Статус UDP-атаки - int tcp_syn_status; // Статус TCP SYN-атаки + // Инициализация глобальных переменных + int argc = arg_ctr; + char **argv = arg_ptr; + std::string attack_type = ""; + std::string domain = ""; + std::string ip = ""; + std::string port = ""; + std::string log_file = "/var/log/DosAtk"; + std::string telegram_id = ""; + std::string telegram_token = ""; + int n_ok_requests = 0; + int n_fail_requests = 0; + std::chrono::system_clock::time_point start_timestamp = std::chrono::system_clock::now(); + std::string log_msg = ""; + std::string fin_msg = ""; + std::string msg; + int status = 0; - // ====== Инициализация программы ====== // - n_ok_requests = 0; // Счетчик успешных запросов - n_fail_requests = 0; // Счетчик неудачных запросов - start_timestamp = std::chrono::system_clock::now(); // Засекаем время начала - status = 0; // Статус программы + // Тело программы - // Получаем текущее время в различных форматах - time_t now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); - auto ms = std::chrono::duration_cast( - start_timestamp.time_since_epoch()) % 1000; - - // Выводим информацию о времени запуска программы - printf("Starting DosAtk at %04d-%02d-%02d %02d:%02d:%02d.%03ld\n", - std::localtime(&now_time_t)->tm_year + 1900, // Год (с 1900) - std::localtime(&now_time_t)->tm_mon + 1, // Месяц (0-11) - std::localtime(&now_time_t)->tm_mday, // День месяца - std::localtime(&now_time_t)->tm_hour, // Часы - std::localtime(&now_time_t)->tm_min, // Минуты - std::localtime(&now_time_t)->tm_sec, // Секунды - ms.count()); // Миллисекунды - - // ====== Основная логика программы ====== // - // 1. Проверяем параметры командной строки - status = my_check_params(argc, argv); + // Проверяем параметры командной строки + my_check_params(); // Обрабатываем результат проверки параметров switch (status) { case 1: // Режим сканирования портов (UDP) // Пытаемся разрешить DNS (если указано доменное имя) - dns_status = my_dns(); + my_dns(); - if (dns_status == 0) // Если DNS разрешен успешно + if (status == 0) // Если DNS разрешен успешно { // Запускаем цикл UDP-атаки - while (udp_status = my_udp()) + while (true) { - if (udp_status == 2) // Код завершения атаки + my_udp() + if (status == 2) // Код завершения атаки { break; } - else if (udp_status < 0) // Обработка ошибок + else if (status < 0) // Обработка ошибок { - status = udp_status; - my_diag(); // Выводим диагностику - log_status = my_log(); // Пытаемся записать в лог - if (log_status == 1) // Если требуется уведомление + my_diag(); // Выводим диагностику + my_log(); // Пытаемся записать в лог + if (status == 1) // Если записать лог не удалось { - my_msg(); // Отправляем сообщение + my_msg(); // Отправляем сообщение } } } // Завершающие действия после атаки - log_status = my_log(); // Логируем завершение - my_msg(); // Отправляем финальное сообщение - my_fin(); // Корректно завершаем программу + my_log(); // Логируем завершение + my_msg(); // Отправляем финальное сообщение + my_fin(); // Корректно завершаем программу } - else if (dns_status == 1) // Ошибка DNS-разрешения + else if (status == 1) // Ошибка DNS-разрешения { my_diag(); // Выводим ошибку - log_status = my_log(); // Логируем ошибку + my_log(); // Логируем ошибку - if (log_status == 0) { // Если не требуется уведомление - my_fin(); // Просто завершаем программу - } - else if (log_status == 1) // Если требуется уведомление + if (status == 0) // Если лог получилось записать { - my_msg(); // Отправляем сообщение - my_fin(); // Завершаем программу + my_fin(); // Просто завершаем программу + } + else if (log_status == 1) // Если лог не удалось записать + { + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } } break; - case 2: // Режим SYN-флуда (TCP) - // Аналогичная логика как для UDP-режима - dns_status = my_dns(); - - if (dns_status == 0) + // Пытаемся разрешить DNS (если указано доменное имя) + my_dns(); + + if (status == 0) // Если DNS разрешен успешно { - while (tcp_syn_status = my_tcp_syn()) + // Запускаем цикл UDP-атаки + while (true) { - if (tcp_syn_status == 2) + my_tcp_syn() + if (status == 2) // Код завершения атаки { break; } - else if (tcp_syn_status < 0) + else if (status < 0) // Обработка ошибок { - status = tcp_syn_status; - my_diag(); - log_status = my_log(); - if (log_status == 1) + my_diag(); // Выводим диагностику + my_log(); // Пытаемся записать в лог + if (status == 1) // Если записать лог не удалось { - my_msg(); + my_msg(); // Отправляем сообщение } } } - log_status = my_log(); - my_msg(); - my_fin(); + // Завершающие действия после атаки + my_log(); // Логируем завершение + my_msg(); // Отправляем финальное сообщение + my_fin(); // Корректно завершаем программу } - else if (dns_status == 1) + else if (status == 1) // Ошибка DNS-разрешения { - my_diag(); - log_status = my_log(); - if (log_status == 0) + my_diag(); // Выводим ошибку + my_log(); // Логируем ошибку + + if (status == 0) // Если лог получилось записать { - my_fin(); + my_fin(); // Просто завершаем программу } - else if (log_status == 1) + else if (log_status == 1) // Если лог не удалось записать { - my_msg(); - my_fin(); + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } } break; - - default: // Некорректные параметры или запрос справки + case 0: // Некорректные параметры или запрос справки + case -1: + case -10: + case -20: + case -101: + case -600: my_diag(); // Выводим диагностику - log_status = my_log(); // Логируем событие + my_log(); // Логируем событие - if (log_status == 0) // Без уведомления + if (status == 0) // Без уведомления { - my_fin(); // Завершаем программу + my_fin(); // Завершаем программу } - else if (log_status == 1) // С уведомлением + else if (status == 1) // С уведомлением { - my_msg(); // Отправляем сообщение - my_fin(); // Завершаем программу + my_msg(); // Отправляем сообщение + my_fin(); // Завершаем программу } break; } return 0; // Возвращаем код успешного завершения -} \ No newline at end of file +} diff --git a/src/a.out b/src/a.out deleted file mode 100755 index 4f5b5792f2db3746c274241df95f010d743a372a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57600 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