16
16
#include " ServerDB.h"
17
17
#include " Version.h"
18
18
19
+ #include < boost/optional/optional_io.hpp>
20
+ #include < boost/tuple/tuple_io.hpp>
19
21
#include < csignal>
20
22
#include < iostream>
21
23
46
48
# include < sys/syslog.h>
47
49
#endif
48
50
51
+ #include < CLI/CLI.hpp>
52
+
49
53
QFile *qfLog = nullptr ;
50
54
51
55
static bool bVerbose = false ;
@@ -200,6 +204,123 @@ void cleanup(int signum) {
200
204
exit (signum);
201
205
}
202
206
207
+ class CLIOptions {
208
+ public:
209
+ bool quit = false ;
210
+ boost::optional< std::string > ini_file;
211
+ boost::tuple< std::string, boost::optional< int > > supw_srv;
212
+ boost::optional< int > disable_su_srv;
213
+ bool verbose_logging = false ;
214
+ bool cli_detach = detach;
215
+ bool wipe_ssl = false ;
216
+ bool wipe_logs = false ;
217
+ bool log_groups = false ;
218
+ bool log_acls = false ;
219
+
220
+ bool print_authors = false ;
221
+ bool print_license = false ;
222
+ bool print_3rd_party_licenses = false ;
223
+
224
+ #ifdef Q_OS_UNIX
225
+ bool limits = false ;
226
+ boost::optional< int > read_supw_srv;
227
+ #endif
228
+
229
+ static constexpr const char *const CLI_ABOUT_SECTION = " About" ;
230
+ static constexpr const char *const CLI_LOGGING_SECTION = " Logging" ;
231
+ static constexpr const char *const CLI_ADMINISTRATION_SECTION = " Administration" ;
232
+ static constexpr const char *const CLI_CONFIGURATION_SECTION = " Configuration" ;
233
+ static constexpr const char *const CLI_TESTING_SECTION = " Testing" ;
234
+ };
235
+
236
+ CLIOptions parseCLI (int argc, char **argv) {
237
+ CLIOptions options;
238
+
239
+ CLI::App app;
240
+ app.set_version_flag (" --version" , Version::getRelease ().toStdString ());
241
+
242
+ app.add_option_no_stream (" -i,--ini" , options.ini_file , " Specify ini file to use." )
243
+ ->option_text (" <inifile>" )
244
+ ->expected (1 , 2 )
245
+ ->check (CLI::ExistingFile)
246
+ ->group (CLIOptions::CLI_CONFIGURATION_SECTION);
247
+
248
+ app.add_option (" -w,--supw" , options.supw_srv , " Set password for 'SuperUser' account on server srv." )
249
+ ->option_text (" <pw> [srv]" )
250
+ ->allow_extra_args ()
251
+ ->expected (0 , 1 )
252
+ ->group (CLIOptions::CLI_ADMINISTRATION_SECTION);
253
+
254
+ #ifdef Q_OS_UNIX
255
+ app.add_option_no_stream (" -r,--readsupw" , options.read_supw_srv ,
256
+ " Reads password for server srv from standard input." )
257
+ ->option_text (" [srv]" )
258
+ ->default_val (1 )
259
+ ->expected (0 , 1 )
260
+ ->group (CLIOptions::CLI_ADMINISTRATION_SECTION);
261
+
262
+ app.add_flag (" -l,--limits" , options.limits ,
263
+ " Tests and shows how many file descriptors and threads can be created.\n "
264
+ " The purpose of this option is to test how many clients Mumble server can handle.\n "
265
+ " Mumble server will exit after this test." )
266
+ ->group (CLIOptions::CLI_TESTING_SECTION);
267
+ #endif
268
+
269
+ app.add_option_no_stream (" -d,--disablesu" , options.disable_su_srv ,
270
+ " Disable password for 'SuperUser' account on server srv." )
271
+ ->option_text (" [srv]" )
272
+ ->expected (0 , 1 )
273
+ ->group (CLIOptions::CLI_ADMINISTRATION_SECTION);
274
+ app.add_flag (" -s,--wipessl" , options.wipe_ssl , " Remove SSL certificates from database." )
275
+ ->group (CLIOptions::CLI_ADMINISTRATION_SECTION);
276
+
277
+ app.add_flag (" -v,--verbose" , options.verbose_logging , " Use verbose logging (include debug-logs)." )
278
+ ->group (CLIOptions::CLI_LOGGING_SECTION);
279
+ app.add_flag (" !-f,!--force-fg" , options.cli_detach ,
280
+ #ifdef Q_OS_UNIX
281
+ " Don't detach from console."
282
+ #else
283
+ " Don't write to the log file."
284
+ #endif
285
+ )
286
+ ->group (CLIOptions::CLI_LOGGING_SECTION);
287
+
288
+ app.add_flag (" -p,--wipelogs" , options.wipe_logs , " Remove all log entries from database." )
289
+ ->group (CLIOptions::CLI_LOGGING_SECTION);
290
+ app.add_flag (" -g,--loggroups" , options.log_groups , " Turns on logging for group changes for all servers." )
291
+ ->group (CLIOptions::CLI_LOGGING_SECTION);
292
+ app.add_flag (" -a,--logacls" , options.log_acls , " Turns on logging for ACL changes for all servers." )
293
+ ->group (CLIOptions::CLI_LOGGING_SECTION);
294
+
295
+
296
+ app.add_flag (" --authors" , options.print_authors , " Show Mumble server's authors." )
297
+ ->group (CLIOptions::CLI_ABOUT_SECTION);
298
+ app.add_flag (" --license" , options.print_license , " Show Mumble server's license." )
299
+ ->group (CLIOptions::CLI_ABOUT_SECTION);
300
+ app.add_flag (" --3rd-party-licenses" , options.print_3rd_party_licenses ,
301
+ " Show licenses for third-party software used by Mumble server." )
302
+ ->group (CLIOptions::CLI_ABOUT_SECTION);
303
+
304
+
305
+ app.footer (" If no inifile is provided, Mumble server will search for one in\n default locations." );
306
+
307
+ try {
308
+ (app).parse (argc, argv);
309
+ } catch (const CLI::ParseError &e) {
310
+ std::stringstream info_stream, error_stream;
311
+ app.exit (e, info_stream, error_stream);
312
+
313
+ if (e.get_exit_code () != static_cast < int >(CLI::ExitCodes::Success)) {
314
+ qFatal (" %s" , error_stream.str ().c_str ());
315
+ } else {
316
+ qInfo (" %s" , info_stream.str ().c_str ());
317
+ }
318
+ options.quit = true ;
319
+ }
320
+
321
+ return options;
322
+ }
323
+
203
324
int main (int argc, char **argv) {
204
325
// Check for SSE and MMX, but only in the windows binaries
205
326
#ifdef Q_OS_WIN
@@ -266,17 +387,6 @@ int main(int argc, char **argv) {
266
387
}
267
388
#endif
268
389
269
- QString inifile;
270
- QString supw;
271
- bool disableSu = false ;
272
- bool wipeSsl = false ;
273
- bool wipeLogs = false ;
274
- int sunum = 1 ;
275
- #ifdef Q_OS_UNIX
276
- bool readPw = false ;
277
- #endif
278
- bool logGroups = false ;
279
- bool logACL = false ;
280
390
281
391
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
282
392
// For Qt >= 5.10 we use QRandomNumberGenerator that is seeded automatically
@@ -285,154 +395,87 @@ int main(int argc, char **argv) {
285
395
286
396
qInstallMessageHandler (murmurMessageOutputWithContext);
287
397
288
- #ifdef Q_OS_WIN
289
- Tray tray (nullptr , &le);
290
- #endif
398
+ CLIOptions cli_options = parseCLI (argc, argv);
291
399
292
- QStringList args = a.arguments ();
293
- for (int i = 1 ; i < args.size (); i++) {
294
- bool bLast = false ;
295
- QString arg = args.at (i).toLower ();
296
- if ((arg == " -supw" )) {
297
- detach = false ;
298
- if (i + 1 < args.size ()) {
299
- i++;
300
- supw = args.at (i);
301
- if (i + 1 < args.size ()) {
302
- i++;
303
- sunum = args.at (i).toInt ();
304
- }
305
- bLast = true ;
306
- } else {
307
- #ifdef Q_OS_UNIX
308
- qFatal (" -supw expects the password on the command line - maybe you meant -readsupw?" );
309
- #else
310
- qFatal (" -supw expects the password on the command line" );
311
- #endif
312
- }
313
- #ifdef Q_OS_UNIX
314
- } else if ((arg == " -readsupw" )) {
315
- // Note that it is essential to set detach = false here. If this is ever to be changed, the code part
316
- // handling the readPw = true part has to be moved up so that it is executed before fork is called on Unix
317
- // systems.
318
- detach = false ;
319
- readPw = true ;
320
- if (i + 1 < args.size ()) {
321
- i++;
322
- sunum = args.at (i).toInt ();
323
- }
324
- bLast = true ;
325
- #endif
326
- } else if ((arg == " -disablesu" )) {
327
- detach = false ;
328
- disableSu = true ;
329
- if (i + 1 < args.size ()) {
330
- i++;
331
- sunum = args.at (i).toInt ();
332
- }
333
- bLast = true ;
334
- } else if ((arg == " -ini" ) && (i + 1 < args.size ())) {
335
- i++;
336
- inifile = args.at (i);
337
- } else if ((arg == " -wipessl" )) {
338
- wipeSsl = true ;
339
- } else if ((arg == " -wipelogs" )) {
340
- wipeLogs = true ;
341
- } else if ((arg == " -fg" )) {
342
- detach = false ;
343
- } else if ((arg == " -v" )) {
344
- bVerbose = true ;
345
- } else if ((arg == " -version" ) || (arg == " --version" )) {
346
- // Print version and exit (print to regular std::cout to avoid adding any useless meta-information from
347
- // using e.g. qWarning
348
- std::cout << " Mumble server version " << Version::getRelease ().toStdString () << std::endl;
349
- return 0 ;
350
- } else if (args.at (i) == QLatin1String (" -license" ) || args.at (i) == QLatin1String (" --license" )) {
400
+ if (cli_options.quit )
401
+ return 0 ;
402
+
403
+ if (cli_options.print_license ) {
351
404
#ifdef Q_OS_WIN
352
- AboutDialog ad (nullptr , AboutDialogOptionsShowLicense);
353
- ad.exec ();
354
- return 0 ;
405
+ AboutDialog ad (nullptr , AboutDialogOptionsShowLicense);
406
+ ad.exec ();
407
+ return 0 ;
355
408
#else
356
- qInfo (" %s\n " , qPrintable (License::license ()));
357
- return 0 ;
409
+ qInfo (" %s\n " , qPrintable (License::license ()));
410
+ return 0 ;
358
411
#endif
359
- } else if (args. at (i) == QLatin1String ( " -authors " ) || args. at (i) == QLatin1String ( " --authors " ) ) {
412
+ } else if (cli_options. print_authors ) {
360
413
#ifdef Q_OS_WIN
361
- AboutDialog ad (nullptr , AboutDialogOptionsShowAuthors);
362
- ad.exec ();
363
- return 0 ;
414
+ AboutDialog ad (nullptr , AboutDialogOptionsShowAuthors);
415
+ ad.exec ();
416
+ return 0 ;
364
417
#else
365
- qInfo (" %s\n " ,
366
- " For a list of authors, please see https://github.com/mumble-voip/mumble/graphs/contributors" );
367
- return 0 ;
418
+ qInfo (" %s\n " , " For a list of authors, please see https://github.com/mumble-voip/mumble/graphs/contributors" );
419
+ return 0 ;
368
420
#endif
369
- } else if (args.at (i) == QLatin1String (" -third-party-licenses" )
370
- || args.at (i) == QLatin1String (" --third-party-licenses" )) {
421
+ } else if (cli_options.print_3rd_party_licenses ) {
371
422
#ifdef Q_OS_WIN
372
- AboutDialog ad (nullptr , AboutDialogOptionsShowThirdPartyLicenses);
373
- ad.exec ();
374
- return 0 ;
423
+ AboutDialog ad (nullptr , AboutDialogOptionsShowThirdPartyLicenses);
424
+ ad.exec ();
425
+ return 0 ;
375
426
#else
376
- qInfo (" %s" , qPrintable (License::printableThirdPartyLicenseInfo ()));
377
- return 0 ;
378
- #endif
379
- } else if ((arg == " -h" ) || (arg == " -help" ) || (arg == " --help" )) {
380
- detach = false ;
381
- qInfo (" Usage: %s [-ini <inifile>] [-supw <password>]\n "
382
- " --version Print version information and exit\n "
383
- " -ini <inifile> Specify ini file to use.\n "
384
- " -supw <pw> [srv] Set password for 'SuperUser' account on server srv.\n "
385
- #ifdef Q_OS_UNIX
386
- " -readsupw [srv] Reads password for server srv from standard input.\n "
427
+ qInfo (" %s" , qPrintable (License::printableThirdPartyLicenseInfo ()));
428
+ return 0 ;
387
429
#endif
388
- " -disablesu [srv] Disable password for 'SuperUser' account on server srv.\n "
430
+ }
431
+
432
+ detach = cli_options.cli_detach ;
433
+ QString inifile = QString::fromStdString (cli_options.ini_file .get_value_or (" " ));
434
+ QString supw;
435
+ bool disableSu = false ;
436
+ bool wipeSsl = cli_options.wipe_ssl ;
437
+ bool wipeLogs = cli_options.wipe_logs ;
438
+ int sunum = 1 ;
389
439
#ifdef Q_OS_UNIX
390
- " -limits Tests and shows how many file descriptors and threads can be created.\n "
391
- " The purpose of this option is to test how many clients Murmur can handle.\n "
392
- " Murmur will exit after this test.\n "
440
+ bool readPw = false ;
393
441
#endif
394
- " -v Use verbose logging (include debug-logs).\n "
395
- #ifdef Q_OS_UNIX
396
- " -fg Don't detach from console.\n "
397
- #else
398
- " -fg Don't write to the log file.\n "
399
- #endif
400
- " -wipessl Remove SSL certificates from database.\n "
401
- " -wipelogs Remove all log entries from database.\n "
402
- " -loggroups Turns on logging for group changes for all servers.\n "
403
- " -logacls Turns on logging for ACL changes for all servers.\n "
404
- " -version Show version information.\n "
405
- " \n "
406
- " -license Show Murmur's license.\n "
407
- " -authors Show Murmur's authors.\n "
408
- " -third-party-licenses Show licenses for third-party software used by Murmur.\n "
409
- " \n "
410
- " If no inifile is provided, murmur will search for one in \n "
411
- " default locations." ,
412
- qPrintable (args.at (0 )));
413
- return 0 ;
414
- #ifdef Q_OS_UNIX
415
- } else if (arg == " -limits" ) {
416
- detach = false ;
417
- Meta::mp.read (inifile);
418
- unixhandler.setuid ();
419
- unixhandler.finalcap ();
420
- LimitTest::testLimits (a);
421
- #endif
422
- } else if (arg == " -loggroups" ) {
423
- logGroups = true ;
424
- } else if (arg == " -logacls" ) {
425
- logACL = true ;
426
- } else {
427
- detach = false ;
428
- qFatal (" Unknown argument %s" , qPrintable (args.at (i)));
429
- }
430
- if (bLast && (i + 1 != args.size ())) {
431
- detach = false ;
432
- qFatal (" Password arguments must be last." );
433
- }
442
+ bool logGroups = cli_options.log_groups ;
443
+ bool logACL = cli_options.log_acls ;
444
+
445
+ bVerbose = cli_options.verbose_logging ;
446
+
447
+ if (cli_options.disable_su_srv .has_value ()) {
448
+ detach = false ;
449
+ disableSu = true ;
450
+ sunum = cli_options.disable_su_srv .get ();
434
451
}
435
452
453
+ if (!cli_options.supw_srv .get < 0 >().empty ()) {
454
+ supw = QString::fromStdString (cli_options.supw_srv .get < 0 >());
455
+ sunum = cli_options.supw_srv .get < 1 >().get_value_or (1 );
456
+ #ifdef Q_OS_LINUX
457
+ } else if (cli_options.read_supw_srv .has_value ()) {
458
+ // Note that it is essential to set detach = false here. If this is ever to be changed, the code part
459
+ // handling the readPw = true part has to be moved up so that it is executed before fork is called on Unix
460
+ // systems.
461
+
462
+ detach = false ;
463
+ readPw = true ;
464
+ sunum = cli_options.read_supw_srv .get ();
465
+ }
466
+
467
+ if (cli_options.limits ) {
468
+ detach = false ;
469
+ Meta::mp.read (inifile);
470
+ unixhandler.setuid ();
471
+ unixhandler.finalcap ();
472
+ LimitTest::testLimits (a);
473
+ #endif
474
+ }
475
+ #ifdef Q_OS_WIN
476
+ Tray tray (nullptr , &le);
477
+ #endif
478
+
436
479
if (QSslSocket::supportsSsl ()) {
437
480
qInfo (" SSL: OpenSSL version is '%s'" , SSLeay_version (SSLEAY_VERSION));
438
481
} else {
0 commit comments