2025-02-26 13:26:37 +01:00
|
|
|
# typed: strict
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require_relative "system/systemctl"
|
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
module Homebrew
|
|
|
|
module Services
|
|
|
|
module System
|
|
|
|
# Path to launchctl binary.
|
|
|
|
sig { returns(T.nilable(Pathname)) }
|
|
|
|
def self.launchctl
|
|
|
|
@launchctl ||= T.let(which("launchctl"), T.nilable(Pathname))
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# Is this a launchctl system
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def self.launchctl?
|
|
|
|
launchctl.present?
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# Is this a systemd system
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def self.systemctl?
|
|
|
|
Systemctl.executable.present?
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# Woohoo, we are root dude!
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def self.root?
|
|
|
|
Process.euid.zero?
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# Current user running `[sudo] brew services`.
|
|
|
|
sig { returns(T.nilable(String)) }
|
|
|
|
def self.user
|
|
|
|
@user ||= T.let(ENV["USER"].presence || Utils.safe_popen_read("/usr/bin/whoami").chomp, T.nilable(String))
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
sig { params(pid: T.nilable(Integer)).returns(T.nilable(String)) }
|
|
|
|
def self.user_of_process(pid)
|
|
|
|
if pid.nil? || pid.zero?
|
|
|
|
user
|
|
|
|
else
|
|
|
|
Utils.safe_popen_read("ps", "-o", "user", "-p", pid.to_s).lines.second&.chomp
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
end
|
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# Run at boot.
|
|
|
|
sig { returns(T.nilable(Pathname)) }
|
|
|
|
def self.boot_path
|
|
|
|
if launchctl?
|
|
|
|
Pathname.new("/Library/LaunchDaemons")
|
|
|
|
elsif systemctl?
|
|
|
|
Pathname.new("/usr/lib/systemd/system")
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
end
|
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# Run at login.
|
|
|
|
sig { returns(T.nilable(Pathname)) }
|
|
|
|
def self.user_path
|
|
|
|
if launchctl?
|
|
|
|
Pathname.new("#{Dir.home}/Library/LaunchAgents")
|
|
|
|
elsif systemctl?
|
|
|
|
Pathname.new("#{Dir.home}/.config/systemd/user")
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
end
|
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
# If root, return `boot_path`, else return `user_path`.
|
|
|
|
sig { returns(T.nilable(Pathname)) }
|
|
|
|
def self.path
|
|
|
|
root? ? boot_path : user_path
|
|
|
|
end
|
2025-02-26 13:26:37 +01:00
|
|
|
|
2025-03-14 04:35:30 +00:00
|
|
|
sig { returns(String) }
|
|
|
|
def self.domain_target
|
|
|
|
if root?
|
|
|
|
"system"
|
|
|
|
elsif (ssh_tty = ENV.fetch("HOMEBREW_SSH_TTY", nil).present? &&
|
|
|
|
File.stat("/dev/console").uid != Process.uid) ||
|
|
|
|
(sudo_user = ENV.fetch("HOMEBREW_SUDO_USER", nil).present?) ||
|
|
|
|
(Process.uid != Process.euid)
|
|
|
|
if @output_warning.blank? && ENV.fetch("HOMEBREW_SERVICES_NO_DOMAIN_WARNING", nil).blank?
|
|
|
|
if ssh_tty
|
|
|
|
opoo "running over SSH without /dev/console ownership, using user/* instead of gui/* domain!"
|
|
|
|
elsif sudo_user
|
|
|
|
opoo "running through sudo, using user/* instead of gui/* domain!"
|
|
|
|
else
|
|
|
|
opoo "uid and euid do not match, using user/* instead of gui/* domain!"
|
|
|
|
end
|
|
|
|
unless Homebrew::EnvConfig.no_env_hints?
|
|
|
|
puts "Hide this warning by setting HOMEBREW_SERVICES_NO_DOMAIN_WARNING."
|
|
|
|
puts "Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`)."
|
|
|
|
end
|
|
|
|
@output_warning = T.let(true, T.nilable(TrueClass))
|
2025-02-26 13:26:37 +01:00
|
|
|
end
|
2025-03-14 04:35:30 +00:00
|
|
|
"user/#{Process.euid}"
|
|
|
|
else
|
|
|
|
"gui/#{Process.uid}"
|
2025-02-26 13:26:37 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|