index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
-rw-r--r-- | archinstall.py | 261 | ||||
-rw-r--r-- | test_archinstall.py | 13 |
diff --git a/archinstall.py b/archinstall.py index 1d0bba3d..5c261662 100644 --- a/archinstall.py +++ b/archinstall.py @@ -2,15 +2,16 @@ import traceback import os, re, struct, sys, json, pty, shlex import urllib.request, urllib.parse, ssl, signal +import time from glob import glob from select import epoll, EPOLLIN, EPOLLHUP from socket import socket, inet_ntoa, AF_INET, AF_INET6, AF_PACKET from collections import OrderedDict as oDict from subprocess import Popen, STDOUT, PIPE -from time import sleep, time from random import choice from string import ascii_uppercase, ascii_lowercase, digits from hashlib import sha512 +from threading import Thread, enumerate as tenum if not os.path.isdir('/sys/firmware/efi'): print('[E] This script only supports UEFI-booted machines.') @@ -24,8 +25,9 @@ else: profiles_path = 'https://raw.githubusercontent.com/Torxed/archinstall/master/deployments' rootdir_pattern = re.compile('^.*?/devices') harddrives = oDict() -commandlog = oDict() -instructions = +commandlog = [] +worker_history = oDict() +instructions = oDict() args = {} positionals = [] for arg in sys.argv[1:]: @@ -61,6 +63,8 @@ class LOG_LEVELS: INFO = 4 DEBUG = 5 +LOG_LEVEL = 4 + def log(*msg, origin='UNKNOWN', level=5, **kwargs): if level <= LOG_LEVEL: msg = [item.decode('UTF-8', errors='backslashreplace') if type(item) == bytes else item for item in msg] @@ -102,7 +106,7 @@ except: self.interface = interface self.bytes_recv = int(bytes_recv) self.bytes_sent = int(bytes_sent) - def __repr__(self, *args, **kwargs): + def __repr__(self, *positionals, **kwargs): return f'iostat@{self.interface}[bytes_sent: {self.bytes_sent}, bytes_recv: {self.bytes_recv}]' class psutil(): @@ -152,7 +156,7 @@ signal.signal(signal.SIGINT, sig_handler) def gen_uid(entropy_length=256): return sha512(os.urandom(entropy_length)).hexdigest() -def get_default_gateway_linux(): +def get_default_gateway_linux(*args, **kwargs): """Read the default gateway directly from /proc.""" with open("/proc/net/route") as fh: for line in fh: @@ -185,12 +189,33 @@ def pid_exists(pid): else: return True -class sys_command(Thread): - def __init__(self, cmd, callback=None, start_callback=None, *args, **kwargs): +def simple_command(cmd, opts=None, *positionals, **kwargs): + if not opts: opts = {} + if 'debug' in opts: + print('[!] {}'.format(cmd)) + handle = Popen(cmd, shell='True', stdout=PIPE, stderr=STDOUT, stdin=PIPE, **kwargs) + output = b'' + while handle.poll() is None: + data = handle.stdout.read() + if len(data): + if 'debug' in opts: + print(data.decode('UTF-8'), end='') + # print(data.decode('UTF-8'), end='') + output += data + data = handle.stdout.read() + if 'debug' in opts: + print(data.decode('UTF-8'), end='') + output += data + handle.stdin.close() + handle.stdout.close() + return output + +class sys_command():#Thread): + def __init__(self, cmd, callback=None, start_callback=None, *positionals, **kwargs): if not 'worker_id' in kwargs: kwargs['worker_id'] = gen_uid() if not 'emulate' in kwargs: kwargs['emulate'] = SAFETY_LOCK - Thread.__init__(self) - if self.kwargs['emulate']: + #Thread.__init__(self) + if kwargs['emulate']: print('Starting command in emulation mode.') self.cmd = shlex.split(cmd) self.args = args @@ -206,24 +231,32 @@ class sys_command(Thread): user_catalogue = os.path.expanduser('~') self.cwd = f"{user_catalogue}/archinstall/cache/workers/{kwargs['worker_id']}/" - self.exec_dir = f'{self.cwd}/{basename(self.cmd[0])}_workingdir' + self.exec_dir = f'{self.cwd}/{os.path.basename(self.cmd[0])}_workingdir' if not self.cmd[0][0] == '/': log('Worker command is not executed with absolute path, trying to find: {}'.format(self.cmd[0]), origin='spawn', level=5) - o = b''.join(sys_command('/usr/bin/which {}'.format(self.cmd[0])).exec()) + o = sys_command('/usr/bin/which {}'.format(self.cmd[0]), emulate=False) log('This is the binary {} for {}'.format(o.decode('UTF-8'), self.cmd[0]), origin='spawn', level=5) self.cmd[0] = o.decode('UTF-8') - if not isdir(self.exec_dir): + if not os.path.isdir(self.exec_dir): os.makedirs(self.exec_dir) commandlog.append(cmd + ' #emulated') - if start_callback: start_callback(self, *args, **kwargs) - self.start() + if start_callback: start_callback(self, *positionals, **kwargs) + #self.start() + self.run() - def __repr__(self, *args, **kwargs): + def __iter__(self, *positionals, **kwargs): + for line in self.trace_log.split(b'\n'): + yield line + + def __repr__(self, *positionals, **kwargs): return self.trace_log.decode('UTF-8') + def decode(self, fmt='UTF-8'): + return self.trace_log.decode(fmt) + def dump(self): return { 'status' : self.status, @@ -237,15 +270,15 @@ class sys_command(Thread): } def run(self): - main = None - for t in tenum(): - if t.name == 'MainThread': - main = t - break - - if not main: - print('Main thread not existing') - return + #main = None + #for t in tenum(): + # if t.name == 'MainThread': + # main = t + # break + + #if not main: + # print('Main thread not existing') + # return self.status = 'running' old_dir = os.getcwd() @@ -262,7 +295,7 @@ class sys_command(Thread): alive = True last_trigger_pos = 0 - while alive and main and main.isAlive() and not self.kwargs['emulate']: + while alive and not self.kwargs['emulate']: for fileno, event in poller.poll(0.1): try: output = os.read(child_fd, 8192).strip() @@ -344,27 +377,6 @@ class sys_command(Thread): if self.callback: self.callback(self, *self.args, **self.kwargs) -def simple_command(cmd, opts=None, *args, **kwargs): - if not opts: opts = {} - if 'debug' in opts: - print('[!] {}'.format(cmd)) - handle = Popen(cmd, shell='True', stdout=PIPE, stderr=STDOUT, stdin=PIPE, **kwargs) - output = b'' - while handle.poll() is None: - data = handle.stdout.read() - if len(data): - if 'debug' in opts: - print(data.decode('UTF-8'), end='') - # print(data.decode('UTF-8'), end='') - output += data - data = handle.stdout.read() - if 'debug' in opts: - print(data.decode('UTF-8'), end='') - output += data - handle.stdin.close() - handle.stdout.close() - return output - def get_drive_from_uuid(uuid): if len(harddrives) <= 0: raise ValueError("No hard drives to iterate in order to find: {}".format(uuid)) @@ -429,7 +441,7 @@ def update_git(branch='master'): os.execv('/usr/bin/python3', ['archinstall.py'] + sys.argv + ['--rebooted',]) extit(1) -def device_state(name): +def device_state(name, *positionals, **kwargs): # Based out of: https://askubuntu.com/questions/528690/how-to-get-list-of-all-non-removable-disk-device-names-ssd-hdd-and-sata-ide-onl/528709#528709 if os.path.isfile('/sys/block/{}/device/block/{}/removable'.format(name, name)): with open('/sys/block/{}/device/block/{}/removable'.format(name, name)) as f: @@ -449,8 +461,8 @@ def device_state(name): def get_partitions(dev): drive_name = os.path.basename(dev) parts = oDict() - #o = b''.join(sys_command('/usr/bin/lsblk -o name -J -b {dev}'.format(dev=dev)).exec()) - o = b''.join(sys_command('/usr/bin/lsblk -J {dev}'.format(dev=dev)).exec()) + #o = b''.join(sys_command('/usr/bin/lsblk -o name -J -b {dev}'.format(dev=dev))) + o = b''.join(sys_command('/usr/bin/lsblk -J {dev}'.format(dev=dev))) if b'not a block device' in o: ## TODO: Replace o = sys_command() with code, o = sys_command() ## and make sys_command() return the exit-code, way safer than checking output strings :P @@ -481,8 +493,8 @@ def get_disk_size(drive): with open(f'/sys/block/{dev_short_name}/device/block/{dev_short_name}/size', 'rb') as fh: return ''.join(human_readable_size(fh.read().decode('UTF-8').strip())) -def disk_info(drive): - info = json.loads(b''.join(sys_command(f'lsblk -J -o "NAME,SIZE,FSTYPE,LABEL" {drive}').exec()).decode('UTF_8'))['blockdevices'][0] +def disk_info(drive, *positionals, **kwargs): + info = json.loads(b''.join(sys_command(f'lsblk -J -o "NAME,SIZE,FSTYPE,LABEL" {drive}', *positionals, **kwargs)).decode('UTF_8'))['blockdevices'][0] fileformats = [] labels = [] for child in info['children']: @@ -506,7 +518,7 @@ def cleanup_args(): print('[E] Failed to setup a yubikey password, is it plugged in?') exit(1) -def merge_in_includes(instructions): +def merge_in_includes(instructions, *positionals, **kwargs): if 'args' in instructions: ## == Recursively fetch instructions if "include" is found under {args: ...} while 'include' in instructions['args']: @@ -515,9 +527,9 @@ def merge_in_includes(instructions): del(instructions['args']['include']) if type(includes) in (dict, list): for include in includes: - instructions = merge_dicts(instructions, get_instructions(include), before=True) + instructions = merge_dicts(instructions, get_instructions(include, *positionals, **kwargs), before=True) else: - instructions = merge_dicts(instructions, get_instructions(includes), before=True) + instructions = merge_dicts(instructions, get_instructions(includes), *positionals, **kwargs, before=True) ## Update arguments if we found any for key, val in instructions['args'].items(): @@ -532,12 +544,12 @@ def merge_in_includes(instructions): return instructions -def update_drive_list(): +def update_drive_list(*args, **kwargs): # https://github.com/karelzak/util-linux/blob/f920f73d83f8fd52e7a14ec0385f61fab448b491/disk-utils/fdisk-list.c#L52 for path in glob('/sys/block/*/device'): name = re.sub('.*/(.*?)/device', '\g<1>', path) - if device_state(name): - harddrives[f'/dev/{name}'] = disk_info(f'/dev/{name}') + if device_state(name, *positionals, **kwargs): + harddrives[f'/dev/{name}'] = disk_info(f'/dev/{name}', *positionals, **kwargs) def human_readable_size(bits, sizes=[{8 : 'b'}, {1024 : 'kb'}, {1024 : 'mb'}, {1024 : 'gb'}, {1024 : 'tb'}, {1024 : 'zb?'}]): # Not needed if using lsblk. @@ -567,12 +579,12 @@ def format_disk(drive, start='512MiB', end='100%', emulate=False): print(f'[N] Setting up {drive}.') # dd if=/dev/random of=args['drive'] bs=4096 status=progress # https://github.com/dcantrell/pyparted would be nice, but isn't officially in the repo's #SadPanda - o = b''.join(sys_command(f'/usr/bin/parted -s {drive} mklabel gpt', emulate=emulate).exec()) - o = b''.join(sys_command(f'/usr/bin/parted -s {drive} mkpart primary FAT32 1MiB {start}', emulate=emulate).exec()) - o = b''.join(sys_command(f'/usr/bin/parted -s {drive} name 1 "EFI"', emulate=emulate).exec()) - o = b''.join(sys_command(f'/usr/bin/parted -s {drive} set 1 esp on', emulate=emulate).exec()) - o = b''.join(sys_command(f'/usr/bin/parted -s {drive} set 1 boot on', emulate=emulate).exec()) - o = b''.join(sys_command(f'/usr/bin/parted -s {drive} mkpart primary {start} {size}', emulate=emulate).exec()) + o = b''.join(sys_command(f'/usr/bin/parted -s {drive} mklabel gpt', emulate=emulate)) + o = b''.join(sys_command(f'/usr/bin/parted -s {drive} mkpart primary FAT32 1MiB {start}', emulate=emulate)) + o = b''.join(sys_command(f'/usr/bin/parted -s {drive} name 1 "EFI"', emulate=emulate)) + o = b''.join(sys_command(f'/usr/bin/parted -s {drive} set 1 esp on', emulate=emulate)) + o = b''.join(sys_command(f'/usr/bin/parted -s {drive} set 1 boot on', emulate=emulate)) + o = b''.join(sys_command(f'/usr/bin/parted -s {drive} mkpart primary {start} {size}', emulate=emulate)) # TODO: grab paritions after each parted/partition step instead of guessing which partiton is which later on. # Create one, grab partitions - dub that to "boot" or something. do the next partition, grab that and dub it "system".. or something.. # This "assumption" has bit me in the ass so many times now I've stoped counting.. Jerker is right.. Don't do it like this :P @@ -605,8 +617,7 @@ def get_application_instructions(target): instructions = grab_url_data('{}/applications/{}.json'.format(args['profiles-path'], target)).decode('UTF-8') print('[N] Found application instructions for: {}'.format(target)) except urllib.error.HTTPError: - print('[N] No instructions found for: {}'.format(target)) - print('[N] Trying local instructions under ./deployments/applications') + print('[N] Could not find remote instructions. yrying local instructions under ./deployments/applications') local_path = './deployments/applications' if os.path.isfile('./archinstall.py') else './archinstall/deployments/applications' # Dangerous assumption if os.path.isfile(f'{local_path}/{target}.json'): with open(f'{local_path}/{target}.json', 'r') as fh: @@ -614,6 +625,7 @@ def get_application_instructions(target): print('[N] Found local application instructions for: {}'.format(target)) else: + print('[N] No instructions found for: {}'.format(target)) return instructions try: @@ -625,14 +637,13 @@ def get_application_instructions(target): return instructions -def get_instructions(target): +def get_instructions(target, *positionals, **kwargs): instructions = oDict() try: instructions = grab_url_data('{}/{}.json'.format(args['profiles-path'], target)).decode('UTF-8') print('[N] Found net-deploy instructions called: {}'.format(target)) except urllib.error.HTTPError: - print('[N] No instructions found called: {}'.format(target)) - print('[N] Trying local instructions under ./deployments') + print('[N] Could not find remote instructions. Trying local instructions under ./deployments') local_path = './deployments' if os.path.isfile('./archinstall.py') else './archinstall/deployments' # Dangerous assumption if os.path.isfile(f'{local_path}/{target}.json'): with open(f'{local_path}/{target}.json', 'r') as fh: @@ -640,6 +651,7 @@ def get_instructions(target): print('[N] Found local instructions called: {}'.format(target)) else: + print('[N] No instructions found called: {}'.format(target)) return instructions try: @@ -671,7 +683,7 @@ def merge_dicts(d1, d2, before=True, overwrite=False): def random_string(l): return ''.join(choice(ascii_uppercase + ascii_lowercase + digits) for i in range(l)) -def setup_args_defaults(args): +def setup_args_defaults(args, interactive=True): if not 'size' in args: args['size'] = '100%' if not 'start' in args: args['start'] = '513MiB' if not 'pwfile' in args: args['pwfile'] = '/tmp/diskpw' @@ -688,18 +700,21 @@ def setup_args_defaults(args): if not 'ignore-rerun' in args: args['ignore-rerun'] = False if not 'localtime' in args: args['localtime'] = 'Europe/Stockholm' if args['country'] == 'SE' else 'GMT+0' # TODO: Arbitrary for now if not 'drive' in args: - drives = sorted(list(harddrives.keys())) - if len(drives) > 1 and 'force' not in args and ('default' in args and 'first-drive' not in args): - for index, drive in enumerate(drives): - print(f'{index}: {drive} ({harddrives[drive]})') - drive = input('Select one of the above disks (by number): ') - if not drive.isdigit(): - raise KeyError("Multiple disks found, --drive=/dev/X not specified (or --force/--first-drive)") - drives = [drives[int(drive)]] # Make sure only the selected drive is in the list of options - args['drive'] = drives[0] # First drive found + if interactive: + drives = sorted(list(harddrives.keys())) + if len(drives) > 1 and 'force' not in args and ('default' in args and 'first-drive' not in args): + for index, drive in enumerate(drives): + print(f"{index}: {drive} ({harddrives[drive]['size'], harddrives[drive]['fstype'], harddrives[drive]['label']})") + drive = input('Select one of the above disks (by number): ') + if not drive.isdigit(): + raise KeyError("Multiple disks found, --drive=/dev/X not specified (or --force/--first-drive)") + drives = [drives[int(drive)]] # Make sure only the selected drive is in the list of options + args['drive'] = drives[0] # First drive found + else: + args['drive'] = None rerun = args['ignore-rerun'] - if args['drive'][0] != '/': + if args['drive'] and args['drive'][0] != '/': ## Remap the selected UUID to the device to be formatted. drive = get_drive_from_uuid(args['drive']) if not drive: @@ -713,15 +728,15 @@ def setup_args_defaults(args): args['drive'] = drive return args -def load_automatic_instructions(): +def load_automatic_instructions(*args, **kwargs): instructions = oDict() - if get_default_gateway_linux(): + if get_default_gateway_linux(*args, **kwargs): locmac = get_local_MACs() if not len(locmac): print('[N] No network interfaces - No net deploy.') else: for mac in locmac: - instructions = get_instructions(mac) + instructions = get_instructions(mac, *positionals, **kwargs) if 'args' in instructions: ## == Recursively fetch instructions if "include" is found under {args: ...} @@ -731,9 +746,9 @@ def load_automatic_instructions(): del(instructions['args']['include']) if type(includes) in (dict, list): for include in includes: - instructions = merge_dicts(instructions, get_instructions(include), before=True) + instructions = merge_dicts(instructions, get_instructions(include, *positionals, **kwargs), before=True) else: - instructions = merge_dicts(instructions, get_instructions(includes), before=True) + instructions = merge_dicts(instructions, get_instructions(includes, *positionals, **kwargs), before=True) ## Update arguments if we found any for key, val in instructions['args'].items(): @@ -799,7 +814,7 @@ if __name__ == '__main__': if not args['rerun'] or args['ignore-rerun']: for i in range(5, 0, -1): print(f'Formatting {args["drive"]} in {i}...') - sleep(1) + time.sleep(1) close_disks() format_disk(args['drive'], start=args['start'], end=args['size']) @@ -816,7 +831,7 @@ if __name__ == '__main__': print(json.dumps(args['paritions'][part_name], indent=4)) if not args['rerun'] or args['ignore-rerun']: - o = b''.join(sys_command('/usr/bin/mkfs.vfat -F32 {drive}{partition_1}'.format(**args)).exec()) + o = b''.join(sys_command('/usr/bin/mkfs.vfat -F32 {drive}{partition_1}'.format(**args))) if (b'mkfs.fat' not in o and b'mkfs.vfat' not in o) or b'command not found' in o: print('[E] Could not setup {drive}{partition_1}'.format(**args), o) exit(1) @@ -824,34 +839,34 @@ if __name__ == '__main__': # "--cipher sha512" breaks the shit. # TODO: --use-random instead of --use-urandom print('[N] Adding encryption to {drive}{partition_2}.'.format(**args)) - o = b''.join(sys_command('/usr/bin/cryptsetup -q -v --type luks2 --pbkdf argon2i --hash sha512 --key-size 512 --iter-time 10000 --key-file {pwfile} --use-urandom luksFormat {drive}{partition_2}'.format(**args)).exec()) + o = b''.join(sys_command('/usr/bin/cryptsetup -q -v --type luks2 --pbkdf argon2i --hash sha512 --key-size 512 --iter-time 10000 --key-file {pwfile} --use-urandom luksFormat {drive}{partition_2}'.format(**args))) if not b'Command successful.' in o: print('[E] Failed to setup disk encryption.', o) exit(1) - o = b''.join(sys_command('/usr/bin/file /dev/mapper/luksdev').exec()) # /dev/dm-0 + o = b''.join(sys_command('/usr/bin/file /dev/mapper/luksdev')) # /dev/dm-0 if b'cannot open' in o: - o = b''.join(sys_command('/usr/bin/cryptsetup open {drive}{partition_2} luksdev --key-file {pwfile} --type luks2'.format(**args)).exec()) - o = b''.join(sys_command('/usr/bin/file /dev/mapper/luksdev').exec()) # /dev/dm-0 + o = b''.join(sys_command('/usr/bin/cryptsetup open {drive}{partition_2} luksdev --key-file {pwfile} --type luks2'.format(**args))) + o = b''.join(sys_command('/usr/bin/file /dev/mapper/luksdev')) # /dev/dm-0 if b'cannot open' in o: print('[E] Could not open encrypted device.', o) exit(1) if not args['rerun'] or args['ignore-rerun']: print('[N] Creating btrfs filesystem inside {drive}{partition_2}'.format(**args)) - o = b''.join(sys_command('/usr/bin/mkfs.btrfs -f /dev/mapper/luksdev').exec()) + o = b''.join(sys_command('/usr/bin/mkfs.btrfs -f /dev/mapper/luksdev')) if not b'UUID' in o: print('[E] Could not setup btrfs filesystem.', o) exit(1) o = simple_command('/usr/bin/mount | /usr/bin/grep /mnt') # /dev/dm-0 if len(o) <= 0: - o = b''.join(sys_command('/usr/bin/mount /dev/mapper/luksdev /mnt').exec()) + o = b''.join(sys_command('/usr/bin/mount /dev/mapper/luksdev /mnt')) os.makedirs('/mnt/boot', exist_ok=True) o = simple_command('/usr/bin/mount | /usr/bin/grep /mnt/boot') # /dev/dm-0 if len(o) <= 0: - o = b''.join(sys_command('/usr/bin/mount {drive}{partition_1} /mnt/boot'.format(**args)).exec()) + o = b''.join(sys_command('/usr/bin/mount {drive}{partition_1} /mnt/boot'.format(**args))) if 'mirrors' in args and args['mirrors'] and 'country' in args and get_default_gateway_linux(): print('[N] Reordering mirrors.') @@ -899,7 +914,7 @@ if __name__ == '__main__': print('[-] Options: {}'.format(opts)) #print('[N] Command: {} ({})'.format(raw_command, opts)) - o = b''.join(sys_command('{c}'.format(c=command), opts).exec()) + o = b''.join(sys_command('{c}'.format(c=command), opts)) if type(conf[title][raw_command]) == bytes and len(conf[title][raw_command]) and not conf[title][raw_command] in b''.join(o): print('[W] Prerequisit step failed: {}'.format(b''.join(o).decode('UTF-8'))) #print(o) @@ -908,28 +923,28 @@ if __name__ == '__main__': print('[N] Straping in packages.') if args['aur-support']: args['packages'] += ' git' - o = b''.join(sys_command('/usr/bin/pacman -Syy').exec()) - o = b''.join(sys_command('/usr/bin/pacstrap /mnt base base-devel linux linux-firmware btrfs-progs efibootmgr nano wpa_supplicant dialog {packages}'.format(**args)).exec()) + o = b''.join(sys_command('/usr/bin/pacman -Syy')) + o = b''.join(sys_command('/usr/bin/pacstrap /mnt base base-devel linux linux-firmware btrfs-progs efibootmgr nano wpa_supplicant dialog {packages}'.format(**args))) if not os.path.isdir('/mnt/etc'): # TODO: This might not be the most long term stable thing to rely on... print('[E] Failed to strap in packages', o) exit(1) if not args['rerun'] or rerun: - o = b''.join(sys_command('/usr/bin/genfstab -pU /mnt >> /mnt/etc/fstab').exec()) + o = b''.join(sys_command('/usr/bin/genfstab -pU /mnt >> /mnt/etc/fstab')) with open('/mnt/etc/fstab', 'a') as fstab: fstab.write('\ntmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0\n') # Redundant \n at the start? who knoes? - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt rm -f /etc/localtime').exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt ln -s /usr/share/zoneinfo/{localtime} /etc/localtime'.format(**args)).exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt hwclock --hctosys --localtime').exec()) - #o = sys_command('arch-chroot /mnt echo "{hostname}" > /etc/hostname'.format(**args)).exec() - #o = sys_command("arch-chroot /mnt sed -i 's/#\(en_US\.UTF-8\)/\1/' /etc/locale.gen").exec() - o = b''.join(sys_command("/usr/bin/arch-chroot /mnt sh -c \"echo '{hostname}' > /etc/hostname\"".format(**args)).exec()) - o = b''.join(sys_command("/usr/bin/arch-chroot /mnt sh -c \"echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen\"").exec()) - o = b''.join(sys_command("/usr/bin/arch-chroot /mnt sh -c \"echo 'LANG=en_US.UTF-8' > /etc/locale.conf\"").exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt locale-gen').exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt chmod 700 /root').exec()) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt rm -f /etc/localtime')) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt ln -s /usr/share/zoneinfo/{localtime} /etc/localtime'.format(**args))) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt hwclock --hctosys --localtime')) + #o = sys_command('arch-chroot /mnt echo "{hostname}" > /etc/hostname'.format(**args)) + #o = sys_command("arch-chroot /mnt sed -i 's/#\(en_US\.UTF-8\)/\1/' /etc/locale.gen") + o = b''.join(sys_command("/usr/bin/arch-chroot /mnt sh -c \"echo '{hostname}' > /etc/hostname\"".format(**args))) + o = b''.join(sys_command("/usr/bin/arch-chroot /mnt sh -c \"echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen\"")) + o = b''.join(sys_command("/usr/bin/arch-chroot /mnt sh -c \"echo 'LANG=en_US.UTF-8' > /etc/locale.conf\"")) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt locale-gen')) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt chmod 700 /root')) with open('/mnt/etc/mkinitcpio.conf', 'w') as mkinit: ## TODO: Don't replace it, in case some update in the future actually adds something. @@ -937,9 +952,9 @@ if __name__ == '__main__': mkinit.write('BINARIES=(/usr/bin/btrfs)\n') mkinit.write('FILES=()\n') mkinit.write('HOOKS=(base udev autodetect modconf block encrypt filesystems keyboard fsck)\n') - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt mkinitcpio -p linux').exec()) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt mkinitcpio -p linux')) ## WORKAROUND: https://github.com/systemd/systemd/issues/13603#issuecomment-552246188 - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt bootctl --no-variables --path=/boot install').exec()) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt bootctl --no-variables --path=/boot install')) with open('/mnt/boot/loader/loader.conf', 'w') as loader: loader.write('default arch\n') @@ -947,7 +962,7 @@ if __name__ == '__main__': ## For some reason, blkid and /dev/disk/by-uuid are not getting along well. ## And blkid is wrong in terms of LUKS. - #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').exec().strip() + #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip() UUID = simple_command("ls -l /dev/disk/by-uuid/ | grep {basename}{partition_2} | awk '{{print $9}}'".format(basename=os.path.basename(args['drive']), **args)).decode('UTF-8').strip() with open('/mnt/boot/loader/entries/arch.conf', 'w') as entry: entry.write('title Arch Linux\n') @@ -957,16 +972,16 @@ if __name__ == '__main__': if args['aur-support']: print('[N] AUR support demanded, building "yay" before running POST steps.') - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "useradd -m -G wheel aibuilder"').exec()) - o = b''.join(sys_command("/usr/bin/sed -i 's/# %wheel ALL=(ALL) NO/%wheel ALL=(ALL) NO/' /mnt/etc/sudoers").exec()) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "useradd -m -G wheel aibuilder"')) + o = b''.join(sys_command("/usr/bin/sed -i 's/# %wheel ALL=(ALL) NO/%wheel ALL=(ALL) NO/' /mnt/etc/sudoers")) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "su - aibuilder -c \\"(cd /home/aibuilder; git clone https://aur.archlinux.org/yay.git)\\""').exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "chown -R aibuilder.aibuilder /home/aibuilder/yay"').exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "su - aibuilder -c \\"(cd /home/aibuilder/yay; makepkg -si --noconfirm)\\" >/dev/null"').exec()) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "su - aibuilder -c \\"(cd /home/aibuilder; git clone https://aur.archlinux.org/yay.git)\\""')) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "chown -R aibuilder.aibuilder /home/aibuilder/yay"')) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "su - aibuilder -c \\"(cd /home/aibuilder/yay; makepkg -si --noconfirm)\\" >/dev/null"')) ## Do not remove aibuilder just yet, can be used later for aur packages. - #o = b''.join(sys_command('/usr/bin/sed -i \'s/%wheel ALL=(ALL) NO/# %wheel ALL=(ALL) NO/\' /mnt/etc/sudoers').exec()) - #o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "userdel aibuilder"').exec()) - #o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "rm -rf /home/aibuilder"').exec()) + #o = b''.join(sys_command('/usr/bin/sed -i \'s/%wheel ALL=(ALL) NO/# %wheel ALL=(ALL) NO/\' /mnt/etc/sudoers')) + #o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "userdel aibuilder"')) + #o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "rm -rf /home/aibuilder"')) print('[N] AUR support added. use "yay -Syy --noconfirm <package>" to deploy in POST.') conf = {} @@ -1057,20 +1072,20 @@ if __name__ == '__main__': bytes(f'login:', 'UTF-8') : b'root\n', #b'Password:' : bytes(args['password']+'\n', 'UTF-8'), bytes(f'[root@{args["hostname"]} ~]#', 'UTF-8') : bytes(command+'\n', 'UTF-8'), - }, **opts}).exec()) + }, **opts})) ## Not needed anymore: And cleanup after out selves.. Don't want to leave any residue.. # os.remove('/mnt/etc/systemd/system/console-getty.service.d/override.conf') else: - o = b''.join(sys_command('/usr/bin/systemd-nspawn -D /mnt --machine temporary {c}'.format(c=command), opts=opts).exec()) + o = b''.join(sys_command('/usr/bin/systemd-nspawn -D /mnt --machine temporary {c}'.format(c=command), opts=opts)) if type(conf[title][raw_command]) == bytes and len(conf[title][raw_command]) and not conf[title][raw_command] in o: print('[W] Post install command failed: {}'.format(o.decode('UTF-8'))) #print(o) if args['aur-support']: - o = b''.join(sys_command('/usr/bin/sed -i \'s/%wheel ALL=(ALL) NO/# %wheel ALL=(ALL) NO/\' /mnt/etc/sudoers').exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "userdel aibuilder"').exec()) - o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "rm -rf /home/aibuilder"').exec()) + o = b''.join(sys_command('/usr/bin/sed -i \'s/%wheel ALL=(ALL) NO/# %wheel ALL=(ALL) NO/\' /mnt/etc/sudoers')) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "userdel aibuilder"')) + o = b''.join(sys_command('/usr/bin/arch-chroot /mnt sh -c "rm -rf /home/aibuilder"')) ## == Passwords # o = sys_command('arch-chroot /mnt usermod --password {} root'.format(args['password'])) diff --git a/test_archinstall.py b/test_archinstall.py new file mode 100644 index 00000000..3b5ddcae --- /dev/null +++ b/test_archinstall.py @@ -0,0 +1,13 @@ +import json +import archinstall + +archinstall.update_drive_list(emulate=False) +archinstall.setup_args_defaults(archinstall.args, interactive=False) +#for drive in archinstall.harddrives: +# print(drive, archinstall.human_disk_info(drive)) + +instructions = archinstall.load_automatic_instructions(emulate=False) +profile_instructions = archinstall.get_instructions('workstation', emulate=False) +profile_instructions = archinstall.merge_in_includes(profile_instructions, emulate=False) + +print(json.dumps(archinstall.args, indent=4))
\ No newline at end of file |