def configure_system(self): """ Final install steps Set clock, language, timezone Run mkinitcpio Populate pacman keyring Setup systemd services ... and more """ self.queue_event('pulse', 'start') self.queue_event('info', _("Configuring your new system")) # This mounts (binds) /dev and others to /DEST_DIR/dev and others chroot.mount_special_dirs(DEST_DIR) self.auto_fstab() logging.debug("fstab file generated.") # If SSD was detected copy udev rule for deadline scheduler if self.ssd: self.set_scheduler() logging.debug("SSD udev rule copied successfully") # Copy configured networks in Live medium to target system if self.network_manager == 'NetworkManager': self.copy_network_config() if self.desktop == "base": # Setup systemd-networkd for systems that won't use the # networkmanager or connman daemons (atm it's just base install) # Enable systemd_networkd services # See: https://github.com/Antergos/Cnchi/issues/332#issuecomment-108745026 self.enable_services(["systemd-networkd", "systemd-resolved"]) # Setup systemd_networkd # TODO: Ask user for SSID and passphrase if a wireless link is found # (should this be done here or inside systemd_networkd.setup() ?) from installation import systemd_networkd systemd_networkd.setup() logging.debug("Network configuration done.") # Copy mirror list mirrorlist_src_path = '/etc/pacman.d/mirrorlist' mirrorlist_dst_path = os.path.join(DEST_DIR, 'etc/pacman.d/mirrorlist') try: shutil.copy2(mirrorlist_src_path, mirrorlist_dst_path) logging.debug("Mirror list copied.") except FileNotFoundError: logging.error("Can't copy mirrorlist file. File %s not found", mirrorlist_src_path) except FileExistsError: logging.warning("File %s already exists.", mirrorlist_dst_path) # Add Antergos repo to /etc/pacman.conf self.update_pacman_conf() logging.debug("pacman.conf has been created successfully") # Enable some useful services services = [] if self.desktop != "base": # In base there's no desktop manager ;) services.append(self.desktop_manager) # In base we use systemd-networkd (setup already done above) services.append(self.network_manager) services.extend(["ModemManager", "haveged"]) self.enable_services(services) # Enable timesyncd service if self.settings.get("use_timesyncd"): timesyncd_path = os.path.join(DEST_DIR, "etc/systemd/timesyncd.conf") with open(timesyncd_path, 'w') as timesyncd: timesyncd.write("[Time]\n") timesyncd.write("NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org\n") timesyncd.write("FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org\n") chroot_run(['timedatectl', 'set-ntp', 'true']) # Set timezone zoneinfo_path = os.path.join("/usr/share/zoneinfo", self.settings.get("timezone_zone")) chroot_run(['ln', '-s', zoneinfo_path, "/etc/localtime"]) logging.debug("Timezone set.") # Wait FOREVER until the user sets his params # FIXME: We can wait here forever! while self.settings.get('user_info_done') is False: # Wait five seconds and try again time.sleep(5) # Set user parameters username = self.settings.get('username') fullname = self.settings.get('fullname') password = self.settings.get('password') hostname = self.settings.get('hostname') sudoers_dir = os.path.join(DEST_DIR, "etc/sudoers.d") if not os.path.exists(sudoers_dir): os.mkdir(sudoers_dir, 0o710) sudoers_path = os.path.join(sudoers_dir, "10-installer") try: with open(sudoers_path, "w") as sudoers: sudoers.write('{0} ALL=(ALL) ALL\n'.format(username)) os.chmod(sudoers_path, 0o440) logging.debug("Sudo configuration for user %s done.", username) except IOError as io_error: # Do not fail if can't write 10-installer file. Something bad must be happening, though. logging.error(io_error) # Configure detected hardware # NOTE: Because hardware can need extra repos, this code must run # always after having called the update_pacman_conf method if self.hardware_install: try: logging.debug("Running hardware drivers post-install jobs...") self.hardware_install.post_install(DEST_DIR) except Exception as general_error: logging.error("Unknown error in hardware module. Output: %s", general_error) # Setup user default_groups = 'lp,video,network,storage,wheel,audio' if self.vbox: # Why there is no vboxusers group? Add it ourselves. chroot_run(['groupadd', 'vboxusers']) default_groups += ',vboxusers,vboxsf' self.enable_services(["vboxservice"]) if self.settings.get('require_password') is False: # Prepare system for autologin. LightDM needs the user to be in the autologin group. chroot_run(['groupadd', 'autologin']) default_groups += ',autologin' cmd = ['useradd', '-m', '-s', '/bin/bash', '-g', 'users', '-G', default_groups, username] chroot_run(cmd) logging.debug("User %s added.", username) self.change_user_password(username, password) cmd = ['chfn', '-f', fullname, username] chroot_run(cmd) cmd = ['chown', '-R', '{0}:users'.format(username), os.path.join("/home", username)] chroot_run(cmd) hostname_path = os.path.join(DEST_DIR, "etc/hostname") if not os.path.exists(hostname_path): with open(hostname_path, "w") as hostname_file: hostname_file.write(hostname) logging.debug("Hostname set to %s", hostname) # User password is the root password self.change_user_password('root', password) logging.debug("Set the same password to root.") # Generate locales locale = self.settings.get("locale") self.queue_event('info', _("Generating locales...")) self.uncomment_locale_gen(locale) chroot_run(['locale-gen']) locale_conf_path = os.path.join(DEST_DIR, "etc/locale.conf") with open(locale_conf_path, "w") as locale_conf: locale_conf.write('LANG={0}\n'.format(locale)) locale_conf.write('LC_COLLATE={0}\n'.format(locale)) # environment_path = os.path.join(DEST_DIR, "etc/environment") # with open(environment_path, "w") as environment: # environment.write('LANG={0}\n'.format(locale)) self.queue_event('info', _("Adjusting hardware clock...")) self.auto_timesetting() self.queue_event('info', _("Configuring keymap...")) keyboard_layout = self.settings.get("keyboard_layout") keyboard_variant = self.settings.get("keyboard_variant") if self.desktop != "base": # Set /etc/X11/xorg.conf.d/00-keyboard.conf for the xkblayout logging.debug("Set /etc/X11/xorg.conf.d/00-keyboard.conf for the xkblayout") xorg_conf_dir = os.path.join(DEST_DIR, "etc/X11/xorg.conf.d") if not os.path.exists(xorg_conf_dir): os.mkdir(xorg_conf_dir, 0o755) xorg_conf_xkb_path = os.path.join(xorg_conf_dir, "00-keyboard.conf") try: with open(xorg_conf_xkb_path, "w") as xorg_conf_xkb: xorg_conf_xkb.write( "# Read and parsed by systemd-localed. It's probably wise not to edit this file\n") xorg_conf_xkb.write('# manually too freely.\n') xorg_conf_xkb.write('Section "InputClass"\n') xorg_conf_xkb.write(' Identifier "system-keyboard"\n') xorg_conf_xkb.write(' MatchIsKeyboard "on"\n') xorg_conf_xkb.write(' Option "XkbLayout" "{0}"\n'.format(keyboard_layout)) if keyboard_variant and len(keyboard_variant) > 0: xorg_conf_xkb.write(' Option "XkbVariant" "{0}"\n'.format(keyboard_variant)) xorg_conf_xkb.write('EndSection\n') logging.debug("00-keyboard.conf written.") except IOError as io_error: # Do not fail if 00-keyboard.conf can't be created. # Something bad must be happening, though. logging.error(io_error) # Set vconsole.conf for console keymap if keyboard_layout == "gb": # The keyboard layout for Great Britain is "uk" in the cli and # "gb" (not uk) in X, just to make things more complicated. keyboard_layout_cli = "uk" else: keyboard_layout_cli = keyboard_layout vconsole_path = os.path.join(DEST_DIR, "etc/vconsole.conf") with open(vconsole_path, 'w') as vconsole: vconsole.write("KEYMAP={0}\n".format(keyboard_layout_cli)) # Install configs for root cmd = ['cp', '-av', '/etc/skel/.', '/root/'] chroot_run(cmd) self.queue_event('info', _("Configuring hardware...")) # Copy generated xorg.conf to target if os.path.exists("/etc/X11/xorg.conf"): shutil.copy2( "/etc/X11/xorg.conf", os.path.join(DEST_DIR, 'etc/X11/xorg.conf')) # Configure ALSA #self.alsa_mixer_setup() #logging.debug("Updated Alsa mixer settings") # Set pulse #if os.path.exists(os.path.join(DEST_DIR, "usr/bin/pulseaudio-ctl")): # chroot_run(['pulseaudio-ctl', 'normal']) # Set fluidsynth audio system (in our case, pulseaudio) self.set_fluidsynth() logging.debug("Updated fluidsynth configuration file") # Let's start without using hwdetect for mkinitcpio.conf. # It should work out of the box most of the time. # This way we don't have to fix deprecated hooks. # NOTE: With LUKS or LVM maybe we'll have to fix deprecated hooks. self.queue_event('info', _("Configuring System Startup...")) mkinitcpio.run(DEST_DIR, self.settings, self.mount_devices, self.blvm) logging.debug("Running Cnchi post-install script") # Call post-install script to fine tune our setup script_path_postinstall = os.path.join( self.settings.get('cnchi'), "scripts", POSTINSTALL_SCRIPT) cmd = ["/usr/bin/bash", script_path_postinstall, username, DEST_DIR, self.desktop, keyboard_layout] if keyboard_variant: cmd.append(keyboard_variant) else: cmd.append("") cmd.append(str(self.vbox)) try: subprocess.check_call(cmd, timeout=300) logging.debug("Post install script completed successfully.") except subprocess.CalledProcessError as process_error: # Even though Post-install script call has failed we will go on logging.error("Error running post-install script, command %s failed: %s", process_error.cmd, process_error.output) except subprocess.TimeoutExpired as timeout_error: logging.error(timeout_error) # Set lightdm config including autologin if selected if self.desktop != "base": self.setup_display_manager() # Configure user features (firewall, libreoffice language pack, ...) self.setup_features() # Encrypt user's home directory if requested # FIXME: This is not working atm if self.settings.get('encrypt_home'): logging.debug("Encrypting user home dir...") encfs.setup(username, DEST_DIR) logging.debug("User home dir encrypted") # Install boot loader (always after running mkinitcpio) if self.settings.get('bootloader_install'): try: logging.debug("Installing bootloader...") from installation import bootloader boot_loader = bootloader.Bootloader(DEST_DIR, self.settings, self.mount_devices) boot_loader.install() except Exception as general_error: logging.warning("While installing boot loader Cnchi encountered this error: %s", general_error) # This unmounts (unbinds) /dev and others to /DEST_DIR/dev and others chroot.umount_special_dirs(DEST_DIR) # Copy installer log to the new installation (just in case something goes wrong) logging.debug("Copying install log to /var/log.") self.copy_log() self.queue_event('pulse', 'stop')
def configure_system(self): """ Final install steps Set clock, language, timezone Run mkinitcpio Populate pacman keyring Setup systemd services ... and more """ self.queue_event("pulse", "start") self.queue_event("info", _("Configuring your new system")) self.auto_fstab() logging.debug("fstab file generated.") # If SSD was detected copy udev rule for deadline scheduler if self.ssd: self.set_scheduler() logging.debug("SSD udev rule copied successfully") # Copy configured networks in Live medium to target system if self.settings.get("network_manager") == "NetworkManager": self.copy_network_config() if self.desktop == "base": # Setup systemd-networkd for systems that won't use the # networkmanager or connman daemons (atm it's just base install) # Enable systemd_networkd services # https://github.com/Antergos/Cnchi/issues/332#issuecomment-108745026 self.enable_services(["systemd-networkd", "systemd-resolved"]) # Setup systemd_networkd # TODO: Ask user for SSID and passphrase if a wireless link is # found (here or inside systemd_networkd.setup() ?) from installation import systemd_networkd systemd_networkd.setup() logging.debug("Network configuration done.") # Copy mirror list mirrorlist_src_path = "/etc/pacman.d/mirrorlist" mirrorlist_dst_path = os.path.join(DEST_DIR, "etc/pacman.d/mirrorlist") try: shutil.copy2(mirrorlist_src_path, mirrorlist_dst_path) logging.debug("Mirror list copied.") except FileNotFoundError: logging.error("Can't copy mirrorlist file. File %s not found", mirrorlist_src_path) except FileExistsError: logging.warning("File %s already exists.", mirrorlist_dst_path) # Add Antergos repo to /etc/pacman.conf self.update_pacman_conf() logging.debug("pacman.conf has been created successfully") # Enable some useful services services = [] if self.desktop != "base": # In base there's no desktop manager ;) services.append(self.settings.get("desktop_manager")) # In base we use systemd-networkd (setup already done above) services.append(self.settings.get("network_manager")) services.extend(["ModemManager", "haveged"]) if self.method == "zfs": services.extend(["zfs", "zfs-mount"]) self.enable_services(services) # Enable timesyncd service if self.settings.get("use_timesyncd"): timesyncd_path = os.path.join(DEST_DIR, "etc/systemd/timesyncd.conf") try: with open(timesyncd_path, "w") as timesyncd: timesyncd.write("[Time]\n") timesyncd.write( "NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org " "2.arch.pool.ntp.org 3.arch.pool.ntp.org\n" ) timesyncd.write("FallbackNTP=0.pool.ntp.org 1.pool.ntp.org " "0.fr.pool.ntp.org\n") except FileNotFoundError as err: logging.warning("Can't find %s file.", timesyncd_path) chroot_call(["timedatectl", "set-ntp", "true"]) # Set timezone zoneinfo_path = os.path.join("/usr/share/zoneinfo", self.settings.get("timezone_zone")) chroot_call(["ln", "-s", zoneinfo_path, "/etc/localtime"]) logging.debug("Timezone set.") # Wait FOREVER until the user sets his params # FIXME: We can wait here forever! while self.settings.get("user_info_done") is False: # Wait five seconds and try again time.sleep(5) # Set user parameters username = self.settings.get("username") fullname = self.settings.get("fullname") password = self.settings.get("password") hostname = self.settings.get("hostname") sudoers_dir = os.path.join(DEST_DIR, "etc/sudoers.d") if not os.path.exists(sudoers_dir): os.mkdir(sudoers_dir, 0o710) sudoers_path = os.path.join(sudoers_dir, "10-installer") try: with open(sudoers_path, "w") as sudoers: sudoers.write("{0} ALL=(ALL) ALL\n".format(username)) os.chmod(sudoers_path, 0o440) logging.debug("Sudo configuration for user %s done.", username) except IOError as io_error: # Do not fail if can't write 10-installer file. # Something bad must be happening, though. logging.error(io_error) # Configure detected hardware # NOTE: Because hardware can need extra repos, this code must run # always after having called the update_pacman_conf method if self.hardware_install: try: logging.debug("Running hardware drivers post-install jobs...") self.hardware_install.post_install(DEST_DIR) except Exception as ex: template = "Error in hardware module. An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) logging.error(message) # Setup user default_groups = "lp,video,network,storage,wheel,audio" if self.vbox: # Why there is no vboxusers group? Add it ourselves. chroot_call(["groupadd", "vboxusers"]) default_groups += ",vboxusers,vboxsf" self.enable_services(["vboxservice"]) if self.settings.get("require_password") is False: # Prepare system for autologin. # LightDM needs the user to be in the autologin group. chroot_call(["groupadd", "autologin"]) default_groups += ",autologin" cmd = ["useradd", "-m", "-s", "/bin/bash", "-g", "users", "-G", default_groups, username] chroot_call(cmd) logging.debug("User %s added.", username) self.change_user_password(username, password) chroot_call(["chfn", "-f", fullname, username]) home_dir = os.path.join("/home", username) cmd = ["chown", "-R", "{0}:users".format(username), home_dir] chroot_call(cmd) # Set hostname hostname_path = os.path.join(DEST_DIR, "etc/hostname") if not os.path.exists(hostname_path): with open(hostname_path, "w") as hostname_file: hostname_file.write(hostname) logging.debug("Hostname set to %s", hostname) # User password is the root password self.change_user_password("root", password) logging.debug("Set the same password to root.") # Generate locales locale = self.settings.get("locale") self.queue_event("info", _("Generating locales...")) self.uncomment_locale_gen(locale) chroot_call(["locale-gen"]) locale_conf_path = os.path.join(DEST_DIR, "etc/locale.conf") with open(locale_conf_path, "w") as locale_conf: locale_conf.write("LANG={0}\n".format(locale)) locale_conf.write("LC_COLLATE={0}\n".format(locale)) # environment_path = os.path.join(DEST_DIR, "etc/environment") # with open(environment_path, "w") as environment: # environment.write('LANG={0}\n'.format(locale)) self.queue_event("info", _("Adjusting hardware clock...")) self.auto_timesetting() self.queue_event("info", _("Configuring keymap...")) if self.desktop != "base": self.set_keyboard_conf() self.set_vconsole_conf() # Install configs for root chroot_call(["cp", "-av", "/etc/skel/.", "/root/"]) self.queue_event("info", _("Configuring hardware...")) # Copy generated xorg.conf to target if os.path.exists("/etc/X11/xorg.conf"): src = "/etc/X11/xorg.conf" dst = os.path.join(DEST_DIR, "etc/X11/xorg.conf") shutil.copy2(src, dst) # Configure ALSA # self.alsa_mixer_setup() # logging.debug("Updated Alsa mixer settings") # Set pulse # if os.path.exists(os.path.join(DEST_DIR, "usr/bin/pulseaudio-ctl")): # chroot_run(['pulseaudio-ctl', 'normal']) # Set fluidsynth audio system (in our case, pulseaudio) self.set_fluidsynth() logging.debug("Updated fluidsynth configuration file") # Workaround for pacman-key bug FS#45351 # https://bugs.archlinux.org/task/45351 # We have to kill gpg-agent because if it stays around we can't # reliably unmount the target partition. logging.debug("Stopping gpg agent...") chroot_call(["killall", "-9", "gpg-agent"]) # FIXME: Temporary workaround for spl and zfs packages if self.method == "zfs": zfs_version = self.get_zfs_version() logging.debug("Installing zfs modules v%s...", zfs_version) chroot_call(["dkms", "install", "spl/{0}".format(zfs_version)]) chroot_call(["dkms", "install", "zfs/{0}".format(zfs_version)]) # Let's start without using hwdetect for mkinitcpio.conf. # It should work out of the box most of the time. # This way we don't have to fix deprecated hooks. # NOTE: With LUKS or LVM maybe we'll have to fix deprecated hooks. self.queue_event("info", _("Configuring System Startup...")) mkinitcpio.run(DEST_DIR, self.settings, self.mount_devices, self.blvm) logging.debug("Running Cnchi post-install script") keyboard_layout = self.settings.get("keyboard_layout") keyboard_variant = self.settings.get("keyboard_variant") # Call post-install script to fine tune our setup script_path_postinstall = os.path.join(self.settings.get("cnchi"), "scripts", POSTINSTALL_SCRIPT) cmd = [ "/usr/bin/bash", script_path_postinstall, username, DEST_DIR, self.desktop, locale, str(self.vbox), keyboard_layout, ] # Keyboard variant is optional if keyboard_variant: cmd.append(keyboard_variant) call(cmd, timeout=300) logging.debug("Post install script completed successfully.") # Patch user-dirs-update-gtk.desktop self.patch_user_dirs_update_gtk() logging.debug("File user-dirs-update-gtk.desktop patched.") # Set lightdm config including autologin if selected if self.desktop != "base": self.setup_display_manager() # Configure user features (firewall, libreoffice language pack, ...) self.setup_features() # Encrypt user's home directory if requested # FIXME: This is not working atm if self.settings.get("encrypt_home"): self.queue_event("info", _("Encrypting user home dir...")) encfs.setup(username, DEST_DIR) logging.debug("User home dir encrypted") # Install boot loader (always after running mkinitcpio) if self.settings.get("bootloader_install"): try: self.queue_event("info", _("Installing bootloader...")) from installation.boot import loader boot_loader = loader.Bootloader(DEST_DIR, self.settings, self.mount_devices) boot_loader.install() except Exception as ex: template = "Cannot install bootloader. An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) logging.error(message) # Create an initial database for mandb self.queue_event("info", _("Updating man pages...")) chroot_call(["mandb", "--quiet"]) # Initialise pkgfile (pacman .files metadata explorer) database logging.debug("Updating pkgfile database") chroot_call(["pkgfile", "--update"]) # Copy installer log to the new installation logging.debug("Copying install log to /var/log.") self.copy_log() self.queue_event("pulse", "stop") self.queue_event("progress_bar", "hide")