# Copyright 2020 Oliver Smith # SPDX-License-Identifier: GPL-3.0-or-later import logging import os import re import pmb.chroot import pmb.config import pmb.config.init import pmb.helpers.pmaports import pmb.helpers.run def folder_size(args, path): """ Run `du` to calculate the size of a folder (this is less code and faster than doing the same task in pure Python). This result is only approximatelly right, but good enough for pmbootstrap's use case (#760). :returns: folder size in bytes """ output = pmb.helpers.run.root(args, ["du", "--summarize", "--block-size=1", path], output_return=True) # Only look at last line to filter out sudo garbage (#1766) last_line = output.split("\n")[-2] ret = int(last_line.split("\t")[0]) return ret def check_grsec(args): """ Check if the current kernel is based on the grsec patchset, and if the chroot_deny_chmod option is enabled. Raise an exception in that case, with a link to the issue. Otherwise, do nothing. """ path = "/proc/sys/kernel/grsecurity/chroot_deny_chmod" if not os.path.exists(path): return raise RuntimeError("You're running a kernel based on the grsec" " patchset. This is not supported.") def check_binfmt_misc(args): """ Check if the 'binfmt_misc' module is loaded by checking, if /proc/sys/fs/binfmt_misc/ exists. If it exists, then do nothing. Otherwise, raise an exception pointing to user to the Wiki. """ path = "/proc/sys/fs/binfmt_misc/status" if os.path.exists(path): return link = "https://postmarketos.org/binfmt_misc" raise RuntimeError("It appears that your system has not loaded the" " module 'binfmt_misc'. This is required to run" " foreign architecture programs with QEMU (eg." " armhf on x86_64):\n See: <" + link + ">") def migrate_success(args, version): logging.info("Migration to version " + str(version) + " done") with open(args.work + "/version", "w") as handle: handle.write(str(version) + "\n") def migrate_work_folder(args): # Read current version current = 0 path = args.work + "/version" if os.path.exists(path): with open(path, "r") as f: current = int(f.read().rstrip()) # Compare version, print warning or do nothing required = pmb.config.work_version if current == required: return logging.info("WARNING: Your work folder version needs to be migrated" " (from version " + str(current) + " to " + str(required) + ")!") # 0 => 1 if current == 0: # Ask for confirmation logging.info("Changelog:") logging.info("* Building chroots have a different username (#709)") logging.info("Migration will do the following:") logging.info("* Zap your chroots") logging.info("* Adjust '" + args.work + "/config_abuild/abuild.conf'") if not pmb.helpers.cli.confirm(args): raise RuntimeError("Aborted.") # Zap and update abuild.conf pmb.chroot.zap(args, False) conf = args.work + "/config_abuild/abuild.conf" if os.path.exists(conf): pmb.helpers.run.root(args, ["sed", "-i", "s./home/user/./home/pmos/.g", conf]) # Update version file migrate_success(args, 1) current = 1 # 1 => 2 if current == 1: # Ask for confirmation logging.info("Changelog:") logging.info("* Fix: cache_distfiles was writable for everyone") logging.info("Migration will do the following:") logging.info("* Fix permissions of '" + args.work + "/cache_distfiles'") if not pmb.helpers.cli.confirm(args): raise RuntimeError("Aborted.") # Fix permissions dir = "/var/cache/distfiles" for cmd in [["chown", "-R", "root:abuild", dir], ["chmod", "-R", "664", dir], ["chmod", "a+X", dir]]: pmb.chroot.root(args, cmd) migrate_success(args, 2) current = 2 if current == 2: # Ask for confirmation logging.info("Changelog:") logging.info("* Device chroots have a different user UID (#1576)") logging.info("Migration will do the following:") logging.info("* Zap your chroots") if not pmb.helpers.cli.confirm(args): raise RuntimeError("Aborted.") # Zap chroots pmb.chroot.zap(args, False) # Update version file migrate_success(args, 3) current = 3 if current == 3: # Ask for confirmation path = args.work + "/cache_git" logging.info("Changelog:") logging.info("* pmbootstrap clones repositories with host system's") logging.info(" 'git' instead of using it from an Alpine chroot") logging.info("Migration will do the following:") logging.info("* Check if 'git' is installed") logging.info("* Change ownership to your user: " + path) if not pmb.helpers.cli.confirm(args): raise RuntimeError("Aborted.") # Require git, set cache_git ownership pmb.config.init.require_programs() if os.path.exists(path): uid_gid = "{}:{}".format(os.getuid(), os.getgid()) pmb.helpers.run.root(args, ["chown", "-R", uid_gid, path]) else: os.makedirs(path, 0o700, True) # Update version file migrate_success(args, 4) current = 4 # Can't migrate, user must delete it if current != required: raise RuntimeError("Sorry, we can't migrate that automatically. Please" " run 'pmbootstrap shutdown', then delete your" " current work folder manually ('sudo rm -rf " + args.work + "') and start over with 'pmbootstrap" " init'. All your binary packages and caches will" " be lost.") def validate_hostname(hostname): """ Check whether the string is a valid hostname, according to """ # Check length if len(hostname) > 63: logging.fatal("ERROR: Hostname '" + hostname + "' is too long.") return False # Check that it only contains valid chars if not re.match("^[0-9a-z-]*$", hostname): logging.fatal("ERROR: Hostname must only contain letters (a-z)," " digits (0-9) or minus signs (-)") return False # Check that doesn't begin or end with a minus sign if hostname[:1] == "-" or hostname[-1:] == "-": logging.fatal("ERROR: Hostname must not begin or end with a minus sign") return False return True