/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2014, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include "core/log.h" #include "core/slog.h" #include "core/app.h" #include "core/plugin.h" #include "core/version.h" #include "utf8/utf8.h" namespace Winix { Log log; Log nlog; // notify log (used by a notification thread) SLog slog; // session logger Plugin plugin; /* application object */ App app; void print_syntax() { std::cout << "Syntax:" << std::endl; std::cout << " winix config_file" << std::endl; } void CreateNewDescriptor(int des_dst, int flags) { int descriptor; descriptor = open("/dev/null", flags | O_NOCTTY); if( descriptor != -1 ) { dup2(descriptor, des_dst); if( descriptor != des_dst ) close(descriptor); } } void CloseDescriptors() { close(0); close(1); close(2); app.stdout_is_closed = true; CreateNewDescriptor(0, O_RDONLY); CreateNewDescriptor(1, O_WRONLY); CreateNewDescriptor(2, O_WRONLY); } void LogInfo(LogManipulators log_level, const char * msg, bool put_version, const char * msg2) { log << log_level; log.PrintDate(PT::Date(std::time(0)), app.config.log_time_zone_id); log << ' ' << msg; if( put_version ) { log << ' ' << WINIX_VER_MAJOR << '.' << WINIX_VER_MINOR << '.' << WINIX_VER_REVISION; } log << ' ' << msg2 << logend; } void SavePidFile() { if( !app.config.pid_file.empty() ) { std::string file_name; PT::WideToUTF8(app.config.pid_file, file_name); std::ofstream file(file_name); if( !file ) { log << log1 << "I cannot save the pid to a file: " << app.config.pid_file << logend; } else { file << getpid() << "\n"; file.close(); log << log3 << "Process pid saved to: " << app.config.pid_file << logend; } } } void RemovePidFile() { if( !app.config.pid_file.empty() ) { std::string file_name; PT::WideToUTF8(app.config.pid_file, file_name); unlink(file_name.c_str()); } } } // namespace Winix int main(int argv, char ** argc) { using Winix::app; std::srand(std::time(0)); if( argv != 2 ) { Winix::print_syntax(); return 1; } app.system.system_start = time(0); if( !PT::UTF8ToWide(argc[1], app.config.config_file) ) { std::wcout << "An incorrect UTF-8 path of the config file" << std::endl; return 6; } if( !app.config.ReadConfig(true, false) ) /* errors to stdout, stdout in not closed */ return 2; if( app.stdout_is_closed || app.config.demonize ) app.config.log_stdout = false; if( !app.config.log_stdout ) Winix::CloseDescriptors(); if( app.config.demonize && !app.Demonize() ) return 4; Winix::log.SetTimeZones(&app.system.time_zones); Winix::log.Init(app.config.log_level, app.config.log_save_each_line, app.config.log_file, app.config.log_stdout, app.config.log_request); Winix::nlog.Init(app.config.log_level, true, app.config.log_notify_file, false, 1); Winix::LogInfo(Winix::log3, "booting Winix", true, ""); if( !app.InitFCGI() ) return 5; if( !app.DropPrivileges() ) return 3; app.LogUserGroups(); Winix::log << Winix::log3 << "base_url: " << app.config.base_url << Winix::logend; Winix::SavePidFile(); // load plugins before loading sessions - session_manager.LoadSessions() // because some of the plugins can init its own sessions dates Winix::plugin.LoadPlugins(app.config.plugins_dir, app.config.plugin_file); // app.Init() starts other threads as well (they will be waiting on the lock) if( !app.Init() ) { Winix::RemovePidFile(); return 1; } app.StartThreads(); // now we have more threads, we should use Lock() and Unlock() // saving all starting logs app.Lock(); Winix::LogInfo(Winix::log1, "Winix", true, "started"); Winix::log << Winix::logsave; app.Unlock(); // main loop app.Start(); app.Lock(); Winix::plugin.Call((Winix::Session*)0, WINIX_CLOSE); app.Close(); // now all sessions are cleared app.Unlock(); app.WaitForThreads(); // now all others threads are terminated Winix::LogInfo(Winix::log1, "Winix", true, "stopped"); Winix::RemovePidFile(); return 0; }