#!/bin/sh # MuntsOS System Configurator # Copyright (C)2017-2025, Philip Munts dba Munts Technologies. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. if [ "$1" != "--save" ]; then echo "" echo "MuntsOS System Configurator" echo "" fi ############################################################################### function GetYesNo { printf "%-58s [y,N] " "$@" read resp resp=`echo $resp | tr '[:lower:]' '[:upper:]'` if [ "$resp" != "Y" ]; then return 1 else return 0 fi } ############################################################################### function Prepare { oldhostname=`hostname -s` mount -o rw /boot if [ ! -f /boot/config.txt ]; then echo "ERROR: Invalid boot file system" exit 1 fi # Try to create some directories under /boot, just in case... mkdir -p /boot/autoexec.d mkdir -p /boot/packages mkdir -p /boot/tarballs # The following files and directories are always saved cat <>/etc/changes.manifest /etc/changes.manifest /etc/environment /etc/group /etc/hidraw.conf /etc/host.conf /etc/hosts /etc/httpd.conf /etc/inittab /etc/modules /etc/motd /etc/network.conf /etc/nsswitch.conf /etc/ntp.conf /etc/passwd /etc/shadow /etc/ssh /root /usr/local/etc EOD if [ -f /etc/g_ether.conf ]; then echo /etc/g_ether.conf >>/etc/changes.manifest chmod 444 /etc/g_ether.conf else sed -i '/\/etc\/g_ether.conf/d' /etc/changes.manifest fi if [ -f /etc/g_hid.conf ]; then echo /etc/g_hid.conf >>/etc/changes.manifest chmod 444 /etc/g_hid.conf else sed -i '/\/etc\/g_hid.conf/d' /etc/changes.manifest fi if [ -f /etc/hostname ]; then echo /etc/hostname >>/etc/changes.manifest chmod 444 /etc/hostname else sed -i '/\/etc\/hostname/d' /etc/changes.manifest fi if [ -f /etc/pinmux.conf ]; then echo /etc/pinmux.conf >>/etc/changes.manifest chmod 444 /etc/pinmux.conf else sed -i '/\/etc\/pinmux.conf/d' /etc/changes.manifest fi if [ -f /etc/rc.local ]; then echo /etc/rc.local >>/etc/changes.manifest chmod 555 /etc/rc.local else sed -i '/\/etc\/rc.local/d' /etc/changes.manifest fi if [ -f /etc/scaling_governor ]; then echo /etc/scaling_governor >>/etc/changes.manifest chmod 444 /etc/scaling_governor else sed -i '/\/etc\/scaling_governor/d' /etc/changes.manifest fi if [ -f /etc/sysctl.conf ]; then echo /etc/sysctl.conf >>/etc/changes.manifest chmod 444 /etc/sysctl.conf else sed -i '/\/etc\/sysctl.conf/d' /etc/changes.manifest fi if [ -f /etc/wpa_supplicant.conf ]; then echo /etc/wpa_supplicant.conf >>/etc/changes.manifest chmod 400 /etc/wpa_supplicant.conf else sed -i '/\/etc\/wpa_supplicant.conf/d' /etc/changes.manifest fi if [ -f /usr/local/bin/pip3 ]; then echo "/usr/local/bin/pip3" >>/etc/changes.manifest chmod 555 /usr/local/bin/pip3 else sed -i '/\/usr\/local\/bin\/pip3/d' /etc/changes.manifest fi # Migrate from /etc/profile.d to /usr/local/etc/profile.d if [ -d /etc/profile.d -a -d /usr/local/etc/profile.d ]; then mv /etc/profile.d/* /usr/local/etc/profile.d rmdir /etc/profile.d fi if [ -d /etc/profile.d -a ! -d /usr/local/etc/profile.d ]; then mv /etc/profile.d /usr/local/etc fi # Don't save /etc/profile or /etc/profile.d anymore. # Put your changes in /usr/local/etc/profile.d/ instead! sed -i '/\/etc\/profile/d' /etc/changes.manifest # Don't save individual files in /etc/ssh/ anymore. sed -i '/\/etc\/ssh\/+*/d' /etc/changes.manifest # Don't save individual files in /root/ anymore. sed -i '/\/root\/+*/d' /etc/changes.manifest # Don't save individual files in /usr/local/etc/ anymore. sed -i '/\/usr\/local\/etc\/+*/d' /etc/changes.manifest chmod -R ugo-w /etc/ssh chmod -R ugo-w /usr/local/etc } ############################################################################### function Hostname { hostname >/etc/hostname echo "/etc/hostname" >>/etc/changes.manifest chmod 444 /etc/hostname GetYesNo "Change hostname from `hostname`" if [ $? -ne 0 ]; then return; fi # Get new hostname /bin/echo -n " New hostname? " read resp resp=`echo $resp | tr '[:upper:]' '[:lower:]'` # Write new hostname to /etc/hostname echo $resp >/etc/hostname chmod 444 /etc/hostname # Activate the new hostname hostname -F /etc/hostname } ############################################################################### function NetConfig { ifconfig -a | grep -q -E '^(eth|wlan).*Link encap:' if [ $? -eq 1 -a $((OPTIONS & 0x800)) -eq 0 ]; then return; fi GetYesNo "Edit static network configuration" if [ $? -ne 0 ]; then return; fi netconfig } ############################################################################### function ServerSSHKeys { GetYesNo "Regenerate SSH server key" if [ $? -ne 0 ]; then return; fi rm -f /etc/ssh/*key ssh-keygen -q -C "`hostname`" -N "" -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key chmod -R ugo-w /etc/ssh } ############################################################################### function RootPassword { GetYesNo "Change superuser password" if [ $? -ne 0 ]; then return; fi passwd root } ############################################################################### function RootSSHKeys { if [ -f /root/.ssh/id_rsa ]; then GetYesNo "Regenerate superuser id_rsa" if [ $? -ne 0 ]; then return; fi rm -f /root/.ssh/id_rsa* else GetYesNo "Generate superuser id_rsa" if [ $? -ne 0 ]; then return; fi fi ssh-keygen -q -C "`hostname -s` system administrator" -N "" -t rsa -b 4096 -f /root/.ssh/id_rsa chmod ugo-w /root/.ssh/id_rsa* } ############################################################################### function RootSSHAuth { GetYesNo "Add public key to superuser authorized_keys" if [ $? -ne 0 ]; then return; fi printf " Paste the public key here: " read pubkey echo "" echo $pubkey >>/root/.ssh/authorized_keys chmod 400 /root/.ssh/authorized_keys } ############################################################################### function DisableSSHPasswords { egrep -q '^PasswordAuthentication no$' /etc/ssh/sshd_config if [ $? -eq 0 ]; then return; fi GetYesNo "Disable SSH password authentication" if [ $? -ne 0 ]; then return; fi echo "PasswordAuthentication no" >>/etc/ssh/sshd_config } ############################################################################### function AddWirelessOpen { ifconfig -a | grep -q -E '^(wlan).*Link encap:' if [ $? -eq 1 ]; then return; fi GetYesNo "Add open wireless network" if [ $? -ne 0 ]; then return; fi printf " Enter SSID: " read ssid printf "\n" >>/etc/wpa_supplicant.conf printf "network={\n" >>/etc/wpa_supplicant.conf printf "\tssid=\"$ssid\"\n" "$ssid" >>/etc/wpa_supplicant.conf printf "\tkey_mgmt=NONE\n" >>/etc/wpa_supplicant.conf printf "}\n" >>/etc/wpa_supplicant.conf echo /etc/wpa_supplicant.conf >>/etc/changes.manifest } ############################################################################### function AddWirelessWPA { ifconfig -a | grep -q -E '^(wlan).*Link encap:' if [ $? -eq 1 ]; then return; fi GetYesNo "Add WPA/PSK wireless network" if [ $? -ne 0 ]; then return; fi printf " Enter SSID: " read ssid printf " Enter password: " read password printf "\n" >>/etc/wpa_supplicant.conf printf "network={\n" >>/etc/wpa_supplicant.conf printf "\tssid=\"$ssid\"\n" "$ssid" >>/etc/wpa_supplicant.conf printf "\tkey_mgmt=WPA-PSK\n" >>/etc/wpa_supplicant.conf printf "\tpsk=\"$password\"\n" "$password" >>/etc/wpa_supplicant.conf printf "}\n" >>/etc/wpa_supplicant.conf echo /etc/wpa_supplicant.conf >>/etc/changes.manifest } ############################################################################### function AddWirelessWEP { ifconfig -a | grep -q -E '^(wlan).*Link encap:' if [ $? -eq 1 ]; then return; fi GetYesNo "Add WEP wireless network" if [ $? -ne 0 ]; then return; fi GetYesNo " WEP is insecure and obsolete! Continue anyway?" if [ $? -ne 0 ]; then return; fi printf " Enter SSID: " read ssid printf " Enter key: " read key printf "\n" >>/etc/wpa_supplicant.conf printf "network={\n" >>/etc/wpa_supplicant.conf printf "\tssid=\"$ssid\"\n" "$ssid" >>/etc/wpa_supplicant.conf printf "\tkey_mgmt=NONE\n" >>/etc/wpa_supplicant.conf printf "\twep_key0=$key\n" "$key" >>/etc/wpa_supplicant.conf printf "}\n" >>/etc/wpa_supplicant.conf echo /etc/wpa_supplicant.conf >>/etc/changes.manifest } ############################################################################### function AddWireless { ifconfig -a | grep -q -E '^(wlan).*Link encap:' if [ $? -eq 1 ]; then return; fi GetYesNo "Add a wireless network" if [ $? -ne 0 ]; then return; fi if [ ! -f /etc/wpa_supplicant.conf ]; then printf "ctrl_interface=DIR=/var/run/wpa_supplicant\n" >/etc/wpa_supplicant.conf printf "update_config=1\n\n" >>/etc/wpa_supplicant.conf fi true while [ $? -eq 0 ]; do AddWirelessOpen AddWirelessWPA AddWirelessWEP GetYesNo "Add another wireless network" done chmod 400 /etc/wpa_supplicant.conf for E in /sys/class/net/wlan*/uevent ; do test -f $E && echo add >$E done } ############################################################################### function RemoveWLANInit { ifconfig -a | grep -q -E '^(wlan).*Link encap:' if [ $? -eq 1 ]; then return; fi if [ -f /boot/autoexec.d/00-wlan-init -a -f /etc/wpa_supplicant.conf ]; then GetYesNo "Remove redundant 00-wlan-init" if [ $? -ne 0 ]; then return; fi rm /boot/autoexec.d/00-wlan-init if [ -f /boot/checksums.md5 ]; then sed -i /00-wlan-init/d /boot/checksums.md5 fi fi } ############################################################################### function DeviceTreeOverlays { grep -q 'OVERLAYS=' /boot/config.txt if [ $? -eq 0 ]; then return; fi if [ ! -f /usr/share/sysconfig/overlays.${BOARDNAME} ]; then return; fi GetYesNo "Enable MuntsOS default device tree overlays" if [ $? -ne 0 ]; then return; fi cat /usr/share/sysconfig/overlays.${BOARDNAME} >>/boot/config.txt if [ -f /boot/checksums.md5 ]; then savepwd=`pwd` cd /boot sed -i "s/.*config.txt/`md5sum -b config.txt`/g" checksums.md5 cd ${savepwd} fi } ############################################################################### function PinMux { if [ -f /etc/pinmux.conf -o ! -f /usr/share/sysconfig/pinmux.${BOARDNAME} ]; then return; fi GetYesNo "Install MuntsOS default pinmux.conf" if [ $? -ne 0 ]; then return; fi install -cm 0444 /usr/share/sysconfig/pinmux.${BOARDNAME} /etc/pinmux.conf echo /etc/pinmux.conf >>/etc/changes.manifest } ############################################################################### function Extensions { ifconfig -a | grep -q -E '^(eth|wlan).*Link encap:' if [ $? -eq 1 -a $((OPTIONS & 0x800)) -eq 0 ]; then return; fi GetYesNo "Manage extensions" if [ $? -ne 0 ]; then return; fi EXTENSIONSDIR=${EXTENSIONSDIR:-http://repo.munts.com/muntsos/${TOOLCHAINREVISION}/extensions} echo "Fetching extensions from ${EXTENSIONSDIR}" wget -q -O /tmp/extensions.manifest ${EXTENSIONSDIR}/.extensions.manifest2.${BOARDARCH} if [ $? -ne 0 ]; then echo "ERROR: Cannot download extensions manifest." return; fi # Replace spaces with a colon so we can do awk -F ':' below sed -r -i 's/ +/:/g' /tmp/extensions.manifest for ERecord in `cat /tmp/extensions.manifest`; do EName=`echo ${ERecord} | awk -F ':' '{ print $1 }'` EURL=${EXTENSIONSDIR}/${EName} NewSum=`echo ${ERecord} | awk -F ':' '{ print $2 }'` echo ${EName} | grep -E -q '\.deb$|\.rpm$|\.nuget$' if [ $? -eq 0 ]; then EFile=/boot/packages/${EName} else EFile=/boot/autoexec.d/${EName} fi # Upgrade this extension if [ -f ${EFile} ]; then OldSum=`sha512sum ${EFile} | awk '{ print $1 }'` if [ "$OldSum" != "$NewSum" ]; then GetYesNo "Upgrade ${EName}" if [ $? -eq 0 ]; then wget -O ${EFile}.new ${EURL} if [ $? -eq 0 ]; then mv ${EFile}.new ${EFile} else echo "ERROR: Cannot download package ${EName}" rm -f ${EFile}.new fi continue fi fi fi # Remove this extension if [ -f ${EFile} ]; then GetYesNo "Remove ${EName}" if [ $? -eq 0 ]; then rm -f ${EFile} continue fi fi # Install this extension if [ ! -f ${EFile} ]; then GetYesNo "Install ${EName}" if [ $? -eq 0 ]; then wget -O ${EFile}.new ${EURL} if [ $? -eq 0 ]; then mv ${EFile}.new ${EFile} else echo "ERROR: Cannot download package ${EName}" rm -f ${EFile}.new fi fi fi done rm -f /tmp/extensions.manifest } ############################################################################### function DynamicDNS { ifconfig -a | grep -q -E '^(eth|wlan).*Link encap:' if [ $? -eq 1 -a $((OPTIONS & 0x800)) -eq 0 ]; then return; fi interfaces=`sort &1 | awk '/driver:/ { print $2 }'`" = "g_ether" -a $((OPTIONS & 0x800)) -eq 0 ]; then continue; fi configfile=/usr/local/etc/noip2-$iface.conf if [ -f $configfile ]; then continue; fi GetYesNo "Register $iface for Dynamic DNS at noip.com" if [ $? -ne 0 ]; then continue; fi noip2 -C -F -I $iface -c $configfile if [ $? -eq 0 ]; then chmod 400 $configfile noip2 -M -c $configfile fi done } ############################################################################### function EditCmdline { if [ ! -f /boot/cmdline.txt ]; then return; fi GetYesNo "Edit cmdline.txt" if [ $? -ne 0 ]; then return; fi chmod u+w /boot/cmdline.txt if [ -n "${EDITOR}" ]; then ${EDITOR} /boot/cmdline.txt else vi /boot/cmdline.txt fi chmod ugo-w /boot/cmdline.txt if [ -f /boot/checksums.md5 ]; then savepwd=`pwd` cd /boot sed -i "s/.*cmdline.txt/`md5sum -b cmdline.txt`/g" checksums.md5 cd ${savepwd} fi clear } ############################################################################### function EditConfig { if [ ! -f /boot/config.txt ]; then return; fi GetYesNo "Edit config.txt" if [ $? -ne 0 ]; then return; fi chmod u+w /boot/config.txt if [ -n "${EDITOR}" ]; then ${EDITOR} /boot/config.txt else vi /boot/config.txt fi chmod ugo-w /boot/config.txt if [ -f /boot/checksums.md5 ]; then savepwd=`pwd` cd /boot sed -i "s/.*config.txt/`md5sum -b config.txt`/g" checksums.md5 cd ${savepwd} fi clear } ############################################################################### function Finalize { find /usr/local/etc/python3* -name __pycache__ -exec rm -rf {} ";" >/dev/null 2>&1 sort -u /etc/changes.manifest.new mv /etc/changes.manifest.new /etc/changes.manifest chmod 444 /etc/changes.manifest rm -f /boot/tarballs/${oldhostname}.tgz extratarballs=`ls /boot/tarballs/* 2>/dev/null` if [ -n "${extratarballs}" ]; then echo "Warning: Extra tarballs (possibly obsolete) in /boot/tarballs/" echo ${extratarballs} | tr " " "\n" fi tar czf /boot/tarballs/`hostname -s`.tgz -T /etc/changes.manifest 2>&1 | grep -v 'removing leading' chmod -R ugo-w /boot/* sync umount /boot } ############################################################################### function Reboot { GetYesNo "Reboot system (recommended)" if [ $? -ne 0 ]; then return; fi reboot } ############################################################################### # Save files listed in /etc/changes.manifest if [ "$1" = "--save" ]; then Prepare Finalize exit 0 fi # Transform named parameters to environment variables for x ; do export ${x%=*}="${x#*=}"; done # Execute configuration operations in order Prepare Hostname NetConfig AddWireless RemoveWLANInit ServerSSHKeys RootPassword RootSSHKeys RootSSHAuth DisableSSHPasswords DeviceTreeOverlays PinMux Extensions DynamicDNS EditCmdline EditConfig Finalize Reboot