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