Skip to content

Commit

Permalink
WIP: initial draft for server cli refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
WOLFI3654 committed Oct 21, 2023
1 parent f6e4840 commit ccb9e45
Showing 1 changed file with 130 additions and 152 deletions.
282 changes: 130 additions & 152 deletions src/murmur/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "ServerDB.h"
#include "Version.h"

#include <boost/optional.hpp>
#include <boost/logic/tribool.hpp>
#include <csignal>
#include <iostream>

Expand Down Expand Up @@ -46,6 +48,8 @@
# include <sys/syslog.h>
#endif

#include <CLI/CLI.hpp>

QFile *qfLog = nullptr;

static bool bVerbose = false;
Expand Down Expand Up @@ -200,6 +204,87 @@ void cleanup(int signum) {
exit(signum);
}

auto parseCLI(int argc, char **argv) {
struct {
bool quit = false;
boost::optional< std::string > ini_file;
boost::optional< std::tuple< std::string, int > > supw_srv;
boost::optional< int > disable_su_srv;
bool verbose_logging = false;
#ifdef QT_NO_DEBUG
bool detach = true;
#else
boost::logic::tribool detach = boost::logic::indeterminate;
#endif
bool wipe_ssl = false;
bool wipe_logs = false;
bool log_groups = false;
bool log_acls = false;
#ifdef Q_OS_UNIX
bool limits = false;
boost::optional< int > read_supw_srv;
#endif
} options;

CLI::App app;
app.set_version_flag("-v,--version", "Mumble server version " + Version::getRelease().toStdString());

app.add_option_no_stream("-i,--ini", options.ini_file, "Specify ini file to use.")
->option_text("<inifile>")
->expected(1, 2)
->check(CLI::ExistingFile);
app.add_option_no_stream("-w,--supw", options.supw_srv, "Set password for 'SuperUser' account on server srv.")
->option_text("<pw> [srv]")
->expected(1, 2);
#ifdef Q_OS_UNIX
app.add_option_no_stream("-r,--readsupw", options.read_supw_srv,
"Reads password for server srv from standard input.")
->option_text("[srv]")
->default_val(1)
->expected(0, 1);
app.add_flag("-l,--limits", options.limits,
"Tests and shows how many file descriptors and threads can be created.\n"
"The purpose of this option is to test how many clients Murmur can handle.\n"
"Murmur will exit after this test.");
#endif
app.add_option_no_stream("-d,--disablesu", options.disable_su_srv,
"Disable password for 'SuperUser' account on server srv.")
->option_text("[srv]")
->default_val(1)
->expected(0, 1);
app.add_flag("-b,--verbose", options.verbose_logging, "Use verbose logging (include debug-logs).");
app.add_flag("!-f,!--force-fg", options.detach,
#ifdef Q_OS_UNIX
"Don't detach from console."
#else
"Don't write to the log file."
#endif
);

app.add_flag("-s,--wipessl", options.wipe_ssl, "Remove SSL certificates from database.");
app.add_flag("-l,--wipelogs", options.wipe_logs, "Remove all log entries from database.");
app.add_flag("-g,--loggroups", options.log_groups, "Turns on logging for group changes for all servers.");
app.add_flag("-a,--logacls", options.log_acls, "Turns on logging for ACL changes for all servers.");

app.footer("If no inifile is provided, murmur will search for one in\ndefault locations.");

try {
(app).parse(argc, argv);
} catch (const CLI::ParseError &e) {
std::stringstream info_stream, error_stream;
app.exit(e, info_stream, error_stream);

if (e.get_exit_code() != static_cast< int >(CLI::ExitCodes::Success)) {
qFatal("%s", error_stream.str().c_str());
} else {
qInfo("%s", info_stream.str().c_str());
}
options.quit = true;
}

return options;
}

int main(int argc, char **argv) {
// Check for SSE and MMX, but only in the windows binaries
#ifdef Q_OS_WIN
Expand Down Expand Up @@ -266,17 +351,6 @@ int main(int argc, char **argv) {
}
#endif

QString inifile;
QString supw;
bool disableSu = false;
bool wipeSsl = false;
bool wipeLogs = false;
int sunum = 1;
#ifdef Q_OS_UNIX
bool readPw = false;
#endif
bool logGroups = false;
bool logACL = false;

#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
// For Qt >= 5.10 we use QRandomNumberGenerator that is seeded automatically
Expand All @@ -285,153 +359,57 @@ int main(int argc, char **argv) {

qInstallMessageHandler(murmurMessageOutputWithContext);

#ifdef Q_OS_WIN
Tray tray(nullptr, &le);
#endif
auto cli_options = parseCLI(argc, argv);
if (cli_options.quit)
return 0;

QStringList args = a.arguments();
for (int i = 1; i < args.size(); i++) {
bool bLast = false;
QString arg = args.at(i).toLower();
if ((arg == "-supw")) {
detach = false;
if (i + 1 < args.size()) {
i++;
supw = args.at(i);
if (i + 1 < args.size()) {
i++;
sunum = args.at(i).toInt();
}
bLast = true;
} else {
#ifdef Q_OS_UNIX
qFatal("-supw expects the password on the command line - maybe you meant -readsupw?");
#else
qFatal("-supw expects the password on the command line");
#endif
}
detach = boost::logic::indeterminate(cli_options.detach)? detach : static_cast<bool>(cli_options.detach);
QString inifile = QString::fromStdString(cli_options.ini_file.get_value_or(""));
QString supw;
bool disableSu = false;
bool wipeSsl = cli_options.wipe_ssl;
bool wipeLogs = cli_options.wipe_logs;
int sunum = 1;
#ifdef Q_OS_UNIX
} else if ((arg == "-readsupw")) {
// Note that it is essential to set detach = false here. If this is ever to be changed, the code part
// handling the readPw = true part has to be moved up so that it is executed before fork is called on Unix
// systems.
detach = false;
readPw = true;
if (i + 1 < args.size()) {
i++;
sunum = args.at(i).toInt();
}
bLast = true;
#endif
} else if ((arg == "-disablesu")) {
detach = false;
disableSu = true;
if (i + 1 < args.size()) {
i++;
sunum = args.at(i).toInt();
}
bLast = true;
} else if ((arg == "-ini") && (i + 1 < args.size())) {
i++;
inifile = args.at(i);
} else if ((arg == "-wipessl")) {
wipeSsl = true;
} else if ((arg == "-wipelogs")) {
wipeLogs = true;
} else if ((arg == "-fg")) {
detach = false;
} else if ((arg == "-v")) {
bVerbose = true;
} else if ((arg == "-version") || (arg == "--version")) {
// Print version and exit (print to regular std::cout to avoid adding any useless meta-information from
// using e.g. qWarning
std::cout << "Mumble server version " << Version::getRelease().toStdString() << std::endl;
return 0;
} else if (args.at(i) == QLatin1String("-license") || args.at(i) == QLatin1String("--license")) {
#ifdef Q_OS_WIN
AboutDialog ad(nullptr, AboutDialogOptionsShowLicense);
ad.exec();
return 0;
#else
qInfo("%s\n", qPrintable(License::license()));
return 0;
bool readPw = false;
#endif
} else if (args.at(i) == QLatin1String("-authors") || args.at(i) == QLatin1String("--authors")) {
#ifdef Q_OS_WIN
AboutDialog ad(nullptr, AboutDialogOptionsShowAuthors);
ad.exec();
return 0;
#else
qInfo("%s\n",
"For a list of authors, please see https://github.com/mumble-voip/mumble/graphs/contributors");
return 0;
bool logGroups = cli_options.log_groups;
bool logACL = cli_options.log_acls;

bVerbose = cli_options.verbose_logging;

if (cli_options.disable_su_srv.has_value()) {
detach = false;
disableSu = true;
sunum = cli_options.disable_su_srv.get();
}

if (cli_options.supw_srv.has_value()) {
auto tuple = cli_options.supw_srv.get();
supw = QString::fromStdString(std::get< 0 >(tuple));
sunum = std::get< 1 >(tuple);
#ifdef Q_OS_LINUX
} else if (cli_options.read_supw_srv.has_value()) {
// Note that it is essential to set detach = false here. If this is ever to be changed, the code part
// handling the readPw = true part has to be moved up so that it is executed before fork is called on Unix
// systems.

detach = false;
readPw = true;
sunum = cli_options.read_supw_srv.get();
}

if (cli_options.limits) {
detach = false;
Meta::mp.read(inifile);
unixhandler.setuid();
unixhandler.finalcap();
LimitTest::testLimits(a);
#endif
} else if (args.at(i) == QLatin1String("-third-party-licenses")
|| args.at(i) == QLatin1String("--third-party-licenses")) {
}
#ifdef Q_OS_WIN
AboutDialog ad(nullptr, AboutDialogOptionsShowThirdPartyLicenses);
ad.exec();
return 0;
#else
qInfo("%s", qPrintable(License::printableThirdPartyLicenseInfo()));
return 0;
#endif
} else if ((arg == "-h") || (arg == "-help") || (arg == "--help")) {
detach = false;
qInfo("Usage: %s [-ini <inifile>] [-supw <password>]\n"
" --version Print version information and exit\n"
" -ini <inifile> Specify ini file to use.\n"
" -supw <pw> [srv] Set password for 'SuperUser' account on server srv.\n"
#ifdef Q_OS_UNIX
" -readsupw [srv] Reads password for server srv from standard input.\n"
#endif
" -disablesu [srv] Disable password for 'SuperUser' account on server srv.\n"
#ifdef Q_OS_UNIX
" -limits Tests and shows how many file descriptors and threads can be created.\n"
" The purpose of this option is to test how many clients Murmur can handle.\n"
" Murmur will exit after this test.\n"
Tray tray(nullptr, &le);
#endif
" -v Use verbose logging (include debug-logs).\n"
#ifdef Q_OS_UNIX
" -fg Don't detach from console.\n"
#else
" -fg Don't write to the log file.\n"
#endif
" -wipessl Remove SSL certificates from database.\n"
" -wipelogs Remove all log entries from database.\n"
" -loggroups Turns on logging for group changes for all servers.\n"
" -logacls Turns on logging for ACL changes for all servers.\n"
" -version Show version information.\n"
"\n"
" -license Show Murmur's license.\n"
" -authors Show Murmur's authors.\n"
" -third-party-licenses Show licenses for third-party software used by Murmur.\n"
"\n"
"If no inifile is provided, murmur will search for one in \n"
"default locations.",
qPrintable(args.at(0)));
return 0;
#ifdef Q_OS_UNIX
} else if (arg == "-limits") {
detach = false;
Meta::mp.read(inifile);
unixhandler.setuid();
unixhandler.finalcap();
LimitTest::testLimits(a);
#endif
} else if (arg == "-loggroups") {
logGroups = true;
} else if (arg == "-logacls") {
logACL = true;
} else {
detach = false;
qFatal("Unknown argument %s", qPrintable(args.at(i)));
}
if (bLast && (i + 1 != args.size())) {
detach = false;
qFatal("Password arguments must be last.");
}
}

if (QSslSocket::supportsSsl()) {
qInfo("SSL: OpenSSL version is '%s'", SSLeay_version(SSLEAY_VERSION));
Expand Down

0 comments on commit ccb9e45

Please sign in to comment.