Commit ac536f85 authored by rgaudin's avatar rgaudin

Added --root for CLI on linux to use losetup instead of udisks (for docker)

parent 3f7c2baa
Pipeline #100466 failed with stage
in 337 minutes and 42 seconds
2.0.3
* Added --root for CLI on linux to use losetup instead of udisks (for docker)
2.0.2
* Better etcher-cli calling and on-error logging on macOS via GUI
* Added `wipe --sdcard /dev/xxx` CLI command
......
......@@ -42,6 +42,9 @@ elif sys.platform == "linux":
udisksctl_exe = "/usr/bin/udisksctl"
udisks_nou = "--no-user-interaction"
mkfs_exe = "/sbin/mkfs.exfat"
umount_exe = "/bin/umount"
mount_exe = "/bin/mount"
losetup_exe = "/sbin/losetup"
elif sys.platform == "darwin":
hdiutil_exe = "/usr/bin/hdiutil"
diskutil_exe = "/usr/sbin/diskutil"
......@@ -190,6 +193,21 @@ def restore_mode(fpath, mode, logger):
def guess_next_loop_device(logger):
def _no_udisks(logger):
""" guess loop device w/o udisks (using losetup/root) """
try:
lines = subprocess_pretty_call(
[losetup_exe, "--find"], logger, check=True, decode=True
)
except Exception as exp:
logger.err(exp)
return None
return re.search(r"(\/dev\/loop[0-9]+)$", lines[-1].strip()).groups()[0]
if bool(os.getenv("NO_UDISKS", False)):
return _no_udisks(logger)
try:
lines = subprocess_pretty_call(
[udisksctl_exe, "dump"], logger, check=True, decode=True
......@@ -286,7 +304,24 @@ def get_virtual_device(image_fpath, logger):
)
# prepare loop device
udisks_loop = subprocess_pretty_call(
if bool(os.getenv("NO_UDISKS", False)):
loop_maker = subprocess_pretty_call(
[
"/sbin/losetup",
"--offset",
str(offset),
"--sizelimit",
str(size),
"--find",
"--show",
image_fpath,
],
logger,
check=True,
decode=True,
)[0].strip()
else:
loop_maker = subprocess_pretty_call(
[
udisksctl_exe,
"loop-setup",
......@@ -303,9 +338,7 @@ def get_virtual_device(image_fpath, logger):
decode=True,
)[0].strip()
target_dev = re.search(r"(\/dev\/loop[0-9]+)\.$", udisks_loop).groups()[0]
return target_dev
target_dev = re.search(r"(\/dev\/loop[0-9]+)\.?$", loop_maker).groups()[0]
elif sys.platform == "darwin":
# attach image to create loop devices
......@@ -317,8 +350,6 @@ def get_virtual_device(image_fpath, logger):
)[0].strip()
target_dev = str(hdiutil_out.splitlines()[0].split()[0])
return target_dev
elif sys.platform == "win32":
# make sure we have imdisk installed
install_imdisk(logger)
......@@ -329,15 +360,29 @@ def get_virtual_device(image_fpath, logger):
return target_dev
def release_virtual_device(device, logger):
if bool(os.getenv("NO_UDISKS", False)):
subprocess_pretty_call([losetup_exe, "--detach", device], logger)
else:
subprocess_pretty_call(
[udisksctl_exe, "loop-delete", "--block-device", device, udisks_nou], logger
)
def format_data_partition(image_fpath, logger):
""" format the QEMU image's 3rd part in exfat on host """
target_dev = get_virtual_device(image_fpath, logger)
if sys.platform == "linux":
# make sure it's not mounted (gnoe automounts)
# make sure it's not mounted (gnome automounts)
if bool(os.getenv("NO_UDISKS", False)):
subprocess_pretty_call([umount_exe, target_dev], logger)
else:
subprocess_pretty_call(
[udisksctl_exe, "unmount", "--block-device", target_dev, udisks_nou], logger
[udisksctl_exe, "unmount", "--block-device", target_dev, udisks_nou],
logger,
)
# change mode via elevation if we can't format it
......@@ -399,7 +444,21 @@ def mount_data_partition(image_fpath, logger):
target_dev = get_virtual_device(image_fpath, logger)
if sys.platform == "linux":
if sys.platform == "linux" and bool(os.getenv("NO_UDISKS", False)):
# create a mount point in /tmp
mount_point = tempfile.mkdtemp()
try:
subprocess_pretty_check_call(
[mount_exe, "-t", "exfat", target_dev, mount_point], logger
)
except Exception:
# ensure we release the loop device on mount failure
unmount_data_partition(mount_point, target_dev, logger)
raise
return mount_point, target_dev
elif sys.platform == "linux":
# mount the loop-device (udisksctl sets the mount point)
udisks_mount_ret, udisks_mount = subprocess_pretty_call(
[udisksctl_exe, "mount", "--block-device", target_dev, udisks_nou],
......@@ -416,6 +475,7 @@ def mount_data_partition(image_fpath, logger):
# udisksctl always mounts under /media/
mount_point = re.search(r"at (\/media\/.+)\.$", udisks_mount).groups()[0]
else:
release_virtual_device(target_dev, logger) # release loop if attached
raise OSError("failed to mount {}".format(target_dev))
return mount_point, target_dev
......@@ -469,17 +529,20 @@ def unmount_data_partition(mount_point, device, logger):
if mount_point:
# unmount using device path
if bool(os.getenv("NO_UDISKS", False)):
subprocess_pretty_call([umount_exe, device], logger)
else:
subprocess_pretty_call(
[udisksctl_exe, "unmount", "--block-device", device, udisks_nou], logger
[udisksctl_exe, "unmount", "--block-device", device, udisks_nou],
logger,
)
try:
os.rmdir(mount_point)
except (FileNotFoundError, PermissionError):
pass
# delete the loop device (might have already been deletec)
subprocess_pretty_call(
[udisksctl_exe, "loop-delete", "--block-device", device, udisks_nou], logger
)
# delete the loop device (might have already been deleted)
release_virtual_device(device, logger)
elif sys.platform == "darwin":
......
......@@ -7,7 +7,7 @@ import sys
from backend.mount import system_has_exfat
if sys.platform == "linux":
from backend.mount import udisksctl_exe
from backend.mount import udisksctl_exe, losetup_exe
requirements_url = "https://github.com/kiwix/kiwix-hotspot/wiki/System-Requirements"
......@@ -27,7 +27,15 @@ def host_matches_requirements(build_dir):
if sys.platform == "linux":
# udisks2
if not os.path.exists(udisksctl_exe) or not os.access(udisksctl_exe, os.X_OK):
if bool(os.getenv("NO_UDISKS", False)):
if not os.path.exists(losetup_exe) or not os.access(losetup_exe, os.X_OK):
missing_reqs.append(
"losetup (mount) is required when excluding udisks2."
)
else:
if not os.path.exists(udisksctl_exe) or not os.access(
udisksctl_exe, os.X_OK
):
missing_reqs.append("udisks2 (udisksctl) is required.")
# exfat
......
......@@ -27,7 +27,7 @@ from util import get_adjusted_image_size
from backend.catalog import get_catalogs
from run_installation import run_installation
from util import human_readable_size, get_cache
from backend.util import sd_has_single_partition
from backend.util import sd_has_single_partition, is_admin
import tzlocal
import humanfriendly
......@@ -200,9 +200,22 @@ parser.add_argument(
parser.add_argument("--filename", help="Output file name (without suffix)")
parser.add_argument("--ram", help="Max RAM for QEMU", default="2G")
parser.add_argument("--sdcard", help="Device to copy image to")
parser.add_argument(
"--root",
action="store_true",
help="Don't use udisks2 (linux-only, must be ran as root)",
)
args = parser.parse_args()
# handle root option (disable udisks use)
if args.root:
if not is_admin():
print("You must be root/elevated to use --root option")
sys.exit(1)
else:
os.environ["NO_UDISKS"] = "yes"
# apply options from config file if requested
if args.config:
try:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment