Mercurial > prosody-hg
comparison util/startup.lua @ 13461:c673ff1075bd
mod_posix: Move everything to util.startup
This allows greater control over the order of events.
Notably, the internal ordering between daemonization, initialization of
libunbound and setup of signal handling is sensitive.
libunbound starts a separate thread for processing DNS requests.
If this thread is started before signal handling has been set up, it
will not inherit the signal handlers and instead behave as it would have
before signal handlers were set up, i.e. cause the whole process to
immediately exit.
libunbound is usually initialized on the first DNS request, usually
triggered by an outgoing s2s connection attempt.
If daemonization happens before signals have been set up, signals may
not be processed at all.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sat, 23 Mar 2024 20:48:19 +0100 |
| parents | 790f60c0843b |
| children | 720aed1f5cf2 |
comparison
equal
deleted
inserted
replaced
| 13460:a688947fab1e | 13461:c673ff1075bd |
|---|---|
| 529 end | 529 end |
| 530 end | 530 end |
| 531 config.set("*", "log", { { levels = { min = log_level or "info" }, to = "console" } }); | 531 config.set("*", "log", { { levels = { min = log_level or "info" }, to = "console" } }); |
| 532 end | 532 end |
| 533 | 533 |
| 534 local function check_posix() | |
| 535 if prosody.platform ~= "posix" then return end | |
| 536 | |
| 537 local want_pposix_version = "0.4.0"; | |
| 538 local have_pposix, pposix = pcall(require, "prosody.util.pposix"); | |
| 539 | |
| 540 if pposix._VERSION ~= want_pposix_version then | |
| 541 print(string.format("Unknown version (%s) of binary pposix module, expected %s", | |
| 542 tostring(pposix._VERSION), want_pposix_version)); | |
| 543 os.exit(1); | |
| 544 end | |
| 545 if have_pposix and pposix then | |
| 546 return pposix; | |
| 547 end | |
| 548 end | |
| 549 | |
| 534 function startup.switch_user() | 550 function startup.switch_user() |
| 535 -- Switch away from root and into the prosody user -- | 551 -- Switch away from root and into the prosody user -- |
| 536 -- NOTE: This function is only used by prosodyctl. | 552 -- NOTE: This function is only used by prosodyctl. |
| 537 -- The prosody process is built with the assumption that | 553 -- The prosody process is built with the assumption that |
| 538 -- it is already started as the appropriate user. | 554 -- it is already started as the appropriate user. |
| 539 | 555 |
| 540 local want_pposix_version = "0.4.0"; | 556 local pposix = check_posix() |
| 541 local have_pposix, pposix = pcall(require, "prosody.util.pposix"); | 557 if pposix then |
| 542 | |
| 543 if have_pposix and pposix then | |
| 544 if pposix._VERSION ~= want_pposix_version then | |
| 545 print(string.format("Unknown version (%s) of binary pposix module, expected %s", | |
| 546 tostring(pposix._VERSION), want_pposix_version)); | |
| 547 os.exit(1); | |
| 548 end | |
| 549 prosody.current_uid = pposix.getuid(); | 558 prosody.current_uid = pposix.getuid(); |
| 550 local arg_root = prosody.opts.root; | 559 local arg_root = prosody.opts.root; |
| 551 if prosody.current_uid == 0 and config.get("*", "run_as_root") ~= true and not arg_root then | 560 if prosody.current_uid == 0 and config.get("*", "run_as_root") ~= true and not arg_root then |
| 552 -- We haz root! | 561 -- We haz root! |
| 553 local desired_user = config.get("*", "prosody_user") or "prosody"; | 562 local desired_user = config.get("*", "prosody_user") or "prosody"; |
| 669 for hostname in pairs(config.getconfig()) do | 678 for hostname in pairs(config.getconfig()) do |
| 670 prosody.hosts[hostname] = startup.make_host(hostname); | 679 prosody.hosts[hostname] = startup.make_host(hostname); |
| 671 end | 680 end |
| 672 end | 681 end |
| 673 | 682 |
| 683 function startup.posix_umask() | |
| 684 if prosody.platform ~= "posix" then return end | |
| 685 local pposix = require "prosody.util.pposix"; | |
| 686 local umask = config.get("*", "umask") or "027"; | |
| 687 pposix.umask(umask); | |
| 688 end | |
| 689 | |
| 690 function startup.check_user() | |
| 691 local pposix = check_posix(); | |
| 692 if not pposix then return end | |
| 693 -- Don't even think about it! | |
| 694 if pposix.getuid() == 0 and not config.get("*", "run_as_root") then | |
| 695 log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!"); | |
| 696 log("error", "For more information on running Prosody as root, see https://prosody.im/doc/root"); | |
| 697 prosody.shutdown("Refusing to run as root", 1); | |
| 698 end | |
| 699 end | |
| 700 | |
| 701 local function remove_pidfile() | |
| 702 local pidfile = prosody.pidfile; | |
| 703 if prosody.pidfile_handle then | |
| 704 prosody.pidfile_handle:close(); | |
| 705 os.remove(pidfile); | |
| 706 prosody.pidfile, prosody.pidfile_handle = nil, nil; | |
| 707 end | |
| 708 end | |
| 709 | |
| 710 function startup.write_pidfile() | |
| 711 local pposix = check_posix(); | |
| 712 if not pposix then return end | |
| 713 local lfs = require "lfs"; | |
| 714 local stat = lfs.attributes; | |
| 715 local pidfile = config.get("*", "pidfile") or nil; | |
| 716 if not pidfile then return end | |
| 717 pidfile = config.resolve_relative_path(prosody.paths.data, pidfile); | |
| 718 local mode = stat(pidfile) and "r+" or "w+"; | |
| 719 local pidfile_handle, err = io.open(pidfile, mode); | |
| 720 if not pidfile_handle then | |
| 721 log("error", "Couldn't write pidfile at %s; %s", pidfile, err); | |
| 722 prosody.shutdown("Couldn't write pidfile", 1); | |
| 723 else | |
| 724 prosody.pidfile = pidfile; | |
| 725 if not lfs.lock(pidfile_handle, "w") then -- Exclusive lock | |
| 726 local other_pid = pidfile_handle:read("*a"); | |
| 727 log("error", "Another Prosody instance seems to be running with PID %s, quitting", other_pid); | |
| 728 prosody.pidfile_handle = nil; | |
| 729 prosody.shutdown("Prosody already running", 1); | |
| 730 else | |
| 731 pidfile_handle:close(); | |
| 732 pidfile_handle, err = io.open(pidfile, "w+"); | |
| 733 if not pidfile_handle then | |
| 734 log("error", "Couldn't write pidfile at %s; %s", pidfile, err); | |
| 735 prosody.shutdown("Couldn't write pidfile", 1); | |
| 736 else | |
| 737 if lfs.lock(pidfile_handle, "w") then | |
| 738 pidfile_handle:write(tostring(pposix.getpid())); | |
| 739 pidfile_handle:flush(); | |
| 740 prosody.pidfile_handle = pidfile_handle; | |
| 741 end | |
| 742 end | |
| 743 end | |
| 744 end | |
| 745 prosody.events.add_handler("server-stopped", remove_pidfile); | |
| 746 end | |
| 747 | |
| 748 local function remove_log_sinks() | |
| 749 local lm = require "prosody.core.loggingmanager"; | |
| 750 lm.register_sink_type("console", nil); | |
| 751 lm.register_sink_type("stdout", nil); | |
| 752 lm.reload_logging(); | |
| 753 end | |
| 754 | |
| 755 function startup.posix_daemonize() | |
| 756 if not prosody.opts.daemonize then return end | |
| 757 local pposix = check_posix(); | |
| 758 log("info", "Prosody is about to detach from the console, disabling further console output"); | |
| 759 remove_log_sinks(); | |
| 760 local ok, ret = pposix.daemonize(); | |
| 761 if not ok then | |
| 762 log("error", "Failed to daemonize: %s", ret); | |
| 763 elseif ret and ret > 0 then | |
| 764 os.exit(0); | |
| 765 else | |
| 766 log("info", "Successfully daemonized to PID %d", pposix.getpid()); | |
| 767 end | |
| 768 end | |
| 769 | |
| 674 function startup.hook_posix_signals() | 770 function startup.hook_posix_signals() |
| 675 if prosody.platform ~= "posix" then return end | 771 if prosody.platform ~= "posix" then return end |
| 676 local have_signal, signal = pcall(require, "prosody.util.signal"); | 772 local have_signal, signal = pcall(require, "prosody.util.signal"); |
| 677 if not have_signal then | 773 if not have_signal then |
| 678 log("warn", "Couldn't load signal library, won't respond to SIGTERM"); | 774 log("warn", "Couldn't load signal library, won't respond to SIGTERM"); |
| 763 | 859 |
| 764 function startup.prosody() | 860 function startup.prosody() |
| 765 -- These actions are in a strict order, as many depend on | 861 -- These actions are in a strict order, as many depend on |
| 766 -- previous steps to have already been performed | 862 -- previous steps to have already been performed |
| 767 prosody.process_type = "prosody"; | 863 prosody.process_type = "prosody"; |
| 864 startup.check_user(); | |
| 768 startup.parse_args(); | 865 startup.parse_args(); |
| 769 startup.init_global_state(); | 866 startup.init_global_state(); |
| 770 startup.read_config(); | 867 startup.read_config(); |
| 771 startup.init_logging(); | 868 startup.init_logging(); |
| 772 startup.init_gc(); | 869 startup.init_gc(); |
| 788 startup.init_promise(); | 885 startup.init_promise(); |
| 789 startup.init_async(); | 886 startup.init_async(); |
| 790 startup.init_http_client(); | 887 startup.init_http_client(); |
| 791 startup.init_data_store(); | 888 startup.init_data_store(); |
| 792 startup.init_global_protection(); | 889 startup.init_global_protection(); |
| 890 startup.posix_daemonize(); | |
| 891 startup.write_pidfile(); | |
| 793 startup.hook_posix_signals(); | 892 startup.hook_posix_signals(); |
| 794 startup.prepare_to_start(); | 893 startup.prepare_to_start(); |
| 795 startup.notify_started(); | 894 startup.notify_started(); |
| 796 end | 895 end |
| 797 | 896 |
