From 68adb3108f8111b1be434bf63c03562d72bbbe6f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 25 Jan 2021 10:31:02 +0100 Subject: Created an embryo for hardware detection. Supports detecting WiFi and UEFI. This fixes #44 and is a start for #82. --- archinstall/lib/hardware.py | 10 ++++++++++ archinstall/lib/networking.py | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 archinstall/lib/hardware.py (limited to 'archinstall/lib') diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py new file mode 100644 index 00000000..c9483919 --- /dev/null +++ b/archinstall/lib/hardware.py @@ -0,0 +1,10 @@ +import os +from .networking import list_interfaces, enrichIfaceTypes + +def hasWifi(): + if 'WIRELESS' in enrichIfaceTypes(list_interfaces().values()).values(): + return True + return False + +def hasUEFI(): + return os.path.isdir('/sys/firmware/efi') \ No newline at end of file diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index 4829a58b..b69a43db 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -1,9 +1,9 @@ +import os import fcntl import socket import struct from collections import OrderedDict - def getHwAddr(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname, 'utf-8')[:15])) @@ -19,5 +19,22 @@ def list_interfaces(skip_loopback=True): interfaces[mac] = iface return interfaces +def enrichIfaceTypes(interfaces :dict): + result = {} + for iface in interfaces: + if os.path.isdir(f"/sys/class/net/{iface}/bridge/"): + result[iface] = 'BRIDGE' + elif os.path.isfile(f"/sys/class/net/{iface}/tun_flags"): + # ethtool -i {iface} + result[iface] = 'TUN/TAP' + elif os.path.isdir(f"/sys/class/net/{iface}/device"): + if os.path.isdir(f"/sys/class/net/{iface}/wireless/"): + result[iface] = 'WIRELESS' + else: + result[iface] = 'PHYSICAL' + else: + result[iface] = 'UNKNOWN' + return result + def get_interface_from_mac(mac): return list_interfaces().get(mac.lower(), None) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 7358dc5a03b0652132ca9debba2aeb43f3610f2b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 25 Jan 2021 10:42:02 +0100 Subject: Added some basic/crude graphics checks in hardware.py --- .gitignore | 1 + archinstall/lib/hardware.py | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'archinstall/lib') diff --git a/.gitignore b/.gitignore index aebb999d..dc75bed8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ SAFETY_LOCK **/**.network **/**.target **/**.qcow2 +**/test.py diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py index c9483919..93eb560f 100644 --- a/archinstall/lib/hardware.py +++ b/archinstall/lib/hardware.py @@ -1,4 +1,5 @@ import os +from .general import sys_command from .networking import list_interfaces, enrichIfaceTypes def hasWifi(): @@ -7,4 +8,29 @@ def hasWifi(): return False def hasUEFI(): - return os.path.isdir('/sys/firmware/efi') \ No newline at end of file + return os.path.isdir('/sys/firmware/efi') + +def graphicsDevices(): + cards = {} + for line in sys_command(f"lspci"): + if b' VGA ' in line: + _, identifier = line.split(b': ',1) + cards[identifier.strip().lower().decode('UTF-8')] = line + return cards + +def hasNvidiaGraphics(): + if [x for x in graphicsDevices() if 'nvidia' in x]: + return True + return False + +def hasAmdGraphics(): + if [x for x in graphicsDevices() if 'amd' in x]: + return True + return False + +def hasIntelGraphics(): + if [x for x in graphicsDevices() if 'intel' in x]: + return True + return False + +# TODO: Add more identifiers \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 3a16d156b946e5a6282b8c364e406cf0b4adea44 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 25 Jan 2021 12:38:11 +0100 Subject: Added an embryo for listing wireless networks. --- archinstall/lib/exceptions.py | 2 ++ archinstall/lib/networking.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index 2a1cae14..84e6a766 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -7,4 +7,6 @@ class ProfileError(BaseException): class SysCallError(BaseException): pass class ProfileNotFound(BaseException): + pass +class HardwareIncompatibilityError(BaseException): pass \ No newline at end of file diff --git a/archinstall/lib/networking.py b/archinstall/lib/networking.py index b69a43db..882bcff3 100644 --- a/archinstall/lib/networking.py +++ b/archinstall/lib/networking.py @@ -3,6 +3,9 @@ import fcntl import socket import struct from collections import OrderedDict +from .exceptions import * +from .general import sys_command +from .storage import storage def getHwAddr(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -37,4 +40,29 @@ def enrichIfaceTypes(interfaces :dict): return result def get_interface_from_mac(mac): - return list_interfaces().get(mac.lower(), None) \ No newline at end of file + return list_interfaces().get(mac.lower(), None) + +def wirelessScan(interface): + interfaces = enrichIfaceTypes(list_interfaces().values()) + if interfaces[interface] != 'WIRELESS': + raise HardwareIncompatibilityError(f"Interface {interface} is not a wireless interface: {interfaces}") + + sys_command(f"iwctl station {interface} scan") + + if not '_WIFI' in storage: + storage['_WIFI'] = {} + if not interface in storage['_WIFI']: + storage['_WIFI'][interface] = {} + + storage['_WIFI'][interface]['scanning'] = True + +# TOOD: Full WiFi experience might get evolved in the future, pausing for now 2021-01-25 +def getWirelessNetworks(interface): + # TODO: Make this oneliner pritter to check if the interface is scanning or not. + if not '_WIFI' in storage or interface not in storage['_WIFI'] or storage['_WIFI'][interface].get('scanning', False) is False: + import time + wirelessScan(interface) + time.sleep(5) + + for line in sys_command(f"iwctl station {interface} get-networks"): + print(line) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1c80a893acfb97859dd6c0f61a2cf74c03958595 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 25 Jan 2021 15:34:35 +0100 Subject: Adding copy mode for #95 (#82). I wouldn't say this is a hacky way of doing it, but using a string as identifier is the only way I can think of currently in guided.py. When user is prompted to select a interface to configure for networking, there's now a zero-option to copy existing ISO configuration to the install medium. This enables advance configuration prior to running the installer - and simply copy it straight over to the install medium. Two requirements: 1: That iwd is used for wifi configuration and config for passwords etc are stored in /var/lib/iwd 2: That systemd-networkd is used to configure networking/IP/DHCP as anything under /etc/systemd/networkd/* is copied over. --- archinstall/lib/installer.py | 43 ++++++++++++++++++++++++++++++++++++++++++- examples/guided.py | 17 +++++++++++++---- 2 files changed, 55 insertions(+), 5 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 8c22b51f..51540060 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,4 @@ -import os, stat, time +import os, stat, time, shutil from .exceptions import * from .disk import * @@ -48,6 +48,7 @@ class Installer(): } self.base_packages = base_packages.split(' ') + self.post_base_install = [] storage['session'] = self self.partition = partition @@ -182,6 +183,40 @@ class Installer(): with open(f"{self.mountpoint}/etc/systemd/network/10-{nic}.network", "a") as netconf: netconf.write(str(conf)) + def copy_network_config(self, enable_services=False): + # Copy (if any) iwd password and config files + if os.path.isdir('/var/lib/iwd/'): + if (psk_files := glob.glob('/var/lib/iwd/*.psk')): + if not os.path.isdir(f"{self.mountpoint}/var/lib/iwd"): + os.makedirs(f"{self.mountpoint}/var/lib/iwd") + + self.base_packages.append('iwd') + + + if enable_services and self.helper_flags.get('base', False) is False: + # This function will be called after minimal_installation() + # as a hook for post-installs. This hook is only needed if + # base is not installed yet. + def post_install_enable_iwd_service(*args, **kwargs): + self.enable_service('iwd') + + self.post_base_install.append(post_install_enable_iwd_service) + elif enable_services and self.helper_flags.get('base', False) is True: + self.enable_service('iwd') + + for psk in psk_files: + shutil.copy2(psk, f"{self.mountpoint}/var/lib/iwd/{os.path.basename(psk)}") + + # Copy (if any) systemd-networkd config files + if (netconfigurations := glob.glob('/etc/systemd/network/*')): + if not os.path.isdir(f"{self.mountpoint}/etc/systemd/network/"): + os.makedirs(f"{self.mountpoint}/etc/systemd/network/") + + for netconf_file in netconfigurations: + shutil.copy2(netconf_file, f"{self.mountpoint}/etc/systemd/network/{os.path.basename(netconf_file)}") + + return True + def minimal_installation(self): ## Add nessecary packages if encrypting the drive ## (encrypted partitions default to btrfs for now, so we need btrfs-progs) @@ -220,6 +255,12 @@ class Installer(): sys_command(f'/usr/bin/arch-chroot {self.mountpoint} mkinitcpio -p linux') self.helper_flags['base'] = True + + # Run registered post-install hooks + for function in self.post_base_install: + self.log(f"Running post-installation hook: {function}", level=LOG_LEVELS.Info) + function(self) + return True def add_bootloader(self, bootloader='systemd-bootctl'): diff --git a/examples/guided.py b/examples/guided.py index 7726d5b9..ab284721 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -49,11 +49,18 @@ def perform_installation(device, boot_partition, language, mirrors): installation.set_keyboard_language(language) installation.add_bootloader() - if archinstall.storage['_guided']['network']: + # If user selected to copy the current ISO network configuration + # Perform a copy of the config + if archinstall.storage['_guided']['network'] == 'Copy ISO network configuration to installation': + installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. + + # Otherwise, if a interface was selected, configure that interface + elif archinstall.storage['_guided']['network']: installation.configure_nic(**archinstall.storage['_guided']['network']) installation.enable_service('systemd-networkd') installation.enable_service('systemd-resolved') + if archinstall.storage['_guided']['packages'] and archinstall.storage['_guided']['packages'][0] != '': installation.add_additional_packages(archinstall.storage['_guided']['packages']) @@ -188,11 +195,12 @@ while 1: # Optionally configure one network interface. #while 1: -interfaces = archinstall.list_interfaces() # {MAC: Ifname} +# {MAC: Ifname} +interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **archinstall.list_interfaces()} archinstall.storage['_guided']['network'] = None nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") -if nic: +if nic and nic != 'Copy ISO network configuration to installation': mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': while 1: @@ -217,7 +225,8 @@ if nic: archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} else: archinstall.storage['_guided']['network'] = {'nic': nic} - +elif nic: + archinstall.storage['_guided']['network'] = nic print() print('This is your chosen configuration:') -- cgit v1.2.3-70-g09d2 From 405794d53f1f47e2a19a906dbdfa6ad39ea79c17 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 25 Jan 2021 15:39:27 +0100 Subject: Adding copy mode for #95 (#82). I wouldn't say this is a hacky way of doing it, but using a string as identifier is the only way I can think of currently in guided.py. When user is prompted to select a interface to configure for networking, there's now a zero-option to copy existing ISO configuration to the install medium. This enables advance configuration prior to running the installer - and simply copy it straight over to the install medium. Two requirements: 1: That iwd is used for wifi configuration and config for passwords etc are stored in /var/lib/iwd 2: That systemd-networkd is used to configure networking/IP/DHCP as anything under /etc/systemd/networkd/* is copied over. --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 51540060..c8cf40d0 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -183,7 +183,7 @@ class Installer(): with open(f"{self.mountpoint}/etc/systemd/network/10-{nic}.network", "a") as netconf: netconf.write(str(conf)) - def copy_network_config(self, enable_services=False): + def copy_ISO_network_config(self, enable_services=False): # Copy (if any) iwd password and config files if os.path.isdir('/var/lib/iwd/'): if (psk_files := glob.glob('/var/lib/iwd/*.psk')): -- cgit v1.2.3-70-g09d2 From a3d9ad9f3f48c9bd06edb6c1ec58b55ac4bb6741 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 26 Jan 2021 00:11:17 +0100 Subject: Corrected a error in the installation of iwd. The package was added to base_packages, which is never installed if the installer has already finished installing the base packages before this function was called. copy_ISO_network_config() there for now properly checks if the installation is complete and if so, simply straps in the package. Otherwise adds it to the base packages and waits for the base to roll through. --- archinstall/lib/installer.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index c8cf40d0..e1a37f32 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -190,20 +190,24 @@ class Installer(): if not os.path.isdir(f"{self.mountpoint}/var/lib/iwd"): os.makedirs(f"{self.mountpoint}/var/lib/iwd") - self.base_packages.append('iwd') - - if enable_services and self.helper_flags.get('base', False) is False: - # This function will be called after minimal_installation() - # as a hook for post-installs. This hook is only needed if - # base is not installed yet. - def post_install_enable_iwd_service(*args, **kwargs): + if enable_services: + # If we haven't installed the base yet (function called pre-maturely) + if self.helper_flags.get('base', False) is False: + self.base_packages.append('iwd') + # This function will be called after minimal_installation() + # as a hook for post-installs. This hook is only needed if + # base is not installed yet. + def post_install_enable_iwd_service(*args, **kwargs): + self.enable_service('iwd') + + self.post_base_install.append(post_install_enable_iwd_service) + # Otherwise, we can go ahead and add the required package + # and enable it's service: + else: + self.pacstrap(self.base_packages) self.enable_service('iwd') - self.post_base_install.append(post_install_enable_iwd_service) - elif enable_services and self.helper_flags.get('base', False) is True: - self.enable_service('iwd') - for psk in psk_files: shutil.copy2(psk, f"{self.mountpoint}/var/lib/iwd/{os.path.basename(psk)}") -- cgit v1.2.3-70-g09d2 From 5bc878d58c5a86dde7d141d60289757d411c80ce Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 26 Jan 2021 00:13:40 +0100 Subject: Added enabling of systemd-networkd and systemd-resolvd in the copying of the ISO network configuration. --- archinstall/lib/installer.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index e1a37f32..d01cb882 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -200,6 +200,8 @@ class Installer(): # base is not installed yet. def post_install_enable_iwd_service(*args, **kwargs): self.enable_service('iwd') + self.enable_service('systemd-networkd') + self.enable_service('systemd-resolved') self.post_base_install.append(post_install_enable_iwd_service) # Otherwise, we can go ahead and add the required package @@ -207,6 +209,8 @@ class Installer(): else: self.pacstrap(self.base_packages) self.enable_service('iwd') + self.enable_service('systemd-networkd') + self.enable_service('systemd-resolved') for psk in psk_files: shutil.copy2(psk, f"{self.mountpoint}/var/lib/iwd/{os.path.basename(psk)}") -- cgit v1.2.3-70-g09d2 From 3db8e3abbc8133ecb1875465f5cb3a1ea8557e86 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 26 Jan 2021 00:22:10 +0100 Subject: Error in copy paste of function name. --- archinstall/lib/installer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'archinstall/lib') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index d01cb882..c9d7e9cc 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -190,7 +190,6 @@ class Installer(): if not os.path.isdir(f"{self.mountpoint}/var/lib/iwd"): os.makedirs(f"{self.mountpoint}/var/lib/iwd") - if enable_services: # If we haven't installed the base yet (function called pre-maturely) if self.helper_flags.get('base', False) is False: @@ -207,7 +206,7 @@ class Installer(): # Otherwise, we can go ahead and add the required package # and enable it's service: else: - self.pacstrap(self.base_packages) + self.pacstrap('iwd') self.enable_service('iwd') self.enable_service('systemd-networkd') self.enable_service('systemd-resolved') -- cgit v1.2.3-70-g09d2