Вариант 1. Выполнение скрипта от имени пользователя, повышение привилегий для пользователя root для pacman -U
Я думаю, что это плохая идея.Скриптам немного неловко читать пароли и довольно долго тащить их через небезопасную память, потому что в конце они хотят выполнить что-то как root.Однако, если вы настаиваете, он будет работать аналогично варианту 2.
Вариант 2. Выполнение сценария от имени пользователя root, понижение уровня подпроцессов для пользователя для git clone
и makepkg
Вы можете использовать опцию subprocess.Popen
preexec_fn
, которая в соответствии с help(subprocess.Popen)
:
preexec_fn: (только POSIX) Объект, который вызывается в дочернем процессе простодо того, как ребенок будет казнен.
Единственная сложность в этом - передать аргументы.Если бы нам не нужно было этого делать, мы могли бы просто указать функцию (os.setuid
) как параметр preexec_fn
в вызове конструктора Popen()
.К сожалению, тогда он будет выполнен, когда мы определим подпроцесс, а не когда мы запустим его как задумано.Поэтому мы должны были бы в конечном итоге демонтировать главный процесс.
Таким образом, мы должны определить небольшую функцию-обертку:
def demote():
os.setuid(1000)
и затем можем определить наш подпроцесс:
process = Popen(["git", "clone", git_url, new_package_path], preexec_fn=demote)
process.wait()
Конечно, это не очень хороший способ сделать это - жестко запрограммировать uid и все.Если мы хотим, чтобы demote()
принимал аргументы, мы вернулись на круги своя.Таким образом, мы должны сделать это немного сложнее и определить вложенную функцию (функцию внутри функции), где внешняя вызывается для определения подпроцесса, принимает аргументы, определяет uid и gid и возвращает внутреннюю функцию, которая применяет понижение.Звучит сложно?Строго говоря, вам не нужно этого делать, но, скажем, мы хотим быть гибкими, поэтому здесь мы идем:
def demote(user_uid, user_gid):
def apply_demotion():
os.setgid(user_gid)
os.setuid(user_uid)
return apply_demotion
Второй вариант - использовать su -c (command) (user)
, который можно вызывать из python с помощьюфункция os.system()
:
os.system("su -c makepkg " + user)
Возможно, вы захотите выполнить и команду git clone
и makepkg
с одним и тем же методом согласованности.
Рабочийпример
import os
from subprocess import Popen
import glob
import sys
def clone_and_makepkg(package_name, aur_folder_path="/tmp/build/", uid=1000, gid=1000):
"""prepare urls and paths"""
git_url = "https://aur.archlinux.org/" + package_name + ".git"
new_package_path = os.path.join(aur_folder_path, package_name)
"""ensure the build directory exists and user has correct privileges to work there"""
if not os.path.exists(aur_folder_path):
os.mkdir(aur_folder_path)
os.chmod(aur_folder_path, 0o777)
"""perform git clone"""
print("Cloning " + git_url + " to " + new_package_path)
Popen(["git", "clone", git_url, new_package_path], preexec_fn=demote(uid, gid)).wait()
"""change to make directory"""
os.chdir(new_package_path)
"""run makepkg"""
Popen("makepkg", preexec_fn=demote(uid, gid)).wait()
"""collect built packages"""
built_packages = glob.glob(new_package_path + os.sep + "*.pkg.tar.xz")
"""install each package"""
for package in built_packages:
print("Installing package {}".format(package))
os.system("pacman -U " + package + " --noconfirm")
def demote(user_uid, user_gid):
def apply_demotion():
os.setgid(user_gid)
os.setuid(user_uid)
return apply_demotion
if __name__ == "__main__":
"""Example call. Will by default install package 3to2 (This example does not have any further dependencies
except for python. Which is evidently already installed. So this example is hassle-free. For
examples with dependencies, you may want to find a way to deal with those in the script.)"""
pkgname = "3to2"
if len(sys.argv) > 1:
pkgname = sys.argv[1]
clone_and_makepkg(package_name=pkgname)