1 /*
2 * Copyright 2003-2021 The Music Player Daemon Project
3 * http://www.musicpd.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "config.h"
21 #include "Main.hxx"
22 #include "Instance.hxx"
23 #include "CommandLine.hxx"
24 #include "PlaylistFile.hxx"
25 #include "MusicChunk.hxx"
26 #include "StateFile.hxx"
27 #include "Mapper.hxx"
28 #include "Permission.hxx"
29 #include "Listen.hxx"
30 #include "client/Config.hxx"
31 #include "client/List.hxx"
32 #include "command/AllCommands.hxx"
33 #include "Partition.hxx"
34 #include "tag/Config.hxx"
35 #include "ReplayGainGlobal.hxx"
36 #include "IdleFlags.hxx"
37 #include "Log.hxx"
38 #include "LogInit.hxx"
39 #include "input/Init.hxx"
40 #include "input/cache/Config.hxx"
41 #include "input/cache/Manager.hxx"
42 #include "event/Loop.hxx"
43 #include "event/Call.hxx"
44 #include "fs/AllocatedPath.hxx"
45 #include "fs/Config.hxx"
46 #include "playlist/PlaylistRegistry.hxx"
47 #include "zeroconf/Glue.hxx"
48 #include "decoder/DecoderList.hxx"
49 #include "pcm/AudioParser.hxx"
50 #include "pcm/Convert.hxx"
51 #include "unix/SignalHandlers.hxx"
52 #include "thread/Slack.hxx"
53 #include "net/Init.hxx"
54 #include "lib/icu/Init.hxx"
55 #include "config/Check.hxx"
56 #include "config/Data.hxx"
57 #include "config/Param.hxx"
58 #include "config/Path.hxx"
59 #include "config/Defaults.hxx"
60 #include "config/Option.hxx"
61 #include "config/Domain.hxx"
62 #include "config/Parser.hxx"
63 #include "util/RuntimeError.hxx"
64 #include "util/ScopeExit.hxx"
65
66 #ifdef ENABLE_DAEMON
67 #include "unix/Daemon.hxx"
68 #endif
69
70 #ifdef ENABLE_DATABASE
71 #include "db/update/Service.hxx"
72 #include "db/Configured.hxx"
73 #include "db/DatabasePlugin.hxx"
74 #include "db/plugins/simple/SimpleDatabasePlugin.hxx"
75 #include "storage/Configured.hxx"
76 #include "storage/CompositeStorage.hxx"
77 #ifdef ENABLE_INOTIFY
78 #include "db/update/InotifyUpdate.hxx"
79 #endif
80 #endif
81
82 #ifdef ENABLE_NEIGHBOR_PLUGINS
83 #include "neighbor/Glue.hxx"
84 #endif
85
86 #ifdef ENABLE_SQLITE
87 #include "sticker/Database.hxx"
88 #endif
89
90 #ifdef ENABLE_ARCHIVE
91 #include "archive/ArchiveList.hxx"
92 #endif
93
94 #ifdef ANDROID
95 #include "java/Global.hxx"
96 #include "java/File.hxx"
97 #include "android/Environment.hxx"
98 #include "android/Context.hxx"
99 #include "android/LogListener.hxx"
100 #include "config/File.hxx"
101 #include "fs/FileSystem.hxx"
102 #include "org_musicpd_Bridge.h"
103 #endif
104
105 #ifdef ENABLE_DBUS
106 #include "lib/dbus/Init.hxx"
107 #endif
108
109 #ifdef ENABLE_SYSTEMD_DAEMON
110 #include <systemd/sd-daemon.h>
111 #endif
112
113 #include <climits>
114
115 #ifndef ANDROID
116 #include <clocale>
117 #endif
118
119 static constexpr size_t KILOBYTE = 1024;
120 static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
121
122 static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
123
124 static constexpr
125 size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
126 64 * KILOBYTE);
127
128 #ifdef ANDROID
129 Context *context;
130 LogListener *logListener;
131 #endif
132
133 Instance *global_instance;
134
135 struct Config {
136 ReplayGainConfig replay_gain;
137
ConfigConfig138 explicit Config(const ConfigData &raw)
139 :replay_gain(LoadReplayGainConfig(raw)) {}
140 };
141
142 #ifdef ENABLE_DAEMON
143
144 static void
glue_daemonize_init(const CommandLineOptions & options,const ConfigData & config)145 glue_daemonize_init(const CommandLineOptions &options,
146 const ConfigData &config)
147 {
148 auto pid_file = config.GetPath(ConfigOption::PID_FILE);
149
150 #ifdef __linux__
151 if (options.systemd && pid_file != nullptr) {
152 pid_file = nullptr;
153 fprintf(stderr,
154 "Ignoring the 'pid_file' setting in systemd mode\n");
155 }
156 #endif
157
158 daemonize_init(config.GetString(ConfigOption::USER),
159 config.GetString(ConfigOption::GROUP),
160 std::move(pid_file));
161
162 if (options.kill)
163 daemonize_kill();
164 }
165
166 #endif
167
168 static void
glue_mapper_init(const ConfigData & config)169 glue_mapper_init(const ConfigData &config)
170 {
171 auto playlist_directory = config.GetPath(ConfigOption::PLAYLIST_DIR);
172
173 #ifdef ANDROID
174 /* if there is no explicit configuration, store playlists in
175 "/sdcard/Android/data/org.musicpd/files/playlists" */
176 if (playlist_directory.IsNull())
177 playlist_directory = context->GetExternalFilesDir(Java::GetEnv(),
178 "playlists");
179 #endif
180
181 mapper_init(std::move(playlist_directory));
182 }
183
184 #ifdef ENABLE_DATABASE
185
186 static void
InitStorage(Instance & instance,EventLoop & event_loop,const ConfigData & config)187 InitStorage(Instance &instance, EventLoop &event_loop,
188 const ConfigData &config)
189 {
190 auto storage = CreateConfiguredStorage(config, event_loop);
191 if (storage == nullptr)
192 return;
193
194 auto *composite = new CompositeStorage();
195 instance.storage = composite;
196 composite->Mount("", std::move(storage));
197 }
198
199 /**
200 * Returns the database. If this function returns false, this has not
201 * succeeded, and the caller should create the database after the
202 * process has been daemonized.
203 */
204 static bool
glue_db_init_and_load(Instance & instance,const ConfigData & config)205 glue_db_init_and_load(Instance &instance, const ConfigData &config)
206 {
207 auto db = CreateConfiguredDatabase(config, instance.event_loop,
208 instance.io_thread.GetEventLoop(),
209 instance);
210 if (!db)
211 return true;
212
213 if (db->GetPlugin().RequireStorage()) {
214 InitStorage(instance, instance.io_thread.GetEventLoop(),
215 config);
216
217 if (instance.storage == nullptr) {
218 LogNotice(config_domain,
219 "Found database setting without "
220 "music_directory - disabling database");
221 return true;
222 }
223 } else {
224 if (IsStorageConfigured(config))
225 LogNotice(config_domain,
226 "Ignoring the storage configuration "
227 "because the database does not need it");
228 }
229
230 try {
231 db->Open();
232 } catch (...) {
233 std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
234 }
235
236 instance.database = std::move(db);
237
238 auto *sdb = dynamic_cast<SimpleDatabase *>(instance.database.get());
239 if (sdb == nullptr)
240 return true;
241
242 instance.update = new UpdateService(config,
243 instance.event_loop, *sdb,
244 static_cast<CompositeStorage &>(*instance.storage),
245 instance);
246
247 /* run database update after daemonization? */
248 return sdb->FileExists();
249 }
250
251 static bool
InitDatabaseAndStorage(Instance & instance,const ConfigData & config)252 InitDatabaseAndStorage(Instance &instance, const ConfigData &config)
253 {
254 const bool create_db = !glue_db_init_and_load(instance, config);
255 return create_db;
256 }
257
258 #endif
259
260 #ifdef ENABLE_SQLITE
261
262 /**
263 * Configure and initialize the sticker subsystem.
264 */
265 static std::unique_ptr<StickerDatabase>
LoadStickerDatabase(const ConfigData & config)266 LoadStickerDatabase(const ConfigData &config)
267 {
268 auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
269 if (sticker_file.IsNull())
270 return nullptr;
271
272 return std::make_unique<StickerDatabase>(std::move(sticker_file));
273 }
274
275 #endif
276
277 static void
glue_state_file_init(Instance & instance,const ConfigData & raw_config)278 glue_state_file_init(Instance &instance, const ConfigData &raw_config)
279 {
280 StateFileConfig config(raw_config);
281 if (!config.IsEnabled())
282 return;
283
284 instance.state_file = std::make_unique< StateFile>(std::move(config),
285 instance.partitions.front(),
286 instance.event_loop);
287 instance.state_file->Read();
288 }
289
290 /**
291 * Initialize the decoder and player core, including the music pipe.
292 */
293 static void
initialize_decoder_and_player(Instance & instance,const ConfigData & config,const ReplayGainConfig & replay_gain_config)294 initialize_decoder_and_player(Instance &instance,
295 const ConfigData &config,
296 const ReplayGainConfig &replay_gain_config)
297 {
298 const ConfigParam *param;
299
300 size_t buffer_size;
301 param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
302 if (param != nullptr) {
303 buffer_size = param->With([](const char *s){
304 size_t result = ParseSize(s, KILOBYTE);
305 if (result <= 0)
306 throw FormatRuntimeError("buffer size \"%s\" is not a "
307 "positive integer", s);
308
309 if (result < MIN_BUFFER_SIZE) {
310 FmtWarning(config_domain, "buffer size {} is too small, using {} bytes instead",
311 result, MIN_BUFFER_SIZE);
312 result = MIN_BUFFER_SIZE;
313 }
314
315 return result;
316 });
317 } else
318 buffer_size = DEFAULT_BUFFER_SIZE;
319
320 const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
321
322 if (buffered_chunks >= 1 << 15)
323 throw FormatRuntimeError("buffer size \"%lu\" is too big",
324 (unsigned long)buffer_size);
325
326 const unsigned max_length =
327 config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
328 DEFAULT_PLAYLIST_MAX_LENGTH);
329
330 AudioFormat configured_audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){
331 if (s == nullptr)
332 return AudioFormat::Undefined();
333
334 return ParseAudioFormat(s, true);
335 });
336
337 instance.partitions.emplace_back(instance,
338 "default",
339 max_length,
340 buffered_chunks,
341 configured_audio_format,
342 replay_gain_config);
343 auto &partition = instance.partitions.back();
344
345 partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){
346 return s != nullptr
347 ? FromString(s)
348 : ReplayGainMode::OFF;
349 });
350 }
351
352 inline void
BeginShutdownUpdate()353 Instance::BeginShutdownUpdate() noexcept
354 {
355 #ifdef ENABLE_DATABASE
356 #ifdef ENABLE_INOTIFY
357 inotify_update.reset();
358 #endif
359
360 if (update != nullptr)
361 update->CancelAllAsync();
362 #endif
363 }
364
365 inline void
BeginShutdownPartitions()366 Instance::BeginShutdownPartitions() noexcept
367 {
368 for (auto &partition : partitions) {
369 partition.BeginShutdown();
370 }
371 }
372
373 static inline void
MainConfigured(const CommandLineOptions & options,const ConfigData & raw_config)374 MainConfigured(const CommandLineOptions &options,
375 const ConfigData &raw_config)
376 {
377 #ifdef ENABLE_DAEMON
378 daemonize_close_stdin();
379 #endif
380
381 #ifndef ANDROID
382 /* initialize locale */
383 std::setlocale(LC_CTYPE,"");
384 std::setlocale(LC_COLLATE, "");
385 #endif
386
387 const ScopeIcuInit icu_init;
388 const ScopeNetInit net_init;
389
390 #ifdef ENABLE_DBUS
391 const ODBus::ScopeInit dbus_init;
392 #endif
393
394 InitPathParser(raw_config);
395 const Config config(raw_config);
396
397 #ifdef ENABLE_DAEMON
398 glue_daemonize_init(options, raw_config);
399 #endif
400
401 TagLoadConfig(raw_config);
402
403 log_init(raw_config, options.verbose, options.log_stderr);
404
405 Instance instance;
406 global_instance = &instance;
407
408 #ifdef ENABLE_NEIGHBOR_PLUGINS
409 instance.neighbors = std::make_unique<NeighborGlue>();
410 instance.neighbors->Init(raw_config,
411 instance.io_thread.GetEventLoop(),
412 instance);
413
414 if (instance.neighbors->IsEmpty())
415 instance.neighbors.reset();
416 #endif
417
418 const unsigned max_clients =
419 raw_config.GetPositive(ConfigOption::MAX_CONN, 100);
420 instance.client_list = std::make_unique<ClientList>(max_clients);
421
422 const auto *input_cache_config = raw_config.GetBlock(ConfigBlockOption::INPUT_CACHE);
423 if (input_cache_config != nullptr) {
424 const InputCacheConfig c(*input_cache_config);
425 instance.input_cache = std::make_unique<InputCacheManager>(c);
426 }
427
428 initialize_decoder_and_player(instance,
429 raw_config, config.replay_gain);
430
431 listen_global_init(raw_config, *instance.partitions.front().listener);
432
433 #ifdef ENABLE_DAEMON
434 daemonize_set_user();
435 daemonize_begin(options.daemon);
436 AtScopeExit() { daemonize_finish(); };
437 #endif
438
439 ConfigureFS(raw_config);
440 AtScopeExit() { DeinitFS(); };
441
442 glue_mapper_init(raw_config);
443
444 initPermissions(raw_config);
445 spl_global_init(raw_config);
446 #ifdef ENABLE_ARCHIVE
447 const ScopeArchivePluginsInit archive_plugins_init;
448 #endif
449
450 pcm_convert_global_init(raw_config);
451
452 const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
453
454 #ifdef ENABLE_DATABASE
455 const bool create_db = InitDatabaseAndStorage(instance, raw_config);
456 #endif
457
458 #ifdef ENABLE_SQLITE
459 instance.sticker_database = LoadStickerDatabase(raw_config);
460 #endif
461
462 command_init();
463
464 for (auto &partition : instance.partitions) {
465 partition.outputs.Configure(instance.io_thread.GetEventLoop(),
466 instance.rtio_thread.GetEventLoop(),
467 raw_config,
468 config.replay_gain);
469 partition.UpdateEffectiveReplayGainMode();
470 }
471
472 client_manager_init(raw_config);
473 const ScopeInputPluginsInit input_plugins_init(raw_config,
474 instance.io_thread.GetEventLoop());
475
476 const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
477
478 #ifdef ENABLE_DAEMON
479 daemonize_commit();
480 #endif
481
482 #ifndef ANDROID
483 setup_log_output();
484
485 const ScopeSignalHandlersInit signal_handlers_init(instance);
486 #endif
487
488 instance.io_thread.Start();
489 instance.rtio_thread.Start();
490
491 #ifdef ENABLE_NEIGHBOR_PLUGINS
492 if (instance.neighbors != nullptr)
493 instance.neighbors->Open();
494
495 AtScopeExit(&instance) {
496 if (instance.neighbors != nullptr)
497 instance.neighbors->Close();
498 };
499 #endif
500
501 #ifdef HAVE_ZEROCONF
502 std::unique_ptr<ZeroconfHelper> zeroconf;
503 try {
504 auto &event_loop = instance.io_thread.GetEventLoop();
505 BlockingCall(event_loop, [&](){
506 zeroconf = ZeroconfInit(raw_config, event_loop);
507 });
508 } catch (...) {
509 LogError(std::current_exception(),
510 "Zeroconf initialization failed");
511 }
512
513 AtScopeExit(&zeroconf, &instance) {
514 if (zeroconf) {
515 auto &event_loop = instance.io_thread.GetEventLoop();
516 BlockingCall(event_loop, [&](){
517 zeroconf.reset();
518 });
519 }
520 };
521 #endif
522
523 #ifdef ENABLE_DATABASE
524 if (create_db) {
525 /* the database failed to load: recreate the
526 database */
527 instance.update->Enqueue("", true);
528 }
529 #endif
530
531 glue_state_file_init(instance, raw_config);
532
533 #ifdef ENABLE_DATABASE
534 if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
535 #ifdef ENABLE_INOTIFY
536 if (instance.storage != nullptr &&
537 instance.update != nullptr) {
538 try {
539 instance.inotify_update =
540 mpd_inotify_init(instance.event_loop,
541 *instance.storage,
542 *instance.update,
543 raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
544 INT_MAX));
545 } catch (...) {
546 LogError(std::current_exception());
547 }
548 }
549 #else
550 LogWarning(config_domain,
551 "inotify: auto_update was disabled. enable during compilation phase");
552 #endif
553 }
554 #endif
555
556 Check(raw_config);
557
558 /* enable all audio outputs (if not already done by
559 playlist_state_restore() */
560 for (auto &partition : instance.partitions)
561 partition.pc.LockUpdateAudio();
562
563 #ifdef _WIN32
564 win32_app_started();
565 #endif
566
567 /* the MPD frontend does not care about timer slack; set it to
568 a huge value to allow the kernel to reduce CPU wakeups */
569 SetThreadTimerSlack(std::chrono::milliseconds(100));
570
571 #ifdef ENABLE_SYSTEMD_DAEMON
572 sd_notify(0, "READY=1");
573 #endif
574
575 /* run the main loop */
576 instance.event_loop.Run();
577
578 #ifdef _WIN32
579 win32_app_stopping();
580 #endif
581
582 /* cleanup */
583
584 if (instance.state_file)
585 instance.state_file->Write();
586
587 instance.BeginShutdownUpdate();
588 instance.BeginShutdownPartitions();
589 }
590
591 #ifdef ANDROID
592
593 static void
AndroidMain()594 AndroidMain()
595 {
596 CommandLineOptions options;
597 ConfigData raw_config;
598
599 const auto sdcard = Environment::getExternalStorageDirectory();
600 if (!sdcard.IsNull()) {
601 const auto config_path =
602 sdcard / Path::FromFS("mpd.conf");
603 if (FileExists(config_path))
604 ReadConfigFile(raw_config, config_path);
605 }
606
607 MainConfigured(options, raw_config);
608 }
609
610 gcc_visibility_default
611 JNIEXPORT void JNICALL
Java_org_musicpd_Bridge_run(JNIEnv * env,jclass,jobject _context,jobject _logListener)612 Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logListener)
613 {
614 Java::Init(env);
615 Java::Object::Initialise(env);
616 Java::File::Initialise(env);
617 Environment::Initialise(env);
618 AtScopeExit(env) { Environment::Deinitialise(env); };
619
620 context = new Context(env, _context);
621 AtScopeExit() { delete context; };
622
623 if (_logListener != nullptr)
624 logListener = new LogListener(env, _logListener);
625 AtScopeExit() { delete logListener; };
626
627 try {
628 AndroidMain();
629 } catch (...) {
630 LogError(std::current_exception());
631 }
632 }
633
634 gcc_visibility_default
635 JNIEXPORT void JNICALL
Java_org_musicpd_Bridge_shutdown(JNIEnv *,jclass)636 Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
637 {
638 if (global_instance != nullptr)
639 global_instance->Break();
640 }
641
642 gcc_visibility_default
643 JNIEXPORT void JNICALL
Java_org_musicpd_Bridge_pause(JNIEnv *,jclass)644 Java_org_musicpd_Bridge_pause(JNIEnv *, jclass)
645 {
646 if (global_instance != nullptr)
647 for (auto &partition : global_instance->partitions)
648 partition.pc.LockSetPause(true);
649 }
650
651 #else
652
653 static inline void
MainOrThrow(int argc,char * argv[])654 MainOrThrow(int argc, char *argv[])
655 {
656 CommandLineOptions options;
657 ConfigData raw_config;
658
659 ParseCommandLine(argc, argv, options, raw_config);
660
661 MainConfigured(options, raw_config);
662 }
663
664 int
mpd_main(int argc,char * argv[])665 mpd_main(int argc, char *argv[])
666 {
667 MainOrThrow(argc, argv);
668 return EXIT_SUCCESS;
669 }
670
671 int
main(int argc,char * argv[])672 main(int argc, char *argv[]) noexcept
673 try {
674 AtScopeExit() { log_deinit(); };
675
676 #ifdef _WIN32
677 return win32_main(argc, argv);
678 #else
679 return mpd_main(argc, argv);
680 #endif
681 } catch (...) {
682 LogError(std::current_exception());
683 return EXIT_FAILURE;
684 }
685
686 #endif
687