mirror of https://git.48k.eu/ogclient
Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
cf9577a40e | |
|
6503d0ffe7 | |
|
0ca16bc46c | |
|
bd190f8d44 | |
|
e0ba9cc98c | |
|
ccdcb7bfc7 | |
|
72406a7d89 | |
|
0f519ecfeb | |
|
c260534534 | |
|
f67f3c598a | |
|
574822907d | |
|
30e0e1dca3 | |
|
59d642f6b5 | |
|
24568356bc | |
|
40e4545bb7 | |
|
d29b601f17 |
|
@ -27,7 +27,7 @@ from src.utils.postinstall import configure_os
|
|||
from src.utils.net import *
|
||||
from src.utils.menu import generate_menu
|
||||
from src.utils.fs import *
|
||||
from src.utils.probe import os_probe, get_cache_dev_path
|
||||
from src.utils.probe import *
|
||||
from src.utils.disk import *
|
||||
from src.utils.cache import *
|
||||
from src.utils.tiptorrent import *
|
||||
|
@ -82,8 +82,10 @@ class OgLiveOperations:
|
|||
code = int(pa.parttype, base=16)
|
||||
|
||||
if mount_mkdir(pa.padev, target):
|
||||
probe_result = os_probe(target)
|
||||
part_setup['os'] = probe_result
|
||||
part_setup['os'] = ''
|
||||
if part_setup['disk'] == '1':
|
||||
probe_result = os_probe(target)
|
||||
part_setup['os'] = probe_result
|
||||
|
||||
total, used, free = shutil.disk_usage(target)
|
||||
part_setup['used_size'] = used
|
||||
|
@ -526,7 +528,12 @@ class OgLiveOperations:
|
|||
raise OgError(f'Invalid disk number {disk}, {len(get_disks())} disks available.')
|
||||
|
||||
diskname = get_disks()[disk-1]
|
||||
self._partition(diskname, table_type, partlist)
|
||||
try:
|
||||
self._partition(diskname, table_type, partlist)
|
||||
except Exception as e:
|
||||
ret = subprocess.run(['wipefs', '-af', f'/dev/{diskname}'])
|
||||
logging.warning(f'wipefs on /dev/{diskname} after failure for consistency, reports {ret.returncode}')
|
||||
raise
|
||||
|
||||
ret = subprocess.run(['partprobe', f'/dev/{diskname}'])
|
||||
logging.info(f'first partprobe /dev/{diskname} reports {ret.returncode}')
|
||||
|
@ -594,19 +601,14 @@ class OgLiveOperations:
|
|||
|
||||
extend_filesystem(disk, partition)
|
||||
|
||||
configure_os(disk, partition)
|
||||
if disk == 1:
|
||||
configure_os(disk, partition)
|
||||
|
||||
self.refresh(ogRest)
|
||||
result = self.refresh(ogRest)
|
||||
|
||||
logging.info('Image restore command OK')
|
||||
|
||||
json_dict = {
|
||||
'disk': request.getDisk(),
|
||||
'partition': request.getPartition(),
|
||||
'image_id': request.getId(),
|
||||
'cache': self._get_cache_contents(),
|
||||
}
|
||||
return json_dict
|
||||
return result
|
||||
|
||||
def image_create(self, request, ogRest):
|
||||
disk = int(request.getDisk())
|
||||
|
@ -655,6 +657,7 @@ class OgLiveOperations:
|
|||
raise OgError(f'Cannot mount {ro_mountpoint} as readonly')
|
||||
|
||||
try:
|
||||
is_windows = get_os_family(ro_mountpoint) == OSFamily.WINDOWS
|
||||
if is_hibernation_enabled(ro_mountpoint):
|
||||
raise OgError(f'Target system in {padev} has hibernation enabled')
|
||||
finally:
|
||||
|
@ -666,10 +669,12 @@ class OgLiveOperations:
|
|||
if os.access(f'/opt/opengnsys/images', os.R_OK | os.W_OK) == False:
|
||||
raise OgError('Cannot access /opt/opengnsys/images in read and write mode, check permissions')
|
||||
|
||||
if os.access(f'{image_path}', os.R_OK) == True:
|
||||
if os.access(image_path, os.R_OK) == True:
|
||||
logging.info(f'image file {image_path} already exists, updating.')
|
||||
|
||||
copy_windows_efi_bootloader(disk, partition)
|
||||
if is_windows and is_uefi_supported():
|
||||
copy_windows_efi_bootloader(disk, partition)
|
||||
|
||||
if ogReduceFs(disk, partition) == -1:
|
||||
raise OgError(f'Failed to shrink {fstype} filesystem in {padev}')
|
||||
|
||||
|
@ -741,7 +746,6 @@ class OgLiveOperations:
|
|||
|
||||
def cache_delete(self, request, ogRest):
|
||||
images = request.getImages()
|
||||
deleted_images = []
|
||||
|
||||
logging.info(f'Request to remove files from cache')
|
||||
|
||||
|
|
|
@ -52,8 +52,9 @@ class ogClient:
|
|||
self.ogrest = ogRest(self.CONFIG)
|
||||
self.seq = None
|
||||
|
||||
self.session_check_thread = threading.Thread(target=self._session_check_loop, daemon=True)
|
||||
self.session_check_thread.start()
|
||||
if self.event_sock:
|
||||
self.session_check_thread = threading.Thread(target=self._session_check_loop, daemon=True)
|
||||
self.session_check_thread.start()
|
||||
|
||||
def _session_check_loop(self):
|
||||
while True:
|
||||
|
@ -80,7 +81,7 @@ class ogClient:
|
|||
def get_state(self):
|
||||
return self.state
|
||||
|
||||
def send_event_hint(self, message):
|
||||
def handle_session_event(self, message):
|
||||
try:
|
||||
event, action, user = message.split(" ")
|
||||
logging.debug('Sending event: %s, %s, %s', event, action, user)
|
||||
|
@ -210,6 +211,6 @@ class ogClient:
|
|||
self.connect2()
|
||||
elif state == State.RECEIVING and event_sock in readable:
|
||||
message = event_sock.recv(4096).decode('utf-8').rstrip()
|
||||
self.send_event_hint(message)
|
||||
self.handle_session_event(message)
|
||||
else:
|
||||
raise OgError(f'Invalid ogClient run state: {str(state)}.')
|
||||
|
|
|
@ -343,7 +343,7 @@ class ogRest():
|
|||
self.process_imagerestore(client, request)
|
||||
elif ("stop" in URI):
|
||||
self.process_stop(client)
|
||||
elif ("image/create" in URI):
|
||||
elif ("image/create" in URI or "image/update" in URI):
|
||||
self.process_imagecreate(client, request)
|
||||
elif ("cache/delete" in URI):
|
||||
self.process_cache_delete(client, request)
|
||||
|
|
|
@ -11,6 +11,7 @@ import logging
|
|||
import shlex
|
||||
import subprocess
|
||||
import json
|
||||
from uuid import UUID
|
||||
from src.log import OgError
|
||||
|
||||
import fdisk
|
||||
|
@ -190,3 +191,38 @@ def get_partition_start_offset(disk, partition):
|
|||
raise OgError(f'Error while trying to parse sfdisk: {e}') from e
|
||||
|
||||
return start_offset
|
||||
|
||||
|
||||
def uuid_to_bytes(uuid):
|
||||
uuid = uuid.replace('-', '')
|
||||
|
||||
group0 = f'{uuid[6:8]}{uuid[4:6]}{uuid[2:4]}{uuid[0:2]}'
|
||||
group1 = f'{uuid[10:12]}{uuid[8:10]}'
|
||||
group2 = f'{uuid[14:16]}{uuid[12:14]}'
|
||||
group3 = uuid[16:20]
|
||||
group4 = uuid[20:32]
|
||||
res = f'{group0}-{group1}-{group2}-{group3}-{group4}'
|
||||
return UUID(res).bytes
|
||||
|
||||
|
||||
def get_disk_id_bytes(disk):
|
||||
from src.utils.uefi import is_uefi_supported
|
||||
disk_id = get_disk_id(disk)
|
||||
|
||||
if is_uefi_supported():
|
||||
return uuid_to_bytes(disk_id)
|
||||
|
||||
return bytes.fromhex(disk_id)[::-1]
|
||||
|
||||
|
||||
def get_part_id_bytes(disk, partition):
|
||||
from src.utils.uefi import is_uefi_supported
|
||||
if is_uefi_supported():
|
||||
part_id = get_partition_id(disk, partition)
|
||||
return uuid_to_bytes(part_id)
|
||||
|
||||
partition_start_offset = get_partition_start_offset(disk, partition)
|
||||
sector_size = get_sector_size(disk)
|
||||
byte_offset = partition_start_offset * sector_size
|
||||
byte_offset = "{0:016x}".format(byte_offset)
|
||||
return bytes.fromhex(byte_offset)[::-1]
|
||||
|
|
|
@ -153,13 +153,19 @@ def mkfs(fs, disk, partition, label=None):
|
|||
if fs not in fsdict:
|
||||
raise OgError(f'mkfs failed, unsupported target filesystem {fs}')
|
||||
|
||||
try:
|
||||
partdev = get_partition_device(disk, partition)
|
||||
except ValueError as e:
|
||||
raise OgError(f'mkfs aborted: {e}') from e
|
||||
partdev = get_partition_device(disk, partition)
|
||||
|
||||
return fsdict[fs](partdev, label)
|
||||
ret = subprocess.run(['wipefs', '-af', f'{partdev}'])
|
||||
if ret.returncode != 0:
|
||||
logging.warning(f'wipefs on {partdev}, fails with {ret.returncode}')
|
||||
|
||||
err = fsdict[fs](partdev, label)
|
||||
if err != 0:
|
||||
ret = subprocess.run(['wipefs', '-af', f'{partdev}'])
|
||||
if ret.returncode != 0:
|
||||
logging.warning(f'wipefs on {partdev} for consistency, fails with {ret.returncode}')
|
||||
|
||||
return err
|
||||
|
||||
def mkfs_ext4(partdev, label=None):
|
||||
err = -1
|
||||
|
|
|
@ -279,7 +279,7 @@ def _get_os_entries(esp_mountpoint):
|
|||
continue
|
||||
|
||||
if not mount_mkdir(p.padev, mountpoint):
|
||||
raise OgError(f'Unable to mount {p.padev} into {mountpoint}')
|
||||
continue
|
||||
|
||||
try:
|
||||
os_family = get_os_family(mountpoint)
|
||||
|
@ -334,6 +334,7 @@ def get_disk_part_type(disk_num):
|
|||
def _update_nvram(esp_disk, esp_part_number):
|
||||
loader_path = '/EFI/grub/Boot/shimx64.efi'
|
||||
bootlabel = 'grub'
|
||||
egibootmgr_reorder_disabled_entries()
|
||||
efibootmgr_delete_bootentry(bootlabel)
|
||||
efibootmgr_create_bootentry(esp_disk, esp_part_number, loader_path, bootlabel, add_to_bootorder=False)
|
||||
efibootmgr_set_entry_order(bootlabel, 1)
|
||||
|
|
|
@ -14,7 +14,6 @@ import subprocess
|
|||
import shutil
|
||||
from src.utils.disk import *
|
||||
from src.utils.fs import *
|
||||
from src.utils.probe import *
|
||||
from src.log import OgError
|
||||
|
||||
import fdisk
|
||||
|
@ -26,7 +25,7 @@ def _find_bootentry(entries, label):
|
|||
if entry['description'] == label:
|
||||
return entry
|
||||
else:
|
||||
raise OgError('Boot entry {label} not found')
|
||||
raise OgError(f'Boot entry {label} not found')
|
||||
|
||||
|
||||
def _strip_boot_prefix(entry):
|
||||
|
@ -96,8 +95,13 @@ def efibootmgr_bootnext(description):
|
|||
entry = _find_bootentry(boot_entries, description)
|
||||
num = _strip_boot_prefix(entry) # efibootmgr output uses BootXXXX for each entry, remove the "Boot" prefix.
|
||||
bootnext_cmd = bootnext_cmd.format(bootnum=num, efibootmgr=EFIBOOTMGR_BIN)
|
||||
subprocess.run(shlex.split(bootnext_cmd), check=True,
|
||||
stdout=subprocess.DEVNULL)
|
||||
try:
|
||||
subprocess.run(shlex.split(bootnext_cmd), check=True,
|
||||
stdout=subprocess.DEVNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.warning("Failed to update BootNext. UEFI firmware might be buggy")
|
||||
except OSError as e:
|
||||
raise OgError(f"Unexpected error updating BootNext: {e}") from e
|
||||
|
||||
|
||||
def efibootmgr_delete_bootentry(label):
|
||||
|
@ -108,7 +112,12 @@ def efibootmgr_delete_bootentry(label):
|
|||
if entry['description'] == label:
|
||||
num = entry['name'][4:] # Remove "Boot" prefix to extract num
|
||||
efibootmgr_cmd = efibootmgr_cmd.format(bootnum=num, efibootmgr=EFIBOOTMGR_BIN)
|
||||
subprocess.run(shlex.split(efibootmgr_cmd), check=True)
|
||||
try:
|
||||
subprocess.run(shlex.split(efibootmgr_cmd), check=True)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.warning(f"Failed to delete boot entry {label}. UEFI firmware might be buggy")
|
||||
except OSError as e:
|
||||
raise OgError(f"Unexpected error deleting boot entry {label}: {e}") from e
|
||||
break
|
||||
else:
|
||||
logging.info(f'Cannot delete boot entry {label} because it was not found.')
|
||||
|
@ -122,8 +131,10 @@ def efibootmgr_create_bootentry(disk, part, loader, label, add_to_bootorder=True
|
|||
logging.info(f'{EFIBOOTMGR_BIN} command creating boot entry: {efibootmgr_cmd}')
|
||||
try:
|
||||
proc = subprocess.run(shlex.split(efibootmgr_cmd), check=True, text=True)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.warning(f"Failed to add boot entry {label} to NVRAM. UEFI firmware might be buggy")
|
||||
except OSError as e:
|
||||
raise OgError(f'Unexpected error adding boot entry to nvram. UEFI firmware might be buggy') from e
|
||||
raise OgError(f"Unexpected error adding boot entry {label}: {e}") from e
|
||||
|
||||
def efibootmgr_set_entry_order(label, position):
|
||||
logging.info(f'Setting {label} entry to position {position} of boot order')
|
||||
|
@ -141,8 +152,29 @@ def efibootmgr_set_entry_order(label, position):
|
|||
|
||||
try:
|
||||
proc = subprocess.run([EFIBOOTMGR_BIN, "-o", ",".join(boot_order)], check=True, text=True)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.warning("Failed to set boot order to NVRAM. UEFI firmware might be buggy")
|
||||
except OSError as e:
|
||||
raise OgError(f'Unexpected error setting boot order to NVRAM. UEFI firmware might be buggy') from e
|
||||
raise OgError(f"Unexpected error updating boot order: {e}") from e
|
||||
|
||||
def egibootmgr_reorder_disabled_entries():
|
||||
logging.info(f'Setting disabled entries at the end of boot order')
|
||||
boot_info = run_efibootmgr_json(validate=False)
|
||||
boot_entries = boot_info.get('vars', [])
|
||||
boot_order = boot_info.get('BootOrder', [])
|
||||
|
||||
for entry in boot_entries:
|
||||
entry_number = _strip_boot_prefix(entry)
|
||||
if not entry['active'] and entry_number in boot_order:
|
||||
boot_order.remove(entry_number)
|
||||
boot_order.append(entry_number)
|
||||
|
||||
try:
|
||||
proc = subprocess.run([EFIBOOTMGR_BIN, "-o", ",".join(boot_order)], check=True, text=True)
|
||||
except subprocess.CalledProcessError:
|
||||
logging.warning("Failed to update boot order. UEFI firmware might be buggy")
|
||||
except OSError as e:
|
||||
raise OgError(f"Unexpected error updating boot order: {e}") from e
|
||||
|
||||
def _find_efi_loader(loader_paths):
|
||||
for efi_app in loader_paths:
|
||||
|
@ -170,13 +202,7 @@ def copy_windows_efi_bootloader(disk, partition):
|
|||
device = get_partition_device(disk, partition)
|
||||
mountpoint = device.replace('dev', 'mnt')
|
||||
if not mount_mkdir(device, mountpoint):
|
||||
raise OgError(f'Cannot probe OS family. Unable to mount {device} into {mountpoint}')
|
||||
|
||||
os_family = get_os_family(mountpoint)
|
||||
is_uefi = is_uefi_supported()
|
||||
|
||||
if not is_uefi or os_family != OSFamily.WINDOWS:
|
||||
return
|
||||
raise OgError(f'Unable to mount {device} into {mountpoint}')
|
||||
|
||||
bootlabel = f'Part-{disk:02d}-{partition:02d}'
|
||||
esp, esp_disk, esp_part_number = get_efi_partition(disk, enforce_gpt=True)
|
||||
|
@ -209,7 +235,7 @@ def restore_windows_efi_bootloader(disk, partition):
|
|||
device = get_partition_device(disk, partition)
|
||||
mountpoint = device.replace('dev', 'mnt')
|
||||
if not mount_mkdir(device, mountpoint):
|
||||
raise OgError(f'Cannot probe OS family. Unable to mount {device} into {mountpoint}')
|
||||
raise OgError(f'Unable to mount {device} into {mountpoint}')
|
||||
|
||||
bootlabel = f'Part-{disk:02d}-{partition:02d}'
|
||||
esp, esp_disk, esp_part_number = get_efi_partition(disk, enforce_gpt=True)
|
||||
|
|
|
@ -10,9 +10,7 @@ import libhivexmod
|
|||
import hivex
|
||||
from enum import Enum
|
||||
from src.log import OgError
|
||||
from uuid import UUID
|
||||
from src.utils.disk import *
|
||||
from src.utils.uefi import is_uefi_supported
|
||||
|
||||
|
||||
WINDOWS_HIVES_PATH = '/Windows/System32/config'
|
||||
|
@ -102,36 +100,3 @@ def get_node_child_from_path(hive, node, path):
|
|||
child_node = get_node_child(hive, child_node, node_name)
|
||||
|
||||
return child_node
|
||||
|
||||
|
||||
def uuid_to_bytes(uuid):
|
||||
uuid = uuid.replace('-', '')
|
||||
|
||||
group0 = f'{uuid[6:8]}{uuid[4:6]}{uuid[2:4]}{uuid[0:2]}'
|
||||
group1 = f'{uuid[10:12]}{uuid[8:10]}'
|
||||
group2 = f'{uuid[14:16]}{uuid[12:14]}'
|
||||
group3 = uuid[16:20]
|
||||
group4 = uuid[20:32]
|
||||
res = f'{group0}-{group1}-{group2}-{group3}-{group4}'
|
||||
return UUID(res).bytes
|
||||
|
||||
|
||||
def get_disk_id_bytes(disk):
|
||||
disk_id = get_disk_id(disk)
|
||||
|
||||
if is_uefi_supported():
|
||||
return uuid_to_bytes(disk_id)
|
||||
|
||||
return bytes.fromhex(disk_id)[::-1]
|
||||
|
||||
|
||||
def get_part_id_bytes(disk, partition):
|
||||
if is_uefi_supported():
|
||||
part_id = get_partition_id(disk, partition)
|
||||
return uuid_to_bytes(part_id)
|
||||
|
||||
partition_start_offset = get_partition_start_offset(disk, partition)
|
||||
sector_size = get_sector_size(disk)
|
||||
byte_offset = partition_start_offset * sector_size
|
||||
byte_offset = "{0:016x}".format(byte_offset)
|
||||
return bytes.fromhex(byte_offset)[::-1]
|
||||
|
|
Loading…
Reference in New Issue