diff --git a/Marchenko_Elizaveta/lab1/CMakeFile.txt b/Marchenko_Elizaveta/lab1/CMakeFile.txt new file mode 100644 index 0000000..85d37b4 --- /dev/null +++ b/Marchenko_Elizaveta/lab1/CMakeFile.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.16.2) +project(lab1) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_FLAGS "-Wall -Werror") +add_executable(lab1 main.cpp daemon.cpp) diff --git a/Marchenko_Elizaveta/lab1/build.sh b/Marchenko_Elizaveta/lab1/build.sh new file mode 100644 index 0000000..4d15570 --- /dev/null +++ b/Marchenko_Elizaveta/lab1/build.sh @@ -0,0 +1,15 @@ +#!bin/bash + +DIR_NAME="lab1_build" +EXE_NAME="lab1" +PID_PATH="/var/run/lab1_daemon.pid" + + +sudo touch $PID_PATH; sudo chmod 0666 $PID_PATH + +mkdir $DIR_NAME +cd $DIR_NAME +cmake ..; make +cd .. +cp $DIR_NAME/$EXE_NAME . +rm -r $DIR_NAME diff --git a/Marchenko_Elizaveta/lab1/config.txt b/Marchenko_Elizaveta/lab1/config.txt new file mode 100644 index 0000000..f5217b1 --- /dev/null +++ b/Marchenko_Elizaveta/lab1/config.txt @@ -0,0 +1,2 @@ +/media/user/DATA1/lab1/testing +3 diff --git a/Marchenko_Elizaveta/lab1/daemon.cpp b/Marchenko_Elizaveta/lab1/daemon.cpp new file mode 100644 index 0000000..e84c9cb --- /dev/null +++ b/Marchenko_Elizaveta/lab1/daemon.cpp @@ -0,0 +1,176 @@ +#include "daemon.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +static void ReceiveSignal(int signal) +{ + switch (signal) + { + case SIGHUP: + { + syslog(LOG_INFO, "Reload config"); + My_Daemon::get_one().config(); + break; + } + case SIGTERM: + { + syslog(LOG_INFO, "Terminate"); + My_Daemon::get_one().terminate(); + break; + } + default: + break; + } +} + +void Deleter(const string& directory, const string& key_file) +{ + if (filesystem::exists(directory + '/' + key_file)) + { + return; + } + for (auto& file : filesystem::directory_iterator(directory)) + { + if (!filesystem::remove(file)) + { + syslog(LOG_WARNING, "Removed was failed: \"%s\"", file.path().c_str()); + } + } +} + +void My_Daemon::start() +{ + syslog(LOG_INFO, "Create daemon"); + + pid_t pid = fork(); + if (pid < 0) + { + syslog(LOG_ERR, "fork error"); + exit(EXIT_FAILURE); + } + else if (pid > 0) + { + exit(EXIT_SUCCESS); + } + + umask(0); + if (setsid() < 0) + { + syslog(LOG_ERR, "Error: Group setting"); + exit(EXIT_FAILURE); + } + if (chdir("/") < 0) + { + syslog(LOG_ERR, "Error: Switching to root dir"); + exit(EXIT_FAILURE); + } + + for (int tmp = sysconf(_SC_OPEN_MAX); tmp >= 0; --tmp) + { + close(tmp); + } + int devNull = open("/dev/null", O_RDWR); + dup2(devNull, STDIN_FILENO); + dup2(devNull, STDOUT_FILENO); + dup2(devNull, STDERR_FILENO); + syslog(LOG_INFO, "end of daemon create"); +} + +void My_Daemon::stop() +{ + unsigned int living_daemon_pid = 0; + syslog(LOG_INFO, "search living daemon"); + ifstream pid_file(pid_path); + + if (pid_file.is_open() && + pid_file >> living_daemon_pid && kill(living_daemon_pid, 0) == 0) + { + syslog(LOG_WARNING, "found living daemon. PID: %i", living_daemon_pid); + kill(living_daemon_pid, SIGTERM); + } +} + +static My_Daemon& My_Daemon::get_one() +{ + static My_Daemon daemon; + return daemon; +} + +void My_Daemon::terminate() +{ + is_Terminate = true; + closelog(); +} + +void My_Daemon::config() +{ + unsigned int update_seconds = 0; + ifstream config_file(abs_path); + if (!config_file.is_open()) + { + syslog(LOG_ERR, "Invalid config"); + exit(EXIT_FAILURE); + } + if (!getline(config_file, dir_path)) + { + syslog(LOG_ERR, "Directory path reading error"); + exit(EXIT_FAILURE); + } + + if (!(config_file >> update_seconds)) + { + syslog(LOG_WARNING, "Update time reading error"); + update_time = defoult_update_time; + } + else + { + update_time = chrono::seconds(update_seconds); + } +} + +void My_Daemon::run() +{ + while (!is_Terminate) + { + if (filesystem::is_directory(dir_path)) + { + Deleter(dir_path, key_file); + } + else + { + syslog(LOG_WARNING, "Not found directory"); + } + this_thread::sleep_for(update_time); + } +} + +void My_Daemon::initialize(const string& config_local) +{ + abs_path = filesystem::absolute(config_local); + openlog("My_Daemon", LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_USER); + syslog(LOG_INFO, "Daemon initialization"); + stop(); + start(); + + syslog(LOG_INFO, "Writing pid"); + ofstream pid_file(pid_path.c_str()); + if (!pid_file.is_open()) + { + syslog(LOG_ERR, "write pid error"); + exit(EXIT_FAILURE); + } + pid_file << getpid(); + + signal(SIGHUP, ReceiveSignal); + signal(SIGTERM, ReceiveSignal); + config(); + syslog(LOG_INFO, "Initialize end"); +} diff --git a/Marchenko_Elizaveta/lab1/daemon.hpp b/Marchenko_Elizaveta/lab1/daemon.hpp new file mode 100644 index 0000000..eaccd8b --- /dev/null +++ b/Marchenko_Elizaveta/lab1/daemon.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include + +using namespace std; + +class My_Daemon +{ +public: + static My_Daemon& get_one(); + void terminate(); + void config(); + void run(); + void initialize(const string& config_local); +private: + My_Daemon() {}; + My_Daemon(const My_Daemon&) = delete; + My_Daemon& operator=(const My_Daemon&) = delete; + void start(); + void stop(); + + const string key_file = "dont.erase"; + const chrono::seconds defoult_update_time = chrono::seconds(5); + const string pid_path = "/var/run/lab1_daemon.pid"; + chrono::seconds update_time; + bool is_Terminate = false; + string abs_path; + string dir_path; +}; diff --git a/Marchenko_Elizaveta/lab1/main.cpp b/Marchenko_Elizaveta/lab1/main.cpp new file mode 100644 index 0000000..68765b2 --- /dev/null +++ b/Marchenko_Elizaveta/lab1/main.cpp @@ -0,0 +1,16 @@ +#include "daemon.hpp" +#include +using namespace std; + +int main(int argc, char** argv) +{ + if (argc < 2) + { + cerr << "Incorrect arguments, it requires two" << endl; + return EXIT_FAILURE; + } + My_Daemon::get_one().initialize(argv[1]); + My_Daemon::get_one().run(); + + return EXIT_SUCCESS; +} \ No newline at end of file