Skip to content

Commit

Permalink
Merge pull request #589 from Homebrew/sudo_service_user
Browse files Browse the repository at this point in the history
Add `--sudo-service-user` flag
  • Loading branch information
MikeMcQuaid authored Sep 28, 2023
2 parents 6f5f509 + 8b4ce6d commit 8a29e18
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 1 deletion.
16 changes: 16 additions & 0 deletions cmd/services.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def services_args
Remove all unused services.
EOS
flag "--file=", description: "Use the service file from this location to `start` the service."
flag "--sudo-service-user=", description: "When run as root on macOS, run the service(s) as this user."
switch "--all", description: "Run <subcommand> on all services."
switch "--json", description: "Output as JSON."
named_args max: 2
Expand All @@ -66,6 +67,21 @@ def services
"`brew services` is supported only on macOS or Linux (with systemd)!"
end

if (sudo_service_user = args.sudo_service_user)
unless ::Service::System.root?
raise UsageError,
"`brew services` is supported only when running as root!"
end

unless ::Service::System.launchctl?
raise UsageError,
"`brew services --sudo-service-user` is currently supported only on macOS " \
"(but we'd love a PR to add Linux support)!"
end

::Service::ServicesCli.sudo_service_user = sudo_service_user
end

# Parse arguments.
subcommand, formula, = args.named

Expand Down
10 changes: 10 additions & 0 deletions lib/service/formula_wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ def service_file_present?(opts = { for: false })
end

def owner
if System.launchctl? && dest.exist?
require "rexml/document"

# read the username from the plist file
plist = REXML::Document.new(dest.read)
username_xpath = "/plist/dict/key[text()='UserName']/following-sibling::*[1]"
plist_username = REXML::XPath.first(plist, username_xpath)&.text

return plist_username if plist_username.present?
end
return "root" if boot_path_service_file_present?
return System.user if user_path_service_file_present?

Expand Down
26 changes: 25 additions & 1 deletion lib/service/services_cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ module ServicesCli

module_function

def sudo_service_user
@sudo_service_user
end

def sudo_service_user=(sudo_service_user)
@sudo_service_user = sudo_service_user
end

# Binary name.
def bin
"brew services"
Expand Down Expand Up @@ -185,6 +193,7 @@ def kill(targets, verbose: false)
# protections to avoid users editing root services
def take_root_ownership(service)
return unless System.root?
return if sudo_service_user

root_paths = []

Expand Down Expand Up @@ -286,7 +295,22 @@ def install_service_file(service, file)

temp = Tempfile.new(service.service_name)
temp << if file.blank?
service.service_file.read
contents = service.service_file.read

if sudo_service_user && System.launchctl?
require "rexml/document"

# set the username in the new plist file
ohai "Setting username in #{service.service_name} to #{System.user}"
plist = REXML::Document.new(contents)
dict_element = REXML::XPath.first(plist, "/plist/dict/")
dict_element.add_element("key").text = "UserName"
dict_element.add_element("string").text = sudo_service_user

plist.to_s
else
contents
end
else
file.read
end
Expand Down

0 comments on commit 8a29e18

Please sign in to comment.