Compare commits

..

1 Commits

Author SHA1 Message Date
obel1x fbb8699f81 Merge pull request 'Upgrade to latest main' (#11) from main into devel
Reviewed-on: #11
2026-04-25 15:47:49 +02:00
43 changed files with 421 additions and 2126 deletions
+7 -8
View File
@@ -1,12 +1,11 @@
.Trash*
*.kdev4
.kdev4/*
ks_pc_prof/*
ks.cfg
config/*
!config/README.md
client_software/.sync_*.db
client_software/setup_system.conf
config/setup_system.conf
config/setup_system.conf.bak
config/skel.tar.zst
config/.sync_*.db
config/.sync_*.db
config.d/*.conf
config.d/*.sys
config.d/*.bak
client_software_cust/*
!client_software_cust/README.md
-88
View File
@@ -1,88 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this is
A Fedora automated mass-installation and post-setup scripting collection. It uses an **OEMDRV** partition (BTRFS, mounted at `/opt/sys_config`) that Anaconda/Kickstart picks up automatically during Fedora installation. The system requires:
- A FreeIPA server (domain controller, KRA vault for encryption keys)
- A Nextcloud instance (config and software sync, WebDAV token auth)
- Client PCs with an OEMDRV partition prepared beforehand
## Configuration
Before any script runs, copy the dist file and fill in your environment:
```sh
cp /opt/sys_config/system_setup/config.dist/setup_system.conf.dist /opt/sys_config/config/setup_system.conf
# Edit setup_system.conf with your domain, server FQDNs, paths, etc.
```
Local per-machine overrides go in `config.d/*.conf` (gitignored). These are sourced after `setup_system.conf` and can override any exported variable (e.g. `config.d/system_defines.conf` overrides `REPO_BRANCH`).
`config/skel.tar.zst` (gitignored) holds the `/etc/skel` archive deployed to new installs. The `.dist` version is at `system_setup/skel/skel.tar.zst.dist`. To modify skel: extract, edit, then repack:
```sh
cd /opt/sys_config/config
tar -I 'zstd -9' -cf skel.tar.zst skel/ # or use system_setup/skel/pack_skel.sh
```
## Installation lifecycle
1. **Kickstart pre**`ks_base_profiles/basic_pre_script.inc` runs inside Anaconda's `%pre` section. It locates the OEMDRV partition, identifies the target drive, and **deletes all other partitions on that drive** (non-interactive, no prompt).
2. **Kickstart post** — After Fedora installs, `setup_system_full.sh install` runs (as root, non-interactive). It adjusts umask, adds the OEMDRV fstab entry, deploys `/etc/skel` via `setup_skel.sh`, and installs the `setup-system.service` systemd unit.
3. **First boot** (`firstrun_run` mode) — The `setup-system.service` unit runs `setup_system_full.sh firstrun_run` on `/dev/tty2`. It calls `ipa_register_host` which prompts for domain credentials and joins the PC to FreeIPA via `ipa-client-install`. The service then disables itself.
4. **User logon**`logon_script.sh` is triggered by KDE autostart. It:
- Mounts the gocryptfs-encrypted home directory (`mount_ecrypt_home.sh`) using a key stored in the FreeIPA KRA vault (`IPAVAULTNAME`)
- Obtains a Nextcloud WebDAV app token (`get_nc_token` in `setup_system.inc.sh`)
- Checks for a matching IPA sudo rule, then calls `sync_client_software.sh install` as root (preserving env) to sync configs and run software installs
- Calls `client_software/user_run.sh` (as the logged-in user)
- Syncs Firefox and Thunderbird profiles via Nextcloud (`mozilla_starter.sh`)
## Script roles
| Script | Who runs it | How called |
|---|---|---|
| `system_setup/setup_system.inc.sh` | sourced, never executed directly | `source`d by all other scripts |
| `system_setup/setup_system_full.sh` | root | kickstart post, firstrun service, or manual |
| `system_setup/logon_script.sh` | domain user | KDE autostart (via `.desktop` in autostart) |
| `system_setup/sync_client_software.sh` | root (sudo, preserve-env) | called by logon_script.sh |
| `system_setup/mount_ecrypt_home.sh` | user | called by logon_script.sh |
| `system_setup/mozilla_starter.sh` | user | called by logon_script.sh; args: `firefox\|thunderbird run\|sync [profile]` |
| `system_setup/setup_skel.sh` | root | called by setup_system_full.sh or manually |
| `system_setup/skel/pack_skel.sh` | root | manually, to repack skel archive after editing |
| `system_setup/create_nc_package_from_sys_config.sh` | user | manually, creates `~/temp/sys_config.tar.zst` |
## client_software layout
`client_software/` is synced from Nextcloud (`CLIENT_SOFTWARE_SRC``CLIENT_SOFTWARE_DST`). Each numbered subdirectory may contain:
- `install.sh` — run as root by `client_software/install.sh` (iterates sorted dirs)
- `user_run.sh` — run as the logged-in user by `client_software/user_run.sh`
Naming convention: directories `< 0100` are base installs, `>= 0100` are additional apps. Pass a filter string to run only matching directories:
```sh
# Run only the kwallet install:
${CLIENT_SOFTWARE_DST}/install.sh 0010_kwallet
```
## Kickstart files
- `ks.cfg` — the primary kickstart used for production installs (Fedora 43, KDE, x86_64, German locale/keyboard)
- `ks_base_profiles/kde_fullsetup.cfg` — an alternate/reference profile generated by Anaconda
- `ks_pc_prof/` — per-machine kickstart overrides, named by system UUID suffix (e.g. `pc-9cdb93ef7c20.cfg`)
## Sudo rule required for logon_script
The logon script requires a FreeIPA sudo rule allowing the domain user group to run `sync_client_software.sh` as root without a password, with environment preservation. The rule must include `!authenticate` and `setenv` options. The expected command pattern:
```
^/opt/sys_config/system_setup/sync_client_software\.sh.*$
```
## gitignore notes
The following are intentionally excluded from git and must be set up locally:
- `config/setup_system.conf` — site-specific config (copy from `.dist`)
- `config/skel.tar.zst` — skel archive (copy from `.dist` or rebuild)
- `config.d/*.conf` — local overrides
- `client_software/.sync_*.db` — Nextcloud sync DB files
+12 -7
View File
@@ -1,18 +1,23 @@
# Fedora automated install script collection
# Fedora OEMDRV
an automated massinstallation scripting collection for Fedora and Anaconda
IN DEVELOPMENT !
This Software is very Specific, it needs at least:
- A Free IPA Server in which IP Clients can be enrolled to
- An Admin that has the rights to do so
- A Nextcloud instance, connected to the Domain which should have Software Configuration and Reository Paths setup
- A Free IPA Server with IP Clients enrolled to the Domain
- A Nextcloud instance, connected to the Domain
- A client pc that will use this software to automate install and setup the PC
## Install
- Look at the file [install.md](install.md)
1. Create Partition named "OEMDRV", at least 1 GByte in size on a local disk that will be readable when starting installation from stick
2. Format it BTRFS and mount it to "/opt/sys_config"
3. Copy git files in it with "git clone --progress --depth 1 https://gitea.dtext.online/obel1x/fedora-OEMDRV.git /opt/sys_config"
1. or for developement "git clone --progress https://gitea.dtext.online/obel1x/fedora-OEMDRV.git /opt/sys_config"
more to come
Setup
- Make a copy of /opt/sys_config/system_setup/setup_system.conf.dist, name it /opt/sys_config/system_setup/setup_system.conf
- Check the settings in it and change to your needs before running
More to come...
+2 -2
View File
@@ -18,13 +18,13 @@ echo "Setup KWallet Password- Service."
#Check for root
if [ "$EUID" -ne 0 ]; then
echo "Error: Script requires root."
echo "Error: Script requires root. Please check if ${SCRIPTPATH}/${SCRIPTNAME} is in sudoers rules and if you are a member. And if executed via sudo."
exit 1
fi
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone and needs a prereserved environment from sync_client_software.sh. Quit."
echo "Error: Script cannot be executed standalone and needs a prereserved Environment. Quit."
exit 1
fi
+1 -13
View File
@@ -1,13 +1,6 @@
#!/bin/bash
# Restart and test Kwallet- Service
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone and needs a prereserved environment from sync_client_software.sh. Quit."
exit 1
fi
# Vars
WALLETAPPID="sys_config_wallet_script"
WALLETNAME="kdewallet"
@@ -18,12 +11,7 @@ if [[ -z $(wmctrl -m | grep "KWin") ]]; then
fi
#Restart the service
# Stop any leftover unit from a previous session before creating a new one
systemctl --user stop kwalletd6-logon.service 2>/dev/null || true
systemd-run --user --unit=kwalletd6-logon \
--property=RemainAfterExit=yes \
--property=SuccessExitStatus=1 \
kwalletd6 >${TEMPDIR}/kwalletd6.log 2>&1 &
/usr/bin/setsid kwalletd6 >${TEMPDIR}/kwalletd6.log 2>&1 &
sleep 1
#Check if kwalletd is enabled now
@@ -1,14 +0,0 @@
#!/usr/bin/env python3
from ipalib import api
from os import environ
api.bootstrap(context="cli", in_server=False)
api.finalize()
api.Backend.rpcclient.connect()
result = api.Command.user_show(environ['USER'])
user_email = result['result']['mail'][0]
user_full_name = result['result']['givenname'][0] + " " + result['result']['sn'][0]
print(result)
print(f"user_email: {user_email}")
print(f"user_full_name: {user_full_name}")
@@ -4,7 +4,6 @@
#
# Will prepare local mozilla and thunderbird folders with given tar.files
#
import re
import sys
import subprocess
import certifi
@@ -12,8 +11,6 @@ import tarfile
import shutil
import os
from os import environ
#see FreeIPA APIs: https://freeipa.readthedocs.io/en/latest/api/basic_usage.html
from ipalib import api
# See https://pypi.org/project/webdavclient3/
# needs pip install webdavclient3
from webdav3.client import Client
@@ -21,9 +18,6 @@ from webdav3.client import Client
#Variables
thunderbird_tar = os.path.dirname(__file__) + '/thunderbird.tar.zst'
firefox_tar = os.path.dirname(__file__) + '/firefox.tar.zst'
#If defined, use another Profile for that Company
if 'PROFILE_FIREFOX_TAR_FILE' in environ:
firefox_tar=environ['PROFILE_FIREFOX_TAR_FILE']
firefoxhome_path = environ['HOME'] + "/.config/mozilla/firefox"
firefoxhome_profile_src = os.path.dirname(__file__) + '/profiles_ff.ini'
firefoxhome_profile_dst = firefoxhome_path + '/profiles.ini'
@@ -34,7 +28,7 @@ if not 'DAVTOKEN_USER' in environ:
sys.exit(1)
options = {
'webdav_hostname': "https://" + environ['SERVERFQDN_NC'] + "/remote.php/dav/files/" + environ['DAVTOKEN_USER'],
'webdav_hostname': "https://nextcloud.obel1x.de/remote.php/dav/files/" + environ['DAVTOKEN_USER'],
'webdav_login': environ['DAVTOKEN_USER'],
'webdav_password': environ['DAVTOKEN_PASS']
}
@@ -84,7 +78,6 @@ if 'PROFILE_FIREFOX_SRC' in environ: # Check and setup mozilla
#Next sync will be executed by logon script
#Thunderbird first profile setup
tb_profile_dir = environ['PROFILE_TB_DST'] + "/default"
if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla
pathstr = environ['PROFILE_TB_SRC'] + "/default"
if not client.check(pathstr):
@@ -100,8 +93,8 @@ if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla
client.execute_request("mkdir", "/" + pathstr)
print("Done.")
#Check and create local Folder
if not os.path.exists(tb_profile_dir):
os.makedirs(tb_profile_dir)
if not os.path.exists(environ['PROFILE_TB_DST'] + "/default"):
os.makedirs(environ['PROFILE_TB_DST'] + "/default")
#First sync to initialise sync-db
print("Call " + environ['SYSCONFIGPATH'] + "/system_setup/mozilla_starter.sh thunderbird sync")
retstr = subprocess.call(['sh', environ['SYSCONFIGPATH'] + '/system_setup/mozilla_starter.sh', 'thunderbird', 'sync'])
@@ -113,90 +106,4 @@ if 'PROFILE_TB_SRC' in environ: # Check and setup mozilla
print("Done.")
#Next sync will be executed by logon script
# Check and auto-provision IMAP account for DAVTOKEN_USER@TLDOMAIN in Thunderbird
if ('PROFILE_TB_DST' in environ and 'TLDOMAIN' in environ and
'SERVERFQDN_IMAP' in environ and 'DAVTOKEN_USER' in environ):
prefs_path = environ['PROFILE_TB_DST'] + "/default/prefs.js"
imap_host = environ['SERVERFQDN_IMAP']
account_name = environ['USER'] + "@" + environ['TLDOMAIN']
#Call IPA api to get the Values
api.bootstrap(context="cli", in_server=False)
api.finalize()
api.Backend.rpcclient.connect()
api_userinfo = api.Command.user_show(environ['USER'])
user_full_name = api_userinfo['result']['givenname'][0] + " " + api_userinfo['result']['sn'][0]
user_email = api_userinfo['result']['mail'][0]
if not os.path.exists(prefs_path):
print("Thunderbird prefs.js not found, skipping mail account setup.")
else:
with open(prefs_path, 'r') as f:
prefs = f.read()
account_exists = bool(re.search(
r'mail\.server\.server\d+\.userName",\s*"' + re.escape(account_name) + '"',
prefs
))
if account_exists:
print(f"Thunderbird IMAP account {account_name} already configured.")
else:
print(f"Adding Thunderbird IMAP account {account_name} ...")
server_nums = [int(x) for x in re.findall(r'mail\.server\.server(\d+)\.type', prefs)]
account_nums = [int(x) for x in re.findall(r'mail\.account\.account(\d+)\.server', prefs)]
id_nums = [int(x) for x in re.findall(r'mail\.identity\.id(\d+)\.useremail', prefs)]
ns = (max(server_nums) + 1) if server_nums else 1
na = (max(account_nums) + 1) if account_nums else 1
ni = (max(id_nums) + 1) if id_nums else 1
sn, an, idn = f"server{ns}", f"account{na}", f"id{ni}"
new_lines = [
f'user_pref("mail.server.{sn}.check_new_mail", true);',
f'user_pref("mail.server.{sn}.cleanup_inbox_on_exit", true);',
f'user_pref("mail.server.{sn}.directory", "{tb_profile_dir}/ImapMail/{imap_host}");',
f'user_pref("mail.server.{sn}.directory-rel", "[ProfD]ImapMail/{imap_host}");',
f'user_pref("mail.server.{sn}.hostname", "{imap_host}");',
f'user_pref("mail.server.{sn}.login_at_startup", true);',
f'user_pref("mail.server.{sn}.max_cached_connections", 5);',
f'user_pref("mail.server.{sn}.name", "{account_name}");',
f'user_pref("mail.server.{sn}.port", 993);',
f'user_pref("mail.server.{sn}.socketType", 3);',
f'user_pref("mail.server.{sn}.storeContractID", "@mozilla.org/msgstore/maildirstore;1");',
f'user_pref("mail.server.{sn}.timeout", 29);',
f'user_pref("mail.server.{sn}.trash_folder_name", "Trash");',
f'user_pref("mail.server.{sn}.type", "imap");',
f'user_pref("mail.server.{sn}.userName", "{environ["USER"]}");',
f'user_pref("mail.identity.{idn}.draft_folder", "imap://{environ["USER"]}@{imap_host}/Drafts");',
f'user_pref("mail.identity.{idn}.drafts_folder_picker_mode", "0");',
f'user_pref("mail.identity.{idn}.fcc_folder", "imap://{environ["USER"]}@{imap_host}/Sent");',
f'user_pref("mail.identity.{idn}.fcc_folder_picker_mode", "0");',
f'user_pref("mail.identity.{idn}.fullName", "{user_full_name}");',
f'user_pref("mail.identity.{idn}.reply_on_top", 1);',
f'user_pref("mail.identity.{idn}.stationery_folder", "imap://{environ["USER"]}@{imap_host}/Templates");',
f'user_pref("mail.identity.{idn}.tmpl_folder_picker_mode", "0");',
f'user_pref("mail.identity.{idn}.useremail", "{user_email}");',
f'user_pref("mail.identity.{idn}.valid", true);',
f'user_pref("mail.account.{an}.identities", "{idn}");',
f'user_pref("mail.account.{an}.server", "{sn}");',
]
# Append account to mail.accountmanager.accounts
m = re.search(r'(mail\.accountmanager\.accounts",\s*")([^"]+)(")', prefs)
if m:
prefs = prefs[:m.start(2)] + m.group(2) + ',' + an + prefs[m.end(2):]
else:
new_lines.append(f'user_pref("mail.accountmanager.accounts", "{an}");')
# Update mail.account.lastKey
m = re.search(r'(mail\.account\.lastKey",\s*)(\d+)', prefs)
if m:
prefs = prefs[:m.start(2)] + str(max(int(m.group(2)), na)) + prefs[m.end(2):]
prefs = prefs.rstrip('\n') + '\n' + '\n'.join(new_lines) + '\n'
with open(prefs_path, 'w') as f:
f.write(prefs)
print(f"Thunderbird IMAP account {account_name} added successfully.")
sys.exit(0)
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env sh
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Sofwareinstallation script for Nextcloud Talk.
#
#Check for root
if [ "$EUID" -ne 0 ]; then
echo "Error: Script requires root. Please check if ${SCRIPTPATH}/${SCRIPTNAME} is in sudoers rules and if you are a member. And if executed via sudo."
exit 1
fi
cp -n *.desktop $SUDO_HOME/Schreibtisch
chown $SUDO_USER:$SUDO_USER $SUDO_HOME/Schreibtisch/*.desktop
@@ -1,8 +0,0 @@
#!/usr/bin/env sh
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Copies the included Desktop files to the Desktop
#
cp -n *.desktop $HOME/Schreibtisch
View File
@@ -4,18 +4,13 @@
#
# Sofwareinstallation script for Nextcloud Desktop
#
# Hint: No check for installed Nextcloud needed, because it will be installed by calling script sync_client_software.sh
# before as it is needed there already
echo "Setup Nextcloud- Sync"
#Local Vars
NC_FLATPAK_APP="com.nextcloud.desktopclient.nextcloud"
NC_FLATPAK_DIR="${HOME}/.var/app/${NC_FLATPAK_APP}"
BASECMD="/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=nextcloud ${NC_FLATPAK_APP}"
BASECMD="/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=nextcloud com.nextcloud.desktopclient.nextcloud"
#Check Token
if [ "${DAVTOKEN_USER}." = "." ]; then
if [ "${DAVTOKEN_USER}." == "." ]; then
# Todo: Move all task to some function to logon as user and get all vars, call it and proceed here
echo "Error: Script cannot be executed standalone and needs a prereserved Environment. Quit."
exit 1
@@ -23,38 +18,33 @@ fi
#Remove Nextcloud from autostart anyway! Must be started by this script manually, because if it was started befor the ecrypted mount,
#it will never sync and always throw an error that the local dir is missing
if [ -f "$HOME/.config/autostart/${NC_FLATPAK_APP}.desktop" ]; then
echo "Remove Autostart Nextcloud (old)"
rm $HOME/.config/autostart/${NC_FLATPAK_APP}.desktop
fi
# Same for NCs nuild-in autostart
if [ -f "$HOME/.config/autostart/Nextcloud.desktop" ]; then
echo "Remove Autostart Nextcloud (from installed binary)"
rm $HOME/.config/autostart/Nextcloud.desktop
if [ -f "$SUDO_HOME/.config/autostart/com.nextcloud.desktopclient.nextcloud.desktop" ]; then
echo "Remove Autostart Nextcloud"
rm $SUDO_HOME/.config/autostart/com.nextcloud.desktopclient.nextcloud.desktop
fi
NC_PID=$( pgrep -u $USER nextcloud )
if [ -n "${NC_PID}" ]; then
if [[ ! -z ${NC_PID} ]]; then
echo "Stopping Nextcloud with PID ${NC_PID}"
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=nextcloud ${NC_FLATPAK_APP} --quit >/dev/null
if [ $? -ne 0 ]; then
echo "Service could not be stopped, please check why."
exit 1
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=nextcloud com.nextcloud.desktopclient.nextcloud --quit >/dev/null
if [[ $? -ne 0 ]]; then
echo "Service could not be stopped, please check why."
exit 1
fi
sleep 0.5
fi
NC_PID=$( pgrep -u $USER nextcloud )
if [ -n "${NC_PID}" ]; then
if [[ ! -z ${NC_PID} ]]; then
echo "Nextcloud still running with PID ${NC_PID}. Force stop"
# Kill does not remove lockfiles in ${NC_FLATPAK_DIR}/cache/tmp/ which will prevent next start
# Kill does not remove lockfiles in ~/.var/app/com.nextcloud.desktopclient.nextcloud/cache/tmp/ which will prevent next start
kill ${NC_PID}
if [ $? -ne 0 ]; then
echo "Service could not be stopped, please check why."
exit 1
if [[ $? -ne 0 ]]; then
echo "Service could not be stopped, please check why."
exit 1
fi
sleep 0.5
rm -rif ${NC_FLATPAK_DIR}/cache/temp/*
rm -rif ${HOME}/.var/app/com.nextcloud.desktopclient.nextcloud/cache/temp/*
fi
#Check if Option is Configured to use Nextcloud Desktop Data- Sync
@@ -62,68 +52,41 @@ declare -p CLIENT_DATA_SYNC_DECLARE >/dev/null
eval "${CLIENT_DATA_SYNC_DECLARE}"
declare -p CLIENT_DATA_SYNC_DECLARE CLIENT_DATA_SYNC >/dev/null
eval "${CLIENT_DATA_SYNC}"
if [ "${#CLIENT_DATA_SYNC[@]}" -eq 0 ]; then
if [[ "${#CLIENT_DATA_SYNC[@]}" == "0" ]]; then
echo "CLIENT_DATA_SYNC not set, skipping setup of Nextcloud Desktop sync"
exit 0
fi
#Check for leftover .bak directories from previous failed setups
_nc_bak_list=$(
for CLIENT_DATA_DECLARE_LINE in "${CLIENT_DATA_SYNC[@]}"; do
eval "${CLIENT_DATA_DECLARE_LINE}"
find "$(dirname "${CLIENT_DATA_SYNC_LINE[0]}")" -maxdepth 1 -type d -name "*.bak" 2>/dev/null
done | sort -u
)
if [ -n "${_nc_bak_list}" ]; then
echo "The following old backup folders were found and should be removed:"
echo "${_nc_bak_list}" | while IFS= read -r _nc_d; do
[ -n "${_nc_d}" ] && echo " $(du -sh "${_nc_d}" 2>/dev/null | cut -f1) ${_nc_d}"
done
read -r -p "Delete these backup folders? [y/N]: " _nc_del
if [ "${_nc_del}" = "y" ] || [ "${_nc_del}" = "Y" ]; then
echo "${_nc_bak_list}" | while IFS= read -r _nc_d; do
if [ -n "${_nc_d}" ]; then
rm -rf "${_nc_d}"
echo "Deleted: ${_nc_d}"
fi
done
fi
fi
#Loop through all Entries
_nc_first=1
_nc_wipe_done=0
for CLIENT_DATA_DECLARE_LINE in "${CLIENT_DATA_SYNC[@]}"; do
for i in {0..99}; do
if [[ -z ${CLIENT_DATA_SYNC[$i]} ]]; then
break
fi
CLIENT_DATA_DECLARE_LINE="${CLIENT_DATA_SYNC[$i]}"
eval "${CLIENT_DATA_DECLARE_LINE}"
# echo "DEBUG user_run.sh(0020)_2: ${CLIENT_DATA_SYNC_LINE[@]}"
# Now, CLIENT_DATA_SYNC_LINE[0] contains the local path and CLIENT_DATA_SYNC_LINE[1] contains the remote path
if grep -q "localPath=${CLIENT_DATA_SYNC_LINE[0]}" "${NC_FLATPAK_DIR}/config/Nextcloud/nextcloud.cfg"; then
if grep -q "localPath=${CLIENT_DATA_SYNC_LINE[0]}" "/${HOME}/.var/app/com.nextcloud.desktopclient.nextcloud/config/Nextcloud/nextcloud.cfg"; then
echo "Already found configured local folder ${CLIENT_DATA_SYNC_LINE[0]} syncing with ${CLIENT_DATA_SYNC_LINE[1]} . Leaving it unchanged."
_nc_first=0
else
echo "Setup new sync from remote ${CLIENT_DATA_SYNC_LINE[1]} to local ${CLIENT_DATA_SYNC_LINE[0]}"
if [ "${_nc_first}" -eq 0 ]; then
echo "Due to Bug in Nextcloud Client, more than one synced Folder cannot be setup currently. Maybe in the Future."
continue
if [[ $i -gt 0 ]]; then
echo "Due to Bug in Nextcloud Client, more than one synced Folder cannot be setup currently. Maybe in the Future."
continue;
fi
_nc_first=0
if [ -d "${CLIENT_DATA_SYNC_LINE[0]}" ]; then
_nc_bak="${CLIENT_DATA_SYNC_LINE[0]}_$(date '+%Y%m%d%H%M%S').bak"
echo "Old unsynced Folder ${CLIENT_DATA_SYNC_LINE[0]} was found, renaming to ${_nc_bak}."
mv "${CLIENT_DATA_SYNC_LINE[0]}" "${_nc_bak}"
echo "Old unsynced Folder ${CLIENT_DATA_SYNC_LINE[0]} was found, renaming to ${CLIENT_DATA_SYNC_LINE[0]}_bak."
mv "${CLIENT_DATA_SYNC_LINE[0]}" "${CLIENT_DATA_SYNC_LINE[0]}_bak"
fi
mkdir -p ${CLIENT_DATA_SYNC_LINE[0]}
SYNCCMD="$BASECMD --userid ${DAVTOKEN_USER} --apppassword ${DAVTOKEN_PASS} --localdirpath ${CLIENT_DATA_SYNC_LINE[0]} --remotedirpath ${CLIENT_DATA_SYNC_LINE[1]} --serverurl https://${SERVERFQDN_NC}"
SYNCCMD_HIDDENPW=$( echo "${SYNCCMD/${DAVTOKEN_PASS}/***HIDDEN***}" )
echo "Exec: ${SYNCCMD_HIDDENPW}"
if [ "${_nc_wipe_done}" -eq 0 ]; then
# Autoprovisioning only works when no configuration is existent — wipe once before first new setup
rm -rif ${NC_FLATPAK_DIR}/data/Nextcloud
rm -rif ${NC_FLATPAK_DIR}/config/Nextcloud
_nc_wipe_done=1
fi
# Due to Bugs in Nextcloud, autoprovisioning will only work when no configuration is existent. Therefore delete any exitsing configs that may be there
rm -rif ${HOME}/.var/app/com.nextcloud.desktopclient.nextcloud/data/Nextcloud
rm -rif ${HOME}/.var/app/com.nextcloud.desktopclient.nextcloud/config/Nextcloud
#Now, execute Nextcloud autoprovisionig
${SYNCCMD} && sleep 0.5
${SYNCCMD}
if [ $? -ne 0 ]; then
echo "=========== !!! ========================"
echo "Error: It looks like this did not work!"
@@ -133,51 +96,33 @@ for CLIENT_DATA_DECLARE_LINE in "${CLIENT_DATA_SYNC[@]}"; do
fi
done
# The Flatpak autoprovisioning may not successfully write the apppassword to
# KWallet from inside the sandbox, so write it directly via D-Bus.
# Nextcloud stores HTTP credentials in folder "Nextcloud" with keys:
# user:url/:0 (legacy password entry)
# user_app-password:url/:0 (app password entry, used for auth)
NC_WALLET_URL="https://${SERVERFQDN_NC}/"
NC_WALLET_APPID="logon_script"
NC_QB_CMD="qdbus-qt6"
if ! command -v ${NC_QB_CMD} >/dev/null 2>&1; then NC_QB_CMD="qdbus"; fi
# Only attempt KWallet on KDE: check that the service is registered on the session bus.
if command -v "${NC_QB_CMD}" >/dev/null 2>&1 && \
"${NC_QB_CMD}" 2>/dev/null | grep -q "org.kde.kwalletd"; then
NC_QB_SVC="org.kde.kwalletd"
NC_QB_PATH="/modules/kwalletd6"
if ! ( ${NC_QB_CMD} "${NC_QB_SVC}" | grep -q "${NC_QB_PATH}" ); then
NC_QB_PATH="/modules/kwalletd5"
fi
echo "Checking Nextcloud app password in KWallet via D-Bus (${NC_QB_PATH})"
NC_WALLET_HANDLE=$(${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.open "kdewallet" 0 "${NC_WALLET_APPID}")
if [ -n "${NC_WALLET_HANDLE}" ] && [ "${NC_WALLET_HANDLE}" != "-1" ]; then
HAS_FOLDER=$(${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.hasFolder "${NC_WALLET_HANDLE}" "Nextcloud" "${NC_WALLET_APPID}")
if [ "${HAS_FOLDER}" != "true" ]; then
${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.createFolder "${NC_WALLET_HANDLE}" "Nextcloud" "${NC_WALLET_APPID}" >/dev/null
fi
HAS_PW1=$(${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.hasEntry "${NC_WALLET_HANDLE}" "Nextcloud" "${DAVTOKEN_USER}:${NC_WALLET_URL}:0" "${NC_WALLET_APPID}")
HAS_PW2=$(${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.hasEntry "${NC_WALLET_HANDLE}" "Nextcloud" "${DAVTOKEN_USER}_app-password:${NC_WALLET_URL}:0" "${NC_WALLET_APPID}")
if [ "${HAS_PW1}" = "true" ] && [ "${HAS_PW2}" = "true" ]; then
echo "Nextcloud app password already present in KWallet — no change needed."
else
${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.writePassword "${NC_WALLET_HANDLE}" "Nextcloud" "${DAVTOKEN_USER}:${NC_WALLET_URL}:0" "${DAVTOKEN_PASS}" "${NC_WALLET_APPID}" >/dev/null
${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.writePassword "${NC_WALLET_HANDLE}" "Nextcloud" "${DAVTOKEN_USER}_app-password:${NC_WALLET_URL}:0" "${DAVTOKEN_PASS}" "${NC_WALLET_APPID}" >/dev/null
echo "Nextcloud app password written to KWallet successfully."
fi
${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.sync "${NC_WALLET_HANDLE}" "${NC_WALLET_APPID}" >/dev/null
${NC_QB_CMD} ${NC_QB_SVC} ${NC_QB_PATH} org.kde.KWallet.close "${NC_WALLET_HANDLE}" false "${NC_WALLET_APPID}" >/dev/null
else
echo "Warning: Could not open KWallet (handle: ${NC_WALLET_HANDLE}). Nextcloud may prompt for credentials on next start."
fi
else
echo "KWallet not available (non-KDE desktop) — skipping credential storage."
fi
##Check if Nextcloud was already setup
#if [ $SETUP_NEEDED = "0" ]; then
# echo "Nextcloud was already setup, skipping configure and starting Service"
# echo "If you want to reset, please delete the Folder [HOME]/.var/app/com.nextcloud.desktopclient.nextcloud manually."
# echo "Command: rm -rif ~/.var/app/com.nextcloud.desktopclient.nextcloud/"
# su -c "nohup ${BASECMD} 1>/dev/null 2>/dev/null &" $SUDO_USER
# exit $?
#fi
#No check for installed Nextcloud needed, because it will be installed by calling script sync_client_software.sh
#Cleanup Nextcloud Configuration completely, while otherwise, the configure will not work
#echo "Remove $SUDO_HOME/.var/app/com.nextcloud.desktopclient.nextcloud"
#rm -rif "$SUDO_HOME/.var/app/com.nextcloud.desktopclient.nextcloud"
#echo "Exec as $SUDO_USER: ${SYNCCMD}"
#echo "Exec as $SUDO_USER: ${SYNCCMD_HIDDENPW}"
#su -c "${SYNCCMD}" $SUDO_USER
#if [ $? -ne 0 ]; then
# echo "=========== !!! ========================"
# echo "Error: It looks like this did not work!"
# echo "Please check the above output!"
# exit 1
#fi
# Now start Nextcloud
echo "Starting Nextcloud Client in Background"
systemd-run --user --no-block --unit=nextcloud-client.service --setenv=SESSION_MANAGER= ${BASECMD} >>${TEMPDIR}/nc_desktop_client.log 2>&1
/usr/bin/setsid ${BASECMD} >${TEMPDIR}/nc_desktop_client.log 2>&1 &
sleep 2
echo "Done Setup of Nextcloud."
exit 0
-24
View File
@@ -1,24 +0,0 @@
# 0060_ssh_key
Provisions a per-user `~/.ssh/id_ed25519` key and escrows it in the FreeIPA
KRA vault (`SSH_PRIV_KEY`), so the same key is reused across machines instead
of generating a new one on every install.
Run as the logged-in user via `client_software/user_run.sh` (needs the
`DAVTOKEN_USER` environment prepared by `sync_client_software.sh`).
Behavior:
- `~/.ssh` is relocated to `${DECRYPTEDDATADIR}/ssh_keys` (the user's
gocryptfs-encrypted data dir) on first run: any existing content is moved
there once, then `~/.ssh` becomes a symlink to it. Subsequent runs detect
the symlink and skip this step.
- If `~/.ssh/id_ed25519` already exists, it's left untouched.
- Otherwise, tries `ipa vault-retrieve` for `SSH_PRIV_KEY`:
- found → key is fetched, permissions fixed to `0600`, public key derived.
- not found → a new vault is created, a new key pair is generated, and the
private key is archived to the vault.
- Requires `IPAVAULTUSE=true` (KRA available); otherwise the script is a
no-op.
Note: this only handles private-key escrow. Publishing the public key to the
user's FreeIPA entry (`ipa user-mod --sshpubkey`) is not done by this script.
-81
View File
@@ -1,81 +0,0 @@
#!/usr/bin/env sh
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# If IPA-KRA is available, use it to store or retrieve personal private ssh key, so that the key won't change every time on new installs
#
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone and needs a prereserved environment from sync_client_software.sh. Quit."
exit 1
fi
SSHDIR="${HOME}/.ssh"
SSHDIR_REAL="${DECRYPTEDDATADIR}/ssh_keys"
KEYFILE="${SSHDIR}/id_ed25519"
SSHVAULTNAME="SSH_PRIV_KEY"
#Relocate ~/.ssh into the encrypted data directory, migrating any existing content once
if [ ! -L "${SSHDIR}" ]; then
mkdir -p "${SSHDIR_REAL}"
chmod 0700 "${SSHDIR_REAL}"
if [ -d "${SSHDIR}" ]; then
echo "Migrating existing ${SSHDIR} contents to ${SSHDIR_REAL}."
cp -a "${SSHDIR}/." "${SSHDIR_REAL}/"
if [ $? -ne 0 ]; then
echo "Error migrating ${SSHDIR} contents to ${SSHDIR_REAL}. Aborting, please check."
exit 1
fi
rm -rf "${SSHDIR}"
fi
ln -s "${SSHDIR_REAL}" "${SSHDIR}"
if [ $? -ne 0 ]; then
echo "Error creating symlink ${SSHDIR} -> ${SSHDIR_REAL}. Aborting, please check."
exit 1
fi
fi
if [ ${IPAVAULTUSE} = "false" ]; then
echo "No IPA- KRA service configured, SSH Key provisioning to and from IPA is not available."
else
if [ -f ${KEYFILE} ]; then
echo "SSH Key already present at ${KEYFILE}. Leaving it untouched."
else
echo "SSH Key ${KEYFILE} not found. Getting Key from IPA- Vault"
ipa vault-retrieve "${SSHVAULTNAME}" --out ${KEYFILE}
if [ $? -ne 0 ]; then
echo "Seems there is no key yet on IPA, creating it new."
ipa vault-add "${SSHVAULTNAME}" --desc "SSH private key (Stored by OEMDRV autoinstall Modules)" --type=standard
if [ $? -ne 0 ]; then
echo "Error creating the new Vault named ${SSHVAULTNAME} on IPA. This should not happen, aborting. Please check."
exit 1
else
ssh-keygen -t ed25519 -C "$(whoami)" -N "" -f ${KEYFILE}
if [ $? -ne 0 ]; then
echo "Error generating the new SSH key at ${KEYFILE}. Aborting without touching the Vault. Please check."
exit 1
fi
ipa vault-archive "${SSHVAULTNAME}" --in ${KEYFILE}
if [ $? -ne 0 ]; then
echo "Error storing the Key to the created Vault ${SSHVAULTNAME}. This should not happen, aborting. Please check."
exit 1
else
echo "Sucessfully created SSH Key and stored it in IPAs KRA Vault named ${SSHVAULTNAME}."
fi
fi
else
# derive public key from private key when enrolling to new system
ssh-keygen -y -f "${KEYFILE}" > "${KEYFILE}.pub"
if [ $? -eq 0 ]; then
chmod 0600 "${KEYFILE}" "${KEYFILE}.pub"
echo "Sucessfully fetched SSH Key from IPA."
else
echo "Something went wrong with Key provisioning, please check."
exit 1
fi
fi
fi
fi
exit 0
@@ -7,13 +7,7 @@
#Check for root
if [ "$EUID" -ne 0 ]; then
echo "Error: Script requires root."
exit 1
fi
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone and needs a prereserved environment from sync_client_software.sh. Quit."
echo "Error: Script requires root. Please check if ${SCRIPTPATH}/${SCRIPTNAME} is in sudoers rules and if you are a member. And if executed via sudo."
exit 1
fi
@@ -5,15 +5,9 @@ if [[ $? -eq 0 ]]; then
/usr/bin/flatpak uninstall -y --user com.nextcloud.talk
fi
# Ensure session bus and KWallet D-Bus access (may be blocked by Flatseal or missing from manifest)
/usr/bin/flatpak override --user --socket=session-bus \
--talk-name=org.kde.kwalletd5 --talk-name=org.kde.kwalletd6 \
com.nextcloud.talk
# Start Nextcloud Talk in Background
#Current Version of Talk is dumping Core
echo "Starting Nextcloud Talk in Background."
systemd-run --user --no-block --unit=nextcloud-talk.service --property=Delegate=yes \
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=electron-wrapper --file-forwarding com.nextcloud.talk --background >>${TEMPDIR}/talk.log 2>&1
/usr/bin/setsid -f /usr/bin/flatpak run --branch=stable --arch=x86_64 --command=electron-wrapper --file-forwarding com.nextcloud.talk --background >${TEMPDIR}/talk.log 2>&1
exit 0
+5 -7
View File
@@ -1,9 +1,7 @@
# Pre installed software installation script repository
Central Software installation script Repository
Must be executed from script ../sync_client_software.sh
Contains Packages to install and setup at user logon first.
Each package is in one directory and may include two scripts which will be called from user logon script:
The install script here will check for the right environment, and execute the install.sh script in each directory.
- install.sh - will be called with root- privileges to install software or other administrative tasks
- user_run.sh - will get executed after all admins scripts had been executed in user context to setup user configs ad data
The execution will be sorted by directory name.
Be sure to name the directories to get sorted the right way.
E.g. you may use all base installations with directories beginning with numbers < 0100 and all additional apps with numbers > 0100
+46 -7
View File
@@ -2,12 +2,51 @@
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Obsolete Script
# Will get removed completely, its only here to advise the user to update and rerun the logon_script
# Central sofwareinstallation script. Should be called from ""/sys_config/system_setup/sync_client_software.sh install"
# If P1 is given, only installs will be executed, that are containing the P1 string in their dirname
#
if [ "$EUID" -ne 0 ] || [ "$SUDO_USER." == "." ]; then
echo "Error: Script requires root privileges and a sudo environment."
exit 1
fi
echo " ==================== "
echo "Obsolete Script $0 called. Please update via git (should have been done already, check above!) and rerun the logon_script by relogon again."
echo "This Message should disappear then. Press any key to continue."
read -n 1 -s -r
exit 1
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone and needs a prereserved environement from logon-script."
echo "To get executed without password prompt, use the NOPASSWD rule in sudo. In FreeIPA you can use the sudo-option !authenticate in the sudo rule."
echo "Additionally add the sudo command to the rule: ^\/sys_config\/system_setup\/sync_client_software\.sh.*$"
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
echo "Installing additional Software."
for DIR in $(ls -d ${CLIENT_SOFTWARE_DST}/*/ | sort); # list directories in the form "/tmp/dirname/"
do
DIR=${DIR%*/} # remove the trailing "/"
if [[ "$1." != "." ]] && [[ "${DIR}" != *"$1"* ]]; then
#search for string in dir
echo "Skipping ${DIR} while not in search parameter ( $1 )."
continue
fi
if [ -f "${DIR}/install.sh" ]; then
echo "*** ==================== ***"
echo "*** Installing ${DIR##*/} ***" # print everything after the final "/"
cd ${DIR}
${DIR}/install.sh
if [ $? -ne 0 ]; then
echo "*** ==================== ***"
echo "Some Error in script, will not continue. Please check."
echo "Press any key to continue."
read -n 1 -s -r
cd ${SCRIPTPATH}
exit 1
fi
echo "*** ==================== ***"
fi
done
cd ${SCRIPTPATH}
#Last, remove unused Flatpak- Runtimes and unused Data
echo "Removing unused Flatpak- Data."
flatpak uninstall --unused -y
su -c "flatpak uninstall --delete-data -y" $SUDO_USER
echo "Sucessfully Installed Software."
+38 -7
View File
@@ -2,12 +2,43 @@
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Obsolete Script
# Will get removed completely, its only here to advise the user to update and rerun the logon_script
# Running user scripts after install (as user, not root)
# If P1 is given, only scripts will be executed, that are containing the P1 string in their dirname
#
echo " ==================== "
echo "Obsolete Script $0 called. Please update via git (should have been done already, check above!) and rerun the logon_script by relogon again."
echo "This Message should disappear then. Press any key to continue."
read -n 1 -s -r
exit 1
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone and needs a prereserved environement from logon-script."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
echo "Running user scripts in software."
for DIR in $(ls -d ${CLIENT_SOFTWARE_DST}/*/ | sort); # list directories in the form "/tmp/dirname/"
do
DIR=${DIR%*/} # remove the trailing "/"
if [[ "$1." != "." ]] && [[ "${DIR}" != *"$1"* ]]; then
#search for string in dir
echo "Skipping ${DIR} while not in search parameter ( $1 )."
continue
fi
if [ -f "${DIR}/user_run.sh" ]; then
echo "*** ==================== ***"
echo "*** Running ${DIR##*/} ***" # print everything after the final "/"
cd ${DIR}
${DIR}/user_run.sh
if [ $? -ne 0 ]; then
echo "*** ==================== ***"
echo "Some Error in script, will not continue. Please check."
echo "Press any key to continue."
read -n 1 -s -r
cd ${SCRIPTPATH}
exit 1
fi
echo "*** ==================== ***"
fi
done
echo "Completed user scripts in software."
cd ${SCRIPTPATH}
exit 0
-14
View File
@@ -1,14 +0,0 @@
# Companys Software Repository
This Repository contains the software of you company, which is delivered by your company admins.
All files here despite this README ar not traked by git and are not part of installation packages.
Your Company is completely free to add files to it.
Your Company is encouraged to setup its own git repository
The scripts will be run at logon time after the scripts of the predefined software has been installed.
Each package is in one directory and may include two scripts which will be called from user logon script:
- install.sh - will be called with root- privileges to install software or other administrative tasks
- user_run.sh - will get executed after all admins scripts had been executed in user context to setup user configs ad data
The execution will be sorted by directory name.
+2 -2
View File
@@ -1,4 +1,4 @@
# Local config Files
You may have SYSTEM specific .conf files in here, which will be not be touched by anything and will be sourced by the scripts to overwrite any of the settings in setup_system.conf.dist.
Don't use this folder for special settings of your company. It is only for the PC itself if it is configured in another way as all others. The syntax should be same as setup_system.conf.dist
You may have .conf files in here, which will be not be touched by anything and will be sourced by the scripts to overwrite any of the settings in setup_system.conf.dist
The syntax should be same as setup_system.conf.dist
-4
View File
@@ -1,4 +0,0 @@
# Shared config Files
in this directory, you should have at least the setup_system.conf as a modified copy of system_setup/config.dist/setup_system.conf.dist for your needs.
This directory will be synced with DISTCONFIGPATH_SRC on your nextcloud instance an thus be delivered to all clients.
@@ -1,6 +1,7 @@
#!/usr/bin/env sh
# Usage: will make a tar-file from folder skel found in the directory where executed
# If you want to change skel- content, extrakt your skel.tar.zstd to this directory, edit the files and use this script to repack
source $(dirname "$0")/setup_system.inc.sh
mv skel.tar.zst backup_skel.tar.zst
if [ $? -eq 0 ]; then
echo "Old Archive renamed to backup_skel.tar.zst"
@@ -8,36 +8,29 @@ export SERVERFQDN_IPA=ipa.${TLDOMAIN} # Needs to be the IPA- Server
export SERVERFQDN_NC=nextcloud.${TLDOMAIN}
export INSTALLDOCS="https://gitea.dtext.online/obel1x/fedora-OEMDRV/src/branch/main/README.md"
#If the REPO_URL and REPO_BRANCH is set, this script collection will do automatic upgrades
export REPO_URL="https://gitea.dtext.online/obel1x/fedora-OEMDRV.git"
export REPO_BRANCH="main"
#If the UPGRADEURL and branch is set, this script collection will do automatic upgrades
export UPGRADEURL="https://gitea.dtext.online/obel1x/fedora-OEMDRV.git"
export UPGRADEBRANCH="main"
#Group, that will have sudo rights on the client
export CLIENTADMINGROUP="clientadmins"
# Method to determine Unique Hostname / FQDN of the Client. May be replaced by your needs
if [ "$EUID" -eq 0 ]; then
export HOSTNM="pc-$( dmidecode -t system | grep -i 'UUID' | sed 's/UUID: //' | tr '[:upper:]' '[:lower:]' | sed 's/[^0-9a-z]*//g' | xargs|tail -c 13)"
else
export HOSTNM=$( hostname -s )
fi
export FQDN=${HOSTNM}.${DOMAIN}
#Configuration Files - maybe syned with your companies settings
export SYSCONFIGPATH="/opt/sys_config"
export DISTCONFIGPATH="/opt/sys_config/config"
export DISTCONFIGPATH_SRC="/Shared/sw_geteilt/client_settings"
#Group, that will have sudo rights on the client
export CLIENTADMINGROUP="clientadmins"
# Method to determine Unique Hostname / FQDN of the Client. May be replaced by your needs
# MACHINEID should be set by install.sh. The Determination is done by setup_system.inc.sh as root for old installs.
if [ -z ${MACHINEID} ]; then
#Fallback if not configured, should only be needed once for very old installations
export HOSTNM=$( hostname -s )
else
export HOSTNM="pc-${MACHINEID}"
fi
export FQDN=${HOSTNM}.${DOMAIN}
#Additional Client-Software- Repository-Folder in Nextcloud (Shared Folder / Systemwide)
export CLIENT_SOFTWARE_CUST_DST="${SYSCONFIGPATH}/client_software_cust" # Required. Must not be changed!
export CLIENT_SOFTWARE_CUST_SRC="/Shared/sw_geteilt/client_software_cust" # Set to the Nextcloud directory where the software should come from
# OBSOLETE / OLD Variables for packaged files under client_software. Those files will not be synced to NC any more!
# if still set, they will cause sync to complain about it
unset CLIENT_SOFTWARE_DST
unset CLIENT_SOFTWARE_SRC
export CLIENT_SOFTWARE_DST="/opt/sys_config/client_software" # Optional. If you don't have a Folder that should always be synced, leave this empty
export CLIENT_SOFTWARE_SRC="/Shared/sw_geteilt/client_software" Set to the Nextcloud directory where the software should come from
#Secure File Encryption
#Needs a running KRA- Service on FreeIPA
@@ -73,23 +66,14 @@ if [ "$EUID" -ne 0 ]; then
export CLIENT_DATA_SYNC_DECLARE="$(declare -p CLIENT_DATA_SYNC)" # Do not remove
#End of Sync Folder for nextcloud client
#Firefox Profiles
#Firefox Profiles of the User
export PROFILE_FIREFOX_RESET_LOCAL="true" # Set this to wipe ~/.mozilla each time if you don't want users to setup their own firefox profile
# Optional: own Firefox profile used for this company if given as default
# You may use any tar file, that contains a valid firefox profile set up to your companies need.
# As example look at 0020_nextcloud_mozilla_pre/firefox.tar.zst
# You should put it under e.g SYSCONFIGPATH and than use the filepath relative. e.g. "${SYSCONFIGPATH}/firefox.tar.zst"
export PROFILE_FIREFOX_TAR_FILE=""
#Mozilla profile paths on Nextcloud Server. Syncs your profiles to Nextcloud.
export PROFILE_FIREFOX_SRC="mozilla_profiles/firefox"
export PROFILE_FIREFOX_DST="${DECRYPTEDDATADIR}/firefox"
#Thunderbird Profiles to also be synced
#Thunderbird Profiles
export PROFILE_TB_SRC="mozilla_profiles/thunderbird"
export PROFILE_TB_DST="${DECRYPTEDDATADIR}/thunderbird"
# Mail account auto-provisioning for DAVTOKEN_USER@TLDOMAIN in Thunderbird
export SERVERFQDN_IMAP="imap.${TLDOMAIN}" # IMAP server hostname (e.g. imap.strato.de)
fi
#Basic commons not needing change
-34
View File
@@ -1,34 +0,0 @@
# configure.sh — First-time setup wizard
Run `system_setup/configure.sh` on the machine that has the OEMDRV partition mounted. It guides you through all site-specific settings, tests the configuration, and leaves the system ready for a Fedora installation. Can be run as root or as a normal user — `install.sh` pre-creates `ks.cfg` at the OEMDRV root with world-write permission so both cases work.
```bash
bash /opt/sys_config/system_setup/configure.sh
```
## What it does
1. **Edits configuration values** — prompts for each setting below. Press Enter to keep the shown default, or type a new value. Derived values (e.g. `SERVERFQDN_IPA`) are updated immediately when you change `TLDOMAIN`, so subsequent prompts always reflect your latest input.
| Variable | Description |
|---|---|
| `TLDOMAIN` | Top-level domain of your infrastructure (e.g. `company.tld`) |
| `SERVERFQDN_IPA` | FQDN of the FreeIPA server (default: `ipa.<TLDOMAIN>`) |
| `SERVERFQDN_NC` | FQDN of the Nextcloud server (default: `nextcloud.<TLDOMAIN>`) |
| `CLIENTADMINGROUP` | IPA group that receives sudo rights on clients |
| `DECRYPTEDDATADIR` | Mount point for the decrypted user data directory |
| `ENCRYPTEDDATADIR` | Path of the gocryptfs-encrypted data directory |
| `IPAVAULTUSE` | `true` to use IPA KRA vault for the encryption key, `false` to disable encryption |
| `IPAVAULTNAME` | Name of the IPA vault entry (default: `CLIENT_FILEENCRYPTION_<hostname>`) |
2. **Confirms the FQDN** — shows the computed `FQDN` (`<hostname>.clients.<TLDOMAIN>`) and lets you override the hostname part if needed.
3. **Tests the encrypted home mount** — runs `mount_ecrypt_home.sh`. On failure you can restart the wizard or quit.
4. **Obtains a Nextcloud WebDAV token** — calls `get_nc_token`, which opens Firefox for login. Verifies that the returned token belongs to the current user. You can retry or quit on failure.
5. On success, the written config file `config.d/configure.conf` is picked up automatically by all other scripts instead of `config/setup_system.conf`.
## After the wizard completes
Boot the target machine from the Fedora USB installer. Anaconda detects the OEMDRV partition and runs the Kickstart automatically.
-78
View File
@@ -1,78 +0,0 @@
# OEMDRV Bootstrap — install.sh
the script `./system_setup/install.sh` prepares a target machine for automated Fedora deployment. It shrinks an existing partition to carve out a dedicated **OEMDRV** partition, which Anaconda/Kickstart will detect automatically during installation.
## What it does
1. Lists all ext4 and btrfs partitions that have enough free space to be shrunk.
2. Asks you to select one and shrinks it by **4 GiB**.
3. Creates a new 4 GiB BTRFS partition labeled `OEMDRV` in the freed space.
4. Mounts it to `/opt/sys_config` with `compress=zstd:6`.
5. Clones this repository (depth 1) into `/opt/sys_config`.
## Prerequisites
- Run as **root** on the target machine (live system or installed OS).
- The following tools must be present: `parted`, `e2fsck`, `resize2fs` or `btrfs-progs`, `mkfs.btrfs`, `git`, `curl`.
- The partition you want to shrink must **not** be the root filesystem (`/`) and must have at least **4.5 GiB free**.
- Network access to `gitea.dtext.online`.
## Run directly from the repository
Download the script first, then run it as root:
```bash
curl -fsSL https://gitea.dtext.online/obel1x/fedora-OEMDRV/raw/branch/main/system_setup/install.sh -o /tmp/install.sh
sudo bash /tmp/install.sh
```
## Run directly from another repository
If you are on another fork or branch and you want to test your changes, do:
```bash
export REPO_URL="https://yourgitserver.tld/.../fedora-OEMDRV.git"
export REPO_BRANCH="anotherbranch"
curl -fsSL ${REPO_URL%.git}/raw/branch/${REPO_BRANCH:-main}/system_setup/install.sh -o /tmp/install.sh
sudo -E bash /tmp/install.sh
```
Both are export parameters are optional. That way, install.sh should know what to pull and use it for your new setup.
## After the script completes
At the end of the installation, you will be asked wheter to run configure.sh . You are encouraged to do this always.
But bevor letting `configure.sh` start, there are some options for making your life easier:
1. You can either get some `setup_system.conf` file from your system admin and put it to `/opt/sys_config/config` . That way all your settings will be prefilled the right way.
2. You may also use some preconfigured file from `config.d/configure.conf(.bak)` and put it to `config.d/configure.conf` - if thats existing from the first setup of this pc.
Pleas mind, that in the meantime your config may have changed dramatically, so this may be only a good choice if your last configure was not that long ago.
3. You may also configure your environment before manually:
```sh
cp /opt/sys_config/system_setup/config.dist/setup_system.conf.dist /opt/sys_config/config/setup_system.conf
# Edit setup_system.conf — set TLDOMAIN, SERVERFQDN_IPA, SERVERFQDN_NC, paths and all you need
```
Mind, that this would be the job of `configure.sh`
4. Optionally add additional local per-machine overrides in `config.d/`:
```sh
# Example: always use the devel branch on this machine, no matter what was specified anywhere
echo 'export REPO_BRANCH="devel"' > /opt/sys_config/config.d/system_defines.conf
```
5. Otherwise, let `configure.sh` do it's job.
Once configured, boot the Fedora installer from USB — Anaconda will detect the `OEMDRV` partition and run the Kickstart automatically.
## Supported filesystems for shrinking
| Filesystem | Method |
|---|---|
| ext4 | `e2fsck` + `resize2fs` (offline) |
| btrfs | `btrfs filesystem resize` (temporary mount) |
@@ -1,11 +1,15 @@
# Full KDE Wayland Setup
#Basic settings
#Basic settings:
graphical
text
# Configure installation source
%include /mnt/anaconda_pre/ks_base_profiles/source_fedora_44.inc
# Configure installation method
url --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-43&arch=x86_64"
repo --name=fedora-updates --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f43&arch=x86_64" --cost=0
repo --name=fedora-cisco-openh264 --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-cisco-openh264-43&arch=x86_64" --install
repo --name=rpmfusion-free --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=free-fedora-43&arch=x86_64"
repo --name=rpmfusion-free-updates --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=free-fedora-updates-released-43&arch=x86_64" --cost=0
repo --name=rpmfusion-nonfree --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-43&arch=x86_64"
repo --name=rpmfusion-nonfree-updates --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-updates-released-43&arch=x86_64" --cost=0
# Keyboard layouts
keyboard --vckeymap=de-nodeadkeys --xlayouts='de (nodeadkeys)'
@@ -27,16 +31,18 @@ mount -L OEMDRV /mnt/anaconda_pre
@domain-client
@system-tools
@kde-media
@kde-spin-initial-setup
@libreoffice
@office
@sound-and-video
okular
libva-utils
libavcodec-freeworld
mesa-va-drivers-freeworld
ffmpeg
@vlc
python-vlc
#@development-tools
#@editors
@firefox
thunderbird
openssh-server
@@ -68,53 +74,9 @@ android-tools
-kmines
#Annoying plasmoids
-kdeplasma-addons
#Replaced by plasma-setup in F44; firstboot --disable does not cover plasma-setup
-plasma-setup
-plasma-welcome
#Exclude akonadi and all packages requiring it (@kde-pim is optional and not selected)
# @kde-spin-initial-setup
#Search - Powerful, but slow
-akonadi-server
-akonadi-server-mysql
-akonadi-calendar
-akonadi-calendar-tools
-akonadi-contacts
-akonadi-mime
-akonadi-search
-akonadi-import-wizard
-akonadiconsole
-kdepim-runtime
-kdepim-runtime-libs
-kdepim-addons
-kalarm
-kgpg
-kleopatra
-kmail
-kmail-libs
-kmail-account-wizard
-kaddressbook
-kaddressbook-libs
-korganizer
-korganizer-libs
-kontact
-akregator
-merkuro
-zanshin
-kjots
-knotes
-knotes-libs
-pimcommon
-calendarsupport
-eventviews
-incidenceeditor
-mailcommon
-mailimporter-akonadi
-mbox-importer
-pim-data-exporter
-pim-data-exporter-libs
-messagelib
-maui-mauikit-calendar
-kmymoney
-kmymoney-libs
-dragon
-kdeconnectd
-kde-connect
@@ -130,9 +92,11 @@ nss-pam-ldapd
# System authorization information
authselect enable-feature with-fingerprint
# Disk selection written by %pre via basic_pre_script.inc
%include /tmp/disk-include.cfg
# Partition clearing information - do NOT USE --initlabel !
# Generated using Blivet version 3.12.1
ignoredisk --only-use=sda
# Partition clearing information
#clearpart --none --initlabel
clearpart --none
autopart --type=btrfs
+1 -4
View File
@@ -33,7 +33,7 @@ if [ ! -f ${FQFILENAME} ]; then
fi
# Check if there is a Partition OEMDRV and on which Drive
. /mnt/anaconda_pre/system_setup/setup_system.inc.sh
/mnt/anaconda_pre/system_setup/setup_system.inc.sh
OEMDRVINFO=$(blkid | grep 'LABEL="OEMDRV"')
if [ "${OEMDRVINFO}." == "." ] ; then
echo "* Error: Required partition with label 'OEMDRV' is not found."
@@ -65,9 +65,6 @@ else
echo "The Drive ${SYSDRIVE} contains a GPT."
fi
# Write the target disk for %include in the kickstart main section
echo "ignoredisk --only-use=${SYSDRIVE:5}" > /tmp/disk-include.cfg
OEMDRVPARTSHORT=${OEMDRVPART:5}
ALLPARTS=$(lsblk -n -l -o NAME "${SYSDRIVE}" -Q 'TYPE=="part"')
REMPARTS=$(echo "$ALLPARTS" | grep -v "${OEMDRVPARTSHORT}")
@@ -1,142 +0,0 @@
# Full Cinnamon Setup
#Basic settings
graphical
text
#Pre script
%pre --log=/root/ks-pre.log
mkdir /mnt/anaconda_pre
mount -L OEMDRV /mnt/anaconda_pre
/bin/sh /mnt/anaconda_pre/ks_base_profiles/basic_pre_script.inc
%end
# Configure installation source
%include /mnt/anaconda_pre/ks_base_profiles/source_fedora_44.inc
# Keyboard layouts
keyboard --vckeymap=de-nodeadkeys --xlayouts='de (nodeadkeys)'
# System language
lang de_DE.UTF-8
# System timezone
timezone Europe/Berlin --utc
%packages
@^cinnamon-desktop-environment
@core
@admin-tools
@domain-client
@system-tools
@libreoffice
@office
@sound-and-video
#Okular is kde only, use evince on cinnamon
#okular
evince
libva-utils
libavcodec-freeworld
mesa-va-drivers-freeworld
ffmpeg
@vlc
python-vlc
@firefox
thunderbird
openssh-server
bash
sudo
gocryptfs
htop
mc
mediawriter
python-pip
pykickstart
xrdp
xorgxrdp
libxcb-doc
xterm
wmctrl
flatpak
btrfs-assistant
btrbk
transmission-gtk
xapps
cadaver
git
diffuse
remmina
android-tools
-samba
-samba-client
-samba-usershares
-BackupPC
#Exclude akonadi and all packages requiring it (pulled in via @office optional: kmymoney)
-akonadi-server
-akonadi-server-mysql
-akonadi-calendar
-akonadi-calendar-tools
-akonadi-contacts
-akonadi-mime
-akonadi-search
-akonadi-import-wizard
-akonadiconsole
-kdepim-runtime
-kdepim-runtime-libs
-kdepim-addons
-kalarm
-kgpg
-kleopatra
-kmail
-kmail-libs
-kmail-account-wizard
-kaddressbook
-kaddressbook-libs
-korganizer
-korganizer-libs
-kontact
-akregator
-merkuro
-zanshin
-kjots
-knotes
-knotes-libs
-pimcommon
-calendarsupport
-eventviews
-incidenceeditor
-mailcommon
-mailimporter-akonadi
-mbox-importer
-pim-data-exporter
-pim-data-exporter-libs
-messagelib
-maui-mauikit-calendar
-kmymoney
-kmymoney-libs
#Needed by SSSD
oddjob-mkhomedir
nss-pam-ldapd
%end
# System authorization information
authselect enable-feature with-fingerprint
# Disk selection written by %pre via basic_pre_script.inc
%include /tmp/disk-include.cfg
# Partition clearing information - do NOT USE --initlabel !
clearpart --none
autopart --type=btrfs
# Root password
# This Password is completely unknown to anyone. After installation, the PC should be Member of Domain and the users may use sudo to become superuser.
rootpw --iscrypted $y$j9T$jpKVkxaFqL6GH6GAgB0Yb/$oc.rfZgnHNlTAIj/boJeI.ZFf1QHvMF7fymZww9bzE3
#user --name=none
# Do not run the Setup Agent on first boot because it will complain about missing user account which we dont want
firstboot --disable
%post --log=/root/ks-post.log
mkdir /opt/sys_config
mount -L OEMDRV /opt/sys_config
/bin/sh /opt/sys_config/system_setup/setup_system_full.sh install
umount /opt/sys_config
%end
+47
View File
@@ -0,0 +1,47 @@
# Generated by Anaconda 43.44
%pre
/bin/sh /mnt/tmp/ks_base_profiles/basic_pre_script.inc
%end
# Keyboard layouts
keyboard --vckeymap=de-nodeadkeys --xlayouts='de (nodeadkeys)'
# System language
lang de_DE.UTF-8
%packages
@^kde-desktop-environment
@admin-tools
@development-tools
@domain-client
@editors
@firefox
@kde-apps
@kde-desktop
@kde-media
@kde-spin-initial-setup
@libreoffice
@office
@sound-and-video
@system-tools
@vlc
%end
# System authorization information
authselect enable-feature with-fingerprint
# Run the Setup Agent on first boot
firstboot --enable
timesource --ntp-server=_gateway
# System timezone
timezone Europe/Berlin --utc
# Root password
# This Password is completely unknown to anyone. After installation, the PC should be Member of Domain and the users may use sudo to become superuser.
rootpw --iscrypted $y$j9T$jpKVkxaFqL6GH6GAgB0Yb/$oc.rfZgnHNlTAIj/boJeI.ZFf1QHvMF7fymZww9bzE3
%post
/bin/sh /mnt/tmp/system_setup/setup_system_full.sh install
%end
+50
View File
@@ -0,0 +1,50 @@
# Generated by Anaconda 43.44
# Keyboard layouts
keyboard --vckeymap=de-nodeadkeys --xlayouts='de (nodeadkeys)'
# System language
lang de_DE.UTF-8
%packages
@^kde-desktop-environment
@admin-tools
@development-tools
@domain-client
@editors
@firefox
@kde-apps
@kde-desktop
@kde-media
@kde-spin-initial-setup
@libreoffice
@office
@sound-and-video
@system-tools
@vlc
%end
# System authorization information
authselect enable-feature with-fingerprint
# Run the Setup Agent on first boot
firstboot --enable
# Generated using Blivet version 3.12.1
ignoredisk --only-use=nvme0n1
# Partition clearing information
clearpart --none --initlabel
# Disk partitioning information
part /boot/efi --fstype="efi" --ondisk=nvme0n1 --size=600 --fsoptions="umask=0077,shortname=winnt"
part /sys_config --fstype="ext4" --noformat --onpart=UUID=3f9837da-5a46-4da1-a98b-62a8899e63cb --label=OEMDRV
part /boot --fstype="ext4" --ondisk=nvme0n1 --size=2048
part btrfs.115 --fstype="btrfs" --ondisk=nvme0n1 --size=485249
btrfs none --label=fedora_fedora btrfs.115
btrfs / --subvol --name=root LABEL=fedora_fedora
btrfs /home --subvol --name=home LABEL=fedora_fedora
timesource --ntp-server=_gateway
# System timezone
timezone Europe/Berlin --utc
# Root password
rootpw --iscrypted $y$j9T$SYQgSGCnU.FUaT7BKMEI9TKz$nLPf1uHlzpoBCmEndvVRK2FnY67wUY2TyxiMUIufH7A
+10
View File
@@ -0,0 +1,10 @@
# Generated using Blivet version 3.12.1
ignoredisk --only-use=sda
# Partition clearing information
clearpart --none --initlabel
# Disk partitioning information
part biosboot --fstype="biosboot" --ondisk=sda --size=1
part btrfs.69 --fstype="btrfs" --ondisk=sda --size=80000
part /boot --fstype="xfs" --ondisk=sda --size=2048
btrfs none --label=fedora btrfs.69
btrfs / --subvol --name=root LABEL=fedora
-9
View File
@@ -1,9 +0,0 @@
#Sources for Fedora 43
url --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-43&arch=x86_64"
repo --name=fedora-updates --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f43&arch=x86_64" --cost=0
repo --name=fedora-cisco-openh264 --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-cisco-openh264-43&arch=x86_64" --install
repo --name=rpmfusion-free --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=free-fedora-43&arch=x86_64"
repo --name=rpmfusion-free-updates --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=free-fedora-updates-released-43&arch=x86_64" --cost=0
repo --name=rpmfusion-nonfree --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-43&arch=x86_64"
repo --name=rpmfusion-nonfree-updates --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-updates-released-43&arch=x86_64" --cost=0
-8
View File
@@ -1,8 +0,0 @@
#Sources for Fedora 44
url --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-44&arch=x86_64"
repo --name=fedora-updates --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f44&arch=x86_64" --cost=0
repo --name=fedora-cisco-openh264 --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-cisco-openh264-44&arch=x86_64" --install
repo --name=rpmfusion-free --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=free-fedora-44&arch=x86_64"
repo --name=rpmfusion-free-updates --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=free-fedora-updates-released-44&arch=x86_64" --cost=0
repo --name=rpmfusion-nonfree --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-44&arch=x86_64"
repo --name=rpmfusion-nonfree-updates --mirrorlist="https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-updates-released-44&arch=x86_64" --cost=0
+1
View File
@@ -0,0 +1 @@
%include ../ks_base_profiles/kde_fullsetup.cfg
-230
View File
@@ -1,230 +0,0 @@
#!/usr/bin/env bash
# configure.sh - Interactive first-time configuration wizard
#
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
SCRIPTDIR="$(cd "$(dirname "$0")" && pwd)"
CONF_DIST="${SCRIPTDIR}/config.dist/setup_system.conf.dist"
CONF_FILE="${SCRIPTDIR}/../config/setup_system.conf"
CONF_PRE="${SCRIPTDIR}/../config.d/configure.conf"
# Prompt for a single value; returns the old value unchanged if the user presses Enter.
prompt_value() {
local name="$1" current="$2" new_val
printf ' %-28s [%s]: ' "$name" "$current" >&2
read -r new_val
printf '%s' "${new_val:-$current}"
}
# Replace the first matching simple export line in configure.conf.
set_conf_var() {
local varname="$1" value="$2"
sed -i "s|^[[:space:]]*export ${varname}=.*|export ${varname}=\"${value}\"|" "$CONF_PRE"
}
# Update an existing bare "export VAR=…" line at the top level, or append one.
override_conf_var() {
local varname="$1" value="$2"
if grep -q "^export ${varname}=" "$CONF_PRE"; then
sed -i "s|^export ${varname}=.*|export ${varname}=\"${value}\"|" "$CONF_PRE"
else
printf 'export %s="%s"\n' "$varname" "$value" >> "$CONF_PRE"
fi
}
do_configure() {
# Possibilities:
# 1 Found CONF_FILE="${SCRIPTDIR}/../config/setup_system.conf": This is a preinstalled company-value filled complete conf file
# 2 Found CONF_PRE="${SCRIPTDIR}/../config.d/configure.conf": This a a configure file from a previous configure run
# 3 Found none of these: use CONF_DIST="${SCRIPTDIR}/config.dist/setup_system.conf.dist"
# -> if 1 or 2 found, ask the user if to use one of them
# -> either choice, the CONF_PRE="${SCRIPTDIR}/../config.d/configure.conf" is written from it and used for further setup
if [ -f "$CONF_FILE" ] || [ -f "$CONF_PRE" ]; then
echo "Some alternatives found for configure source:"
if [[ -f "$CONF_PRE" ]]; then
echo " Choice (p): Another config run result was found in $CONF_PRE."
echo " Hint: May contain Values that already were setup different for your details"
fi
if [[ -f "$CONF_FILE" ]]; then
echo " Choice (c): Found companys full config in $CONF_FILE."
echo " This may be a full config, that is valid for your company."
else
unset CONF_FILE
fi
# Always possible: Use new dist
echo " Choice (d): You may discard all, and use distributed defaults from the maintainers."
echo " Hint: Will always start from scratch which guaranties to have a valid config for your current version"
while true; do
read -r -p " Please make a coice: " CHOICE
case "${CHOICE}" in
"p")
if [[ -f "$CONF_PRE" ]]; then
echo "Using the existing config run file $CONF_PRE"
break
fi
;;
"c")
if [[ -f "$CONF_FILE" ]]; then
echo "Replacing $CONF_PRE with $CONF_FILE"
rm "$CONF_PRE" >/dev/null 2>&1
cp "$CONF_FILE" "$CONF_PRE" && break
fi
;;
"d")
rm "$CONF_PRE" >/dev/null 2>&1
cp "$CONF_DIST" "$CONF_PRE" && break
;;
esac
echo "Invalid choice or error in selection made."
done
else
cp "${CONF_DIST}" "$CONF_PRE"
fi
echo ""
echo "=== System Configuration ==="
echo "Press Enter to keep the current value, or type a new one."
echo "Configuration will be reread for each value to make sure the settings are applied."
echo
# If other Repo infos are given, set them first
if [[ ! -z $REPO_URL ]]; then
echo "REPO_URL is set to $REPO_URL . Will use it for configure.conf."
set_conf_var "REPO_URL" "$REPO_URL"
fi
if [[ ! -z $REPO_BRANCH ]]; then
echo "REPO_BRANCH is set to $REPO_BRANCH . Will use it for configure.conf."
set_conf_var "REPO_BRANCH" "$REPO_BRANCH"
fi
# Now there should all starting values be defined in $CONF_PRE file.
# We will additionally first read the dists defaults again to make sure, that all relevant settings that may be new to existing configs are predefined
# Could be no good idea when sysadmins are only deleting lines instead of unsettings its value, but makes sure there is not missing something for setup
source "$CONF_DIST"
#Now, read the users setting
source "$CONF_PRE"
VARS=("TLDOMAIN" "SERVERFQDN_IPA" "DOMAIN" "SERVERFQDN_NC" "IPAVAULTUSE" "IPAVAULTNAME" "DISTCONFIGPATH_SRC" "CLIENTADMINGROUP" )
for ELE in "${VARS[@]}"
do
while true; do
echo ""
new_ELE=$(prompt_value "${ELE}" "${!ELE}")
set_conf_var "${ELE}" "${new_ELE}"
source "$CONF_PRE"
REPEAT_TEST=1
case ${ELE} in
"SERVERFQDN_NC") echo "=== Testing: Nextcloud server ==="
NC_STATUS=$(curl -fsSL "https://${SERVERFQDN_NC}/status.php" 2>/dev/null)
if echo "$NC_STATUS" | grep -q '"installed":true'; then
NC_VERSION=$(echo "$NC_STATUS" | grep -oP '(?<="versionstring":")[^"]+')
echo "Nextcloud confirmed at ${SERVERFQDN_NC} (version ${NC_VERSION})."
REPEAT_TEST=0
else
echo ""
echo "WARNING: '${SERVERFQDN_NC}' does not appear to be a valid Nextcloud server."
echo " Could not reach https://${SERVERFQDN_NC}/status.php or response was unexpected."
read -rp "Start configuration again (a) or quit (q)? [a/q]: " ans
if [[ "${ans,,}" == "q" ]]; then
echo "Quitting."
exit 1
fi
fi
;;
"SERVERFQDN_IPA") echo "=== Testing: FreeIPA server ==="
IPA_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"https://${SERVERFQDN_IPA}/ipa/session/json" 2>/dev/null)
if [[ "$IPA_CODE" == "200" || "$IPA_CODE" == "401" ]]; then
echo "FreeIPA server confirmed at ${SERVERFQDN_IPA}."
REPEAT_TEST=0
else
echo ""
echo "WARNING: '${SERVERFQDN_IPA}' does not appear to be a valid FreeIPA server."
echo " https://${SERVERFQDN_IPA}/ipa/session/json returned: ${IPA_CODE:-no response}"
read -rp "Start configuration again (a) or quit (q)? [a/q]: " ans
if [[ "${ans,,}" == "q" ]]; then
echo "Quitting."
exit 1
fi
fi
;;
"DOMAIN") echo "=== Testing: IPA Domain DNS records ==="
if ! command -v dig &>/dev/null; then
echo "WARNING: 'dig' not found; skipping DNS check."
REPEAT_TEST=0
else
LDAP_SRV=$(dig +short SRV "_ldap._tcp.${DOMAIN}" 2>/dev/null)
KRB_TXT=$(dig +short TXT "_kerberos.${DOMAIN}" 2>/dev/null)
KDC_SRV=$(dig +short SRV "_kerberos._udp.${DOMAIN}" 2>/dev/null)
if [[ -n "$LDAP_SRV" && -n "$KRB_TXT" ]]; then
REALM=$(echo "$KRB_TXT" | tr -d '"')
echo "IPA domain confirmed: ${DOMAIN}"
echo " Kerberos realm : ${REALM}"
[[ -n "$KDC_SRV" ]] && echo " KDC SRV : ${KDC_SRV}"
REPEAT_TEST=0
else
echo ""
[[ -z "$LDAP_SRV" ]] && echo "WARNING: No _ldap._tcp.${DOMAIN} SRV record found."
[[ -z "$KRB_TXT" ]] && echo "WARNING: No _kerberos.${DOMAIN} TXT record found."
echo " '${DOMAIN}' does not appear to be a valid IPA domain."
read -rp "Start configuration again (a) or quit (q)? [a/q]: " ans
if [[ "${ans,,}" == "q" ]]; then
echo "Quitting."
exit 1
fi
fi
fi
;;
*) echo "Not tests available."
REPEAT_TEST=0
;;
esac
[[ $REPEAT_TEST == 0 ]] && break
done
done
echo ""
echo "Configuration written to: ${CONF_PRE}"
}
while true; do
do_configure
echo ""
echo "=== Select Kickstart Profile ==="
KS_DIR="${SCRIPTDIR}/../ks_base_profiles"
KS_DEST="${SCRIPTDIR}/../ks.cfg"
mapfile -t KS_FILES < <(find "$KS_DIR" -maxdepth 1 -name "*.cfg" | sort)
if [[ ${#KS_FILES[@]} -eq 0 ]]; then
echo "No kickstart profiles found in ${KS_DIR}."
exit 1
fi
echo ""
for i in "${!KS_FILES[@]}"; do
desc=$(awk '/^$/{exit} {print}' "${KS_FILES[$i]}" \
| sed 's/^#[[:space:]]*//' | tr '\n' ' ' | xargs)
printf " %d) %-36s %s\n" "$((i+1))" "$(basename "${KS_FILES[$i]}")" "$desc"
done
echo ""
while true; do
read -rp "Select profile [1-${#KS_FILES[@]}]: " sel
[[ "$sel" =~ ^[0-9]+$ ]] && (( sel >= 1 && sel <= ${#KS_FILES[@]} )) && break
echo " Invalid selection, please enter a number between 1 and ${#KS_FILES[@]}."
done
cp "${KS_FILES[$((sel-1))]}" "$KS_DEST"
echo "Copied '$(basename "${KS_FILES[$((sel-1))]}")' to ${KS_DEST}."
echo ""
echo "=== Configuration complete ==="
echo "All values have been configured and verified successfully."
echo "The system is now ready for the new installation."
echo "Boot from the Fedora USB installer — Anaconda will detect the OEMDRV partition"
echo "and run the Kickstart automatically."
exit 0
done
-643
View File
@@ -1,643 +0,0 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Bootstrap script: creates an OEMDRV partition by shrinking an existing
# ext4 or btrfs partition by 4 GiB, formats the freed space as BTRFS with
# label OEMDRV, mounts it to /opt/sys_config and clones the repository.
#
# Run as root on a target machine before any Kickstart installation.
[[ "$EUID" -eq 0 ]] || { echo "ERROR: This script must be run as root." >&2; exit 1; }
SHRINK_MIB=4096
OEMDRV_LABEL="OEMDRV"
MOUNT_POINT="/opt/sys_config"
MOUNT_OPTS="compress=zstd:6"
REPO_URL="${REPO_URL:-https://gitea.dtext.online/obel1x/fedora-OEMDRV.git}"
REPO_BRANCH="${REPO_BRANCH:-main}"
MIN_FREE_MIB=$(( SHRINK_MIB + 512 )) # require 512 MiB headroom above the shrink size
# ── Helpers ───────────────────────────────────────────────────────────────────
die() { echo; echo "ERROR: $*" >&2; exit 1; }
info() { echo; echo ">>> $*"; }
hr() { printf '%.0s─' {1..100}; echo; }
finish_install() {
local dev="$1"
chown root:root "$MOUNT_POINT" -R
chmod ug=rwX,o=rX "$MOUNT_POINT" -R
chmod o+w "$MOUNT_POINT/config" "$MOUNT_POINT/config.d" -R
# Create an empty ks.cfg at the OEMDRV root so non-root can overwrite it
# with configure.sh (the OEMDRV root itself is not world-writable).
touch "$MOUNT_POINT/ks.cfg"
chmod o+w "$MOUNT_POINT/ks.cfg"
info "Done."
echo
echo " OEMDRV device : $dev"
echo " Mounted at : $MOUNT_POINT"
echo
CONF_SCRIPT="$MOUNT_POINT/system_setup/configure.sh"
echo
read -r -p "Run configure.sh now to set up your environment? [y/N]: " RUN_CONF
if [[ "${RUN_CONF,,}" == "y" ]]; then
if [[ -n "$SUDO_USER" && "$SUDO_USER" != "root" ]]; then
info "Running configure.sh as user '$SUDO_USER'..."
su - "$SUDO_USER" -c "DISPLAY='${DISPLAY}' WAYLAND_DISPLAY='${WAYLAND_DISPLAY}' REPO_URL='${REPO_URL}' REPO_BRANCH='${REPO_BRANCH}' bash '$CONF_SCRIPT'"
else
info "Running configure.sh as root..."
REPO_URL="$REPO_URL" REPO_BRANCH="$REPO_BRANCH" bash "$CONF_SCRIPT"
fi
else
echo
echo "Next steps:"
echo " 1. Run: bash $CONF_SCRIPT"
echo " 2. Boot the Kickstart installer — it will detect the OEMDRV partition automatically."
echo
fi
}
do_clone_and_done() {
local dev="$1"
info "Cloning $REPO_URL into $MOUNT_POINT..."
cd "$MOUNT_POINT" || die "Cannot cd to $MOUNT_POINT."
git clone --progress --depth 1 -b $REPO_BRANCH "$REPO_URL" . || die "git clone failed."
source "$MOUNT_POINT/system_setup/setup_system.inc.sh" --missingconfok
finish_install "$dev"
}
require_root() {
[[ "$EUID" -eq 0 ]] || die "This script must be run as root."
}
check_tools() {
declare -A tool_pkg=(
[lsblk]="util-linux" [blkid]="util-linux"
[parted]="parted" [partprobe]="parted"
[mkfs.btrfs]="btrfs-progs" [git]="git"
[e2fsck]="e2fsprogs" [resize2fs]="e2fsprogs"
[tune2fs]="e2fsprogs"
)
local missing=()
for tool in lsblk blkid parted partprobe mkfs.btrfs git e2fsck resize2fs tune2fs; do
command -v "$tool" >/dev/null 2>&1 || missing+=("$tool")
done
[[ ${#missing[@]} -eq 0 ]] && return 0
echo "Missing required tools: ${missing[*]}"
local pkgs=()
for tool in "${missing[@]}"; do
local pkg="${tool_pkg[$tool]}"
[[ " ${pkgs[*]} " != *" $pkg "* ]] && pkgs+=("$pkg")
done
read -r -p " Install missing packages (${pkgs[*]}) with dnf? [y/N]: " ans
if [[ "${ans,,}" == "y" ]]; then
dnf install -y "${pkgs[@]}" || die "Package installation failed."
local still_missing=()
for tool in "${missing[@]}"; do
command -v "$tool" >/dev/null 2>&1 || still_missing+=("$tool")
done
[[ ${#still_missing[@]} -eq 0 ]] || die "Still missing after install: ${still_missing[*]}"
else
die "Missing required tools: ${missing[*]}"
fi
}
# Returns 0 if the remote install.sh matches this script's checksum,
# 1 if the URL is unreachable or the file cannot be downloaded,
# 2 if the checksum does not match.
check_repo_url() {
local tmpdir sum_remote sum_local
tmpdir=$(mktemp -d /tmp/oemdrv_repocheck.XXXXXX)
if ! curl -fsSL "${REPO_URL%.git}/raw/branch/${REPO_BRANCH}/system_setup/install.sh" \
-o "$tmpdir/install.sh" 2>/dev/null; then
rm -rf "$tmpdir"
return 1
fi
sum_remote=$(sha256sum "$tmpdir/install.sh" | awk '{print $1}')
sum_local=$(sha256sum "$0" | awk '{print $1}')
rm -rf "$tmpdir"
[[ "$sum_remote" == "$sum_local" ]] || return 2
return 0
}
# ── Free-space helpers ────────────────────────────────────────────────────────
# Free MiB for a mounted device via df
mounted_free_mib() {
df --output=avail -BM "$1" 2>/dev/null | awk 'NR==2{gsub("M",""); print $1+0}'
}
# Free MiB for an unmounted ext4 device via tune2fs (no mount needed)
ext4_free_mib() {
local dev="$1" fb bs
fb=$(tune2fs -l "$dev" 2>/dev/null | awk '/^Free blocks:/{print $3}')
bs=$(tune2fs -l "$dev" 2>/dev/null | awk '/^Block size:/{print $3}')
[[ -n "$fb" && -n "$bs" ]] || { echo 0; return; }
echo $(( fb * bs / 1048576 ))
}
# Free MiB for a btrfs device mounts temporarily if not already mounted
btrfs_free_mib() {
local dev="$1" mnt free tmp=0
mnt=$(lsblk -n -o MOUNTPOINT "$dev" 2>/dev/null | grep -v '^$' | head -1)
if [[ -z "$mnt" ]]; then
mnt=$(mktemp -d /tmp/oemdrv_check.XXXXXX)
mount -o ro "$dev" "$mnt" 2>/dev/null && tmp=1 || { rmdir "$mnt"; echo 0; return; }
fi
free=$(mounted_free_mib "$mnt")
[[ $tmp -eq 1 ]] && { umount "$mnt"; rmdir "$mnt"; }
echo "${free:-0}"
}
# ── Partition discovery ───────────────────────────────────────────────────────
# Parallel arrays, indexed 0..PT_IDX-1
PT_IDX=0
PT_DEV=() # /dev/sda2
PT_DISK=() # /dev/sda
PT_PNUM=() # 2
PT_SIZE=() # "100G"
PT_FS=() # ext4 | btrfs
PT_LABEL=() # home | -
PT_UUID=() # xxxxxxxx | -
PT_MNT=() # /home | -
PT_FREE=() # free MiB (integer)
PT_OK=() # 1 = shrinkable
# Parallel arrays for unpartitioned free space regions, indexed 0..FS_IDX-1
FS_IDX=0
FS_DISK=() # /dev/sda
FS_START=() # region start, MiB
FS_END=() # region end, MiB
FS_SIZE=() # region size, MiB
collect_partitions() {
local NAME SIZE FSTYPE LABEL UUID MOUNTPOINT TYPE PKNAME
while IFS= read -r line; do
NAME="" SIZE="" FSTYPE="" LABEL="" UUID="" MOUNTPOINT="" TYPE="" PKNAME=""
eval "$line"
[[ "$TYPE" != "part" ]] && continue
[[ "$FSTYPE" != "ext4" && "$FSTYPE" != "btrfs" ]] && continue
[[ "$LABEL" == "$OEMDRV_LABEL" ]] && continue
[[ -z "$PKNAME" ]] && continue
local disk="/dev/${PKNAME##*/}"
local pnum
pnum=$(cat /sys/class/block/"${NAME##/dev/}"/partition 2>/dev/null) || continue
# Free space check
local free_mib
if [[ -n "$MOUNTPOINT" ]]; then
free_mib=$(mounted_free_mib "$NAME")
elif [[ "$FSTYPE" == "ext4" ]]; then
free_mib=$(ext4_free_mib "$NAME")
else
free_mib=$(btrfs_free_mib "$NAME")
fi
free_mib=${free_mib:-0}
# Shrinkable: not /, enough free space
local ok=0
[[ "$MOUNTPOINT" != "/" && "$free_mib" -ge "$MIN_FREE_MIB" ]] && ok=1
PT_DEV[$PT_IDX]="$NAME"
PT_DISK[$PT_IDX]="$disk"
PT_PNUM[$PT_IDX]="$pnum"
PT_SIZE[$PT_IDX]="$SIZE"
PT_FS[$PT_IDX]="$FSTYPE"
PT_LABEL[$PT_IDX]="${LABEL:--}"
PT_UUID[$PT_IDX]="${UUID:--}"
PT_MNT[$PT_IDX]="${MOUNTPOINT:--}"
PT_FREE[$PT_IDX]="$free_mib"
PT_OK[$PT_IDX]="$ok"
(( PT_IDX++ )) || true
done < <(lsblk -o NAME,SIZE,FSTYPE,LABEL,UUID,MOUNTPOINT,TYPE,PKNAME -p -P -n 2>/dev/null)
}
collect_free_space() {
local disk
while IFS= read -r disk; do
[[ -b "$disk" ]] || continue
while read -r s e sz; do
FS_DISK[$FS_IDX]="$disk"
FS_START[$FS_IDX]="$s"
FS_END[$FS_IDX]="$e"
FS_SIZE[$FS_IDX]="$sz"
(( FS_IDX++ )) || true
done < <(
parted -s "$disk" -m unit MiB print free 2>/dev/null \
| awk -F'[;:]' -v min="$SHRINK_MIB" '
$1+0 > 0 {
for (i = 1; i <= NF; i++) {
if ($i == "free") {
gsub(/MiB/,"",$2); gsub(/MiB/,"",$3);
e=int($3+0);
raw_s=$2+0;
s=int(raw_s)+(raw_s>int(raw_s)?1:0);
if (s < 1) s = 1;
sz=e-s;
if (sz >= min) print s " " e " " sz;
break
}
}
}'
)
done < <(lsblk -d -p -n -o NAME 2>/dev/null)
}
# ── Table display ─────────────────────────────────────────────────────────────
show_table() {
hr
printf " %-4s %-14s %-6s %-8s %-10s %-6s %-18s %-36s %s\n" \
"#" "Device" "Disk" "Size" "Free (MiB)" "FS" "Label" "UUID" "Mountpoint"
hr
local i mark note
for (( i=0; i<PT_IDX; i++ )); do
mark=" "
note=""
if [[ "${PT_OK[$i]}" == "1" ]]; then
mark="* "
elif [[ "${PT_MNT[$i]}" == "/" ]]; then
note=" (root — skip)"
else
note=" (not enough free space)"
fi
printf "%s%-4s %-14s %-6s %-8s %-10s %-6s %-18s %-36s %s%s\n" \
"$mark" \
"$((i+1))" \
"${PT_DEV[$i]}" \
"${PT_DISK[$i]##/dev/}" \
"${PT_SIZE[$i]}" \
"${PT_FREE[$i]}" \
"${PT_FS[$i]}" \
"${PT_LABEL[$i]}" \
"${PT_UUID[$i]}" \
"${PT_MNT[$i]}" \
"$note"
done
hr
printf " * = shrinkable: will be reduced by %s MiB to create OEMDRV\n" "$SHRINK_MIB"
echo
}
show_free_table() {
[[ $FS_IDX -gt 0 ]] || return
echo
echo "Unpartitioned free space regions (>= ${SHRINK_MIB} MiB):"
hr
printf " %-4s %-14s %-12s %-12s %s\n" "#" "Disk" "Start (MiB)" "End (MiB)" "Size (MiB)"
hr
for (( i=0; i<FS_IDX; i++ )); do
printf " %-4s %-14s %-12s %-12s %s\n" \
"$((i+1))" \
"${FS_DISK[$i]}" \
"${FS_START[$i]}" \
"${FS_END[$i]}" \
"${FS_SIZE[$i]}"
done
hr
echo
}
# ── Partition geometry via parted -m ─────────────────────────────────────────
part_end_mib() {
parted -s "$1" -m unit MiB print 2>/dev/null \
| awk -F: -v p="$2" '$1==p{gsub("MiB","",$3); printf "%.0f\n",$3; exit}'
}
part_start_mib() {
parted -s "$1" -m unit MiB print 2>/dev/null \
| awk -F: -v p="$2" '$1==p{gsub("MiB","",$2); printf "%.0f\n",$2; exit}'
}
# Device name for a new partition on a given disk
new_part_device() {
local disk="$1" pnum="$2"
if [[ "$disk" =~ (nvme|mmcblk) ]]; then
echo "${disk}p${pnum}"
else
echo "${disk}${pnum}"
fi
}
# ── Main ──────────────────────────────────────────────────────────────────────
require_root
check_tools
# ── Check for existing OEMDRV partition ───────────────────────────────────────
EXISTING_OEMDRV_DEV=$(blkid -L "$OEMDRV_LABEL" 2>/dev/null || true)
if [[ -n "$EXISTING_OEMDRV_DEV" ]]; then
echo
echo "Found existing '$OEMDRV_LABEL' partition: $EXISTING_OEMDRV_DEV"
read -r -p " Use this partition and overwrite its install files? [y/N]: " ans
if [[ "${ans,,}" == "y" ]]; then
EXISTING_MNT=$(lsblk -n -o MOUNTPOINT "$EXISTING_OEMDRV_DEV" 2>/dev/null | grep -v '^$' | head -1)
if [[ -n "$EXISTING_MNT" ]]; then
echo " Partition is already mounted at $EXISTING_MNT — using that mountpoint."
MOUNT_POINT="$EXISTING_MNT"
else
info "Mounting $EXISTING_OEMDRV_DEV to $MOUNT_POINT..."
[[ -d "$MOUNT_POINT" ]] || mkdir -p "$MOUNT_POINT"
mount -o "$MOUNT_OPTS" "$EXISTING_OEMDRV_DEV" "$MOUNT_POINT" || die "mount failed."
fi
if [[ -f "$MOUNT_POINT/system_setup/setup_system.inc.sh" && -f "$MOUNT_POINT/config/setup_system.conf" ]]; then
if [ ! -z $REPO_URL ]; then BACK_REPO_URL="$REPO_URL"; fi
if [ ! -z $REPO_BRANCH ]; then BACK_REPO_BRANCH="$REPO_BRANCH"; fi
info "Reading existing configuration from ${MOUNT_POINT} ..."
source "$MOUNT_POINT/system_setup/setup_system.inc.sh"
if [ ! -z $BACK_REPO_URL ]; then REPO_URL="$BACK_REPO_URL"; fi
if [ ! -z $BACK_REPO_BRANCH ]; then REPO_BRANCH="$BACK_REPO_BRANCH"; fi
fi
# ── Check existing git repository origin ──────────────────────────────
if git -C "$MOUNT_POINT" rev-parse --git-dir >/dev/null 2>&1; then
EXIST_URL=$(git -C "$MOUNT_POINT" remote get-url origin 2>/dev/null || true)
EXIST_BRANCH=$(git -C "$MOUNT_POINT" symbolic-ref --short HEAD 2>/dev/null \
|| git -C "$MOUNT_POINT" rev-parse --abbrev-ref HEAD 2>/dev/null || true)
if [[ -n "$EXIST_URL" && ( "$EXIST_URL" != "$REPO_URL" || "$EXIST_BRANCH" != "$REPO_BRANCH" ) ]]; then
echo
echo " The existing repository differs from the configured values:"
printf " %-12s %-55s %s\n" "" "Origin" "Branch"
printf " %-12s %-55s %s\n" "Existing:" "$EXIST_URL" "$EXIST_BRANCH"
printf " %-12s %-55s %s\n" "Configured:" "$REPO_URL" "$REPO_BRANCH"
echo
echo " Hint: set REPO_URL / REPO_BRANCH env vars before running to override the configured values."
echo
echo " How should this be resolved?"
echo " 1) Keep existing origin/branch — pull latest from $EXIST_URL / $EXIST_BRANCH"
echo " 2) Switch to configured origin — migrate to $REPO_URL / $REPO_BRANCH (preserves local files)"
while true; do
read -r -p " Choice [1/2]: " GIT_CHOICE
case "${GIT_CHOICE}" in
1)
REPO_URL="$EXIST_URL"
REPO_BRANCH="$EXIST_BRANCH"
break
;;
2)
info "Switching origin to $REPO_URL (branch: $REPO_BRANCH)..."
git -C "$MOUNT_POINT" remote set-url origin "$REPO_URL" \
|| die "git remote set-url failed."
break
;;
*)
echo " Please enter 1 or 2."
;;
esac
done
fi
info "Pulling latest from $REPO_URL (branch: $REPO_BRANCH)..."
git -C "$MOUNT_POINT" fetch --depth 1 origin "$REPO_BRANCH" \
|| die "git fetch failed."
git -C "$MOUNT_POINT" checkout -B "$REPO_BRANCH" FETCH_HEAD \
|| die "git checkout failed."
#Backup Repovalues if the config was read from existing config with production values and we configured
#devel values above
BACK_REPO_URL="$REPO_URL"
BACK_REPO_BRANCH="$REPO_BRANCH"
source "$MOUNT_POINT/system_setup/setup_system.inc.sh" --missingconfok
export REPO_URL="$EXIST_URL"
export REPO_BRANCH="$BACK_REPO_BRANCH"
finish_install "$EXISTING_OEMDRV_DEV"
exit 0
fi
# No git repo on the partition — clear and do a fresh clone
if [[ -n "$(ls -A "$MOUNT_POINT" 2>/dev/null)" ]]; then
info "No git repository found on $MOUNT_POINT — clearing before fresh clone..."
find "$MOUNT_POINT" -mindepth 1 -delete
fi
do_clone_and_done "$EXISTING_OEMDRV_DEV"
exit 0
fi
fi
info "Verifying repository URL..."
check_repo_url
case $? in
1) echo
echo "WARNING: '$REPO_URL' branch '${REPO_BRANCH}' is not a reachable git repository."
read -r -p " Continue anyway? [y/N]: " ans
[[ "${ans,,}" == "y" ]] || { echo "Aborted."; exit 0; }
;;
2) echo
echo "WARNING: The checksum of this script does not match 'system_setup/install.sh'"
echo " at '$REPO_URL' branch '${REPO_BRANCH}'."
echo " You may be running an outdated or modified version of install.sh."
read -r -p " Continue anyway? [y/N]: " ans
[[ "${ans,,}" == "y" ]] || { echo "Aborted."; exit 0; }
;;
esac
info "Scanning for shrinkable partitions and unpartitioned free space..."
collect_partitions
collect_free_space
[[ $PT_IDX -gt 0 || $FS_IDX -gt 0 ]] \
|| die "No ext4 or btrfs partitions and no free disk space found on this system."
# Count shrinkable partitions
shrink_count=0
for (( i=0; i<PT_IDX; i++ )); do [[ "${PT_OK[$i]}" == "1" ]] && (( shrink_count++ )) || true; done
[[ $PT_IDX -gt 0 ]] && show_table
show_free_table
[[ $shrink_count -gt 0 || $FS_IDX -gt 0 ]] \
|| die "No shrinkable partitions and no free space found. A non-root ext4 or btrfs partition needs at least ${MIN_FREE_MIB} MiB free."
# ── Selection ─────────────────────────────────────────────────────────────────
MODE="" # "freespace" | "shrink"
SEL=-1
while true; do
echo
if [[ $FS_IDX -gt 0 && $shrink_count -gt 0 ]]; then
read -r -p "Enter f<n> to use free space, s<n> to shrink a partition, or q to quit: " INPUT || { echo; echo "Aborted."; exit 0; }
elif [[ $FS_IDX -gt 0 ]]; then
read -r -p "Enter number of free space region to use, or q to quit: " INPUT || { echo; echo "Aborted."; exit 0; }
[[ "$INPUT" =~ ^[0-9]+$ ]] && INPUT="f${INPUT}"
else
read -r -p "Enter number of partition to shrink, or q to quit: " INPUT || { echo; echo "Aborted."; exit 0; }
[[ "$INPUT" =~ ^[0-9]+$ ]] && INPUT="s${INPUT}"
fi
[[ "$INPUT" =~ ^[qQ]$ ]] && { echo "Aborted."; exit 0; }
if [[ "$INPUT" =~ ^[fF]([0-9]+)$ ]]; then
local_i=$(( ${BASH_REMATCH[1]} - 1 ))
(( local_i >= 0 && local_i < FS_IDX )) || { echo " Number out of range."; continue; }
MODE="freespace"; SEL=$local_i; break
elif [[ "$INPUT" =~ ^[sS]([0-9]+)$ ]]; then
local_i=$(( ${BASH_REMATCH[1]} - 1 ))
(( local_i >= 0 && local_i < PT_IDX )) || { echo " Number out of range."; continue; }
[[ "${PT_OK[$local_i]}" == "1" ]] || { echo " That partition cannot be shrunk (see marks above)."; continue; }
MODE="shrink"; SEL=$local_i; break
else
echo " Invalid input."
fi
done
# ── Confirm ───────────────────────────────────────────────────────────────────
echo
if [[ "$MODE" == "freespace" ]]; then
WORK_DISK="${FS_DISK[$SEL]}"
OEMDRV_START="${FS_START[$SEL]}"
OEMDRV_END=$(( FS_START[$SEL] + SHRINK_MIB ))
echo " Disk : $WORK_DISK"
echo " Free region : ${FS_START[$SEL]} MiB ${FS_END[$SEL]} MiB (${FS_SIZE[$SEL]} MiB available)"
echo " New OEMDRV : ${OEMDRV_START} MiB ${OEMDRV_END} MiB (${SHRINK_MIB} MiB)"
echo " It will be mounted at $MOUNT_POINT and the repository cloned into it."
else
S_DEV="${PT_DEV[$SEL]}"
S_DISK="${PT_DISK[$SEL]}"
S_PNUM="${PT_PNUM[$SEL]}"
S_FS="${PT_FS[$SEL]}"
S_MNT="${PT_MNT[$SEL]}"
WORK_DISK="$S_DISK"
echo " Partition : $S_DEV (${PT_FS[$SEL]}, ${PT_SIZE[$SEL]}, ${PT_FREE[$SEL]} MiB free)"
echo " Disk : $S_DISK Partition number: $S_PNUM"
echo " Mountpoint: $S_MNT"
echo
echo " $S_DEV will be shrunk by ${SHRINK_MIB} MiB."
echo " A new ${SHRINK_MIB} MiB BTRFS partition labeled OEMDRV will be created."
echo " It will be mounted at $MOUNT_POINT and the repository cloned into it."
fi
echo
read -r -p " Type YES (uppercase) to confirm, anything else to abort: " CONFIRM
[[ "$CONFIRM" == "YES" ]] || { echo "Aborted."; exit 0; }
# ── Shrink path: geometry + filesystem resize + partition table update ─────────
WAS_MOUNTED=0
ORIG_MNT=""
if [[ "$MODE" == "shrink" ]]; then
info "Reading partition geometry on $S_DISK..."
CURR_END=$(part_end_mib "$S_DISK" "$S_PNUM")
CURR_START=$(part_start_mib "$S_DISK" "$S_PNUM")
[[ -n "$CURR_END" && -n "$CURR_START" ]] \
|| die "Could not read geometry for partition $S_PNUM on $S_DISK."
NEW_END=$(( CURR_END - SHRINK_MIB ))
NEW_FS_MIB=$(( NEW_END - CURR_START ))
OEMDRV_START=$NEW_END
OEMDRV_END=$CURR_END
echo " Current partition : ${CURR_START} MiB ${CURR_END} MiB"
echo " After shrink : ${CURR_START} MiB ${NEW_END} MiB (filesystem: ${NEW_FS_MIB} MiB)"
echo " New OEMDRV : ${OEMDRV_START} MiB ${OEMDRV_END} MiB (${SHRINK_MIB} MiB)"
if [[ "$S_FS" == "ext4" ]]; then
# ext4 requires offline resize — unmount first
if [[ "$S_MNT" != "-" && -n "$S_MNT" ]]; then
info "Unmounting $S_DEV from $S_MNT..."
ORIG_MNT="$S_MNT"
umount "$S_DEV" || die "Cannot unmount $S_DEV. Close all open files and try again."
WAS_MOUNTED=1
fi
info "Running e2fsck on $S_DEV..."
e2fsck -f "$S_DEV" || die "e2fsck found errors on $S_DEV. Fix them before retrying."
info "Shrinking ext4 filesystem to ${NEW_FS_MIB} MiB..."
resize2fs "$S_DEV" "${NEW_FS_MIB}M" || die "resize2fs failed."
elif [[ "$S_FS" == "btrfs" ]]; then
# btrfs supports online resize — use existing mount point if available,
# otherwise mount temporarily
info "Shrinking btrfs filesystem on $S_DEV to ${NEW_FS_MIB} MiB..."
if [[ "$S_MNT" != "-" && -n "$S_MNT" ]]; then
btrfs filesystem resize "${NEW_FS_MIB}m" "$S_MNT" \
|| die "btrfs filesystem resize failed."
else
TMP_MNT=$(mktemp -d /tmp/oemdrv_btrfs.XXXXXX)
mount "$S_DEV" "$TMP_MNT" || { rmdir "$TMP_MNT"; die "Cannot mount $S_DEV for btrfs resize."; }
btrfs filesystem resize "${NEW_FS_MIB}m" "$TMP_MNT" \
|| { umount "$TMP_MNT"; rmdir "$TMP_MNT"; die "btrfs filesystem resize failed."; }
sync
umount "$TMP_MNT" && rmdir "$TMP_MNT"
fi
fi
info "Shrinking partition $S_PNUM to ${NEW_END} MiB in partition table..."
SECTOR_SIZE=$(cat /sys/block/"${S_DISK##*/}"/queue/hw_sector_size 2>/dev/null || echo 512)
NEW_END_SEC=$(( NEW_END * 1048576 / SECTOR_SIZE ))
sfdisk -d "$S_DISK" | awk -v dev="$S_DEV" -v new_end="$NEW_END_SEC" '
$0 ~ "^" dev " : " {
match($0, /start= *([0-9]+)/, a)
sub(/size= *[0-9]+/, "size= " (new_end - a[1]+0))
}
{ print }
' | sfdisk --no-reread --force "$S_DISK" \
|| die "sfdisk partition resize failed."
fi
# ── Create OEMDRV partition ───────────────────────────────────────────────────
info "Creating new OEMDRV partition (${OEMDRV_START}${OEMDRV_END} MiB) on $WORK_DISK..."
parted -s "$WORK_DISK" mkpart anacondainstall btrfs "${OEMDRV_START}MiB" "${OEMDRV_END}MiB" \
|| die "parted mkpart failed. Check that the target area is free space on $WORK_DISK."
partprobe "$WORK_DISK"
sleep 1
# Find the partition whose start matches OEMDRV_START (±1 MiB for alignment)
NEW_PNUM=$(parted -s "$WORK_DISK" -m unit MiB print 2>/dev/null \
| awk -F: -v s="$OEMDRV_START" '
/^[0-9]/ { gsub(/MiB/,"",$2); if (int($2+0) >= s-1 && int($2+0) <= s+1) { print $1; exit } }')
[[ -n "$NEW_PNUM" ]] || die "Could not determine new partition number on $WORK_DISK."
OEMDRV_DEV=$(new_part_device "$WORK_DISK" "$NEW_PNUM")
[[ -b "$OEMDRV_DEV" ]] || die "New partition device $OEMDRV_DEV not found after partprobe."
info "New partition device: $OEMDRV_DEV"
# ── Format ────────────────────────────────────────────────────────────────────
info "Formatting $OEMDRV_DEV as BTRFS (label: $OEMDRV_LABEL)..."
mkfs.btrfs -f -L "$OEMDRV_LABEL" "$OEMDRV_DEV" || die "mkfs.btrfs failed."
# ── Remount original partition (shrink path only) ─────────────────────────────
if [[ $WAS_MOUNTED -eq 1 && -n "$ORIG_MNT" ]]; then
info "Remounting $S_DEV to $ORIG_MNT..."
mount "$S_DEV" "$ORIG_MNT" \
|| echo "WARNING: Could not remount $S_DEV to $ORIG_MNT — remount manually."
fi
# ── Mount OEMDRV ──────────────────────────────────────────────────────────────
info "Mounting $OEMDRV_DEV to $MOUNT_POINT (options: $MOUNT_OPTS)..."
[[ -d "$MOUNT_POINT" ]] || mkdir -p "$MOUNT_POINT"
mount -o "$MOUNT_OPTS" "$OEMDRV_DEV" "$MOUNT_POINT" || die "mount failed."
# ── Clone repository + done ───────────────────────────────────────────────────
do_clone_and_done "$OEMDRV_DEV"
+19 -120
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
# SPDX-FileCopyrightText: Daniel Pätzold
# SPDX-License-Identifier: AGPL-3.0-or-later
#
@@ -17,49 +17,26 @@ if [ "$EUID" -eq 0 ]; then
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
# Check DNS resolution before proceeding - logon depends on IPA and Nextcloud being reachable
_dns_target="${SERVERFQDN_IPA}"
while ! getent hosts "${_dns_target}" >/dev/null 2>&1; do
elog_add "Warning: DNS resolution failed for ${_dns_target} - network or DNS not ready."
echo ""
echo "Warning: DNS resolution failed for ${_dns_target}."
echo "Please check your network connection and DNS settings before continuing."
echo ""
printf " [R]etry [C]ontinue anyway [Q]uit: "
read -r _dns_choice
case "${_dns_choice}" in
[Cc]) elog_add "Continuing despite DNS failure (user choice)."; break ;;
[Qq]) elog_add "Script aborted by user due to DNS failure."; exit 1 ;;
*) elog_add "Retrying DNS check for ${_dns_target}..." ;;
esac
done
#Check for needed python-modules
#For WEBDAV
python -c "import webdav3">/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "Installing pip module webdav3"
pip install webdavclient3>/dev/null
fi
#For IPA (system package python3-ipaclient, cannot be pip-installed)
python -c "import ipalib">/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "Error: python3-ipaclient is not installed. Please install it via: sudo dnf install python3-ipaclient"
fi
if [ "${XDG_CURRENT_DESKTOP}" = "KDE" ]; then
# Start each session empty (not restoring previous apps) - avoids stale mounts and autostart conflicts
kwriteconfig5 --file ksmserverrc --group General --key loginMode 2 >/dev/null 2>&1
# Make kdesu use sudo
kwriteconfig5 --file kdesurc --group super-user-command --key super-user-command sudo >/dev/null 2>&1
#TODO C: Check if Desktop is KDE/Plasma and support other Displays
# Make kdesu use sudo
kwriteconfig5 --file kdesurc --group super-user-command --key super-user-command sudo
if [ $? -ne 0 ]; then
elog_add "This script should be run in KDE- Desktop. The setup of kwriteconfig5 has failed. Please check, if you are using KDE."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
# Mount the private Directory
elog_add_command "${SYSCONFIGPATH}/system_setup/mount_ecrypt_home.sh"
if [ $? -ne 0 ]; then
elog_add "Some Error when running/mounting private Directory, cannot continue. Your Data will not be available."
elog_add "If the File was not found: The mount script was searched in directory ${SYSCONFIGPATH} which is defined by SYSCONFIGPATH in your config."
elog_add "Please check if your setup is correct."
elog_add "Some Error when mounting private Directory, cannot continue. Your Data will not be available."
elog_add "The script was searched by SYSCONFIGPATH in directory ${SYSCONFIGPATH}, please check if your setup is correct."
elog_add "If you want to redo this script here, execute ${SCRIPTPATH}/${SCRIPTNAME}"
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
@@ -67,7 +44,7 @@ fi
#Get WEBDAV TOKEN from Nextcloud
get_nc_token
if [ $? -ne 0 ]; then
elog_add "Some Error when getting WEBDAV token. Cannot continue. Your Data will not be available."
elog_add "Some Error when mounting private Directory, cannot continue. Your Data will not be available."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
elog_add "Successfully obtained Token for User ${DAVTOKEN_USER}"
@@ -79,20 +56,6 @@ elog_add "Update and install client software"
#Set global to enable git
git config --global --add safe.directory /opt/sys_config
# Pre check for old configuration parameters, will be removed in the future
if [ ! -z "${CLIENT_SOFTWARE_DST}" ] || [ ! -z "${CLIENT_SOFTWARE_SRC}" ]; then
elog_add " ===================="
elog_add ""
elog_add "WARNING: Your company/setup has still CLIENT_SOFTWARE_DST or CLIENT_SOFTWARE_SRC set."
elog_add "These parameters are obsolete and must be removed! The new parameters are CLIENT_SOFTWARE_CUST_DST and CLIENT_SOFTWARE_CUST_SRC"
elog_add "as the software repository has been split into customer software and distributed software."
elog_add "Please try to relog first. If this problem reoccures, contact your system admins to correct it."
elog_add "Will continue with the new path. Press any key to continue."
elog_add ""
elog_add " ===================="
read -n 1 -s -r
fi
# First, check the sudo rule
elog_add "Check the matching client rule:"
#Somewhat strange "sudo -l" will *sometimes* ask for password instead of just checking if the rule can be found, so it needs -n to be silent
@@ -129,8 +92,10 @@ else
# Rule seems to be ok, executing script
elog_add "Matching Sudo rule found."
elog_add ""
elog_add "Running ${SYSCONFIGPATH}/system_setup/sync_client_software.sh"
elog_add "Running client software sync..."
elog_add_command "/usr/bin/sudo -n --preserve-env ${SYSCONFIGPATH}/system_setup/sync_client_software.sh install $1"
#ERRTXT=$( { /usr/bin/sudo -n --preserve-env ${SYSCONFIGPATH}/system_setup/sync_client_software.sh install > >(tee -a ${LOGFILE}); } 2>&1 )
#ERR=$?
if [[ $RETNO -ne 0 ]]; then
elog_add "Errorcode was $RETNO"
elog_add "Error executing software sync and install, please check your output!"
@@ -138,84 +103,18 @@ else
fi
fi
fi
echo ""
#Anyway run user scripts if existent
elog_add "Running user setup scripts in user- context."
#1. Run the scripts, that are delivered by the package maintainers
elog_add "Pre installed user setup scripts"
for DIR in $(ls -d ${SYSCONFIGPATH}/client_software/*/ | sort); # list directories in the form "/tmp/dirname/"
do
DIR=${DIR%*/} # remove the trailing "/"
if [[ "$1." != "." ]] && [[ "${DIR}" != *"$1"* ]]; then
#search for string in dir
elog_add "Skipping ${DIR} while not in search parameter ( $1 )."
continue
fi
if [ -f "${DIR}/user_run.sh" ]; then
elog_add " >>> Running ${DIR}/user_run.sh"
cd ${DIR}
elog_add_command "${DIR}/user_run.sh"
if [ $? -ne 0 ]; then
elog_add " ===================="
elog_add "Some Error in script, will not continue. Please check."
elog_add "Press any key to continue."
read -n 1 -s -r
exit 1
fi
elog_add " ===================="
fi
done
elog_add "Done running pre installed user setup scripts"
#2. Run the scripts, that are delivered by the package maintainers
# To run scripts, the tepository path must always be set right (but maybe empty, which is fine)
if [ "${CLIENT_SOFTWARE_CUST_DST}" != "${SYSCONFIGPATH}/client_software_cust" ]; then
echo "Error in config: Required parameter CLIENT_SOFTWARE_CUST_DST is missing or set wrong."
echo "Please relog and if the problem reoccures, contact your system admins to correct the Values."
read -n 1 -s -r -p "Press any key to continue"
else
elog_add "Running company delivered user setup scripts in ${CLIENT_SOFTWARE_CUST_DST}"
for DIR in $(ls -d ${CLIENT_SOFTWARE_CUST_DST}/*/ | sort); # list directories in the form "/tmp/dirname/"
do
DIR=${DIR%*/} # remove the trailing "/"
if [[ "$1." != "." ]] && [[ "${DIR}" != *"$1"* ]]; then
#search for string in dir
elog_add "Skipping ${DIR} while not in search parameter ( $1 )."
continue
fi
if [ -f "${DIR}/user_run.sh" ]; then
elog_add " >>> Running ${DIR}/user_run.sh"
cd ${DIR}
elog_add_command "${DIR}/user_run.sh"
if [ $? -ne 0 ]; then
elog_add " ===================="
elog_add "Some Error in script, will not continue. Please check."
elog_add "Press any key to continue."
read -n 1 -s -r
exit 1
fi
elog_add " ===================="
fi
done
elog_add "Done running company user setup scripts"
elog_add_command "${CLIENT_SOFTWARE_DST}/user_run.sh $1"
if [ $? -ne 0 ]; then
exit 1
fi
elog_add "Completed user setup scripts."
elog_add ""
# Remove unused flatpak user installed software and data
flatpak uninstall --unused -y --user
flatpak uninstall --delete-data -y
#SYNC Firefox + Thunderbird Profile
if [ ! -z "${PROFILE_FIREFOX_SRC}" ]; then
${SYSCONFIGPATH}/system_setup/mozilla_starter.sh firefox sync
fi
if [ $? -eq 0 ] && [ ! -z "${PROFILE_TB_SRC}" ]; then
${SYSCONFIGPATH}/system_setup/mozilla_starter.sh thunderbird sync
if [ $? -eq 0 ]; then
elog_add "Successfully synced Mozilla profiles (log in another file)."
fi
fi
${SYSCONFIGPATH}/system_setup/mozilla_starter.sh firefox sync && ${SYSCONFIGPATH}/system_setup/mozilla_starter.sh thunderbird sync
elog_add "Successfully synced Mozilla profiles (log in another file)."
elog_add "Sucessfully run logon script (Wait 3 seconds)"
sleep 3
+12 -24
View File
@@ -42,7 +42,7 @@ if [ $? -ne 0 ]; then
if [ -d "${ENCRYPTEDDATADIR}" ]; then
echo "The encrypted Directory ${ENCRYPTEDDATADIR} exists."
read -p "To mount it with your Key, that you noticed when installing that PC, enter the Key now or press CTRL+C to abort: " ENCKEY
echo ${ENCKEY} > ${XDG_RUNTIME_DIR}/IPAVAULTKEY
echo ${ENCKEY} > /var/tmp/IPAVAULTKEY.txt
else
echo "The Server ${SERVERFQDN_IPA} is offline and no Directory ${ENCRYPTEDDATADIR} exists. Cannot continue."
echo "Please check your Connection/Server and retry."
@@ -52,12 +52,12 @@ else
# Server is online
#Get the Token from IPA
echo Getting the Vault ${IPAVAULTNAME}
ipa vault-retrieve ${IPAVAULTNAME} --out ${XDG_RUNTIME_DIR}/IPAVAULTKEY >/dev/null
ipa vault-retrieve ${IPAVAULTNAME} --out /var/tmp/IPAVAULTKEY.txt >/dev/null #TODO: Instead of /var/tmp use tmpfs for more security
if [ $? -ne 0 ]; then
echo "No Key found. Will try to Setup a new one."
ENCKEY=$( openssl rand -base64 24 )
echo ${ENCKEY} > ${XDG_RUNTIME_DIR}/IPAVAULTKEY
ipa vault-add "${IPAVAULTNAME}" --desc "Key for Fileencrytption of ${HOSTNM}" --type=standard && ipa vault-archive "${IPAVAULTNAME}" --in ${XDG_RUNTIME_DIR}/IPAVAULTKEY
echo ${ENCKEY} > /var/tmp/IPAVAULTKEY.txt
ipa vault-add "${IPAVAULTNAME}" --desc "Key for Fileencrytption of ${HOSTNM}" --type=standard && ipa vault-archive "${IPAVAULTNAME}" --in /var/tmp/IPAVAULTKEY.txt
if [ $? -eq 0 ]; then
echo
echo "Your Key has been sucessfully stored to the Vault ${IPAVAULTNAME}"
@@ -75,43 +75,31 @@ else
ENCKEY=""
fi
else
ENCKEY=$( cat ${XDG_RUNTIME_DIR}/IPAVAULTKEY )
ENCKEY=$( cat /var/tmp/IPAVAULTKEY.txt )
# echo "The Key is: ${ENCKEY}"
fi
fi
if [ "${ENCKEY}." == "." ]; then
echo "Some Error while fetching your IPA Vault Key. This should not happen. Quit."
rm ${XDG_RUNTIME_DIR}/IPAVAULTKEY
echo "Some Error while fetching your Credentials. This should not happen. Quit."
rm /var/tmp/IPAVAULTKEY.txt
exit 2
fi
echo "Sucessfuly obtained IPA vault fileencryption key."
#Setup and use encrypted filesystem
if [ ! -d "${DECRYPTEDDATADIR}" ] || [ ! -f "${HOME}/.config/gocryptfs/gocryptfs.conf" ]; then
if [ ! -d "${DECRYPTEDDATADIR}" ]; then
#Key has been obtained, but no Directory was created till know
echo "First Setup of encryption: Creating new Directories now"
mkdir -p ${ENCRYPTEDDATADIR} ${DECRYPTEDDATADIR} ${HOME}/.config/gocryptfs
gocryptfs -init -allow_other -passfile ${XDG_RUNTIME_DIR}/IPAVAULTKEY -config ${HOME}/.config/gocryptfs/gocryptfs.conf ${ENCRYPTEDDATADIR} >/dev/null
gocryptfs -init -passfile /var/tmp/IPAVAULTKEY.txt -config ${HOME}/.config/gocryptfs/gocryptfs.conf ${ENCRYPTEDDATADIR} >/dev/null
fi
systemd-run --user --unit=gocryptfs-home \
--property="ExecStop=/usr/bin/fusermount -u ${DECRYPTEDDATADIR}" \
--property=KillMode=none \
--property=TimeoutStopSec=30 \
gocryptfs -fg -noprealloc -allow_other -passfile ${XDG_RUNTIME_DIR}/IPAVAULTKEY -config ${HOME}/.config/gocryptfs/gocryptfs.conf ${ENCRYPTEDDATADIR} ${DECRYPTEDDATADIR} >/dev/null
gocryptfs -noprealloc -passfile /var/tmp/IPAVAULTKEY.txt -config ${HOME}/.config/gocryptfs/gocryptfs.conf ${ENCRYPTEDDATADIR} ${DECRYPTEDDATADIR} >/dev/null
RETVAL=$?
# Service starts asynchronously - wait for the FUSE mount to appear before removing
# the passfile, otherwise gocryptfs may not have read it yet
_t=0
while [ "${_t}" -lt 10 ] && ! grep -q "${DECRYPTEDDATADIR}" /proc/mounts 2>/dev/null; do
sleep 1
_t=$((_t + 1))
done
rm -f ${XDG_RUNTIME_DIR}/IPAVAULTKEY
rm /var/tmp/IPAVAULTKEY.txt
cd ${EXECDIR}
if [ ${RETVAL} -eq 0 ]; then
echo "Sucessfully mounted encrypted private Directory ${DECRYPTEDDATADIR}"
exit 0
else
echo "Errorcode ${RETVAL}"
echo "Errorcode ${RETAVAL}"
exit 1
fi
+1 -1
View File
@@ -3,7 +3,7 @@
source $(dirname "$0")/setup_system.inc.sh
EXECDIR=$(pwd)
SRCFILE="${SYSCONFIGPATH}/config/skel.tar.zst"
SRCFILEDIST="$(dirname "$0")/skel/skel.tar.zst.dist"
SRCFILEDIST="${SYSCONFIGPATH}/config/skel.tar.zst.dist"
#Check for root
if [ "$EUID" -ne 0 ]; then
+20 -57
View File
@@ -5,57 +5,25 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This is not a runnig script-file. No real logic to execute. Its used for includes in other scripts.
#
# Parameters (pass as arguments to the `source` call, e.g. source setup_system.inc.sh --missingconfok):
# --missingconfok Print a warning instead of prompting and aborting when config/setup_system.conf is missing.
# Parse flags passed to this inc (e.g. source setup_system.inc.sh --missingconfok).
# In bash, arguments to `source` temporarily replace $@ for the duration of the sourced file.
_INC_MISSINGCONFOK=0
for _inc_arg in "$@"; do
[[ "$_inc_arg" == "--missingconfok" ]] && _INC_MISSINGCONFOK=1
done
unset _inc_arg
#Get the machine_uuid wich is needed by some userspace programs.
#As all Parameters that are bound to CPU or Mainboard, are only readable by root, we need to get the values at installtime.
#On old installations without the file, we will write it whenever possible
MACHINEID_FILE="$( dirname "${BASH_SOURCE[0]:-$0}" )/../config.d/machine_uuid.sys"
if [ -f ${MACHINEID_FILE} ]; then
export MACHINEID="$( cat ${MACHINEID_FILE} )"
elif [ "$EUID" -eq 0 ]; then
dmidecode -t system | grep -i 'UUID' \
| sed 's/UUID: //' | tr '[:upper:]' '[:lower:]' \
| sed 's/[^0-9a-z]*//g' | xargs | tail -c 13 \
> "${MACHINEID_FILE}"
export MACHINEID="$( cat ${MACHINEID_FILE} )"
echo "Wrote MACHINEID ${MACHINEID} to ${MACHINEID_FILE}"
#Check if we are root
# Deprectaed - use if Statement itself
#check_root()
#{
# if [ "$EUID" -ne 0 ]; then
# return 1
# fi
# return 0
#}
if [ ! -f $(dirname "$0")/../config/setup_system.conf ]; then
echo "System configuration not found. Please make a copy of setup_system.conf.dist, name it setup_system.conf and check the settings in it before running."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
source $(dirname "$0")/../config/setup_system.conf
#Check for configure.conf - used for first setup of system
if [[ -f $(dirname "${BASH_SOURCE[0]:-$0}")/../config.d/configure.conf ]]; then
echo "System in configure-mode. Will use $(dirname "${BASH_SOURCE[0]:-$0}")/../config.d/configure.conf for setup."
source $(dirname "${BASH_SOURCE[0]:-$0}")/../config.d/configure.conf
else
#Load default system setup file
if [[ ! -f $(dirname "${BASH_SOURCE[0]:-$0}")/../config/setup_system.conf ]]; then
echo "WARNING: System configuration not found."
if [[ $_INC_MISSINGCONFOK -eq 1 ]]; then
echo "Continuing without system configuration (--missingconfok), but this should only be for installing."
else
echo "Please copy system_setup/config.dist/setup_system.conf.dist to config/setup_system.conf and adjust the settings before running."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
else
echo "Found and use configfile $(dirname "${BASH_SOURCE[0]:-$0}")/../config/setup_system.conf"
source $(dirname "${BASH_SOURCE[0]:-$0}")/../config/setup_system.conf
fi
#Parse additional client-configs
if [[ `ls -1 $(dirname "${BASH_SOURCE[0]:-$0}")/../config.d/*.conf 2>/dev/null | wc -l ` -gt 0 ]]; then
echo "Additional config file found $(dirname "${BASH_SOURCE[0]:-$0}")/../config.d/*.conf - using it"
source $(dirname "${BASH_SOURCE[0]:-$0}")/../config.d/*.conf
fi
#Parse additional client-configs
if [[ `ls -1 $(dirname "$0")/../config.d/*.conf 2>/dev/null | wc -l ` -gt 0 ]]; then
source $(dirname "$0")/../config.d/*.conf
fi
#Check if the Data- Directory is encrypted
@@ -106,8 +74,7 @@ get_nc_token() {
return 1 # Token for Superuser makes no sense and cannot work
fi
# If Filename is given andf encryption is turned on, than first check for encrypted Directory
if [ ${IPAVAULTUSE} == "true" ] && [ ! -z ${DAVTOKENFILENAME} ]; then
if [ ${IPAVAULTUSE} == "true" ]; then
check_data_isecrypted
if [ $? -ne 0 ]; then
echo "Data Directory is not encrypted. Please mount it first."
@@ -115,7 +82,7 @@ get_nc_token() {
fi
fi
if [ ! -f ${DAVTOKENFILENAME} ] || [ -z ${DAVTOKENFILENAME} ]; then
if [ ! -f ${DAVTOKENFILENAME} ]; then
echo "No token found here. Getting a new WEBDAV Token for this Device."
echo "Please logon to your Nextcloud instance via SSO/kerberos"
@@ -135,12 +102,8 @@ get_nc_token() {
echo -n "Poll Number ${i}..."
POLLJSON=$( curl -s -X POST "https://${SERVERFQDN_NC}/login/v2/poll" -d "token=${REQTOKEN}" )
if [[ "${POLLJSON}" == *"appPassword"* ]]; then
if [ ! -z ${DAVTOKENFILENAME} ]; then
echo "${POLLJSON}" > ${DAVTOKENFILENAME}
echo "Token has been written to ${DAVTOKENFILENAME}"
else
echo "Temporary token was obtained."
fi
echo "${POLLJSON}" > ${DAVTOKENFILENAME}
echo "found token. Token has been written to ${DAVTOKENFILENAME}"
pkill firefox
break
else
+3 -6
View File
@@ -67,7 +67,7 @@ ExecStart=/bin/sh ${SCRIPTPATH}/${SCRIPTNAME} firstrun_run
#ExecStart=-/sbin/agetty --noclear -n -l "/bin/sh ${SCRIPTPATH}/${SCRIPTNAME} firstrun_run" %I 38400
# user interaction in tty8
StandardInput=tty
TTYPath=/dev/tty8
TTYPath=/dev/tty2
TTYReset=yes
TTYVHangup=yes
@@ -127,14 +127,11 @@ install_sw()
( sed 's/^UMASK.*022$/UMASK\t077/' /etc/login.defs | sudo tee /etc/login.defs ) >/dev/null
#Append OEMDRV mount to SYSCONFIGPATH in fstab
echo "LABEL=OEMDRV ${SYSCONFIGPATH} btrfs noatime,nodiratime,nofail,compress=zstd:6 0 0" >> /etc/fstab
echo "LABEL=OEMDRV ${SYSCONFIGPATH} btrfs noatime,nodiratime,nofail 0 0" >> /etc/fstab
#Make KDE single click
echo -e "[KDE]\nSingleClick=true" | tee -a /etc/xdg/kdeglobals
#Make encryption accessible for root
echo "user_allow_other" >>/etc/fuse.conf
#Set openh264 enabled
dnf config-manager setopt fedora-cisco-openh264.enabled=1
@@ -145,7 +142,7 @@ install_sw()
ipa_register_host()
{
#Integrate this PC into Domain
chvt 8
chvt 2
#Check if IPA is already Configured
echo "Checking for existing IPA- Setup."
if ( grep -q "${FQDN}" /etc/ipa/default.conf ); then
+31 -175
View File
@@ -10,29 +10,9 @@ if [ "$EUID" -ne 0 ]; then
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
# Remove 'server _gateway iburst' from chrony.conf — Anaconda adds it as a fallback but
# _gateway is not resolvable by chronyd at startup; DHCP-sourced servers via sourcedir
# /run/chrony-dhcp already cover NTP discovery so this line is redundant and noisy.
_CHRONY_CONF="/etc/chrony.conf"
if [ -f "${_CHRONY_CONF}" ] && grep -q "^server _gateway" "${_CHRONY_CONF}"; then
echo "Patching chrony.conf: removing unresolvable 'server _gateway' entry"
sed -i "/^server _gateway/d" "${_CHRONY_CONF}"
systemctl restart chronyd
fi
# Ensure krb5_validate = False in sssd.conf to restore offline auth
# (SSSD >= 2.10.1 skips the CAP_DAC_READ_SEARCH raise in offline mode, so validate_tgt
# fails with EACCES before the cached-credential fallback is reached)
_SSSD_CONF="/etc/sssd/sssd.conf"
if [ -f "${_SSSD_CONF}" ] && ! grep -q "^krb5_validate" "${_SSSD_CONF}"; then
echo "Patching sssd.conf: adding 'krb5_validate = False' to restore offline authentication"
sed -i "/^\[domain\/${DOMAIN}\]/a krb5_validate = False" "${_SSSD_CONF}"
systemctl restart sssd
fi
#Check Token
if [ "${DAVTOKEN_USER}." == "." ]; then
echo "Error: Script cannot be executed standalone, must be run with a matching sudo rule and needs a prereserved environment from logon-script."
echo "Error: Script cannot be executed standalone, must be run with a matching sudo rule and needs a prereserved environement from logon-script."
echo "A matching sudo rule could look like this: "'^'${SYSCONFIGPATH////'\/'}'\/system_setup\/sync_client_software\.sh.*$'
echo "Hint: the rule must contain the !authenticate and setenv option to work."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
@@ -40,58 +20,37 @@ fi
#Install or update Nextcloud com.nextcloud.desktopclient.nextcloud
echo "Update or install Nextcloud client"
/usr/bin/flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo && \
/usr/bin/flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
/usr/bin/flatpak install -y --or-update --noninteractive flathub com.nextcloud.desktopclient.nextcloud && echo "Done Update/Install of Nextcloud."
if [[ $? -ne 0 ]]; then
echo ""
echo "There seems to be a problem with your network connection. Please first check, if your network can be established before reuming."
echo "You can press CRTL+C to abort now. Than your data wont be accessible and you need to run \"$0\" again."
echo "You can also continue without network. You may need your personal encryptionkey for accessing your data."
read -n 1 -s -r -p "Please check Network and press any Key to continue"
fi
echo ""
# Ensure session bus access for Nextcloud (may be blocked by Flatseal or missing from manifest)
/usr/bin/flatpak override --system --socket=session-bus com.nextcloud.desktopclient.nextcloud
#Do an upgrade of the Base package if its configured and if there are changes
#Sync remote Files
chown root:${CLIENTADMINGROUP} -R ${SYSCONFIGPATH}
chmod ug+rwX,o=rX -R ${SYSCONFIGPATH}
if [[ ! -z "${REPO_URL}" ]]; then
echo "Checking for Upgrades on ${REPO_URL} and Branch ${REPO_BRANCH}"
#Do an upgrade of the Base package if its configured and if there are changes
if [[ ! -z "${UPGRADEURL}" ]]; then
echo "Checking for Upgrades on ${UPGRADEURL} and Branch ${UPGRADEBRANCH}"
REMOTEURL=$( git config --get remote.origin.url )
echo "Remote git URL is ${REMOTEURL}"
if [[ "${REMOTEURL}" != "${REPO_URL}" ]]; then
if [[ "${REMOTEURL}" != "${UPGRADEURL}" ]]; then
echo "This Repo is not on the matching URL, so no update is possible. If you want to change this, check out the docs on how to setup from scratch."
else
GITBRANCH=$( git rev-parse --abbrev-ref HEAD )
echo "Current branch is ${GITBRANCH}"
if [[ "${GITBRANCH}" != "${REPO_BRANCH}" ]]; then
if [[ "${GITBRANCH}" != "${UPGRADEBRANCH}" ]]; then
echo "This Repo is not on the right branch, so no update is possible."
else
# Doing upgrade, discarding all local changes frist (is more save than forced pull)
echo "Checks have passed, we are now upgrading via git."
#Fetch latest commit only (depth=1), reset working tree, purge old history and untracked files
git fetch --depth=1 origin ${REPO_BRANCH} && git reset --hard FETCH_HEAD && git -C "${SYSCONFIGPATH}" clean -fd && git gc --prune=now --quiet
if [[ $? -ne 0 ]]; then
echo "Error: Failure while updating, will continue as is."
fi
git fetch origin
git reset --hard origin/${UPGRADEBRANCH}
#Remove all history
git rebase HEAD^
fi
fi
else
echo "REPO_URL is not specified in conf - No Upgrade option available."
echo ""
fi
echo ""
# Before running sync or software installs, restore the rights to all filles.
# They must be owned by root, changeable by admingroup and readable by otherusers (we are root, so we can change!)
# user_run.sh must also be executable by users
chown root:${CLIENTADMINGROUP} -R ${SYSCONFIGPATH}
chmod ug+rwX,o=rX -R ${SYSCONFIGPATH}
#Make all install.sh executable
find ${SYSCONFIGPATH}/client_software -type f -name install.sh -exec chmod ug+x,o-x {} \;
find ${SYSCONFIGPATH}/client_software -type f -name user_run.sh -exec chmod ugo+x {} \;
# At first, sync central configs if they are configured to be synced
if [[ ! -z "${DISTCONFIGPATH_SRC}" ]]; then
@@ -113,89 +72,17 @@ if [[ ! -z "${DISTCONFIGPATH_SRC}" ]]; then
fi
echo "Sucessfully synced."
echo ""
# Check, if we are in configure-mode and if so, remove the file and reread the now new synced configuration
if [ -f $(dirname "$0")/../config.d/configure.conf ]; then
#Check if configuration was obtained by sync
if [ -f $(dirname "$0")/../config/setup_system.conf ]; then
echo "Existing configuration found in Repository, removing configure-mode and reread the configuration."
rm -f $(dirname "$0")/../config.d/configure.conf.bak >/dev/null
mv $(dirname "$0")/../config.d/configure.conf $(dirname "$0")/../config.d/configure.conf.bak
OLD_REPO_URL="$REPO_URL"
OLD_REPO_BRANCH="$REPO_BRANCH"
source $(dirname "$0")/setup_system.inc.sh
#Compare the Repository URLS after that
if [ "$REPO_URL" != "$OLD_REPO_URL" ] || [ "$REPO_BRANCH" != "$OLD_REPO_BRANCH" ]; then
echo "The Repository for installation was"
echo "$OLD_REPO_URL Branch $OLD_REPO_BRANCH"
echo "After reading the config, the Repository has changed to"
echo "$REPO_URL Branch $REPO_BRANCH"
echo
echo "Do you want to create a system specific configuration for the installation Repository, so that"
read -r -p "only this system will stay on the Repository for installation? [y/N]: " CREATE_REPO_CONF
if [[ "${CREATE_REPO_CONF,,}" == "y" ]]; then
echo "export REPO_URL=\"$OLD_REPO_URL\"" >$(dirname "$0")/../config.d/repo.conf
echo "export REPO_BRANCH=\"$OLD_REPO_BRANCH\"" >>$(dirname "$0")/../config.d/repo.conf
echo "Wrote new $(dirname "$0")/../config.d/repo.conf"
fi
fi
else
echo "System is in configure-mode and configuration repository was found and synced, but still not configuration was found"
echo "checking file $(dirname "$0")/../config/setup_system.conf"
echo ""
echo "Please make a copy of system_setup/config.dist/setup_system.conf.dist to config/setup_system.conf and check all settings there."
echo "Then rerun the logon script to sync the file to your repository."
echo "Press any key to continue" && read -n 1 -s -r && exit 1
fi
fi
fi
echo "Running install scripts in admin- context."
# Run pre installed scripts in client_software
echo "Running pre installed install scripts in admin- context."
for DIR in $(ls -d ${SYSCONFIGPATH}/client_software/*/ | sort); do
DIR=${DIR%*/} # remove the trailing "/"
if [[ "$2." != "." ]] && [[ "${DIR}" != *"$2"* ]]; then
#search for string in dir
echo "Skipping ${DIR} while not in search parameter ( $2 )."
continue
fi
if [ -f "${DIR}/install.sh" ]; then
echo " ===================="
echo " >>> Running ${DIR}/install.sh"
cd ${DIR}
${DIR}/install.sh
if [ $? -ne 0 ]; then
echo " ===================="
echo "Some Error in script, will not continue. Please check."
echo "Press any key to continue."
read -n 1 -s -r
exit 1
fi
echo " ===================="
fi
done
echo "Done running pre installed install scripts in admin- context."
echo
# To run scripts, the repository path must always be set right (but maybe empty, which is fine)
if [ "${CLIENT_SOFTWARE_CUST_DST}" != "${SYSCONFIGPATH}/client_software_cust" ]; then
echo "Error in config: Required parameter CLIENT_SOFTWARE_CUST_DST is missing or set wrong."
echo "Please relog and if the problem reoccures, contact your system admins to correct the Values."
read -n 1 -s -r -p "Press any key to continue"
echo
exit 1
#Check if Repository is defined
if [ "${CLIENT_SOFTWARE_DST}." == "." ]; then
echo "No central softwarerepository defined (CLIENT_SOFTWARE_DST). Skipping sync."
else
# Then, sync all client_software-files
if [[ -z "${CLIENT_SOFTWARE_CUST_SRC}" ]]; then
echo "No customer software sync is defined, skipping sync"
echo "${CLIENT_SOFTWARE_CUST_DST} with ${CLIENT_SOFTWARE_CUST_SRC}"
echo
else
echo "Syncing customer software repository ${CLIENT_SOFTWARE_CUST_DST}"
if [[ ! -z "${CLIENT_SOFTWARE_SRC}" ]]; then
echo "Syncing central softwarerepository ${CLIENT_SOFTWARE_DST}"
# Create Directory if not existent
mkdir -p ${CLIENT_SOFTWARE_CUST_DST}
SYNCCMD="sudo -i /usr/bin/flatpak run --branch=stable --arch=x86_64 --command=nextcloudcmd com.nextcloud.desktopclient.nextcloud -h -u ${DAVTOKEN_USER} -p ${DAVTOKEN_PASS} --path ${CLIENT_SOFTWARE_CUST_SRC} ${CLIENT_SOFTWARE_CUST_DST} https://${SERVERFQDN_NC}"
mkdir -p ${CLIENT_SOFTWARE_DST}
SYNCCMD="sudo -i /usr/bin/flatpak run --branch=stable --arch=x86_64 --command=nextcloudcmd com.nextcloud.desktopclient.nextcloud -h -u ${DAVTOKEN_USER} -p ${DAVTOKEN_PASS} --path ${CLIENT_SOFTWARE_SRC} ${CLIENT_SOFTWARE_DST} https://${SERVERFQDN_NC}"
SYNCCMD_HIDDENPW=$( echo "${SYNCCMD/${DAVTOKEN_PASS}/***HIDDEN***}" )
echo "Exec: ${SYNCCMD_HIDDENPW}"
echo "Sync Client Software"
@@ -212,53 +99,22 @@ else
fi
echo "Sucessfully synced."
fi
echo
echo ""
# After Snc NC is not able to set permission the right way (like execution flag)
# So this need to be done again for new files coming in via sync
# we do it either with or without sync for better safety
# After sync again, restore the rights to all filles. They must be owned by root, changeable by admingroup and readable by otherusers (we are root, so we can change!)
chown root:${CLIENTADMINGROUP} -R ${SYSCONFIGPATH}
chmod ug+rwX,o=rX -R ${SYSCONFIGPATH}
#Make all install.sh executable
find ${SYSCONFIGPATH}/client_software -type f -name install.sh -exec chmod ug+x,o-x {} \;
find ${SYSCONFIGPATH}/client_software -type f -name user_run.sh -exec chmod ugo+x {} \;
find ${SYSCONFIGPATH}/client_software_cust -type f -name install.sh -exec chmod ug+x,o-x {} \;
find ${SYSCONFIGPATH}/client_software_cust -type f -name user_run.sh -exec chmod ugo+x {} \;
find ${CLIENT_SOFTWARE_DST} -type f -name install.sh -exec chmod ugo+x {} \;
#Run customer setup
if [ ! -z "${CLIENT_SOFTWARE_CUST_DST}" ]; then
echo "Running company install scripts in admin- context."
for DIR in $(ls -d ${CLIENT_SOFTWARE_CUST_DST}/*/ | sort); do
DIR=${DIR%*/} # remove the trailing "/"
if [[ "$2." != "." ]] && [[ "${DIR}" != *"$2"* ]]; then
#search for string in dir
echo "Skipping ${DIR} while not in search parameter ( $2 )."
continue
fi
if [ -f "${DIR}/install.sh" ]; then
echo " ===================="
echo " >>> Running ${DIR}/install.sh"
cd ${DIR}
${DIR}/install.sh
if [ $? -ne 0 ]; then
echo " ===================="
echo "Some Error in script, will not continue. Please check."
echo "Press any key to continue."
read -n 1 -s -r
exit 1
fi
echo " ===================="
fi
done
echo "Done running company install scripts in admin- context."
#Run Software setup
echo "Running Setup of Software"
if [ $1 == "install" ]; then
${CLIENT_SOFTWARE_DST}/install.sh $2
if [ $? -ne 0 ]; then
exit 1
fi
fi
fi
#Last, remove unused Flatpak- Runtimes and unused Data
echo "Removing unused Flatpak- Data."
flatpak uninstall --unused -y
echo "Done running install scripts in admin- context."
echo ""
exit 0