├── .flake8
├── .gitattributes
├── .github
└── workflows
│ └── block-autosquash-commits.yml
├── .gitignore
├── 10-eos-oom-policy.conf
├── 50-disk-bfq.rules
├── 50-eos.preset
├── 50-usb-mouse-wakeup.rules
├── 60-suspend-mode.rules
├── COPYING
├── Makefile.am
├── autogen.sh
├── com.endlessm.TestMode.policy.in
├── configure.ac
├── debian
├── changelog
├── compat
├── control
├── copyright
├── eos-boot-helper.triggers
├── rules
└── source
│ └── format
├── dracut
├── Makefile.am
├── customization
│ ├── Makefile.am
│ ├── eos-install-custom-boot-splash
│ ├── eos-install-custom-boot-splash.service
│ └── module-setup.sh
├── endless.conf
├── image-boot
│ ├── Makefile.am
│ ├── eos-image-boot-generator
│ ├── eos-image-boot-setup
│ ├── eos-image-boot-setup.service
│ ├── eos-live-storage-setup
│ └── module-setup.sh
└── repartition
│ ├── Makefile.am
│ ├── endless-repartition.service
│ ├── endless-repartition.sh
│ └── module-setup.sh
├── eos-config-journal
├── eos-config-journal.service
├── eos-enable-zram
├── eos-enable-zram.service
├── eos-esp-generator
├── eos-firewall-localonly
├── eos-firewall-localonly-nm
├── eos-firewall-localonly.service
├── eos-firstboot
├── eos-firstboot.service
├── eos-fix-flatpak-overrides.service
├── eos-live-boot-generator
├── eos-live-boot-overlayfs-setup
├── eos-live-boot-overlayfs-setup.service
├── eos-migrate-chromium-profile
├── eos-migrate-chromium-profile.service
├── eos-migrate-firefox-profile
├── eos-migrate-firefox-profile.service
├── eos-migrate-shotwell.service
├── eos-repartition-mbr
├── eos-test-mode
├── eos-transient-setup
├── eos-transient-setup.service
├── eos-update-efi-uuid.c
├── eos-update-flatpak-repos
├── eos-update-flatpak-repos.service
├── eos-update-system-ca.service
├── eos-vm-generator
├── factory-reset
├── Makefile.am
├── eos-factory-reset
├── eos-factory-reset-users
└── eos-factory-reset-users.service
├── fallback-fb-setup
├── Makefile.am
├── fallback-fb-setup.c
└── fallback-fb-setup.service
├── flatpak-repos
├── Makefile.am
├── eos-sdk.flatpakrepo
└── flathub.flatpakrepo
├── nvidia
├── Makefile.am
├── asus-pci-blacklist
├── dmi-blacklist
├── dmi-board-blacklist
├── nouveau.conf
├── nvidia-graphics-setup
└── nvidia-graphics.service
├── psi-monitor
├── Makefile.am
├── psi-monitor.c
└── psi-monitor.service
├── pytest.ini
├── record-boot-success
├── Makefile.am
├── com.endlessm.RecordBootSuccess.conf
├── com.endlessm.RecordBootSuccess.service
├── record-boot-success
├── record-boot-success.desktop
└── record-boot-success.service
├── tests
├── Makefile.am
├── __init__.py
├── check-syntax
├── conftest.py
├── efivars
│ ├── Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── ErrOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── FALLBACK_VERBOSE-605dab50-e046-4300-abb6-3dd810dd8b23
│ ├── KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Key0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Key0001-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Lang-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── LangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── MTC-eb704011-1402-11d3-8e77-00a0c969723b
│ ├── MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23
│ ├── MokListTrustedRT-605dab50-e046-4300-abb6-3dd810dd8b23
│ ├── MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23
│ ├── OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── PK-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── PlatformRecovery0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23
│ ├── SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── VarErrorFlag-04b37fe8-f6ae-480b-bdd5-37d98c5e89aa
│ ├── VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c
│ ├── certdb-d9bee56e-75dc-49d9-b4d7-b534210f637a
│ ├── certdbv-d9bee56e-75dc-49d9-b4d7-b534210f637a
│ └── db-d719b2cb-3d3a-4596-a3bc-dad00e67656f
├── espgen
│ ├── README.md
│ ├── grub-gpt-fstab-efi-fstab.json
│ ├── grub-gpt-fstab-efi-kcmdline.json
│ ├── grub-gpt-fstab-efi-mounts-init.json
│ ├── grub-gpt-fstab-efi-mounts-reload.json
│ ├── grub-gpt-fstab-efi-partitions-init.json
│ ├── grub-gpt-fstab-efi-partitions-reload.json
│ ├── grub-gpt-fstab.json
│ ├── grub-gpt-kcmdline.json
│ ├── grub-gpt-mounts-init.json
│ ├── grub-gpt-mounts-reload.json
│ ├── grub-gpt-partitions-init.json
│ ├── grub-gpt-partitions-reload.json
│ ├── grub-mbr-fstab.json
│ ├── grub-mbr-kcmdline.json
│ ├── grub-mbr-mounts-init.json
│ ├── grub-mbr-mounts-reload.json
│ ├── grub-mbr-partitions-init.json
│ ├── grub-mbr-partitions-reload.json
│ ├── sdboot-fstab.json
│ ├── sdboot-kcmdline.json
│ ├── sdboot-mounts-init.json
│ ├── sdboot-mounts-reload.json
│ ├── sdboot-partitions-init.json
│ ├── sdboot-partitions-reload.json
│ ├── sdboot-xbootldr-fstab.json
│ ├── sdboot-xbootldr-kcmdline.json
│ ├── sdboot-xbootldr-mounts-init.json
│ ├── sdboot-xbootldr-mounts-reload.json
│ ├── sdboot-xbootldr-partitions-init.json
│ ├── sdboot-xbootldr-partitions-reload.json
│ ├── windows-efi-fstab.json
│ ├── windows-efi-kcmdline.json
│ ├── windows-efi-mounts-init.json
│ ├── windows-efi-mounts-reload.json
│ ├── windows-efi-partitions-init.json
│ └── windows-efi-partitions-reload.json
├── run-tests
├── test_esp_generator.py
├── test_image_boot.py
├── test_live_storage.py
├── test_migrate_chromium_profile.py
├── test_migrate_firefox_profile.py
├── test_repartition.py
├── test_repartition_mbr.py
├── test_update_efi_uuid.py
├── test_update_flatpak_repos.py
└── util.py
└── tmpfiles.d
├── chromium-system-services.conf.in
└── eos-boot-helper.conf
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | # The default is 79 characters. One popular Python code formatter
3 | # https://github.com/ambv/black#line-length defaults to 88 which is based on
4 | # some empirical research on reducing annoying line wrapping on real source
5 | # code.
6 | max-line-length = 88
7 |
8 | # Include scripts to check in addition to the default *.py.
9 | filename =
10 | *.py,
11 | ./eos-esp-generator,
12 | ./eos-migrate-chromium-profile,
13 | ./eos-migrate-firefox-profile,
14 | ./eos-update-flatpak-repos,
15 | ./factory-reset/eos-factory-reset,
16 | ./record-boot-success/record-boot-success,
17 | ./tests/check-syntax
18 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Define hexdump textconv with "git config diff.efivars.textconv hd"
2 | tests/efivars/* diff=efivars
3 |
--------------------------------------------------------------------------------
/.github/workflows/block-autosquash-commits.yml:
--------------------------------------------------------------------------------
1 | on: pull_request
2 |
3 | name: Pull Requests
4 |
5 | jobs:
6 | message-check:
7 | name: Block Autosquash Commits
8 |
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Block Autosquash Commits
13 | uses: xt0rted/block-autosquash-commits-action@v2.0.0
14 | with:
15 | repo-token: ${{ secrets.GITHUB_TOKEN }}
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.[oa]
3 | .deps/
4 | .pytest_cache/
5 | __pycache__/
6 | com.endlessm.TestMode.policy
7 | Makefile
8 | Makefile.in
9 | aclocal.m4
10 | autom4te.cache/
11 | compile
12 | config.guess
13 | config.log
14 | config.status
15 | config.sub
16 | configure
17 | depcomp
18 | eos-update-efi-uuid
19 | fallback-fb-setup/fallback-fb-setup
20 | install-sh
21 | missing
22 | psi-monitor/psi-monitor
23 | tmpfiles.d/chromium-system-services.conf
24 | test-driver
25 | tests/*.log
26 | tests/*.trs
27 |
--------------------------------------------------------------------------------
/10-eos-oom-policy.conf:
--------------------------------------------------------------------------------
1 | [Manager]
2 | # The default DefaultOOMPolicy=stop causes undesirable behaviour in Endless OS
3 | # when systemd-oomd is not being used. Instead, instruct systemd to log when
4 | # a process is killed but allow its associated unit to continue running.
5 | DefaultOOMPolicy=continue
6 |
--------------------------------------------------------------------------------
/50-disk-bfq.rules:
--------------------------------------------------------------------------------
1 | ACTION=="add|change", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ATTR{queue/scheduler}="bfq"
2 |
--------------------------------------------------------------------------------
/50-eos.preset:
--------------------------------------------------------------------------------
1 | # Systemd unit file presets for EOS. We do not install a wildcard
2 | # "disable *" rule, so here we simply disable any units that aren't
3 | # desired. All others will be enabled by systemd.
4 |
5 | # Reverse systemd defaults
6 | disable systemd-networkd.service
7 | disable systemd-networkd.socket
8 | disable systemd-resolved.service
9 | disable systemd-networkd-wait-online.service
10 | disable systemd-sysupdate.service
11 | disable systemd-sysupdate.timer
12 | disable systemd-sysupdate-reboot.service
13 | disable systemd-sysupdate-reboot.timer
14 |
15 | # Disable other unwanted units
16 | disable apt-daily.timer
17 | disable apt-daily-upgrade.timer
18 | disable bluetooth-init.service
19 | disable checkbox-ng.service
20 | disable cni-dhcp.service
21 | disable crio.service
22 | disable crio-shutdown.service
23 | disable cron.service
24 | disable dpkg-db-backup.timer
25 | disable eos-factory-reset-users.service
26 | disable eos-firewall-localonly.service
27 | disable eos-safe-defaults.service
28 | disable eos-update-server.service
29 | disable eos-update-server.socket
30 | disable eos-updater-avahi.path
31 | disable eos-updater-avahi.service
32 | disable ifupdown-wait-online.service
33 | disable networking.service
34 | disable NetworkManager-wait-online.service
35 | disable logrotate.timer
36 | disable openvpn-client@.service
37 | disable openvpn-server@.service
38 | disable openvpn.service
39 | disable openvpn@.service
40 | disable podman-auto-update.service
41 | disable podman-auto-update.timer
42 | disable pppd-dns.service
43 | disable rtkit-daemon.service
44 | disable rsyslog.service
45 | disable serial-getty@.service
46 | disable smartmontools.service
47 | disable speech-dispatcherd.service
48 | disable strongswan-starter.service
49 | disable ssh*.service
50 | disable ssh.socket
51 | disable systemd-nspawn@.service
52 | disable wpa_supplicant.service
53 | disable wpa_supplicant@.service
54 | disable wpa_supplicant-nl80211@.service
55 | disable wpa_supplicant-wired@.service
56 | disable xl2tpd.service
57 |
58 | # Disable virtualbox-guest-utils.service by default. It will be enabled
59 | # dynamically by eos-vm-generator when running in virtualbox.
60 | # ConditionVirtualization=oracle on the unit is not enought as it will
61 | # prevent conflicted units (systemd-timesyncd.service) from starting.
62 | # https://phabricator.endlessm.com/T32330#906081
63 | disable virtualbox-guest-utils.service
64 |
65 | # Disable units masked by Debian, as systemctl preset-all fails to
66 | # handle them. Without this, `systemctl preset-all` will fail with:
67 | #
68 | # Operation failed: Cannot send after transport endpoint shutdown
69 | #
70 | # Units masked in systemd. See debian/systemd.links.
71 | disable x11-common.service
72 | disable hostname.service
73 | disable rmnologin.service
74 | disable bootmisc.service
75 | disable fuse.service
76 | disable bootlogd.service
77 | disable stop-bootlogd-single.service
78 | disable stop-bootlogd.service
79 | disable hwclock.service
80 | disable mountkernfs.service
81 | disable mountdevsubfs.service
82 | disable mountall.service
83 | disable mountall-bootclean.service
84 | disable mountnfs.service
85 | disable mountnfs-bootclean.service
86 | disable umountfs.service
87 | disable umountnfs.service
88 | disable umountroot.service
89 | disable checkfs.service
90 | disable checkroot.service
91 | disable checkroot-bootclean.service
92 | disable cryptdisks.service
93 | disable cryptdisks-early.service
94 | disable single.service
95 | disable killprocs.service
96 | disable sendsigs.service
97 | disable halt.service
98 | disable reboot.service
99 | disable rc.service
100 | disable rcS.service
101 | disable motd.service
102 | disable bootlogs.service
103 | #
104 | # Units masked by other packages. Run the following to find them:
105 | #
106 | # find /usr/lib/systemd/system -lname /dev/null -printf 'disable %f\n' | sort
107 | disable screen-cleanup.service
108 |
--------------------------------------------------------------------------------
/50-usb-mouse-wakeup.rules:
--------------------------------------------------------------------------------
1 | # On desktop/AIO/mini pc/stick pc systems, enable USB-HID mouse devices supporting boot protocol
2 | # as a wakeup source.
3 | SUBSYSTEM=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceSubClass}=="01", ATTRS{bInterfaceProtocol}=="02", ATTR{[dmi/id]chassis_type}=="3|13|35|36", RUN+="/bin/sh -c 'echo enabled > /sys$env{DEVPATH}/../power/wakeup'"
4 |
--------------------------------------------------------------------------------
/60-suspend-mode.rules:
--------------------------------------------------------------------------------
1 | SUBSYSTEM=="dmi", ENV{ID_VENDOR}=="GIGABYTE", ENV{ID_MODEL}=="Mission one", RUN{program}+="/bin/sh -c 'echo s2idle > /sys/power/mem_sleep'"
2 | SUBSYSTEM=="dmi", ENV{ID_MODEL}=="GB-BXBT-2807", RUN{program}+="/bin/sh -c 'echo s2idle > /sys/power/mem_sleep'"
3 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | SUBDIRS = dracut factory-reset fallback-fb-setup flatpak-repos nvidia psi-monitor record-boot-success . tests
2 | EXTRA_DIST = debian .flake8 pytest.ini
3 | CLEANFILES =
4 |
5 | AM_CFLAGS = -Wall -Werror
6 |
7 | # Install systemd units, generators, preset files, and udev rules
8 | # under $prefix for distcheck
9 | AM_DISTCHECK_CONFIGURE_FLAGS = \
10 | --with-systemdutildir='$${prefix}/lib/systemd' \
11 | --with-systemdunitdir='$${prefix}/lib/systemd/system' \
12 | --with-systemduserunitdir='$${prefix}/lib/systemd/user' \
13 | --with-systemdgeneratordir='$${prefix}/lib/systemd/system-generators' \
14 | --with-systemdpresetdir='$${prefix}/lib/systemd/system-preset' \
15 | --with-udevdir='$${prefix}/lib/udev' \
16 | --with-modprobedir='$${prefix}/lib/modprobe.d' \
17 | --with-dbussystemconfigdir='$${prefix}/share/dbus-1/system.d' \
18 | --with-system-bus-services-dir='$${prefix}/share/dbus-1/system-services' \
19 | --with-polkitpolicydir='$${prefix}/share/polkit-1/actions' \
20 | $(NULL)
21 |
22 | dist_systemdunit_DATA = \
23 | eos-config-journal.service \
24 | eos-enable-zram.service \
25 | eos-firewall-localonly.service \
26 | eos-firstboot.service \
27 | eos-fix-flatpak-overrides.service \
28 | eos-live-boot-overlayfs-setup.service \
29 | eos-transient-setup.service \
30 | eos-update-flatpak-repos.service \
31 | eos-update-system-ca.service \
32 | $(NULL)
33 |
34 | dist_systemduserunit_DATA = \
35 | eos-migrate-chromium-profile.service \
36 | eos-migrate-firefox-profile.service \
37 | eos-migrate-shotwell.service \
38 | $(NULL)
39 |
40 | dist_systemdgenerator_SCRIPTS = \
41 | eos-esp-generator \
42 | eos-live-boot-generator \
43 | eos-vm-generator \
44 | $(NULL)
45 |
46 | dist_systemdpreset_DATA = \
47 | 50-eos.preset \
48 | $(NULL)
49 |
50 | dist_systemdsystemmanagerconf_DATA = \
51 | 10-eos-oom-policy.conf \
52 | $(NULL)
53 |
54 | dist_systemdusermanagerconf_DATA = \
55 | 10-eos-oom-policy.conf \
56 | $(NULL)
57 |
58 | # Network Manager dispatcher script for the firewall - scripts which
59 | # are a symlink to no-wait.d will be run without blocking/ordering.
60 | # install the script here and make the symlink in install-data-hook
61 | # below
62 | networkscriptdir = $(sysconfdir)/NetworkManager/dispatcher.d
63 | networkscriptnowaitdir = $(networkscriptdir)/no-wait.d
64 | dist_networkscriptnowait_DATA = eos-firewall-localonly-nm
65 |
66 | install-data-hook:
67 | $(MKDIR_P) '$(DESTDIR)$(networkscriptdir)'
68 | ln -s 'no-wait.d/eos-firewall-localonly-nm' \
69 | '$(DESTDIR)$(networkscriptdir)/eos-firewall-localonly-nm'
70 | chmod +x '$(DESTDIR)$(networkscriptdir)/eos-firewall-localonly-nm'
71 | $(MKDIR_P) '$(DESTDIR)$(systemduserunitdir)/gnome-session.target.wants'
72 | ln -s ../eos-migrate-chromium-profile.service '$(DESTDIR)$(systemduserunitdir)/gnome-session.target.wants'
73 | ln -s ../eos-migrate-firefox-profile.service '$(DESTDIR)$(systemduserunitdir)/gnome-session.target.wants'
74 | ln -s ../eos-migrate-shotwell.service '$(DESTDIR)$(systemduserunitdir)/gnome-session.target.wants'
75 |
76 | uninstall-hook:
77 | rm -f '$(DESTDIR)$(networkscriptdir)/eos-firewall-localonly-nm'
78 |
79 | udevrulesdir = $(udevdir)/rules.d
80 | dist_udevrules_DATA = \
81 | 50-disk-bfq.rules \
82 | 50-usb-mouse-wakeup.rules \
83 | 60-suspend-mode.rules \
84 | $(NULL)
85 |
86 | dist_sbin_SCRIPTS = \
87 | eos-config-journal \
88 | eos-enable-zram \
89 | eos-firewall-localonly \
90 | eos-firstboot \
91 | eos-live-boot-overlayfs-setup \
92 | eos-repartition-mbr \
93 | eos-test-mode \
94 | eos-transient-setup \
95 | eos-update-flatpak-repos \
96 | $(NULL)
97 |
98 | sbin_PROGRAMS = \
99 | eos-update-efi-uuid \
100 | $(NULL)
101 |
102 | eos_update_efi_uuid_SOURCES = eos-update-efi-uuid.c
103 | eos_update_efi_uuid_CFLAGS = $(AM_CFLAGS) $(EFIBOOT_CFLAGS)
104 | eos_update_efi_uuid_LDADD = $(EFIBOOT_LIBS)
105 |
106 | dist_libexec_SCRIPTS = \
107 | eos-migrate-chromium-profile \
108 | eos-migrate-firefox-profile \
109 | $(NULL)
110 |
111 | tmpfilesdir = $(prefix)/lib/tmpfiles.d
112 | dist_tmpfiles_DATA = \
113 | tmpfiles.d/chromium-system-services.conf \
114 | tmpfiles.d/eos-boot-helper.conf \
115 | $(NULL)
116 |
117 | com.endlessm.TestMode.policy: com.endlessm.TestMode.policy.in
118 | $(AM_V_GEN) $(SED) -e 's|[@]sbindir@|$(sbindir)|g' < "$<" > "$@"
119 |
120 | polkitpolicy_DATA = \
121 | com.endlessm.TestMode.policy \
122 | $(NULL)
123 |
124 | CLEANFILES += \
125 | com.endlessm.TestMode.policy
126 | EXTRA_DIST += \
127 | com.endlessm.TestMode.policy.in
128 |
--------------------------------------------------------------------------------
/autogen.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Run this to generate all the initial makefiles, etc.
3 |
4 | PROJECT=eos-boot-helper
5 | builddir=`pwd`
6 | srcdir=`dirname "$0"`
7 | [ -z "$srcdir" ] && srcdir=.
8 |
9 | # Rebuild the autotools
10 | cd "$srcdir"
11 | ${AUTORECONF-autoreconf} -iv || exit $?
12 | cd "$builddir"
13 |
14 | # Run configure unless NOCONFIGURE set.
15 | if [ -z "$NOCONFIGURE" ]; then
16 | "$srcdir"/configure "$@"
17 | echo "Now type 'make' to compile $PROJECT."
18 | else
19 | echo "Now type './configure && make' to compile $PROJECT."
20 | fi
21 |
--------------------------------------------------------------------------------
/com.endlessm.TestMode.policy.in:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | Endless
8 | https://endlessm.com/
9 |
10 |
11 | Initiate system test mode
12 | Authentication is required to start test mode
13 |
14 | auth_admin
15 | auth_admin
16 | auth_admin_keep
17 |
18 | @sbindir@/eos-test-mode
19 |
20 |
21 |
--------------------------------------------------------------------------------
/debian/changelog:
--------------------------------------------------------------------------------
1 | eos-boot-helper (1) eos; urgency=low
2 |
3 | * Initial release.
4 |
5 | -- Daniel Drake Thu, 12 Mar 2015 19:50:46 -0600
6 |
--------------------------------------------------------------------------------
/debian/compat:
--------------------------------------------------------------------------------
1 | 8
2 |
--------------------------------------------------------------------------------
/debian/control:
--------------------------------------------------------------------------------
1 | Source: eos-boot-helper
2 | Section: admin
3 | Priority: optional
4 | Maintainer: Daniel Drake
5 | Build-Depends: automake,
6 | debhelper (>= 8),
7 | flake8 ,
8 | gir1.2-flatpak-1.0 ,
9 | gir1.2-glib-2.0 ,
10 | gir1.2-ostree-1.0 ,
11 | gir1.2-eosmetrics-0 ,
12 | libdbus-1-dev,
13 | libefiboot-dev,
14 | libefivar-dev,
15 | libpolkit-gobject-1-dev,
16 | pkg-config,
17 | python3 ,
18 | python3-gi ,
19 | python3-parted ,
20 | python3-pytest ,
21 | python3-systemd ,
22 | systemd,
23 | udev,
24 | Standards-Version: 3.9.1
25 | Homepage: https://endlessm.com
26 |
27 | Package: eos-boot-helper
28 | Architecture: any
29 | Description: Endless boot helper
30 | Depends: ${misc:Depends},
31 | ca-certificates,
32 | dracut,
33 | iptables,
34 | ostree,
35 | flatpak,
36 | gir1.2-eosmetrics-0,
37 | gir1.2-flatpak-1.0,
38 | gir1.2-glib-2.0,
39 | gir1.2-ostree-1.0,
40 | python3,
41 | python3-gi,
42 | python3-parted,
43 | python3-systemd,
44 | util-linux (>= 2.30.0),
45 | Breaks: systemd (<= 232+dev145.a41a4e3-23)
46 | Replaces: systemd (<= 232+dev145.a41a4e3-23)
47 |
--------------------------------------------------------------------------------
/debian/copyright:
--------------------------------------------------------------------------------
1 | License: GPL-2
2 | This program is free software; you can redistribute it
3 | and/or modify it under the terms of the GNU General Public
4 | License as published by the Free Software Foundation; version
5 | 2 dated June 1991.
6 | .
7 | This program is distributed in the hope that it will be
8 | useful, but WITHOUT ANY WARRANTY; without even the implied
9 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 | PURPOSE. See the GNU General Public License for more
11 | details.
12 | .
13 | You should have received a copy of the GNU General Public
14 | License along with this package; if not, write to the Free
15 | Software Foundation, Inc., 51 Franklin St, Fifth Floor,
16 | Boston, MA 02110-1301 USA
17 | .
18 | On Debian systems, the full text of the GNU General Public
19 | License version 2 can be found in the file
20 | `/usr/share/common-licenses/GPL-2'.
21 |
--------------------------------------------------------------------------------
/debian/eos-boot-helper.triggers:
--------------------------------------------------------------------------------
1 | activate update-initramfs
2 |
--------------------------------------------------------------------------------
/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 |
3 | %:
4 | dh $@ --with systemd
5 |
6 | override_dh_systemd_start:
7 | dh_systemd_start --no-start
8 |
9 | # don't automatically enable eos-firewall-localonly
10 | override_dh_systemd_enable:
11 | dh_systemd_enable \
12 | -Xeos-firewall-localonly.service \
13 | $(NULL)
14 | dh_systemd_enable --no-enable \
15 | eos-firewall-localonly.service \
16 | $(NULL)
17 |
--------------------------------------------------------------------------------
/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (native)
2 |
--------------------------------------------------------------------------------
/dracut/Makefile.am:
--------------------------------------------------------------------------------
1 | SUBDIRS = repartition image-boot customization
2 |
3 | dracutconfdir = $(sysconfdir)/dracut.conf.d
4 | dist_dracutconf_DATA = endless.conf
5 |
--------------------------------------------------------------------------------
/dracut/customization/Makefile.am:
--------------------------------------------------------------------------------
1 | dracutmoddir = $(prefix)/lib/dracut/modules.d/50eos-customization
2 | dist_dracutmod_SCRIPTS = module-setup.sh \
3 | eos-install-custom-boot-splash
4 | dist_dracutmod_DATA = eos-install-custom-boot-splash.service
5 |
--------------------------------------------------------------------------------
/dracut/customization/eos-install-custom-boot-splash:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | CUSTOM_SPLASH_DIR="/eos-customization/plymouth"
4 | CUSTOM_SPLASH_CONFIG="${CUSTOM_SPLASH_DIR}/plymouthd.defaults"
5 | PLYMOUTH_RUNTIME_DIR="/run/plymouth"
6 |
7 | if [ ! -d ${CUSTOM_SPLASH_DIR} ] ; then
8 | echo "${CUSTOM_SPLASH_DIR} not found" >&2
9 | exit 1
10 | fi
11 |
12 | if [ ! -f ${CUSTOM_SPLASH_CONFIG} ] ; then
13 | echo "${CUSTOM_SPLASH_CONFIG} not found" >&2
14 | exit 1
15 | fi
16 |
17 | theme_name="`sed -n 's/Theme=\(.*\)/\1/p' ${CUSTOM_SPLASH_CONFIG}`"
18 | if [ -z ${theme_name} ]; then
19 | echo "Theme entry missing from ${CUSTOM_SPLASH_CONFIG}" >&2
20 | exit 1
21 | fi
22 |
23 | if [ ! -d ${CUSTOM_SPLASH_DIR}/themes/${theme_name} ] ; then
24 | echo "${CUSTOM_SPLASH_DIR}/themes/${theme_name} not found" >&2
25 | exit 1
26 | fi
27 |
28 | mkdir -p ${PLYMOUTH_RUNTIME_DIR}
29 | cp ${CUSTOM_SPLASH_CONFIG} ${PLYMOUTH_RUNTIME_DIR}
30 | cp -r ${CUSTOM_SPLASH_DIR}/themes ${PLYMOUTH_RUNTIME_DIR}
31 | sed -i "s:ImageDir=.*:ImageDir=${PLYMOUTH_RUNTIME_DIR}/themes/${theme_name}:" \
32 | ${PLYMOUTH_RUNTIME_DIR}/themes/${theme_name}/${theme_name}.plymouth
33 |
--------------------------------------------------------------------------------
/dracut/customization/eos-install-custom-boot-splash.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Install custom splash theme to runtime dir
3 | DefaultDependencies=no
4 | ConditionKernelCommandLine=splash
5 | ConditionPathExists=/etc/initrd-release
6 | ConditionDirectoryNotEmpty=/eos-customization/plymouth
7 | Before=plymouth-start.service
8 |
9 | [Service]
10 | Type=oneshot
11 | ExecStart=/bin/eos-install-custom-boot-splash
12 |
--------------------------------------------------------------------------------
/dracut/customization/module-setup.sh:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2017 Endless Mobile, Inc.
2 | # Licensed under the GPLv2
3 |
4 | check() {
5 | return 0
6 | }
7 |
8 | depends() {
9 | echo systemd
10 | }
11 |
12 | install() {
13 | dracut_install sed
14 | inst_script "$moddir/eos-install-custom-boot-splash" \
15 | /bin/eos-install-custom-boot-splash
16 | inst_simple "$moddir/eos-install-custom-boot-splash.service" \
17 | "$systemdsystemunitdir/eos-install-custom-boot-splash.service"
18 | mkdir -p "${initdir}/$systemdsystemunitdir/plymouth-start.service.wants"
19 | ln_r "$systemdsystemunitdir/eos-install-custom-boot-splash.service" \
20 | "$systemdsystemunitdir/plymouth-start.service.wants/eos-install-custom-boot-splash.service"
21 | }
22 |
--------------------------------------------------------------------------------
/dracut/endless.conf:
--------------------------------------------------------------------------------
1 | compress="zstd"
2 |
3 | dracutmodules="dracut-systemd systemd-initrd dash drm eos-repartition eos-image-boot plymouth kernel-modules resume ostree systemd base fs-lib eos-customization busybox"
4 | fscks="fsck fsck.ext4"
5 | filesystems="isofs ntfs3 exfat"
6 |
7 | # Embed microcode into ramdisk
8 | early_microcode="yes"
9 |
10 | # Don't include nouveau in the initramfs, so that we can later choose
11 | # between nouveau and nvidia.
12 | # (nouveau cannot be unloaded after it has bound to a device)
13 | omit_drivers="nouveau"
14 |
15 | # Don't include simpledrm in the initramfs to avoid the frame buffer transition
16 | # on some platforms, like RPi 4B, which blocks system during plymouth splash.
17 | #
18 | # We should be able to drop this change with a newer plymouth that includes
19 | # commit 5dedca81 "ply-device-manager: Also ignore SimpleDRM devs in coldplug
20 | # enumeration path". See https://phabricator.endlessm.com/T34648 and
21 | # https://bugzilla.redhat.com/show_bug.cgi?id=2127663.
22 | omit_drivers+=" simpledrm "
23 |
24 | # Ship the bfq IO scheduler module in the initrd, as it's relied upon by
25 | # our udev rules that detect block devices
26 | add_drivers+=" bfq "
27 |
28 | # The initramfs will be distributed by ostree, so it needs to be generic. If
29 | # anyone needs to generate a host specific initramfs, they can pass the
30 | # "--hostonly" option.
31 | hostonly=no
32 |
--------------------------------------------------------------------------------
/dracut/image-boot/Makefile.am:
--------------------------------------------------------------------------------
1 | dracutmoddir = $(prefix)/lib/dracut/modules.d/50eos-image-boot
2 | dist_dracutmod_SCRIPTS = \
3 | eos-image-boot-generator \
4 | eos-image-boot-setup \
5 | eos-live-storage-setup \
6 | module-setup.sh \
7 | $(NULL)
8 | dist_dracutmod_DATA = \
9 | eos-image-boot-setup.service \
10 | $(NULL)
11 |
--------------------------------------------------------------------------------
/dracut/image-boot/eos-image-boot-generator:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright (C) 2016 Endless Mobile, Inc.
3 | # Licensed under the GPLv2
4 | #
5 | # Support booting from an image file hosted on a filesystem.
6 | # We parse the kernel parameters requesting this functionality and configure
7 | # other systemd units to go about setting up the block devices and mounting
8 | # the target filesystem.
9 |
10 | type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
11 |
12 | GENERATOR_DIR="$1"
13 |
14 | image_device=$(getarg endless.image.device=)
15 | image_path=$(getarg endless.image.path=)
16 |
17 | [ -z "${image_device}" -o -z "${image_path}" ] && exit 0
18 |
19 | case "${image_device}" in
20 | UUID=*)
21 | image_device=/dev/disk/by-uuid/${image_device#UUID=}
22 | ;;
23 | esac
24 |
25 | image_device_escaped=$(systemd-escape -p "${image_device}")
26 |
27 | # When the image device appears, run the setup.
28 | # Note that when booting an ISO using HD emulation (e.g. booting an ISO file
29 | # flashed to USB), udev records that the ISO UUID applies to both the iso9660
30 | # data partition *and* the parent disk node. So it's a little unwise to
31 | # rely on the /dev/disk/by-uuid symlink, but it's good enough as a way
32 | # of ensuring that the overall device has appeared.
33 | # eos-image-boot-setup will then deal with the UUID clash problem.
34 | mkdir -p ${GENERATOR_DIR}/initrd-fs.target.wants
35 | ln -s /lib/systemd/system/eos-image-boot-setup.service \
36 | ${GENERATOR_DIR}/initrd-fs.target.wants
37 | mkdir -p ${GENERATOR_DIR}/eos-image-boot-setup.service.d
38 | cat <${GENERATOR_DIR}/eos-image-boot-setup.service.d/50-device.conf
39 | [Unit]
40 | Requires=${image_device_escaped}.device
41 | After=${image_device_escaped}.device
42 | EOF
43 |
44 | if getargbool 0 endless.live_boot; then
45 | rwflag=ro
46 | else
47 | rwflag=rw
48 | fi
49 |
50 | # Once the actual EOS device has appeared, use the normal infrastructure
51 | # to fsck and mount it.
52 | cat <${GENERATOR_DIR}/sysroot.mount
53 | [Unit]
54 | Before=initrd-root-fs.target
55 | Requires=systemd-fsck-root.service
56 | After=systemd-fsck-root.service
57 | [Mount]
58 | What=/dev/disk/endless-image3
59 | Where=/sysroot
60 | Options=$rwflag
61 | EOF
62 |
63 | cat <${GENERATOR_DIR}/systemd-fsck-root.service
64 | [Unit]
65 | DefaultDependencies=no
66 | BindsTo=dev-disk-endless\x2dimage3.device
67 | After=initrd-root-device.target local-fs-pre.target
68 | Before=shutdown.target
69 | ConditionKernelCommandLine=!endless.live_boot
70 | [Service]
71 | Type=oneshot
72 | RemainAfterExit=yes
73 | ExecStart=/lib/systemd/systemd-fsck /dev/disk/endless-image3
74 | TimeoutSec=0
75 | EOF
76 |
77 | mkdir -p ${GENERATOR_DIR}/initrd-root-device.target.d
78 | cat <${GENERATOR_DIR}/initrd-root-device.target.d/50-device.conf
79 | [Unit]
80 | Requires=dev-disk-endless\x2dimage3.device
81 | After=dev-disk-endless\x2dimage3.device
82 | EOF
83 |
84 | mkdir -p ${GENERATOR_DIR}/initrd-root-fs.target.requires
85 | ln -s ${GENERATOR_DIR}/sysroot.mount \
86 | ${GENERATOR_DIR}/initrd-root-fs.target.requires
87 |
--------------------------------------------------------------------------------
/dracut/image-boot/eos-image-boot-setup:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright (C) 2016-2017 Endless Mobile, Inc.
3 | # Licensed under the GPLv2
4 | #
5 | # Support booting from an image file hosted on a filesystem, through the use
6 | # of loopback devices.
7 |
8 | if [ $# -ge 1 ]; then
9 | # For testing
10 | if [ "$1" = "--readonly" ]; then
11 | shift
12 | roflag="-r"
13 | fi
14 |
15 | host_device="$1"
16 | image_path="$2"
17 | else
18 | type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
19 |
20 | image_device=$(getarg endless.image.device)
21 | image_path=$(getarg endless.image.path)
22 |
23 | # When booting an ISO using HD emulation (e.g. booting an ISO file flashed
24 | # to USB), udev records that the ISO UUID applies to both the iso9660
25 | # data partition and the parent disk node, so we have to be careful
26 | # when finding host_device.
27 | #
28 | # We wait for udev to finish probing the partitions, and rely on the data
29 | # partition node having been probed after the parent device, hence it
30 | # will win the race to own the by-uuid symlink.
31 | udevadm settle
32 | host_device=/dev/disk/by-uuid/${image_device#UUID=}
33 | if ! [ -b "${host_device}" ]; then
34 | echo "Failed to find host partition device"
35 | exit 1
36 | fi
37 |
38 | # If possible, create partition for persistent data storage
39 | eos-live-storage-setup "${host_device}"
40 |
41 | getargbool 0 endless.live_boot && roflag="-r"
42 | fi
43 |
44 | fstype=$(lsblk --noheadings -o FSTYPE "${host_device}")
45 | if [ $? != 0 ]; then
46 | echo "image-boot: failed to detect filesystem type"
47 | exit 1
48 | fi
49 | if [ "${fstype}" = "ntfs" ]; then
50 | fstype=ntfs3
51 | fi
52 |
53 | case "$image_path" in
54 | *.squash) squashfs=1 ;;
55 | *) squashfs= ;;
56 | esac
57 |
58 | # Identify the EOS image extents on the host device, and create a dm-linear
59 | # block device that maps exactly to that. If the image is a squashfs, then
60 | # first map that, then setup a loopback device for the uncompressed image
61 | # within it.
62 |
63 | # First, map the outermost image file (uncompressed or squashfs)
64 | mkdir -p /outer_image
65 |
66 | # /usr/bin/mount recently became busybox, and it seems to have a hard time
67 | # guessing the filesystem when the isofs kernel module isn't loaded.
68 | # If we specify it manually, it should be ok.
69 | #
70 | # Even with util-linux mount, manually specifying this saves a few
71 | # pointless read operations, so it's probably a good idea anyway.
72 | if ! mount -t $fstype ${host_device} /outer_image; then
73 | echo "Failed to mount ${host_device}"
74 | exit 1
75 | fi
76 |
77 | # Create a loopback device backing the image
78 | image_device=$(losetup -f)
79 | losetup ${roflag} ${image_device} /outer_image/${image_path}
80 | if [ $? != 0 ]; then
81 | echo "losetup failed for /outer_image/${image_path}"
82 | exit 1
83 | fi
84 |
85 | # If $image_path is a squashfs, now create a loopback device for the
86 | # uncompressed image within it
87 | if [ -n "$squashfs" ]; then
88 | # Mount the squashfs
89 | mkdir /squash
90 | if ! mount ${image_device} /squash; then
91 | echo "Failed to mount ${image_device}"
92 | exit 1
93 | fi
94 |
95 | # Create a loopback device backing the endless image
96 | image_device=$(losetup -f)
97 | losetup ${image_device} /squash/endless.img
98 | fi
99 |
100 | if ! partx -a -v "${image_device}"; then
101 | echo "image-boot: failed to probe partitions"
102 | exit 1
103 | fi
104 |
105 | # Setup a stable /dev/disk/endless-image symlink for our image device and
106 | # partitions.
107 | #
108 | # This is used by eos-installer, which doesn't have the knowledge how
109 | # to find the image inside a squashfs, so it uses this path. This also
110 | # requires the device node to have appropriate permissions.
111 | # This path is also used by the rest of the initramfs which is hardcoded
112 | # to find the rootfs at /dev/disk/endless-image3.
113 | image_device_name="${image_device##*/}"
114 | mkdir -p /run/udev/rules.d
115 | cat < /run/udev/rules.d/70-endless-image.rules
116 | SUBSYSTEM=="block", KERNEL=="${image_device_name}", MODE="0664", SYMLINK+="disk/endless-image"
117 | SUBSYSTEM=="block", KERNEL=="${image_device_name}p?", MODE="0664", SYMLINK+="disk/endless-image%n"
118 | EOF
119 |
120 | udevadm control --reload-rules
121 |
122 | # Ideally these rules could be placed before the disk devices appear and they
123 | # would then kick in automatically, but in practice, since there are some
124 | # devices like loop0 which always exist, it is necessary to explicitly trigger.
125 | udevadm trigger "${image_device}"
126 |
127 | exit 0
128 |
--------------------------------------------------------------------------------
/dracut/image-boot/eos-image-boot-setup.service:
--------------------------------------------------------------------------------
1 | # This unit is dynamically enabled by endless-image-boot-generator
2 | [Unit]
3 | Description=EndlessOS image boot filesystem setup
4 | DefaultDependencies=no
5 | Before=initrd-switch-root.target initrd-fs.target
6 | ConditionKernelCommandLine=endless.image.device
7 |
8 | [Service]
9 | Type=oneshot
10 | ExecStart=/bin/eos-image-boot-setup
11 | RemainAfterExit=yes
12 |
--------------------------------------------------------------------------------
/dracut/image-boot/eos-live-storage-setup:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright (C) 2019 Endless Mobile, Inc.
3 | # Licensed under the GPLv2
4 | #
5 | # When performing a live boot from an ISO image on a writeable medium, create a 3rd partition filling the remaining
6 | # space on the device. This partition will later be used for persistent data
7 | # storage, so that your documents are kept for next time you boot.
8 | #
9 | # The filesystem is not created here (within the initramfs) as that can be
10 | # deferred until we are running from the real root. We just write a textual
11 | # marker to the start of the partition to indicate that the partition is
12 | # pending filesystem creation.
13 |
14 | image_partition_dev=$(readlink -f "$1")
15 | image_partition_type=$(lsblk -d -n -o TYPE "${image_partition_dev}")
16 | image_partition_sysfs=/sys/class/block/$(lsblk -d -n -o KNAME "${image_partition_dev}")
17 |
18 | if [ "${image_partition_type}" = "rom" ]; then
19 | echo "Skipping storage setup - read only media"
20 | exit 0
21 | fi
22 |
23 | case ${image_partition_dev} in
24 | *1)
25 | # partition 1 - ok
26 | ;;
27 | *)
28 | echo "Skipping storage setup as image is not on partition 1"
29 | exit 0
30 | ;;
31 | esac
32 |
33 | case ${image_partition_dev} in
34 | /dev/loop*p?)
35 | using_loop=1
36 | ;;
37 | esac
38 |
39 | host_disk_dev=/dev/$(lsblk -d -n -o PKNAME "${image_partition_dev}")
40 | host_disk_size=$(blockdev --getsz "${host_disk_dev}")
41 |
42 | # Identify EFI partition, which precedes the partition we will create
43 | efi_partition_dev=${image_partition_dev%?}2
44 | [ -e "${efi_partition_dev}" ] || exit 0
45 |
46 | efi_partition_sysfs=/sys/class/block/$(lsblk -d -n -o KNAME "${efi_partition_dev}")
47 | efi_partition_start=$(cat "${efi_partition_sysfs}"/start)
48 | efi_partition_size=$(blockdev --getsz "${efi_partition_dev}")
49 | [ -z "${efi_partition_start}" ] && exit 1
50 |
51 | # Set up target storage partition
52 | storage_partition_dev=${image_partition_dev%?}3
53 | [ -e "${storage_partition_dev}" ] && exit 0
54 |
55 | # Find a start position after the EFI partition
56 | storage_partition_start=$(( efi_partition_start + efi_partition_size ))
57 |
58 | # Fill the remainder of the disk
59 | storage_partition_size=$(( host_disk_size - storage_partition_start ))
60 |
61 | # Only create a storage partition if we have more than 1GB available,
62 | # otherwise assume that live mode is preferable.
63 | if [ ${storage_partition_size} -lt 2097152 ]; then
64 | echo "Skip partition creation ($storage_partition_size sectors available)"
65 | exit 0
66 | fi
67 |
68 | # Align storage partition start to 1MB boundary
69 | residue=$(( storage_partition_start % 2048 ))
70 | if [ $residue -gt 0 ]; then
71 | storage_partition_start=$(( storage_partition_start + 2048 - residue ))
72 | storage_partition_size=$(( host_disk_size - storage_partition_start ))
73 | fi
74 |
75 | # Just in case we ever want to convert to GPT, reserve 33 sectors at the
76 | # end of the disk, big enough for the secondary GPT header
77 | storage_partition_size=$(( storage_partition_size - 33 ))
78 |
79 | # udev might still be busy probing the disk, meaning that it will be in use.
80 | udevadm settle
81 |
82 | # Apply partition table change
83 | echo "start=${storage_partition_start}" |
84 | sfdisk --no-reread --append "${host_disk_dev}"
85 | ret=$?
86 | echo "sfdisk returned $ret"
87 | udevadm settle
88 |
89 | # Loop devices need a prod for the new partition to show up
90 | if [ -n "${using_loop}" ]; then
91 | partprobe "$host_disk_dev"
92 | udevadm settle
93 | fi
94 |
95 | # write marker bytes to new partition, to trigger filesystem creation
96 | # later during boot
97 | echo "endless_live_storage_marker" > ${storage_partition_dev}
98 | exit 0
99 |
--------------------------------------------------------------------------------
/dracut/image-boot/module-setup.sh:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016-2017 Endless Mobile, Inc.
2 | # Licensed under the GPLv2
3 |
4 | check() {
5 | return 0
6 | }
7 |
8 | depends() {
9 | echo systemd dm
10 | }
11 |
12 | install() {
13 | dracut_install blockdev partx lsblk losetup
14 | instmods overlay
15 | inst_rules 60-cdrom_id.rules
16 | inst_script "$moddir"/eos-image-boot-setup /bin/eos-image-boot-setup
17 | inst_script "$moddir"/eos-live-storage-setup /bin/eos-live-storage-setup
18 | inst_simple "$moddir"/eos-image-boot-setup.service \
19 | "$systemdsystemunitdir"/eos-image-boot-setup.service
20 | mkdir -p "${initdir}${systemdsystemconfdir}/initrd-switch-root.target.wants"
21 | inst_script "$moddir/eos-image-boot-generator" $systemdutildir/system-generators/eos-image-boot-generator
22 | }
23 |
--------------------------------------------------------------------------------
/dracut/repartition/Makefile.am:
--------------------------------------------------------------------------------
1 | dracutmoddir = $(prefix)/lib/dracut/modules.d/50eos-repartition
2 | dist_dracutmod_SCRIPTS = module-setup.sh endless-repartition.sh
3 | dist_dracutmod_DATA = endless-repartition.service
4 |
--------------------------------------------------------------------------------
/dracut/repartition/endless-repartition.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=EOS repartitioning
3 | ConditionPathExists=/etc/initrd-release
4 | ConditionKernelCommandLine=!endless.live_boot
5 |
6 | # Our position in the boot order is important. Naturally, we need to run
7 | # after the root device is available, before the root fs is mounted.
8 | # We also need to run before fsck: the repartitioning process causes the disk
9 | # device to be reprobed, which would otherwise cause the fsck unit to run
10 | # multiple times.
11 | DefaultDependencies=no
12 | Before=initrd-root-fs.target sysroot.mount systemd-fsck-root.service
13 | After=initrd-root-device.target dracut-pre-mount.service
14 |
15 | [Service]
16 | Type=oneshot
17 | ExecStart=-/bin/endless-repartition
18 | RemainAfterExit=yes
19 |
--------------------------------------------------------------------------------
/dracut/repartition/module-setup.sh:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2014 Endless Mobile, Inc.
2 | # Licensed under the GPLv2
3 |
4 | check() {
5 | return 0
6 | }
7 |
8 | depends() {
9 | echo systemd
10 | }
11 |
12 | install() {
13 | dracut_install eos-update-efi-uuid
14 | dracut_install sfdisk
15 | dracut_install blockdev
16 | dracut_install readlink
17 | dracut_install sed
18 | dracut_install tune2fs
19 | dracut_install iconv
20 | dracut_install blkid
21 | dracut_install partx
22 | inst_script "$moddir/endless-repartition.sh" /bin/endless-repartition
23 | inst_simple "$moddir/endless-repartition.service" \
24 | "$systemdsystemunitdir/endless-repartition.service"
25 | mkdir -p "${initdir}/$systemdsystemunitdir/initrd.target.wants"
26 | ln_r "$systemdsystemunitdir/endless-repartition.service" \
27 | "$systemdsystemunitdir/initrd.target.wants/endless-repartition.service"
28 | }
29 |
--------------------------------------------------------------------------------
/eos-config-journal:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # Copyright (C) 2018 Endless Technologies, Inc.
3 | # Licensed under the GPLv2
4 |
5 | parentdir=/var/log
6 | # if this dir exists, the journal will be persistently stored to it
7 | JOURNALDIR=$parentdir/journal
8 | blockerfile=$parentdir/.no_journal_on_fragile_storage
9 | cmdname=${0##*/}
10 |
11 | # get the device which will hold the journal
12 | device=$(df --output=source $parentdir | tail -n 1)
13 |
14 | # will contain non-empty string if this device is an MMC or SD device (both of
15 | # which are susceptible to damage with excessive writing)
16 | subsystem=$(lsblk --noheading -o SUBSYSTEMS --inverse "$device" | grep '^block:mmc' \
17 | || true)
18 |
19 | if [ "x$subsystem" != "x" ]; then
20 | echo "$cmdname: not enabling persistent journal: non-durable storage" \
21 | "(MMC or SD)"
22 | touch $blockerfile
23 | exit 0
24 | fi
25 |
26 | if [ -e $blockerfile ]; then
27 | echo "$cmdname: not enabling persistent journal: $blockerfile exists"
28 | exit 0
29 | fi
30 |
31 | if [ ! -d $JOURNALDIR ]; then
32 | echo "$cmdname: enabling persistent journal on durable storage"
33 | mkdir $JOURNALDIR
34 | systemd-tmpfiles --create --prefix $JOURNALDIR
35 | fi
36 |
--------------------------------------------------------------------------------
/eos-config-journal.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=configure persistent journal on durable storage
3 |
4 | # Setup /var/log/journal early after /var is mounted but before
5 | # systemd-journal-flush.service. Make sure journald is started like
6 | # systemd-journal-flush.service does.
7 | DefaultDependencies=no
8 | Conflicts=shutdown.target
9 | Before=shutdown.target
10 | After=systemd-remount-fs.service ostree-remount.service
11 | Before=systemd-journal-flush.service
12 | Wants=systemd-journald.service
13 | After=systemd-journald.service
14 | RequiresMountsFor=/var/log /var/log/journal
15 |
16 | ConditionPathExists=!/var/log/journal
17 | ConditionPathExists=!/var/log/.no_journal_on_fragile_storage
18 | ConditionKernelCommandLine=!endless.live_boot
19 |
20 | [Service]
21 | Type=oneshot
22 | RemainAfterExit=true
23 | ExecStart=/usr/sbin/eos-config-journal
24 |
25 | [Install]
26 | WantedBy=sysinit.target
27 |
--------------------------------------------------------------------------------
/eos-enable-zram:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright (C) 2018 Endless Mobile, Inc.
3 | # Licensed under the GPLv2
4 |
5 | if [ $# -lt 1 -o "$1" -lt 0 -o "$1" -gt 1 ]; then
6 | echo "Error: 0 or 1 must be specified" >&2
7 | exit 1
8 | fi
9 |
10 | ram_size_kb=$(awk '/MemTotal/{print $2}' /proc/meminfo)
11 |
12 | if [ "$1" -ne 0 ]; then
13 | set -e
14 | if [ ! -e /sys/block/zram0 ]; then
15 | modprobe zram
16 | fi
17 | echo $(($ram_size_kb * 3 / 2))K > /sys/block/zram0/disksize
18 | udevadm settle
19 | # For now, disable the swap partition if in use
20 | swapoff -a
21 | mkswap /dev/zram0
22 | swapon -d /dev/zram0
23 | else
24 | swapoff /dev/zram0
25 | echo 1 > /sys/block/zram0/reset
26 | fi
27 |
--------------------------------------------------------------------------------
/eos-enable-zram.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=swap with zram
3 | Before=multi-user.target
4 | After=swap.target
5 |
6 | [Service]
7 | Type=oneshot
8 | RemainAfterExit=true
9 | ExecStart=/usr/sbin/eos-enable-zram 1
10 | ExecStopPost=/usr/sbin/eos-enable-zram 0
11 |
12 | [Install]
13 | WantedBy=multi-user.target
14 |
--------------------------------------------------------------------------------
/eos-firewall-localonly:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # eos-firewall-localonly - simple firewall to restrict host to local networks
4 | #
5 | # Copyright (C) 2017 Endless Mobile, Inc.
6 | #
7 | # This program is free software; you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation; either version 2 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License along
18 | # with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 |
21 | # this script sets up "localonly" iptables/ip6tables chains which are connected
22 | # to the OUTPUT chain, so that the host can reach typical local network and
23 | # local multicast address ranges, a couple of internet services (DNS and NTP)
24 | # but are otherwise left offline. a NetworkManager dispatcher hook adds
25 | # any other local network routes and looks up the IP addresses for the Endless
26 | # metrics servers too.
27 |
28 | LOCALONLY_CHAIN="localonly"
29 | METRICS_CHAIN="${LOCALONLY_CHAIN}-metrics"
30 |
31 | # deep madness lies in blocking any localhost traffic
32 | allowed_interfaces="lo"
33 |
34 | # allowed v4 ranges:
35 | # - the three usual ranges for private IPs (these should always be handled
36 | # by eos-firewall-localonly-nm, this is just belt & braces)
37 | # - the "link-local autoconf" address range
38 | # - link-local multicast for mDNS etc
39 | # - local broadcast (all 1s) for DHCP etc
40 | allowed_v4_networks="10.0.0.0/8 172.16.0.0/12 169.254.0.0/16 192.168.0.0/16 224.0.0.0/24 255.255.255.255"
41 |
42 | # allowed v6 ranges (IPv6 is so much more elegant!):
43 | # - unique local addresses
44 | # - link-local addresses
45 | # - link-local multicast ranges
46 | allowed_v6_networks="fc00::/7 fe80::/10 ff02::/16"
47 |
48 | # these are the services where we want to talk *outside* the local networks
49 | # so eg DHCP is not here: it should be permitted by the allowed networks
50 | allowed_internet_services="ntp domain"
51 |
52 | # add the localonly chain to OUTPUT
53 | enable() {
54 | for cmd in iptables ip6tables; do
55 | ${cmd} -F OUTPUT
56 | ${cmd} -A OUTPUT -j "${LOCALONLY_CHAIN}"
57 | ${cmd} -P OUTPUT DROP
58 | done
59 | }
60 |
61 | # remove the localonly chain from OUTPUT
62 | disable() {
63 | for cmd in iptables ip6tables; do
64 | ${cmd} -P OUTPUT ACCEPT
65 | ${cmd} -F OUTPUT
66 | done
67 | }
68 |
69 | # initialise the localonly chain
70 | setup() {
71 | for cmd in iptables ip6tables; do
72 | ${cmd} -N ${LOCALONLY_CHAIN}
73 |
74 | for i in ${allowed_interfaces}; do
75 | ${cmd} -A ${LOCALONLY_CHAIN} -o ${i} -j ACCEPT
76 | done
77 |
78 | for p in tcp udp; do
79 | for s in ${allowed_internet_services}; do
80 | ${cmd} -A ${LOCALONLY_CHAIN} -p ${p} --dport ${s} -j ACCEPT
81 | done
82 | done
83 | done
84 |
85 | for n in ${allowed_v4_networks}; do
86 | iptables -A ${LOCALONLY_CHAIN} -d ${n} -j ACCEPT
87 | done
88 |
89 | for n in ${allowed_v6_networks}; do
90 | ip6tables -A ${LOCALONLY_CHAIN} -d ${n} -j ACCEPT
91 | done
92 |
93 | # log anything we're about to DROP, but reset TCP connections for faster app feedback
94 | for cmd in iptables ip6tables; do
95 | ${cmd} -A ${LOCALONLY_CHAIN} -m limit --limit 1/min -j LOG --log-prefix "eos-firewall-localonly: "
96 | ${cmd} -A ${LOCALONLY_CHAIN} -p tcp -j REJECT --reject-with tcp-reset
97 |
98 | ${cmd} -A ${LOCALONLY_CHAIN} -j RETURN
99 | done
100 | }
101 |
102 | remove_localonly_chain() {
103 | local chain="${1}"
104 |
105 | for cmd in iptables ip6tables; do
106 | if ${cmd} -n -L "${chain}" >/dev/null 2>&1; then
107 | # ignore failure in case chain is not present
108 | ${cmd} -D "${LOCALONLY_CHAIN}" -j "${chain}" >/dev/null 2>&1 || true
109 | ${cmd} -F "${chain}"
110 | ${cmd} -X "${chain}"
111 | fi
112 | done
113 | }
114 |
115 | # clear and remove any localonly chains
116 | reset() {
117 | # disable first because otherwise we can't erase our chains
118 | disable
119 |
120 | for iface in $(find /sys/class/net -maxdepth 1 -type l -printf "%f\n"); do
121 | remove_localonly_chain "${LOCALONLY_CHAIN}-${iface}"
122 | done
123 |
124 | remove_localonly_chain "${METRICS_CHAIN}"
125 |
126 | # this will try and remove the localonly chain from itself, but the failure
127 | # is ignored so this saves code
128 | remove_localonly_chain "${LOCALONLY_CHAIN}"
129 | }
130 |
131 | usage() {
132 | cat </dev/null 2>&1; then
42 | exit 0
43 | fi
44 | done
45 | }
46 |
47 | # if the given chain doesn't exist, create it and prepend it to the localonly table
48 | ensure_localonly_chain() {
49 | local chain="${1}"
50 |
51 | for cmd in iptables ip6tables; do
52 | if ! ${cmd} -n -L "${chain}" >/dev/null 2>&1; then
53 | ${cmd} -N "${chain}"
54 | ${cmd} -A "${chain}" -j RETURN
55 | ${cmd} -I "${LOCALONLY_CHAIN}" -j "${chain}"
56 | fi
57 | done
58 | }
59 |
60 | # if the given ACCEPT doesn't exist, create it and prepend it to the given table
61 | ensure_accept_rule_v4() {
62 | local chain="${1}"
63 | local dst="${2}"
64 |
65 | if ! iptables -C "${chain}" -d "${dst}" -j ACCEPT >/dev/null 2>&1; then
66 | echo "eos-firewall-localonly-nm: allowing ${dst} on ${chain}"
67 | iptables -I "${chain}" -d "${dst}" -j ACCEPT
68 | fi
69 | }
70 |
71 | # if the given ACCEPT doesn't exist, create it and prepend it to the given table
72 | ensure_accept_rule_v6() {
73 | local chain="${1}"
74 | local dst="${2}"
75 |
76 | if ! ip6tables -C "${chain}" -d "${dst}" -j ACCEPT >/dev/null 2>&1; then
77 | echo "eos-firewall-localonly-nm: allowing ${dst} on ${chain}"
78 | ip6tables -I "${chain}" -d "${dst}" -j ACCEPT
79 | fi
80 | }
81 |
82 | # look up the v4 and v6 addresses for the hosts in METRICS_HOSTS and prepend
83 | # ACCEPT rules to the METRICS_CHAIN. we don't expect the addresses to change
84 | # often, so there isn't any real benefit to the complexity of trying to
85 | # atomically clean / remove the old ones
86 | update_metrics() {
87 | ensure_localonly_chain "${METRICS_CHAIN}"
88 |
89 | for addr in $(getent ahostsv4 ${METRICS_HOSTS} | cut -f1 -d' ' | sort -u); do
90 | ensure_accept_rule_v4 "${METRICS_CHAIN}" "${addr}"
91 | done
92 |
93 | # same but for v6 - filter out the v4 mapped addresses as these won't occur
94 | # in the v6 output chain - if an IPv6 app is accessing a ::ffff: address, it
95 | # will leave the host via the v4 stack
96 | for addr in $(getent ahostsv6 ${METRICS_HOSTS} | cut -f1 -d' ' | sort -u | grep -v ^::ffff:); do
97 | ensure_accept_rule_v6 "${METRICS_CHAIN}" "${addr}"
98 | done
99 | }
100 |
101 | # iterate the NetworkManager provided address/subnet and route/subnet variables
102 | # add ACCEPT rules for any missing ones to a chain named after the interface
103 | add_rules_v4() {
104 | local chain="${1}"
105 | local num_addrs="${2}"
106 | local num_routes="${3}"
107 |
108 | for ((i=0; i/dev/null 2>&1; then
141 | # ignore failure in case chain is empty
142 | ${cmd} -D "${LOCALONLY_CHAIN}" -j "${chain}" >/dev/null 2>&1 || true
143 | ${cmd} -F "${chain}"
144 | ${cmd} -X "${chain}"
145 | fi
146 | done
147 | }
148 |
149 | check_iptables_loaded
150 | check_for_localonly
151 |
152 | case "${ACTION}" in
153 | connectivity-change)
154 | # not interested
155 | exit 0
156 | ;;
157 | dhcp4-change)
158 | ensure_localonly_chain "${IFACE_CHAIN}"
159 | add_rules_v4 "${IFACE_CHAIN}" "${IP4_NUM_ADDRESSES}" "${IP4_NUM_ROUTES}"
160 | update_metrics
161 | ;;
162 | dhcp6-change)
163 | ensure_localonly_chain "${IFACE_CHAIN}"
164 | add_rules_v6 "${IFACE_CHAIN}" "${IP6_NUM_ADDRESSES}" "${IP6_NUM_ROUTES}"
165 | update_metrics
166 | ;;
167 | down)
168 | remove_localonly_chain "${IFACE_CHAIN}"
169 | ;;
170 | hostname)
171 | # not interested
172 | exit 0
173 | ;;
174 | pre-*)
175 | # not interested
176 | exit 0
177 | ;;
178 | up)
179 | ensure_localonly_chain "${IFACE_CHAIN}"
180 | add_rules_v4 "${IFACE_CHAIN}" "${IP4_NUM_ADDRESSES}" "${IP4_NUM_ROUTES}"
181 | add_rules_v6 "${IFACE_CHAIN}" "${IP6_NUM_ADDRESSES}" "${IP6_NUM_ROUTES}"
182 | update_metrics
183 | ;;
184 | vpn-*)
185 | # VPN interfaces coming and going also cause normal up/down events - these
186 | # events are for VPN-specific actions
187 | exit 0
188 | ;;
189 | *)
190 | echo "eos-firewall-localonly-nm: ignoring unknown action ${1}"
191 | exit 0
192 | ;;
193 | esac
194 |
195 | exit 0
196 |
197 |
--------------------------------------------------------------------------------
/eos-firewall-localonly.service:
--------------------------------------------------------------------------------
1 | # Run eos-firewall-localonly before NetworkManager starts
2 |
3 | [Unit]
4 | Description=Endless local-only firewall
5 | Before=NetworkManager.service
6 |
7 | [Service]
8 | Type=oneshot
9 | ExecStart=/usr/sbin/eos-firewall-localonly start
10 | ExecStopPost=/usr/sbin/eos-firewall-localonly stop
11 | RemainAfterExit=true
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/eos-firstboot:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # Copyright (C) 2014 Endless Mobile, Inc.
3 | # Licensed under the GPLv2
4 |
5 | root_part=$(findmnt -rvnf -o SOURCE /)
6 |
7 | resize2fs "${root_part}"
8 |
9 | > /var/lib/eos-firstboot
10 | exit 0
11 |
--------------------------------------------------------------------------------
/eos-firstboot.service:
--------------------------------------------------------------------------------
1 | # Run eos-firstboot early during boot
2 |
3 | [Unit]
4 | Description=Endless Boot Helper
5 | DefaultDependencies=no
6 | After=sysinit.target local-fs.target
7 | Before=basic.target
8 | ConditionPathExists=!/var/lib/%N
9 | ConditionKernelCommandLine=!endless.live_boot
10 |
11 | [Service]
12 | ExecStart=/usr/sbin/eos-firstboot
13 | ExecStartPost=-rm -f /var/eos-booted
14 | StandardOutput=journal+console
15 |
16 | [Install]
17 | WantedBy=basic.target
18 |
--------------------------------------------------------------------------------
/eos-fix-flatpak-overrides.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Fix incorrect Flatpak override symlink
3 | DefaultDependencies=no
4 | Conflicts=shutdown.target
5 | Wants=local-fs.target
6 | After=local-fs.target
7 |
8 | # Only run on updates
9 | Before=multi-user.target systemd-update-done.service
10 | ConditionNeedsUpdate=|/etc
11 | ConditionNeedsUpdate=|/var
12 |
13 | # Run only if this path is a dangling symbolic link
14 | ConditionPathIsSymbolicLink=/var/lib/flatpak/overrides
15 | ConditionPathExists=!/var/lib/flatpak/overrides
16 |
17 | [Service]
18 | Type=oneshot
19 | ExecStart=rm -f /var/lib/flatpak/overrides
20 |
21 | [Install]
22 | WantedBy=multi-user.target
23 |
--------------------------------------------------------------------------------
/eos-live-boot-generator:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Usage: eos-live-boot-generator normal-dir [...]
4 | #
5 | # Conditionally adds additional boot dependencies for live boots.
6 | # This script implements systemd.generator(7).
7 |
8 | dest_dir="${1:?normal-dir argument missing}"
9 |
10 | # Check $proc_cmdline, if set, for testing purposes
11 | if grep -q "\" "${proc_cmdline:-/proc/cmdline}"; then
12 | # Don't try to remount the (read-only) root filesystem read-write
13 | ln -sf /dev/null "$dest_dir/systemd-remount-fs.service"
14 | fi
15 |
--------------------------------------------------------------------------------
/eos-live-boot-overlayfs-setup.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Endless live boot overlayfs setup
3 | DefaultDependencies=no
4 | After=ostree-remount.service var.mount
5 | Before=local-fs.target
6 | ConditionKernelCommandLine=endless.live_boot
7 |
8 | # Systemd ships several units that require access to /var but are not ordered
9 | # after local-fs.target. It would be better if they did, but that's not the
10 | # case today. Systemd doesn't expect the kind of mount post-processing that's
11 | # done here.
12 | #
13 | # You can find these with the following command:
14 | #
15 | # grep -rl -e StateDirectory -e CacheDirectory -e LogsDirectory -e var.mount \
16 | # -e 'RequiresMountsFor=.*/var' /usr/lib/systemd/system \
17 | # | xargs grep -l -e DefaultDependencies | sort
18 | Before=systemd-backlight@.service
19 | Before=systemd-coredump@.service
20 | Before=systemd-journal-flush.service
21 | Before=systemd-pstore.service
22 | Before=systemd-random-seed.service
23 | Before=systemd-rfkill.service
24 | Before=systemd-rfkill.socket
25 | Before=systemd-timesyncd.service
26 | Before=systemd-update-utmp-runlevel.service
27 | Before=systemd-update-utmp.service
28 |
29 | [Service]
30 | Type=oneshot
31 | ExecStart=/usr/sbin/eos-live-boot-overlayfs-setup
32 | RemainAfterExit=yes
33 |
34 | [Install]
35 | WantedBy=local-fs.target
36 |
--------------------------------------------------------------------------------
/eos-migrate-chromium-profile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | #
3 | # eos-migrate-chromium-profile: move users' Chromium profile to its new home
4 | #
5 | # This script is based on eos-migrate-firefox-profile.
6 | #
7 | # Copyright © 2020 Endless OS Foundation LLC
8 | #
9 | # This program is free software; you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation; either version 2 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # This program is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with this program; if not, write to the Free Software
21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 |
23 | import fileinput
24 | import os
25 | from gi.repository import GLib
26 |
27 | USER_HOME_DIR = os.path.expanduser("~/")
28 | DESKTOP_SHORTCUTS_DIR = os.path.join(USER_HOME_DIR, ".local", "share", "applications")
29 | OLD_CHROMIUM_CONFIG_DIR = os.path.join(USER_HOME_DIR, ".config", "chromium")
30 | NEW_CHROMIUM_DATA_DIR = os.path.join(USER_HOME_DIR, ".var", "app",
31 | "org.chromium.Chromium")
32 | NEW_CHROMIUM_CONFIG_DIR = os.path.join(NEW_CHROMIUM_DATA_DIR, "config", "chromium")
33 |
34 | OLD_WIDEVINE_SYSTEM_DIR = os.path.join(os.path.sep, "usr", "lib",
35 | "chromium-browser", "WidevineCdm")
36 |
37 | MIMEAPPS_LIST = os.path.join(GLib.get_user_config_dir(), "mimeapps.list")
38 | MIMEAPPS_GROUPS = [
39 | "Default Applications",
40 | "Added Associations",
41 | "Removed Associations",
42 | ]
43 | OLD_DESKTOP_FILE = "chromium-browser.desktop"
44 | NEW_DESKTOP_FILE = "org.chromium.Chromium.desktop"
45 |
46 |
47 | def update_mimeapps_list(path):
48 | """Update file associations, which in particular includes x-scheme-handler/http and
49 | friends to specify the default web browser.
50 |
51 | We cannot use GLib's own API to query what mime types the old Chromium desktop file
52 | is a handler for, because we can't construct a GDesktopAppInfo for it, because its
53 | desktop file no longer exists.
54 | """
55 |
56 | keyfile = GLib.KeyFile()
57 | try:
58 | keyfile.load_from_file(
59 | path, GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS,
60 | )
61 | except GLib.GError as gerror:
62 | if gerror.matches(GLib.file_error_quark(), GLib.FileError.NOENT):
63 | return
64 |
65 | raise
66 |
67 | changed = False
68 |
69 | for group in MIMEAPPS_GROUPS:
70 | if not keyfile.has_group(group):
71 | continue
72 |
73 | keys, _length = keyfile.get_keys(group)
74 | for key in keys:
75 | values = keyfile.get_string_list(group, key)
76 | try:
77 | i = values.index(OLD_DESKTOP_FILE)
78 | except ValueError:
79 | pass
80 | else:
81 | values[i] = NEW_DESKTOP_FILE
82 | keyfile.set_string_list(group, key, values)
83 | changed = True
84 |
85 | if changed:
86 | keyfile.save_to_file(path)
87 |
88 |
89 | def update_desktop_shortcut(path):
90 | keyfile = GLib.KeyFile()
91 | print("path: " + path)
92 | keyfile.load_from_file(path, GLib.KeyFileFlags.NONE)
93 |
94 | group = "Desktop Entry"
95 | if not keyfile.has_group(group):
96 | return
97 |
98 | exec_cmd = keyfile.get_string(group, "Exec")
99 | if not exec_cmd.startswith("/usr/bin/chromium-browser"):
100 | return
101 |
102 | keyfile.set_string(group, "Exec",
103 | "/usr/bin/flatpak run org.chromium.Chromium" +
104 | exec_cmd[len("/usr/bin/chromium-browser"):])
105 | keyfile.set_string(group, "X-Flatpak-Part-Of", "org.chromium.Chromium")
106 | keyfile.save_to_file(path)
107 |
108 |
109 | def update_desktop_shortcuts(path=DESKTOP_SHORTCUTS_DIR):
110 | try:
111 | shortcuts = os.listdir(path)
112 | except FileNotFoundError:
113 | return
114 |
115 | for filename in shortcuts:
116 | if filename.endswith(".desktop"):
117 | update_desktop_shortcut(os.path.join(path, filename))
118 |
119 |
120 | def update_old_config_references(path):
121 | if not os.path.isfile(path):
122 | return
123 |
124 | for line in fileinput.input(path, inplace=True):
125 | line = line.replace(OLD_CHROMIUM_CONFIG_DIR, NEW_CHROMIUM_CONFIG_DIR)
126 | line = line.replace(OLD_WIDEVINE_SYSTEM_DIR, "")
127 | print(line, end='')
128 |
129 |
130 | def main():
131 | migrated_file = os.path.join(NEW_CHROMIUM_DATA_DIR, ".migrated")
132 | if os.path.exists(migrated_file):
133 | return
134 |
135 | update_mimeapps_list(MIMEAPPS_LIST)
136 | update_desktop_shortcuts()
137 |
138 | if (
139 | os.path.isdir(OLD_CHROMIUM_CONFIG_DIR) and
140 | not os.path.isdir(NEW_CHROMIUM_CONFIG_DIR)
141 | ):
142 | update_old_config_references(
143 | os.path.join(OLD_CHROMIUM_CONFIG_DIR,
144 | "WidevineCdm", "latest-component-updated-widevine-cdm"))
145 | os.makedirs(os.path.dirname(NEW_CHROMIUM_CONFIG_DIR), exist_ok=True)
146 | os.rename(OLD_CHROMIUM_CONFIG_DIR, NEW_CHROMIUM_CONFIG_DIR)
147 |
148 | os.makedirs(NEW_CHROMIUM_DATA_DIR, exist_ok=True)
149 |
150 | os.mknod(migrated_file)
151 |
152 |
153 | if __name__ == "__main__":
154 | main()
155 |
--------------------------------------------------------------------------------
/eos-migrate-chromium-profile.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Migrate Chromium profile to new path
3 |
4 | ConditionPathExists=!%h/.var/app/org.chromium.Chromium/.migrated
5 |
6 | [Service]
7 | Type=oneshot
8 | ExecStart=/usr/lib/eos-boot-helper/eos-migrate-chromium-profile
9 | Restart=no
10 | RemainAfterExit=yes
11 |
12 | [Install]
13 | WantedBy=gnome-session.target
14 |
--------------------------------------------------------------------------------
/eos-migrate-firefox-profile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | #
3 | # eos-migrate-firefox-profile: move users' Firefox profile to its new home
4 | #
5 | # Copyright © 2020 Endless OS LLC
6 | # Authors:
7 | # Will Thompson
8 | #
9 | # This program is free software; you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation; either version 2 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # This program is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with this program; if not, write to the Free Software
21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 | #
23 | #
24 | # Endless's Firefox Flatpak stored its data in the real ~/.mozilla in the user's
25 | # home directory. Mozilla's Firefox Flatpak stores its data in what it thinks is
26 | # ~/.mozilla, but which is actually ~/.var/app/$APP_ID/.mozilla through the magic of
27 | # --persist=.mozilla.
28 | #
29 | # eos-update-flatpak-repos adjusts our Flatpak's permissions to match Mozilla's more
30 | # restrictive set. This script moves the actual user data.
31 | import os
32 | from gi.repository import GLib
33 |
34 | APP_DATA_DIR = os.path.expanduser("~/.var/app/org.mozilla.Firefox")
35 | APP_DATA_DIR_DOT_MOZILLA = os.path.join(APP_DATA_DIR, ".mozilla")
36 | HOME_DOT_MOZILLA = os.path.expanduser("~/.mozilla")
37 | PROFILES_INI = os.path.join(HOME_DOT_MOZILLA, "firefox", "profiles.ini")
38 |
39 | ENDLESS_FLATPAK_INSTALL_GROUP = "InstallFF6C2EBF42BF07E5"
40 | MOZILLA_FLATPAK_INSTALL_GROUP = "InstallCF146F38BCAB2D21"
41 |
42 | MIMEAPPS_LIST = os.path.join(GLib.get_user_config_dir(), "mimeapps.list")
43 | MIMEAPPS_GROUPS = [
44 | "Default Applications",
45 | "Added Associations",
46 | "Removed Associations",
47 | ]
48 | OLD_DESKTOP_FILE = "org.mozilla.Firefox.desktop"
49 | NEW_DESKTOP_FILE = "org.mozilla.firefox.desktop"
50 |
51 |
52 | def update_mimeapps_list(path):
53 | """Update file associations, which in particular includes x-scheme-handler/http and
54 | friends to specify the default web browser.
55 |
56 | Strictly speaking, a user may have had the old Firefox specified as their default
57 | browser without ever having launched it (in which case this script would not be
58 | run); in practice, this seems vanishingly unlikely.
59 |
60 | We cannot use GLib's own API to query what mime types the old Firefox desktop file
61 | is a handler for, because we can't construct a GDesktopAppInfo for it, because its
62 | desktop file no longer exists.
63 | """
64 |
65 | keyfile = GLib.KeyFile()
66 | try:
67 | keyfile.load_from_file(
68 | path, GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS,
69 | )
70 | except GLib.GError as gerror:
71 | if gerror.matches(GLib.file_error_quark(), GLib.FileError.NOENT):
72 | return
73 |
74 | raise
75 |
76 | changed = False
77 |
78 | for group in MIMEAPPS_GROUPS:
79 | if not keyfile.has_group(group):
80 | continue
81 |
82 | keys, _length = keyfile.get_keys(group)
83 | for key in keys:
84 | values = keyfile.get_string_list(group, key)
85 | try:
86 | i = values.index(OLD_DESKTOP_FILE)
87 | except ValueError:
88 | pass
89 | else:
90 | values[i] = NEW_DESKTOP_FILE
91 | keyfile.set_string_list(group, key, values)
92 | changed = True
93 |
94 | if changed:
95 | keyfile.save_to_file(path)
96 |
97 |
98 | def copy_install_section(path):
99 | """The default profile is keyed by a hash of the Firefox executable's installed
100 | path. Endless's Firefox Flatpak has the executable at a different path to Mozilla's.
101 | Copy the Endless installation's data to the group for Mozilla's."""
102 | keyfile = GLib.KeyFile()
103 | keyfile.load_from_file(
104 | path, GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS,
105 | )
106 |
107 | has_mozilla_group = keyfile.has_group(MOZILLA_FLATPAK_INSTALL_GROUP)
108 | has_endless_group = keyfile.has_group(ENDLESS_FLATPAK_INSTALL_GROUP)
109 |
110 | if not has_mozilla_group and has_endless_group:
111 | keys, _length = keyfile.get_keys(ENDLESS_FLATPAK_INSTALL_GROUP)
112 | for key in keys:
113 | value = keyfile.get_string(ENDLESS_FLATPAK_INSTALL_GROUP, key)
114 | keyfile.set_string(MOZILLA_FLATPAK_INSTALL_GROUP, key, value)
115 |
116 | # Uses g_file_set_contents(), is reasonably atomic
117 | keyfile.save_to_file(path)
118 |
119 |
120 | def main():
121 | if (
122 | os.path.isdir(APP_DATA_DIR)
123 | and not os.path.isdir(APP_DATA_DIR_DOT_MOZILLA)
124 | and os.path.isdir(HOME_DOT_MOZILLA)
125 | ):
126 | update_mimeapps_list(MIMEAPPS_LIST)
127 | copy_install_section(PROFILES_INI)
128 | os.rename(HOME_DOT_MOZILLA, APP_DATA_DIR_DOT_MOZILLA)
129 |
130 |
131 | if __name__ == "__main__":
132 | main()
133 |
--------------------------------------------------------------------------------
/eos-migrate-firefox-profile.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Migrate Firefox profile to new path
3 |
4 | ConditionPathIsDirectory=%h/.mozilla
5 | ConditionPathIsDirectory=%h/.var/app/org.mozilla.Firefox
6 | ConditionPathIsDirectory=!%h/.var/app/org.mozilla.Firefox/.mozilla
7 |
8 | [Service]
9 | Type=oneshot
10 | ExecStart=/usr/lib/eos-boot-helper/eos-migrate-firefox-profile
11 | Restart=no
12 | RemainAfterExit=yes
13 |
14 | [Install]
15 | WantedBy=gnome-session.target
16 |
--------------------------------------------------------------------------------
/eos-migrate-shotwell.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Migrate Shotwell database to new flatpak path
3 |
4 | # Only run if we have something to migrate and a flatpak db does not exist
5 | ConditionPathExists=%h/.local/share/shotwell/data/photo.db
6 | ConditionPathExists=!%h/.var/app/org.gnome.Shotwell/data/shotwell/data/photo.db
7 |
8 | [Service]
9 | Type=oneshot
10 | ExecStartPre=/usr/bin/mkdir -p %h/.var/app/org.gnome.Shotwell/data/shotwell/data/
11 | ExecStart=/usr/bin/cp %h/.local/share/shotwell/data/photo.db %h/.var/app/org.gnome.Shotwell/data/shotwell/data/photo.db
12 | Restart=no
13 | RemainAfterExit=yes
14 |
15 | [Install]
16 | WantedBy=gnome-session.target
17 |
--------------------------------------------------------------------------------
/eos-repartition-mbr:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # Copyright (C) 2016-2017 Endless Mobile, Inc.
3 | # Licensed under the GPLv2
4 |
5 | # arguments checking
6 | if [ $# -lt 1 ]; then
7 | echo "Usage: $0 " >&2
8 | exit 1
9 | fi
10 |
11 | root_disk="$1"
12 |
13 | # udev might still be busy probing the disk, meaning that it will be in use.
14 | udevadm settle
15 |
16 | # take current partition table
17 | parts=$(sfdisk -d "$root_disk")
18 |
19 | check_partition_exists() {
20 | local name=${1:?No name supplied to ${FUNCNAME[0]}}
21 | local guid=${2:?No GUID supplied to ${FUNCNAME[0]}}
22 |
23 | if ! echo "$parts" | grep -iq "type=$guid"; then
24 | echo "$0: $name partition not found" >&2
25 | exit 1
26 | fi
27 | }
28 |
29 | esp_guid="C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
30 | bios_boot_guid="21686148-6449-6E6F-744E-656564454649"
31 | dps_root_guid="4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709"
32 |
33 | check_partition_exists "ESP" "$esp_guid"
34 | check_partition_exists "BIOS boot" "$bios_boot_guid"
35 | check_partition_exists "Endless OS root" "$dps_root_guid"
36 | # If any other partitions exist, the call to sfdisk with the modified table
37 | # will fail due to type=UUid being invalid with 'label: dos'
38 |
39 | # “See if you can use ${variable//search/replace} instead.” For some of these,
40 | # we cannot.
41 | # shellcheck disable=SC2001
42 | {
43 | # Reset partition indexes
44 | parts=$(echo "$parts" | sed -e "s/^\/[^: ]\+//")
45 |
46 | # GPT -> DOS
47 | parts=$(echo "$parts" | sed -e "s/label: gpt/label: dos/")
48 |
49 | # Set ESP partition type to EF
50 | parts=$(echo "$parts" | sed -e "s/, type=$esp_guid/, type=EF/")
51 | # Remove BIOS boot partition (but leave its former contents intact)
52 | parts=$(echo "$parts" | grep -v "$bios_boot_guid")
53 | # Set MBR partition type on root partition, and mark as bootable (not strictly
54 | # true, but our MBR does not care - some BIOSes don't consider a drive to be
55 | # bootable without it)
56 | parts=$(echo "$parts" | sed -e "s/, type=$dps_root_guid/, type=83, bootable/")
57 | # Remove partition UUIDs and GPT attributes
58 | parts=$(echo "$parts" | sed -e "s/, \(uuid\|attrs\)=[^\s,]\+//g")
59 | }
60 |
61 | echo "$parts" | sfdisk --force --no-reread "$root_disk"
62 | udevadm settle
63 | partprobe "${root_disk}"
64 | udevadm settle
65 |
66 | # Set marker on 4th partition so that the partition gets enlarged to fill the
67 | # disk on first boot
68 | printf "\xdd" | dd of="$root_disk" bs=1 count=1 seek=498 conv=notrunc
69 | udevadm settle
70 |
--------------------------------------------------------------------------------
/eos-test-mode:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # eos-test-mode - Setup system for non-persistent testing.
4 | # Copyright (C) 2015 Dan Nicholson
5 | #
6 | # This program is free software; you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation; either version 2 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License along
17 | # with this program; if not, write to the Free Software Foundation, Inc.,
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 |
20 | # Check to see if we've run eos-live-boot-overlayfs-setup already
21 | [ -d /run/eos-live ] && exit 0
22 |
23 | # Mount overlays over any directory that might be written to
24 | eos-live-boot-overlayfs-setup
25 |
26 | # Disable the updater for this boot
27 | systemctl mask --runtime --now eos-autoupdater.timer eos-autoupdater.service
28 |
29 | # Disable phoning home for this boot, too
30 | systemctl mask --runtime --now eos-phone-home.{service,timer,path}
31 |
--------------------------------------------------------------------------------
/eos-transient-setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # eos-transient-setup – configures the system for transient sessions
3 | # Copyright (C) 2016-2018 Endless Mobile, Ltd.
4 | #
5 | # This program is free software; you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation; either version 2 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License along
16 | # with this program; if not, write to the Free Software Foundation, Inc.,
17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 |
19 | import argparse
20 | import glob
21 | import json
22 | import logging
23 | import os
24 | import subprocess
25 | import sys
26 | import tempfile
27 |
28 | import gi
29 | gi.require_version('OSTree', '1.0')
30 | # pylint: disable=wrong-import-position
31 | from gi.repository import GLib, Gio, OSTree # noqa: E402
32 |
33 | log = logging.getLogger(sys.argv[0])
34 |
35 | EOS_INSTALLER = 'com.endlessm.Installer.desktop'
36 | EOS_INSTALLER_PATH = os.path.join('/usr/share/applications', EOS_INSTALLER)
37 | LOCAL_APPS_DIR = '/usr/local/share/applications'
38 | LOCAL_DESKTOP_PATH = os.path.join(LOCAL_APPS_DIR, EOS_INSTALLER)
39 |
40 | LIVE_SETTINGS_DB = '/var/lib/eos-image-defaults/settings.live'
41 | USER_PROFILE_PATH = '/usr/local/share/dconf/profile/user'
42 | USER_PROFILE = '''user-db:user
43 | file-db:/var/lib/eos-image-defaults/settings.live
44 | file-db:/var/lib/eos-image-defaults/settings
45 | file-db:/usr/share/eos-default-settings/settings
46 | '''
47 |
48 | SHELL_SCHEMA = 'org.gnome.shell'
49 | FAVORITE_APPS_KEY = 'favorite-apps'
50 |
51 | GS_SCHEMA = 'org.gnome.software'
52 | ALLOW_UPDATES = 'allow-updates'
53 |
54 |
55 | class AdjustGSettings:
56 | def __init__(self):
57 | self.keyfile = GLib.KeyFile()
58 |
59 | def update(self, schema, key, variant):
60 | """Stages 'variant' as the new value for 'key' in 'schema'."""
61 | value = variant.print_(False)
62 | log.info('Updating %s: %s to %s', schema, key, value)
63 | self.keyfile.set_string(schema.replace('.', '/'), key, value)
64 |
65 | def prepare(self):
66 | """Stage all settings to be overridden."""
67 | self.update_favorite_apps()
68 | self.disallow_app_center_updates()
69 |
70 | def write_dconf_compile(self):
71 | """Write dconf database with overridden settings.
72 |
73 | We also adjust the 'user' profile to use it.
74 | """
75 | with tempfile.TemporaryDirectory(suffix='.d') as tempdir:
76 | keyfile_path = os.path.join(tempdir, '00-live')
77 | log.info('writing keyfile to %s', keyfile_path)
78 | self.keyfile.save_to_file(keyfile_path)
79 |
80 | os.makedirs(os.path.dirname(LIVE_SETTINGS_DB), exist_ok=True)
81 |
82 | args = ['dconf', 'compile', LIVE_SETTINGS_DB, tempdir]
83 | log.info('$ %s', ' '.join(args))
84 | subprocess.check_call(args)
85 |
86 | log.info('Installing new DConf profile to %s', USER_PROFILE_PATH)
87 | os.makedirs(os.path.dirname(USER_PROFILE_PATH), exist_ok=True)
88 | with open(USER_PROFILE_PATH, 'w') as user_profile_file:
89 | user_profile_file.write(USER_PROFILE)
90 |
91 | def write_stdout(self):
92 | """Write keyfile with overridden settings to stdout, for debugging."""
93 | data, _ = self.keyfile.to_data()
94 | print(data)
95 |
96 | def update_favorite_apps(self):
97 | """Adjust default favourite apps, which are shown on the taskbar."""
98 | settings = Gio.Settings(schema=SHELL_SCHEMA)
99 | favorite_apps = settings.get_strv(FAVORITE_APPS_KEY)
100 |
101 | # Prepend installer icon
102 | if EOS_INSTALLER not in favorite_apps:
103 | favorite_apps.insert(0, EOS_INSTALLER)
104 |
105 | self.update(SHELL_SCHEMA, FAVORITE_APPS_KEY,
106 | GLib.Variant('as', favorite_apps))
107 |
108 | def disallow_app_center_updates(self):
109 | """Forbid installing app updates."""
110 | self.update(GS_SCHEMA, ALLOW_UPDATES, GLib.Variant('b', False))
111 |
112 |
113 | def install_installer_desktop_file():
114 | """Make eos-installer visible in user sessions.
115 |
116 | eos-installer is shipped in all images, but its desktop file contains
117 | NoDisplay=true. Make a copy with this setting removed so it can be added to
118 | the desktop and taskbar and found via search.
119 | """
120 | log.info('Copying %s to %s with NoDisplay removed',
121 | EOS_INSTALLER_PATH, LOCAL_DESKTOP_PATH)
122 | os.makedirs(LOCAL_APPS_DIR, exist_ok=True)
123 |
124 | eos_installer_desktop = GLib.KeyFile()
125 | eos_installer_desktop.load_from_file(
126 | EOS_INSTALLER_PATH,
127 | GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS,
128 | )
129 | eos_installer_desktop.remove_key('Desktop Entry', 'NoDisplay')
130 | eos_installer_desktop.save_to_file(LOCAL_DESKTOP_PATH)
131 |
132 |
133 | def reduce_ostree_min_free_space():
134 | '''Don't require any free space on disk when installing apps. On live
135 | systems, free space is at most half of physical RAM, and running out is not
136 | a big deal.'''
137 | repo = OSTree.Repo.new_default()
138 | repo.open()
139 | config = repo.copy_config()
140 | # -size alone takes precedence but set both for clarity.
141 | config.set_string('core', 'min-free-space-size', '0MB')
142 | config.set_integer('core', 'min-free-space-percent', 0)
143 | repo.write_config(config)
144 |
145 |
146 | def main():
147 | """Configures system settings for live sessions."""
148 | parser = argparse.ArgumentParser(description=main.__doc__)
149 | parser.add_argument(
150 | "--dry-run",
151 | action="store_true",
152 | help="Just print the DConf keyfile to stdout",
153 | )
154 | args = parser.parse_args()
155 |
156 | logging.basicConfig(
157 | level=logging.INFO,
158 | format='%(name)s:%(lineno)-3s %(funcName)20s %(levelname)7s: '
159 | '%(message)s')
160 |
161 | setup = AdjustGSettings()
162 | setup.prepare()
163 |
164 | if args.dry_run:
165 | setup.write_stdout()
166 | else:
167 | setup.write_dconf_compile()
168 |
169 | reduce_ostree_min_free_space()
170 | install_installer_desktop_file()
171 |
172 |
173 | if __name__ == '__main__':
174 | main()
175 |
--------------------------------------------------------------------------------
/eos-transient-setup.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Adjust desktop settings for live boot
3 | After=eos-live-boot-overlayfs-setup.service
4 | Before=display-manager.service
5 | ConditionKernelCommandLine=endless.live_boot
6 |
7 | [Service]
8 | Type=oneshot
9 | ExecStart=/usr/sbin/eos-transient-setup
10 | RemainAfterExit=yes
11 |
12 | [Install]
13 | WantedBy=graphical.target
14 |
--------------------------------------------------------------------------------
/eos-update-flatpak-repos.service:
--------------------------------------------------------------------------------
1 | # Clean up the flatpak repositories after an OS upgrade
2 | # so that existing users match our current default configuration
3 |
4 | [Unit]
5 | Description=Configure default flatpak repositories
6 | DefaultDependencies=no
7 | Conflicts=shutdown.target
8 | Wants=local-fs.target
9 | After=local-fs.target
10 |
11 | # Only run on updates
12 | Before=multi-user.target systemd-update-done.service
13 | ConditionNeedsUpdate=|/etc
14 | ConditionNeedsUpdate=|/var
15 |
16 | # Try to run before any ostree and flatpak clients so that they all see
17 | # the updated repo configuration
18 | Before=eos-autoupdater.service eos-updater.service
19 | Before=eos-updater-avahi.service eos-update-server.service
20 | Before=eos-updater-flatpak-installer.service
21 |
22 | [Service]
23 | Type=oneshot
24 | RemainAfterExit=true
25 | ExecStart=/usr/sbin/eos-update-flatpak-repos
26 |
27 | # Flatpak checks parental controls at deploy time. In order to do this, it
28 | # needs to talk to accountsservice on the system bus, neither of which are
29 | # running when this job runs.
30 | Environment=FLATPAK_SKIP_PARENTAL_CONTROLS_NO_SYSTEM_BUS=1
31 |
32 | [Install]
33 | WantedBy=multi-user.target
34 |
--------------------------------------------------------------------------------
/eos-update-system-ca.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Update system CA store
3 |
4 | # Only run on updates
5 | DefaultDependencies=no
6 | Conflicts=shutdown.target
7 | Wants=local-fs.target
8 | After=local-fs.target
9 | Before=multi-user.target systemd-update-done.service
10 | ConditionNeedsUpdate=|/etc
11 |
12 | [Service]
13 | Type=oneshot
14 | RemainAfterExit=true
15 | ExecStart=/usr/sbin/update-ca-certificates
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/eos-vm-generator:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Usage: eos-vm-generator normal-dir [...]
4 | #
5 | # Conditionally adds additional boot dependencies for vm boots.
6 | # This script implements systemd.generator(7).
7 |
8 | dest_dir="${1:?normal-dir argument missing}"
9 | system_dir=/usr/lib/systemd/system
10 | multi_user_target_wants_dir="$dest_dir/multi-user.target.wants"
11 |
12 | # Only run on virtualbox
13 | vm_string=$(/usr/bin/systemd-detect-virt)
14 | if [ "$vm_string" != "oracle" ] ; then
15 | exit 0
16 | fi
17 |
18 | unit_path="$system_dir/virtualbox-guest-utils.service"
19 | mkdir -p "$multi_user_target_wants_dir"
20 | ln -sf "$unit_path" "$multi_user_target_wants_dir/"
21 |
--------------------------------------------------------------------------------
/factory-reset/Makefile.am:
--------------------------------------------------------------------------------
1 | dist_sbin_SCRIPTS = \
2 | eos-factory-reset \
3 | $(NULL)
4 |
5 | dist_systemdunit_DATA = \
6 | eos-factory-reset-users.service \
7 | $(NULL)
8 |
9 | eosfactoryresetdir = $(libexecdir)/eos-factory-reset
10 | dist_eosfactoryreset_SCRIPTS = \
11 | eos-factory-reset-users \
12 | $(NULL)
13 |
--------------------------------------------------------------------------------
/factory-reset/eos-factory-reset:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | import argparse
3 | import logging
4 | import subprocess
5 | import sys
6 |
7 | from systemd import journal
8 |
9 | # Options list
10 | # Each entry has the form (short name, long name, description)
11 | OPTS = [
12 | ("D", "disable", "fully remove a scheduled factory reset"),
13 | ]
14 |
15 | # Stages dictionary
16 | # Each entry has the form {name: description}
17 | # When creating a new stage make sure to check both STAGES and OPTS so names
18 | # don't clash, as they both create optional command line arguments.
19 | STAGES = {
20 | "users": "remove all user accounts (and home directories)",
21 | }
22 |
23 |
24 | def yes_or_no(question):
25 | answer = ""
26 | while answer not in ["y", "n"]:
27 | answer = input(f"{question} ").lower()
28 | return answer == "y"
29 |
30 |
31 | def toggle_stage(logger, stage, action):
32 | unit = f"eos-factory-reset-{stage}.service"
33 | cmd = ["systemctl", "--quiet", action, unit]
34 | sp = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
35 | status, msg = sp.returncode, sp.stdout.decode().rstrip("\n")
36 | if status != 0:
37 | logger.error(f"Failed to {action} stage '{stage}': {msg}")
38 | return status, msg
39 |
40 |
41 | if __name__ == "__main__":
42 | desc = "reboot the machine and perform a factory reset."
43 |
44 | logger = logging.getLogger(__name__)
45 | logger.propagate = False
46 | logger.setLevel(logging.INFO)
47 | logger.addHandler(logging.StreamHandler())
48 | logger.addHandler(journal.JournalHandler())
49 |
50 | parser = argparse.ArgumentParser(description=desc,
51 | argument_default=argparse.SUPPRESS)
52 | for n, name, desc in OPTS:
53 | parser.add_argument(f"-{n}", f"--{name}", help=desc, action="store_true")
54 |
55 | group = parser.add_argument_group("stages to be performed on the next boot",
56 | "if no stage is selected all stages will"
57 | " be scheduled")
58 | for name, desc in STAGES.items():
59 | group.add_argument(f"--{name}", help=desc, dest="stages", const=name,
60 | action="append_const")
61 |
62 | args = vars(parser.parse_args())
63 | disable = args.pop("disable", False)
64 | if disable:
65 | stages = STAGES.keys()
66 | else:
67 | stages = args.pop("stages", STAGES.keys())
68 |
69 | if not disable:
70 | action = "enable"
71 | warn_msg = [
72 | f"Selected stages: {' '.join(stages)}",
73 | "WARNING: You are about to schedule IRREVERSIBLE changes to be",
74 | "performed on the next boot. If you do not want to schedule these",
75 | "changes for the next boot say 'n' now.",
76 | ]
77 | success_msg = [
78 | "A factory reset procedure is scheduled for the next boot.",
79 | "Please reboot the machine to proceed with the reset process.",
80 | f"If this was a mistake, run '{parser.prog} --disable'.",
81 | ]
82 | else:
83 | action = "disable"
84 | warn_msg = [
85 | "You are about to remove the scheduled factory reset process.",
86 | "Unless scheduled again, a factory reset will NOT be performed.",
87 | ]
88 | success_msg = [
89 | "A factory reset procedure is not scheduled for the next boot.",
90 | ]
91 |
92 | print(*warn_msg, sep="\n", end="\n\n")
93 | if not yes_or_no("Do you want to proceed [y/n]?"):
94 | logging.shutdown()
95 | sys.exit(0)
96 | print()
97 |
98 | formatted_verb = f"{action[0].upper()}{action[1:-1]}ing"
99 | logger.info(f"{formatted_verb} stages: {' '.join(stages)}")
100 | for stage in stages:
101 | status, msg = toggle_stage(logger, stage, action)
102 | if status != 0:
103 | if not disable:
104 | logger.warning(f"Disabling selected stages: {' '.join(stages)}")
105 | for s in stages:
106 | toggle_stage(logger, s, "disable")
107 | logging.shutdown()
108 | sys.exit(1)
109 |
110 | logging.shutdown()
111 | print()
112 | print(*success_msg, sep="\n")
113 |
--------------------------------------------------------------------------------
/factory-reset/eos-factory-reset-users:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ADM_GROUP="sudo"
4 |
5 | if [ -f /etc/adduser.conf ]; then
6 | . /etc/adduser.conf
7 | fi
8 |
9 | first_uid=${FIRST_UID:-1000}
10 | last_uid=${LAST_UID:-59999}
11 |
12 | admin_users=()
13 | nonadmin_users=()
14 |
15 | IFS=':'
16 | while read -r user _ uid _ _ _ _; do
17 | if [[ $uid -ge $first_uid && $uid -le $last_uid ]]; then
18 | /usr/bin/id -Gn $user | grep --word-regexp --quiet $ADM_GROUP
19 | if [[ $? -eq 0 ]] ; then
20 | echo "Found admin user '$user' ($uid)"
21 | admin_users+=($user)
22 | else
23 | echo "Found non-admin user '$user' ($uid)"
24 | nonadmin_users+=($user)
25 | fi
26 | fi
27 | done
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #define FBDEV "/dev/fb0"
16 | #define TTYDEV "/dev/tty0"
17 |
18 | int main(int argc, char **argv) {
19 | int ret = 0, fb_fd = -1, tty_fd = -1, tty_mode;
20 | uint8_t *fbp = MAP_FAILED;
21 | size_t screensize, bytes_per_pixel;
22 | struct fb_var_screeninfo vinfo;
23 |
24 | tty_fd = open(TTYDEV, O_RDWR);
25 | if (tty_fd == -1) {
26 | perror("Failed to open " TTYDEV);
27 | ret = errno;
28 | goto exit;
29 | }
30 |
31 | if (ioctl(tty_fd, KDGETMODE, &tty_mode) == -1) {
32 | perror("KDGETMODE failed on " TTYDEV);
33 | ret = errno;
34 | goto exit;
35 | }
36 |
37 | if (tty_mode == KD_TEXT) {
38 | printf("VT is in text mode, exiting");
39 | goto exit;
40 | }
41 |
42 | fb_fd = open(FBDEV, O_RDWR);
43 | if (fb_fd == -1) {
44 | perror("Failed to open " FBDEV);
45 | ret = errno;
46 | goto exit;
47 | }
48 |
49 | if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
50 | perror("FBIOGET_VSCREENINFO failed on " FBDEV);
51 | ret = errno;
52 | goto exit;
53 | }
54 |
55 | bytes_per_pixel = vinfo.bits_per_pixel / 8;
56 | screensize = vinfo.xres * vinfo.yres * bytes_per_pixel;
57 |
58 | fbp = mmap(NULL, screensize, PROT_WRITE, MAP_SHARED, fb_fd, (off_t) 0);
59 | if (fbp == MAP_FAILED) {
60 | perror("Failed to mmap " FBDEV);
61 | ret = errno;
62 | goto exit;
63 | }
64 |
65 | memset(fbp, 0, screensize);
66 | printf("Cleared %s", FBDEV);
67 |
68 | exit:
69 | if (fbp != MAP_FAILED)
70 | munmap(fbp, screensize);
71 |
72 | if (fb_fd != -1)
73 | close(fb_fd);
74 |
75 | if (tty_fd != -1)
76 | close(tty_fd);
77 |
78 | return ret;
79 | }
80 |
--------------------------------------------------------------------------------
/fallback-fb-setup/fallback-fb-setup.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Setup The Fallback Framebuffer
3 | Requires=display-manager.service
4 | After=display-manager.service
5 |
6 | [Service]
7 | ExecStart=/usr/lib/eos-boot-helper/fallback-fb-setup/fallback-fb-setup
8 |
9 | [Install]
10 | WantedBy=graphical.target
11 |
--------------------------------------------------------------------------------
/flatpak-repos/Makefile.am:
--------------------------------------------------------------------------------
1 | flatpakrepodir = $(pkgdatadir)/flatpak-repos
2 | dist_flatpakrepo_DATA = \
3 | eos-sdk.flatpakrepo \
4 | flathub.flatpakrepo \
5 | $(NULL)
6 |
7 |
--------------------------------------------------------------------------------
/flatpak-repos/eos-sdk.flatpakrepo:
--------------------------------------------------------------------------------
1 | [Flatpak Repo]
2 | Title=Endless Apps Runtimes
3 | Url=https://ostree.endlessm.com/ostree/eos-sdk
4 | Homepage=https://endlessm.github.io/eos-knowledge-lib/
5 | Comment=Flatpak runtime for developing apps for Endless OS
6 | Description=Endless apps runtimes are released on a three month schedule and contain the libraries necessary for developing and running offline content apps. They receive minor bug fixing and security updates, and should be considered ABI stable and frozen.
7 | Icon=https://endlessos.com/wp-content/themes/endless/assets/images/logo.svg
8 | DefaultBranch=stable
9 | GPGKey=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
10 |
--------------------------------------------------------------------------------
/flatpak-repos/flathub.flatpakrepo:
--------------------------------------------------------------------------------
1 | [Flatpak Repo]
2 | Title=Flathub
3 | Url=https://dl.flathub.org/repo/
4 | Homepage=https://flathub.org/
5 | Comment=Central repository of Flatpak applications
6 | Description=Central repository of Flatpak applications
7 | Icon=https://dl.flathub.org/repo/logo.svg
8 | GPGKey=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
9 |
--------------------------------------------------------------------------------
/nvidia/Makefile.am:
--------------------------------------------------------------------------------
1 | dist_systemdunit_DATA = \
2 | nvidia-graphics.service \
3 | $(NULL)
4 |
5 | dist_sbin_SCRIPTS = \
6 | nvidia-graphics-setup \
7 | $(NULL)
8 |
9 | dist_modprobe_DATA = \
10 | nouveau.conf \
11 | $(NULL)
12 |
13 | nvidiadatadir = $(datadir)/endless-external-drivers/nvidia
14 | dist_nvidiadata_DATA = \
15 | asus-pci-blacklist \
16 | dmi-blacklist \
17 | dmi-board-blacklist
18 |
--------------------------------------------------------------------------------
/nvidia/asus-pci-blacklist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/nvidia/asus-pci-blacklist
--------------------------------------------------------------------------------
/nvidia/dmi-blacklist:
--------------------------------------------------------------------------------
1 | # List of platforms (matched by DMI data) where the proprietary nvidia driver
2 | # should not be loaded.
3 | #
4 | # Format: CSV
5 | # delimiter: ,
6 | # Quote character: "
7 |
8 | # Massive graphics corruption (940MX) (T23366)
9 | Acer,TravelMate P648-G2-MG
10 |
--------------------------------------------------------------------------------
/nvidia/dmi-board-blacklist:
--------------------------------------------------------------------------------
1 | # List of platforms (matched by DMI data) where the proprietary nvidia driver
2 | # should not be loaded.
3 | #
4 | # Format: CSV
5 | # delimiter: ,
6 | # Quote character: "
7 |
--------------------------------------------------------------------------------
/nvidia/nouveau.conf:
--------------------------------------------------------------------------------
1 | # Prevent nouveau from being auto-loaded.
2 | # We load it conditionally from nvidia-graphics.service
3 | blacklist nouveau
4 |
--------------------------------------------------------------------------------
/nvidia/nvidia-graphics.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Nvidia graphics management
3 | Before=gdm.service
4 |
5 | [Service]
6 | Type=oneshot
7 | RemainAfterExit=yes
8 | ExecStart=/usr/sbin/nvidia-graphics-setup
9 |
10 | [Install]
11 | WantedBy=graphical.target
12 |
--------------------------------------------------------------------------------
/psi-monitor/Makefile.am:
--------------------------------------------------------------------------------
1 | AM_CFLAGS = -Wall -Werror
2 |
3 | sbin_PROGRAMS = psi-monitor
4 | psi_monitor_SOURCES = psi-monitor.c
5 |
6 | dist_systemdunit_DATA = \
7 | psi-monitor.service \
8 | $(NULL)
9 |
--------------------------------------------------------------------------------
/psi-monitor/psi-monitor.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | /* Daemon parameters */
16 | static unsigned int poll_interval = 5;
17 | static unsigned int recovery_interval = 15;
18 | static unsigned int mem_threshold = 40;
19 |
20 | #define SYSRQ_TRIGGER_FILE "/proc/sysrq-trigger"
21 | /*
22 | * "/proc/pressure/memory" is memory pressure interface provided by kernel.
23 | * Please refer to PSI - Pressure Stall Information for more detail:
24 | * https://docs.kernel.org/accounting/psi.html
25 | */
26 | #define PSI_MEMORY_FILE "/proc/pressure/memory"
27 | #define BUFSIZE 256
28 |
29 | static bool opt_debug = false;
30 | static const char *short_options = "m:p:r:dh";
31 | static struct option long_options[] = {
32 | {"mem-threshold", 1, 0, 'm'},
33 | {"poll-interval", 1, 0, 'p'},
34 | {"recovery-interval", 1, 0, 'r'},
35 | {"debug", 0, 0, 'd'},
36 | {"help", 0, 0, 'h'},
37 | {0, 0, 0, 0}
38 | };
39 |
40 | static void usage(const char *progname) {
41 | printf("Usage: %s [OPTION]...\n"
42 | "Invoke out of memory killer on excessive memory pressure.\n"
43 | "\n"
44 | " -m, --mem-threshold PCT\tmemory threshold percentage (default: %u)\n"
45 | " -p, --poll-interval SEC\tpoll interval seconds (default: %u)\n"
46 | " -r, --recovery-interval SEC\trecovery interval seconds (default: %u)\n"
47 | " -d, --debug\t\t\tprint debugging messages\n"
48 | " -h, --help\t\t\tdisplay this help and exit\n",
49 | progname, mem_threshold, poll_interval, recovery_interval);
50 | }
51 |
52 | static void set_mem_threshold(const char *arg) {
53 | long val;
54 | char *endptr = NULL;
55 |
56 | errno = 0;
57 | val = strtol(arg, &endptr, 10);
58 | if (errno != 0)
59 | err(1, "Invalid memory threshold value \"%s\"", arg);
60 | if (endptr == arg)
61 | errx(1, "No memory threshold value provided");
62 | if (val < 0)
63 | errx(1, "Memory threshold value cannot be negative");
64 | if (val > 100)
65 | errx(1, "Memory threshold value cannot exceed 100");
66 | mem_threshold = (unsigned int) val;
67 | }
68 |
69 | static void set_interval(unsigned int *var, const char *arg) {
70 | long val;
71 | char *endptr = NULL;
72 |
73 | assert(var != NULL);
74 |
75 | errno = 0;
76 | val = strtol(arg, &endptr, 10);
77 | if (errno != 0)
78 | err(1, "Invalid interval value \"%s\"", arg);
79 | if (endptr == arg)
80 | errx(1, "No interval value provided");
81 | if (val < 0)
82 | errx(1, "Interval value cannot be negative");
83 | if (val > UINT_MAX)
84 | errx(1, "Interval value cannot exceed %u", UINT_MAX);
85 | *var = (unsigned int) val;
86 | }
87 |
88 | static ssize_t fstr(const char *path, char *rbuf, const char *wbuf) {
89 | int fd;
90 | ssize_t n;
91 |
92 | /* one and only one operation per call */
93 | if ((!rbuf && !wbuf) || (rbuf && wbuf))
94 | return 0;
95 |
96 | fd = open(path, rbuf ? O_RDONLY : O_WRONLY);
97 | if (fd < 0)
98 | err(1, "%s", path);
99 |
100 | if (rbuf)
101 | n = read(fd, rbuf, BUFSIZE);
102 | else
103 | n = write(fd, wbuf, strlen(wbuf));
104 | if (n < 0)
105 | err(1, "%s", path);
106 | close(fd);
107 |
108 | if (rbuf)
109 | rbuf[n-1] = '\0';
110 |
111 | return n;
112 | }
113 |
114 | static void sysrq_trigger_oom() {
115 | fstr(SYSRQ_TRIGGER_FILE, NULL, "f");
116 | sleep(recovery_interval);
117 | }
118 |
119 | int main(int argc, char **argv) {
120 | while (true) {
121 | int c = getopt_long(argc, argv, short_options, long_options, NULL);
122 | if (c == -1)
123 | break;
124 |
125 | switch (c) {
126 | case 'm':
127 | set_mem_threshold(optarg);
128 | break;
129 | case 'p':
130 | set_interval(&poll_interval, optarg);
131 | break;
132 | case 'r':
133 | set_interval(&recovery_interval, optarg);
134 | break;
135 | case 'd':
136 | opt_debug = true;
137 | break;
138 | case 'h':
139 | usage(argv[0]);
140 | return 0;
141 | default:
142 | return 1;
143 | }
144 | }
145 |
146 | setvbuf(stdout, NULL, _IOLBF, 0);
147 | printf("poll_interval=%us, recovery_interval=%us, mem_threshold=%u%%\n",
148 | poll_interval, recovery_interval, mem_threshold);
149 |
150 | while (true) {
151 | int i;
152 | char buf[BUFSIZE];
153 | float full_avg10;
154 |
155 | fstr(PSI_MEMORY_FILE, buf, NULL);
156 |
157 | for (i = 0; buf[i] != '\n'; i++);
158 | i++; /* skip \n */
159 | i+=11; /* skip "full avg10=" */
160 |
161 | sscanf(buf+i, "%f", &full_avg10);
162 | if (opt_debug) printf("full_avg10=%f\n", full_avg10);
163 |
164 | if (full_avg10 > mem_threshold) {
165 | printf("Memory pressure %.1f%% above threshold limit %u%%, "
166 | "killing task and pausing %u seconds for recovery\n",
167 | full_avg10, mem_threshold, recovery_interval);
168 | sysrq_trigger_oom();
169 | } else {
170 | sleep(poll_interval);
171 | }
172 | }
173 |
174 | return 0;
175 | }
176 |
--------------------------------------------------------------------------------
/psi-monitor/psi-monitor.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Pressure Stall Information Monitor
3 | ConditionPathExists=/proc/pressure
4 | After=sysinit.target
5 |
6 | [Service]
7 | ExecStart=/usr/sbin/psi-monitor
8 | Restart=on-failure
9 |
10 | [Install]
11 | WantedBy=basic.target
12 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | # Run in verbose mode by default. Use -q to bump the verbosity down.
3 | addopts = -v
4 |
5 | # Enable debug logging by default to help track down issues. This is set
6 | # on the root logger, but it seems the only current log messages are
7 | # from our modules. The alternative is to use the caplog fixture on all
8 | # tests to just set the level on our loggers.
9 | log_level = DEBUG
10 |
11 | # Raise an error if tests marked xfail pass
12 | xfail_strict = True
13 |
--------------------------------------------------------------------------------
/record-boot-success/Makefile.am:
--------------------------------------------------------------------------------
1 | recordbootsuccessdir = $(libexecdir)/record-boot-success
2 | dist_recordbootsuccess_SCRIPTS = \
3 | record-boot-success \
4 | $(NULL)
5 |
6 | dist_systemdunit_DATA = \
7 | record-boot-success.service \
8 | $(NULL)
9 |
10 | dist_systembusservices_DATA = \
11 | com.endlessm.RecordBootSuccess.service \
12 | $(NULL)
13 |
14 | dist_dbussystemconfig_DATA = \
15 | com.endlessm.RecordBootSuccess.conf \
16 | $(NULL)
17 |
18 | xdgautostartdir = $(sysconfdir)/xdg/autostart
19 | dist_xdgautostart_DATA = \
20 | record-boot-success.desktop \
21 | $(NULL)
22 |
23 | gdmgreeterautostartdir = $(prefix)/share/gdm/greeter/autostart
24 | dist_gdmgreeterautostart_DATA = \
25 | record-boot-success.desktop \
26 | $(NULL)
27 |
--------------------------------------------------------------------------------
/record-boot-success/com.endlessm.RecordBootSuccess.conf:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/record-boot-success/com.endlessm.RecordBootSuccess.service:
--------------------------------------------------------------------------------
1 | [D-BUS Service]
2 | Name=com.endlessm.RecordBootSuccess
3 | User=root
4 | SystemdService=record-boot-success.service
5 | Exec=/usr/lib/eos-boot-helper/record-boot-success/record-boot-success
6 |
--------------------------------------------------------------------------------
/record-boot-success/record-boot-success:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | import dbus
3 | import dbus.service
4 | import logging
5 | import os
6 | import subprocess
7 | import sys
8 |
9 | from systemd import journal
10 |
11 | BUSNAME = "com.endlessm.RecordBootSuccess"
12 |
13 |
14 | def record_boot_success():
15 | envfile = "/boot/grub/grubenv"
16 | program = "/usr/bin/grub-editenv"
17 |
18 | try:
19 | if os.path.getsize(envfile) == 0:
20 | os.remove(envfile)
21 | except FileNotFoundError:
22 | pass
23 |
24 | cmd = [program, envfile, "unset", "recordfail"]
25 | sp = subprocess.run(cmd)
26 | status = sp.returncode
27 | if status != 0:
28 | logger.error(f"{program} failed with exit code {status}")
29 | else:
30 | logger.info("Marked boot as successful")
31 | return status
32 |
33 |
34 | if __name__ == '__main__':
35 | logger = logging.getLogger(__name__)
36 | logger.propagate = False
37 | logger.setLevel(logging.INFO)
38 | logger.addHandler(logging.StreamHandler())
39 | logger.addHandler(journal.JournalHandler())
40 |
41 | status = record_boot_success()
42 | if status == 0:
43 | busname = dbus.service.BusName(BUSNAME, dbus.SystemBus())
44 |
45 | logging.shutdown()
46 | sys.exit(status)
47 |
--------------------------------------------------------------------------------
/record-boot-success/record-boot-success.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Record boot status
3 | Type=Application
4 | NoDisplay=true
5 | Exec=dbus-send --system --type=method_call --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.StartServiceByName string:"com.endlessm.RecordBootSuccess" uint32:0
6 |
--------------------------------------------------------------------------------
/record-boot-success/record-boot-success.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Record Boot Success
3 | ConditionPathIsDirectory=/boot/grub
4 | ConditionFileIsExecutable=/usr/bin/grub-editenv
5 |
6 | [Service]
7 | Type=dbus
8 | BusName=com.endlessm.RecordBootSuccess
9 | ExecStart=/usr/lib/eos-boot-helper/record-boot-success/record-boot-success
10 | RemainAfterExit=yes
11 |
--------------------------------------------------------------------------------
/tests/Makefile.am:
--------------------------------------------------------------------------------
1 | AM_TESTS_ENVIRONMENT = \
2 | BUILDDIR='$(builddir)' \
3 | TOP_BUILDDIR='$(top_builddir)' \
4 | ABS_BUILDDIR='$(abs_builddir)' \
5 | ABS_TOP_BUILDDIR='$(abs_top_builddir)' \
6 | SRCDIR='$(srcdir)' \
7 | TOP_SRCDIR='$(top_srcdir)' \
8 | ABS_SRCDIR='$(abs_srcdir)' \
9 | ABS_TOP_SRCDIR='$(abs_top_srcdir)' \
10 | $(NULL)
11 |
12 | TESTS = \
13 | check-syntax \
14 | run-tests \
15 | $(NULL)
16 |
17 | EXTRA_DIST = \
18 | $(TESTS) \
19 | __init__.py \
20 | conftest.py \
21 | efivars \
22 | espgen \
23 | test_esp_generator.py \
24 | test_image_boot.py \
25 | test_live_storage.py \
26 | test_migrate_chromium_profile.py \
27 | test_migrate_firefox_profile.py \
28 | test_repartition.py \
29 | test_repartition_mbr.py \
30 | test_update_efi_uuid.py \
31 | test_update_flatpak_repos.py \
32 | util.py \
33 | $(NULL)
34 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/__init__.py
--------------------------------------------------------------------------------
/tests/check-syntax:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | import os
3 | import subprocess
4 | import glob
5 |
6 | ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
7 |
8 |
9 | def find_files(pattern):
10 | '''Find files matching 'pattern' on the first line.'''
11 | output = subprocess.check_output([
12 | 'grep', '-r', '--files-with-match', '--null',
13 | # Only first line
14 | '--max-count', '1',
15 | # Skip .git and friends
16 | '--exclude-dir=.*',
17 | # Skip temporary files
18 | '--exclude=.*', '--exclude=*~',
19 | pattern, ROOT
20 | ])
21 | return [x.decode('utf-8') for x in output.split(b'\x00') if x]
22 |
23 |
24 | def main():
25 | '''Checks shell scripts' syntax, printing results in TAP format and
26 | exiting non-zero if any script has syntax errors.'''
27 | checks = []
28 |
29 | for bash_script in find_files("^#!/bin/bash"):
30 | checks.append(["bash", "-n", bash_script])
31 |
32 | for dash_script in find_files("^#!/bin/sh"):
33 | checks.append(["dash", "-n", dash_script])
34 |
35 | # All files with a shebang, regardless of their extension (if any)
36 | python_scripts = set(find_files("^#!/usr/bin/python"))
37 | # .py files in the tests/ directory, which may or may not have a hashtag yell
38 | python_scripts.update(glob.glob(os.path.join(ROOT, 'tests', '*.py')))
39 | checks.append(["flake8"] + sorted(python_scripts))
40 |
41 | print('1..{}'.format(len(checks)))
42 | failed = False
43 | for i, check in enumerate(checks, 1):
44 | label = ' '.join(check)
45 | try:
46 | subprocess.check_call(check)
47 | except subprocess.CalledProcessError:
48 | result = 'not ok'
49 | failed = True
50 | else:
51 | result = 'ok'
52 |
53 | print('{} {} - {}'.format(result, i, label))
54 |
55 | exit(failed)
56 |
57 |
58 | if __name__ == '__main__':
59 | main()
60 |
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | # Copyright 2024 Endless OS Foundation LLC
2 | # SPDX-License-Identifier: GPL-2.0-or-later
3 |
4 | # pytest fixtures
5 |
6 | import pytest
7 | from shutil import copyfile, copytree
8 |
9 | from .util import EFIVARFS_PATH
10 |
11 |
12 | @pytest.fixture(autouse=True)
13 | def default_env_vars(monkeypatch):
14 | monkeypatch.setenv('LANG', 'C.UTF-8')
15 |
16 |
17 | @pytest.fixture
18 | def efivarfs(tmp_path, monkeypatch):
19 | """Temporary efivarfs data
20 |
21 | Copy the test efivarfs data to a temporary location. The environment
22 | variable EFIVARFS_PATH is set to the temporary location. This is supported
23 | by libefivar.
24 | """
25 | # Only the data is copied in case EFIVARFS_PATH is read only like
26 | # during distcheck. None of the metadata matters here.
27 | tmp_efivarfs = tmp_path / 'efivars'
28 | copytree(EFIVARFS_PATH, tmp_efivarfs, copy_function=copyfile)
29 |
30 | # libefivar expects this to end with a trailing /.
31 | monkeypatch.setenv('EFIVARFS_PATH', f'{tmp_efivarfs}/')
32 |
33 | return tmp_efivarfs
34 |
--------------------------------------------------------------------------------
/tests/efivars/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/Boot0001-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/Boot0002-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/Boot0003-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/ErrOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/ErrOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/ErrOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/FALLBACK_VERBOSE-605dab50-e046-4300-abb6-3dd810dd8b23:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Key0000-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/Key0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Key0001-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/Key0001-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Lang-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 | eng
--------------------------------------------------------------------------------
/tests/efivars/LangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 | engfraengfra
--------------------------------------------------------------------------------
/tests/efivars/MTC-eb704011-1402-11d3-8e77-00a0c969723b:
--------------------------------------------------------------------------------
1 | '
--------------------------------------------------------------------------------
/tests/efivars/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23
--------------------------------------------------------------------------------
/tests/efivars/MokListTrustedRT-605dab50-e046-4300-abb6-3dd810dd8b23:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/MokListXRT-605dab50-e046-4300-abb6-3dd810dd8b23
--------------------------------------------------------------------------------
/tests/efivars/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 | A
--------------------------------------------------------------------------------
/tests/efivars/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 | en
--------------------------------------------------------------------------------
/tests/efivars/PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 | en;fr;en-US;fr-FR
--------------------------------------------------------------------------------
/tests/efivars/PlatformRecovery0000-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/PlatformRecovery0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23:
--------------------------------------------------------------------------------
1 | sbat,1,2024010900
2 | shim,4
3 | grub,3
4 | grub.debian,4
5 |
--------------------------------------------------------------------------------
/tests/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/SignatureSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c
--------------------------------------------------------------------------------
/tests/efivars/Timeout-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/VarErrorFlag-04b37fe8-f6ae-480b-bdd5-37d98c5e89aa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/endlessm/eos-boot-helper/4c265269fc7553d2b2acffbfd5ab8a056374da5b/tests/efivars/VarErrorFlag-04b37fe8-f6ae-480b-bdd5-37d98c5e89aa
--------------------------------------------------------------------------------
/tests/efivars/VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/efivars/certdb-d9bee56e-75dc-49d9-b4d7-b534210f637a:
--------------------------------------------------------------------------------
1 | '
--------------------------------------------------------------------------------
/tests/efivars/certdbv-d9bee56e-75dc-49d9-b4d7-b534210f637a:
--------------------------------------------------------------------------------
1 | &