Use doas instead of sudo if installed (MR 2091)

Prefer using doas over sudo if both are installed. Let the user override
the sudo tool with PMB_SUDO.
This commit is contained in:
Anjandev Momi 2021-08-08 23:14:39 -04:00 committed by Oliver Smith
parent 2801b5d687
commit c1407f921b
No known key found for this signature in database
GPG Key ID: 5AE7F5513E0885CB
8 changed files with 60 additions and 8 deletions

View File

@ -195,6 +195,12 @@ $ pmbootstrap stats --arch=armhf
$ pmbootstrap log_distccd
```
### Use alternative sudo
pmbootstrap supports `doas` and `sudo`.
If multiple sudo implementations are installed, pmbootstrap will use `doas`.
You can set the `PMB_SUDO` environmental variable to define the sudo implementation you want to use.
## Development
### Requirements for running tests
* [Shellcheck](https://shellcheck.net/)

View File

@ -71,7 +71,7 @@ def root(args, cmd, suffix="native", working_dir="/", output="log",
executables = executables_absolute_path()
cmd_chroot = [executables["chroot"], chroot, "/bin/sh", "-c",
pmb.helpers.run.flat_cmd(cmd, working_dir)]
cmd_sudo = ["sudo", "env", "-i", executables["sh"], "-c",
cmd_sudo = [pmb.config.sudo, "env", "-i", executables["sh"], "-c",
pmb.helpers.run.flat_cmd(cmd_chroot, env=env_all)]
return pmb.helpers.run_core.core(args, msg, cmd_sudo, None, output,
output_return, check, True,

View File

@ -11,6 +11,7 @@ import sys
from pmb.config.load import load
from pmb.config.save import save
from pmb.config.merge_with_args import merge_with_args
from pmb.config.sudo import which_sudo
#
@ -50,6 +51,7 @@ ondev_min_version = "0.2.0"
# in sync with README.md, and try to keep the list as small as possible. The
# idea is to run almost everything in Alpine chroots.
required_programs = ["git", "openssl", "ps"]
sudo = which_sudo()
# Keys saved in the config file (mostly what we ask in 'pmbootstrap init')
config_keys = ["aports",

28
pmb/config/sudo.py Normal file
View File

@ -0,0 +1,28 @@
# Copyright 2021 Anjandev Momi
# SPDX-License-Identifier: GPL-3.0-or-later
import os
import shutil
def which_sudo():
"""
Find whether sudo or doas is installed for commands that require root.
Allows user to override preferred sudo with PMB_SUDO env variable.
"""
supported_sudos = ['doas', 'sudo']
user_set_sudo = os.getenv("PMB_SUDO")
if user_set_sudo is not None:
if shutil.which(user_set_sudo) is None:
raise RuntimeError("PMB_SUDO environmental variable is set to"
f" {user_set_sudo} but pmbootstrap cannot find"
" this command on your system.")
return user_set_sudo
for sudo in supported_sudos:
if shutil.which(sudo) is not None:
return sudo
raise RuntimeError("Can't find sudo or doas required to run pmbootstrap."
" Please install sudo, doas, or specify your own sudo"
" with the PMB_SUDO environmental variable.")

View File

@ -62,7 +62,7 @@ def user(args, cmd, working_dir=None, output="log", output_return=False,
def root(args, cmd, working_dir=None, output="log", output_return=False,
check=None, env={}):
"""
Run a command on the host system as root, with sudo.
Run a command on the host system as root, with sudo or doas.
:param env: dict of environment variables to be passed to the command, e.g.
{"JOBS": "5"}
@ -72,7 +72,7 @@ def root(args, cmd, working_dir=None, output="log", output_return=False,
"""
if env:
cmd = ["sh", "-c", flat_cmd(cmd, env=env)]
cmd = ["sudo"] + cmd
cmd = [pmb.config.sudo] + cmd
return user(args, cmd, working_dir, output, output_return, check, env,
True)

View File

@ -224,7 +224,10 @@ def sudo_timer_iterate():
Run sudo -v and schedule a new timer to repeat the same.
"""
subprocess.Popen(["sudo", "-v"]).wait()
if pmb.config.sudo == "sudo":
subprocess.Popen(["sudo", "-v"]).wait()
else:
subprocess.Popen([pmb.config.sudo, "true"]).wait()
timer = threading.Timer(interval=60, function=sudo_timer_iterate)
timer.daemon = True

View File

@ -79,8 +79,9 @@ def bootimg(args, path):
if not os.path.exists(path):
raise RuntimeError("Could not find file '" + path + "'")
logging.info("NOTE: You will be prompted for your sudo password, so we can"
" set up a chroot to extract and analyze your boot.img file")
logging.info("NOTE: You will be prompted for your sudo/doas password, so"
" we can set up a chroot to extract and analyze your"
" boot.img file")
pmb.chroot.apk.install(args, ["file", "unpackbootimg"])
temp_path = pmb.chroot.other.tempfolder(args, "/tmp/bootimg_parser")

View File

@ -4,6 +4,7 @@
import sys
import subprocess
import pytest
import time
import pmb_test # noqa
import pmb.helpers.run_core
@ -81,7 +82,7 @@ def test_foreground_pipe(args):
assert ret == (-9, "first\n")
# Kill with output timeout as root
cmd = ["sudo", "sh", "-c", "printf first; sleep 2; printf second"]
cmd = [pmb.config.sudo, "sh", "-c", "printf first; sleep 2; printf second"]
args.timeout = 0.3
ret = func(args, cmd, output_return=True, output_timeout=True,
sudo=True)
@ -97,7 +98,7 @@ def test_foreground_pipe(args):
# Check if all child processes are killed after timeout.
# The first command uses ps to get its process group id (pgid) and echo it
# to stdout. All of the test commands will be running under that pgid.
cmd = ["sudo", "sh", "-c",
cmd = [pmb.config.sudo, "sh", "-c",
"pgid=$(ps -o pgid= | grep ^${1:-$$});echo $pgid | tr -d '\n';" +
"sleep 10 | sleep 20 | sleep 30"]
args.timeout = 0.3
@ -152,3 +153,14 @@ def test_core(args):
with pytest.raises(RuntimeError) as e:
func(args, msg, ["sleep", "1"], output="log")
assert str(e.value).startswith("Command failed:")
@pytest.mark.skip_ci
def test_sudo_timer(args):
pmb.helpers.run.root(args, ["whoami"])
time.sleep(300)
out = pmb.helpers.run.root(args, ["whoami"])
assert out == 0