2008-12-10 05:42:49 +01:00
|
|
|
/*
|
2010-02-28 01:08:10 +01:00
|
|
|
* This file is a part of Winix
|
2014-10-04 20:04:03 +02:00
|
|
|
* and is distributed under the 2-Clause BSD licence.
|
|
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2022-04-16 18:38:30 +02:00
|
|
|
* Copyright (c) 2008-2022, Tomasz Sowa
|
2008-12-10 05:42:49 +01:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
2014-10-04 20:04:03 +02:00
|
|
|
* 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.
|
|
|
|
*
|
2008-12-10 05:42:49 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <ctime>
|
|
|
|
#include <iostream>
|
2014-08-04 23:11:14 +02:00
|
|
|
#include <fstream>
|
2010-11-23 22:52:25 +01:00
|
|
|
#include <sys/param.h>
|
changed: when winix demonizes it creates a three new descriptors (0, 1 and 3)
pointing to /dev/null
added: DbBase::AssertValueBin(PGresult * r, int row, int col, std::string & result)
it reads binary (bytea) data
added: DbTextStream can handle 'bool' types now
(is puts 'true' of 'false' to the stream)
changed: now passwords can be stored either as plain text, a hash or can be encrypted
with RSA
currently we have following hashes:
md4, md5, sha1, sha224, sha256, sha384, sha512
we are using openssl to manage them
(look at config options for more info)
changed: winix version to 0.4.7
added: class Run - you can run any program from os and send a buffer to its standard input
and read what the program put on its standard output
added: class Crypt (in System) - calculating hashes, and crypting/decrypting
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@734 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-06-09 23:22:08 +02:00
|
|
|
#include <fcntl.h>
|
2014-08-04 23:11:14 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2010-08-10 18:12:50 +02:00
|
|
|
#include "core/app.h"
|
2012-09-06 19:50:14 +02:00
|
|
|
#include "core/version.h"
|
2014-08-04 23:11:14 +02:00
|
|
|
#include "utf8/utf8.h"
|
2022-04-16 18:38:30 +02:00
|
|
|
#include "mainoptions/mainoptionsparser.h"
|
2010-08-10 18:12:50 +02:00
|
|
|
|
|
|
|
|
2014-02-12 17:30:49 +01:00
|
|
|
|
2022-04-16 21:50:23 +02:00
|
|
|
|
2014-02-12 17:30:49 +01:00
|
|
|
namespace Winix
|
|
|
|
{
|
|
|
|
|
2008-12-10 05:42:49 +01:00
|
|
|
|
2010-01-28 16:39:01 +01:00
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
/*
|
|
|
|
application object
|
|
|
|
*/
|
|
|
|
App app;
|
|
|
|
|
|
|
|
|
2008-12-10 05:42:49 +01:00
|
|
|
|
2008-12-11 03:46:16 +01:00
|
|
|
void print_syntax()
|
|
|
|
{
|
2022-04-16 18:38:30 +02:00
|
|
|
std::cout << "Winix version " << WINIX_VER_MAJOR << '.' << WINIX_VER_MINOR << '.' << WINIX_VER_REVISION << std::endl;
|
|
|
|
std::cout << "Copyright (c) 2008-2022, Tomasz Sowa" << std::endl;
|
|
|
|
|
|
|
|
std::cout << "Usage: winix [options]" << std::endl;
|
|
|
|
std::cout << " -c : a path to the config file" << std::endl;
|
|
|
|
std::cout << " --config : a path to the config file" << std::endl;
|
2022-04-16 21:50:23 +02:00
|
|
|
std::cout << " --use-env : allow to use environment variables" << std::endl;
|
|
|
|
std::cout << " --dump-config : dump all read config options to stdout and exit" << std::endl;
|
2022-04-16 18:38:30 +02:00
|
|
|
std::cout << " -h : print usage information" << std::endl;
|
|
|
|
std::cout << " --help : print usage information" << std::endl;
|
|
|
|
std::cout << " -? : print usage information" << std::endl;
|
2022-04-16 21:50:23 +02:00
|
|
|
std::cout << std::endl;
|
2022-04-16 18:38:30 +02:00
|
|
|
std::cout << "At least one -c or --config parameter is required, use -c or --config option" << std::endl;
|
|
|
|
std::cout << "multiple times to load more than one config." << std::endl;
|
2022-04-16 21:50:23 +02:00
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << "Environment variables must be prefixed with winix_ to be loaded by winix." << std::endl;
|
|
|
|
std::cout << "The winix_ prefix is then removed and the key value converted to lowercase." << std::endl;
|
|
|
|
std::cout << "Sample:" << std::endl;
|
|
|
|
std::cout << "evn WINIX_MY_OPTION=TEST123test winix -c config_file" << std::endl;
|
|
|
|
std::cout << "This will add my_option to the config with value TEST123test." << std::endl;
|
|
|
|
std::cout << "Environment variables are read last so they will overwrite the values" << std::endl;
|
|
|
|
std::cout << "from the configuration files." << std::endl;
|
2008-12-11 03:46:16 +01:00
|
|
|
}
|
2008-12-10 05:42:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
changed: when winix demonizes it creates a three new descriptors (0, 1 and 3)
pointing to /dev/null
added: DbBase::AssertValueBin(PGresult * r, int row, int col, std::string & result)
it reads binary (bytea) data
added: DbTextStream can handle 'bool' types now
(is puts 'true' of 'false' to the stream)
changed: now passwords can be stored either as plain text, a hash or can be encrypted
with RSA
currently we have following hashes:
md4, md5, sha1, sha224, sha256, sha384, sha512
we are using openssl to manage them
(look at config options for more info)
changed: winix version to 0.4.7
added: class Run - you can run any program from os and send a buffer to its standard input
and read what the program put on its standard output
added: class Crypt (in System) - calculating hashes, and crypting/decrypting
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@734 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-06-09 23:22:08 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-21 18:51:15 +01:00
|
|
|
void LogInfo(Log & log, LogManipulators log_level, const char * msg, bool put_version, const char * msg2)
|
2012-09-06 19:50:14 +02:00
|
|
|
{
|
|
|
|
log << log_level;
|
2021-05-20 20:59:12 +02:00
|
|
|
log.PrintDate(pt::Date(std::time(0)));
|
2012-09-06 19:50:14 +02:00
|
|
|
log << ' ' << msg;
|
|
|
|
|
|
|
|
if( put_version )
|
|
|
|
{
|
|
|
|
log << ' ' << WINIX_VER_MAJOR
|
|
|
|
<< '.' << WINIX_VER_MINOR
|
|
|
|
<< '.' << WINIX_VER_REVISION;
|
|
|
|
}
|
|
|
|
|
|
|
|
log << ' ' << msg2 << logend;
|
|
|
|
}
|
|
|
|
|
changed: when winix demonizes it creates a three new descriptors (0, 1 and 3)
pointing to /dev/null
added: DbBase::AssertValueBin(PGresult * r, int row, int col, std::string & result)
it reads binary (bytea) data
added: DbTextStream can handle 'bool' types now
(is puts 'true' of 'false' to the stream)
changed: now passwords can be stored either as plain text, a hash or can be encrypted
with RSA
currently we have following hashes:
md4, md5, sha1, sha224, sha256, sha384, sha512
we are using openssl to manage them
(look at config options for more info)
changed: winix version to 0.4.7
added: class Run - you can run any program from os and send a buffer to its standard input
and read what the program put on its standard output
added: class Crypt (in System) - calculating hashes, and crypting/decrypting
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@734 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-06-09 23:22:08 +02:00
|
|
|
|
2018-11-21 18:51:15 +01:00
|
|
|
void SavePidFile(Log & log)
|
2014-08-04 23:11:14 +02:00
|
|
|
{
|
|
|
|
if( !app.config.pid_file.empty() )
|
|
|
|
{
|
|
|
|
std::string file_name;
|
2021-05-21 00:41:27 +02:00
|
|
|
pt::wide_to_utf8(app.config.pid_file, file_name);
|
2014-08-04 23:11:14 +02:00
|
|
|
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;
|
2021-05-21 00:41:27 +02:00
|
|
|
pt::wide_to_utf8(app.config.pid_file, file_name);
|
2014-08-04 23:11:14 +02:00
|
|
|
unlink(file_name.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-16 18:38:30 +02:00
|
|
|
bool ReadConfigs(const pt::Space::TableType & table, size_t & config_read)
|
|
|
|
{
|
|
|
|
bool status = true;
|
|
|
|
|
|
|
|
for(const pt::Space * config : table)
|
|
|
|
{
|
|
|
|
if( config->is_table() && config->table_size() == 1 )
|
|
|
|
{
|
|
|
|
std::wstring config_file = config->value.value_table[0]->to_wstr();
|
|
|
|
config_read += 1;
|
|
|
|
|
|
|
|
if( !app.config.ReadConfig(config_file) )
|
|
|
|
{
|
|
|
|
status = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-16 21:50:23 +02:00
|
|
|
void ReadEnvOption(const char * option)
|
|
|
|
{
|
|
|
|
const char winix_prefix[] = "winix_";
|
|
|
|
size_t prefix_len = sizeof(winix_prefix) - 1; // null terminating table
|
|
|
|
std::wstring opt, val;
|
|
|
|
|
|
|
|
if( pt::is_substr_nc(winix_prefix, option) )
|
|
|
|
{
|
|
|
|
pt::utf8_to_wide(option + prefix_len, opt);
|
|
|
|
|
|
|
|
std::wstring::size_type sep = opt.find('=');
|
|
|
|
|
|
|
|
if( sep != std::wstring::npos )
|
|
|
|
{
|
|
|
|
val = opt.substr(sep + 1);
|
|
|
|
opt.erase(sep);
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplatesFunctions::locale.ToSmall(opt);
|
|
|
|
app.config.space.add(opt, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReadConfigFromEnv(const char ** env)
|
|
|
|
{
|
|
|
|
for(size_t i = 0 ; env[i] ; ++i)
|
|
|
|
{
|
|
|
|
ReadEnvOption(env[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool ReadConfigs(const pt::Space & options, const char ** env)
|
2022-04-16 18:38:30 +02:00
|
|
|
{
|
|
|
|
size_t config_read = 0;
|
|
|
|
bool status = true;
|
|
|
|
const pt::Space::TableType * table = options.get_table(L"c");
|
|
|
|
app.config.space.clear();
|
|
|
|
|
|
|
|
if( table )
|
|
|
|
{
|
|
|
|
status = status && ReadConfigs(*table, config_read);
|
|
|
|
}
|
|
|
|
|
|
|
|
table = options.get_table(L"config");
|
|
|
|
|
|
|
|
if( table )
|
|
|
|
{
|
|
|
|
status = status && ReadConfigs(*table, config_read);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( config_read == 0 )
|
|
|
|
{
|
|
|
|
std::cout << "You have to provide a config file with c parameter" << std::endl;
|
|
|
|
Winix::print_syntax();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-04-16 21:50:23 +02:00
|
|
|
if( options.has_key(L"use-env") )
|
|
|
|
{
|
|
|
|
ReadConfigFromEnv(env);
|
|
|
|
}
|
|
|
|
|
|
|
|
app.config.AssignValuesFromSpace();
|
|
|
|
|
2022-04-16 18:38:30 +02:00
|
|
|
return status;
|
|
|
|
}
|
2014-08-04 23:11:14 +02:00
|
|
|
|
2014-02-12 17:30:49 +01:00
|
|
|
} // namespace Winix
|
|
|
|
|
2011-01-24 00:23:24 +01:00
|
|
|
|
2022-04-16 18:38:30 +02:00
|
|
|
|
2022-04-16 21:50:23 +02:00
|
|
|
int main(int argc, const char ** argv, const char ** env)
|
2008-12-11 03:46:16 +01:00
|
|
|
{
|
2014-02-12 17:30:49 +01:00
|
|
|
using Winix::app;
|
|
|
|
|
2008-12-11 03:46:16 +01:00
|
|
|
std::srand(std::time(0));
|
2022-04-16 18:38:30 +02:00
|
|
|
app.system.system_start = time(0);
|
2008-12-11 03:46:16 +01:00
|
|
|
|
2022-04-16 18:38:30 +02:00
|
|
|
pt::Space options;
|
|
|
|
pt::Space arguments;
|
|
|
|
pt::MainOptionsParser options_parser;
|
|
|
|
|
|
|
|
arguments.add(L"c", 1);
|
|
|
|
arguments.add(L"config", 1);
|
|
|
|
|
|
|
|
pt::MainOptionsParser::Status status = options_parser.parse(argc, argv, options, arguments);
|
|
|
|
|
|
|
|
if( status != pt::MainOptionsParser::status_ok )
|
2008-12-11 03:46:16 +01:00
|
|
|
{
|
2014-02-12 17:30:49 +01:00
|
|
|
Winix::print_syntax();
|
2022-04-16 18:38:30 +02:00
|
|
|
return 6;
|
2008-12-11 03:46:16 +01:00
|
|
|
}
|
|
|
|
|
2022-04-16 18:38:30 +02:00
|
|
|
if( options.has_key(L"h") || options.has_key(L"help") || options.has_key(L"?") )
|
2014-10-09 22:44:56 +02:00
|
|
|
{
|
2022-04-16 18:38:30 +02:00
|
|
|
Winix::print_syntax();
|
|
|
|
return 0;
|
2014-10-09 22:44:56 +02:00
|
|
|
}
|
|
|
|
|
2022-04-16 18:38:30 +02:00
|
|
|
Winix::Log & log = app.GetMainLog();
|
2022-04-16 21:50:23 +02:00
|
|
|
pt::WTextStream * log_buffer = log.get_log_buffer();
|
2022-04-16 18:38:30 +02:00
|
|
|
Winix::LogInfo(log, Winix::log3, "UTC booting Winix", true, ""); // date will be printed as UTC because the time zones are not loaded yet
|
|
|
|
|
2022-04-16 21:50:23 +02:00
|
|
|
if( !Winix::ReadConfigs(options, env) )
|
2022-04-16 18:38:30 +02:00
|
|
|
{
|
|
|
|
// we need to print the buffer by hand because the logger
|
|
|
|
// is not fully initialized yet
|
2022-04-16 21:50:23 +02:00
|
|
|
if( log_buffer && !log_buffer->empty() )
|
2022-04-16 18:38:30 +02:00
|
|
|
{
|
2022-04-16 21:50:23 +02:00
|
|
|
pt::wide_stream_to_utf8(*log_buffer, std::cout);
|
2022-04-16 18:38:30 +02:00
|
|
|
}
|
|
|
|
|
2008-12-11 03:46:16 +01:00
|
|
|
return 2;
|
2022-04-16 18:38:30 +02:00
|
|
|
}
|
2008-12-11 03:46:16 +01:00
|
|
|
|
2022-04-16 21:50:23 +02:00
|
|
|
if( options.has_key(L"dump-config") )
|
|
|
|
{
|
|
|
|
if( log_buffer )
|
|
|
|
{
|
|
|
|
log << "all read config options (some of the values could have been modified by winix"
|
|
|
|
<< " but the modified values are not printed here):" << Winix::logend;
|
|
|
|
app.config.space.serialize_to_space_stream(*log_buffer, true);
|
|
|
|
log << Winix::logend;
|
|
|
|
pt::wide_stream_to_utf8(*log_buffer, std::cout);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-21 23:53:24 +01:00
|
|
|
app.InitLoggers();
|
|
|
|
|
2010-10-24 21:26:54 +02:00
|
|
|
if( app.stdout_is_closed || app.config.demonize )
|
2010-08-10 18:12:50 +02:00
|
|
|
app.config.log_stdout = false;
|
|
|
|
|
|
|
|
if( !app.config.log_stdout )
|
2014-02-12 17:30:49 +01:00
|
|
|
Winix::CloseDescriptors();
|
2008-12-10 05:42:49 +01:00
|
|
|
|
2012-05-19 17:14:35 +02:00
|
|
|
if( app.config.demonize && !app.Demonize() )
|
2022-04-16 18:38:30 +02:00
|
|
|
{
|
|
|
|
log << Winix::logsave;
|
2012-05-19 17:14:35 +02:00
|
|
|
return 4;
|
2022-04-16 18:38:30 +02:00
|
|
|
}
|
2010-11-23 22:52:25 +01:00
|
|
|
|
|
|
|
if( !app.InitFCGI() )
|
2022-04-16 18:38:30 +02:00
|
|
|
{
|
|
|
|
log << Winix::logsave;
|
2012-05-19 17:14:35 +02:00
|
|
|
return 5;
|
2022-04-16 18:38:30 +02:00
|
|
|
}
|
2010-11-23 22:52:25 +01:00
|
|
|
|
2010-10-24 19:49:38 +02:00
|
|
|
if( !app.DropPrivileges() )
|
2022-04-16 18:38:30 +02:00
|
|
|
{
|
|
|
|
log << Winix::logsave;
|
2010-10-24 19:49:38 +02:00
|
|
|
return 3;
|
2022-04-16 18:38:30 +02:00
|
|
|
}
|
2010-10-24 19:49:38 +02:00
|
|
|
|
|
|
|
app.LogUserGroups();
|
2018-11-21 18:51:15 +01:00
|
|
|
Winix::SavePidFile(log);
|
2009-12-30 21:46:12 +01:00
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
// load plugins before loading sessions - session_manager.LoadSessions()
|
2010-08-14 18:23:18 +02:00
|
|
|
// because some of the plugins can init its own sessions dates
|
2018-11-21 12:03:53 +01:00
|
|
|
app.InitPlugins();
|
2009-11-13 21:40:11 +01:00
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
// app.Init() starts other threads as well (they will be waiting on the lock)
|
2010-08-10 18:12:50 +02:00
|
|
|
if( !app.Init() )
|
2014-08-04 23:11:14 +02:00
|
|
|
{
|
|
|
|
Winix::RemovePidFile();
|
2021-06-27 23:31:50 +02:00
|
|
|
log << Winix::logsave;
|
2009-10-01 00:31:20 +02:00
|
|
|
return 1;
|
2014-08-04 23:11:14 +02:00
|
|
|
}
|
2009-10-01 00:31:20 +02:00
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
app.StartThreads();
|
|
|
|
// now we have more threads, we should use Lock() and Unlock()
|
|
|
|
|
2011-07-29 00:18:10 +02:00
|
|
|
// saving all starting logs
|
|
|
|
app.Lock();
|
2018-11-21 18:51:15 +01:00
|
|
|
Winix::LogInfo(log, Winix::log1, "Winix", true, "started");
|
|
|
|
log << Winix::logsave;
|
2011-07-29 00:18:10 +02:00
|
|
|
app.Unlock();
|
|
|
|
|
2010-12-02 02:02:02 +01:00
|
|
|
// main loop
|
2010-08-10 18:12:50 +02:00
|
|
|
app.Start();
|
2010-11-23 22:52:25 +01:00
|
|
|
|
2010-08-10 18:12:50 +02:00
|
|
|
app.Close();
|
2010-10-11 22:42:49 +02:00
|
|
|
|
2018-11-21 18:51:15 +01:00
|
|
|
Winix::LogInfo(log, Winix::log1, "Winix", true, "stopped");
|
2014-08-04 23:11:14 +02:00
|
|
|
Winix::RemovePidFile();
|
2018-11-21 18:51:15 +01:00
|
|
|
log << Winix::logsave;
|
2008-12-10 05:42:49 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2010-11-23 22:52:25 +01:00
|
|
|
|