#!/bin/bash # usage ## curl -s https://raw.githubusercontent.com/PrincessPi3/Precision-Timekeeping-Fuckery/refs/heads/main/installer_auto.sh?nocache=$RANDOM | $SHELL ## test: bash time_fuckery.sh [t|T] ## reconfigure: bash time_fuckery.sh [r|R] [conf-level-info|conf-level-debug|conf-level-warm|=conf-level-info] ## nuke logs: bash time_fuckery.sh [n|N] ## uninstall: bash time_fuckery.sh [u|U] ## services: bash time_fuckery.sh [s|S] [stop|start|restart|status|enable|disable|=status] ## measure offset (chrony_statistics): bash time_fuckery.sh [mM] [int number of logs to process=500] # explicitly die on any error # set -e # delays in minutes long_delay=1 short_delay=1 # first install first_install="git" # packages packages="btop build-essential byobu chrony gawk gh grafana gpsd gpsd-clients i2c-tools influxdb iptraf-ng util-linux util-linux-extra lynx net-tools nginx picocom pps-tools python3 python3-pip python3-virtualenv python3-setuptools python3-pandas python3-smbus python3-matplotlib restic ripgrep screen syslog-ng telegraf" # purge packages purge_packages="build-essential bluetooth* wireless* fonts* bluez* pci* alsa*" # services services="gpsd gpsd.socket chrony influxdb telegraf grafana-server syslog-ng nginx" # configs place in system gpsd="/etc/default/gpsd" chrony="/etc/chrony/conf.d/precision_timekeeping.conf" grafana="/etc/grafana/grafana.ini" influxdb="/etc/influxdb/influxdb.conf" telegraf="/etc/telegraf/telegraf.conf" udev_rule="/etc/udev/rules.d/50-tty.rules" bootfirmwareconfig="/boot/firmware/config.txt" sudoers="/etc/sudoers" # hwclockset="/lib/udev/hwclock-set" # log locations chrony_tracking_log=/var/log/chrony/tracking.log chrony_statistics_log=/var/log/chrony/statistics.log chrony_measurements_log=/var/log/chrony/measurements.log telegraf_log=/var/log/telegraf/telegraf.log grafana_log=/var/log/grafana/grafana.log syslog_log=/var/log/syslog rootcrontab_log=/var/log/root-crontab.log # get real username (not root) if run with sudo if [ ! -z $SUDO_USER ]; then username=$SUDO_USER else username=$USER fi # calculated values git_dir="/home/$username/Precision-Timekeeping-Fuckery" status_log="$git_dir/status.txt" installer_status="$git_dir/installer.tmp" long_delay_seconds=$(($long_delay * 60)) short_delay_seconds=$(($short_delay * 60)) # stability sleeps short_sleep () { echo -e "\nSleeping $short_delay minutes to make sure everything is as stable as possible\n" sleep $short_delay_seconds } long_sleep () { echo -e "\nSleeping $long_delay minutes to make sure everything is as stable as possible\n" sleep $long_delay_seconds } # reboot host run_reboot () { echo -e "\n\nREBOOTING IN $short_delay MINUTES!\n\n" sudo shutdown -r +$short_delay } # to the pause thing like in dos function hold_for_enter() { echo -e "\nPress ENTER to Continue..." read -p "" } # handle the services services_cmd () { if [ -z $1 ]; then echo "Usage: bash services.sh stop|start|restart|status|enable" exit fi echo -e "\nRunning $1 on Services\n" sudo bash -c "systemctl $1 $services" echo "services complete" >> $status_log } # dump/backup configs dump_configs () { dname=./conf-$(date +%s) long_sleep echo -e "\nBacking up configa\n" echo -e "\nMaking $dname\n" mkdir $dname echo "Copying the config files" echo -e "\tBacking up gpsd config" sudo cp $gpsd $dname/gpsd echo -e "\tBacking up chrony config" sudo cp $chrony $dname/chrony.conf echo -e "\tBacking up grafana config" sudo cp $grafana $dname/grafana.ini echo -e "\tBacking up influxdb config" sudo cp $influxdb $dname/influxdb.conf echo -e "\tBacking up telegraf config" sudo cp $telegraf $dname/telegraf.conf echo -e "\tBacking up /boot/firmware/config.txt" sudo cp $telegraf $dname/boot-firmware-config.txt echo -e "\tBacking up root crontab" sudo crontab -l > $dname/root-crontab if [ -f $udev_rule ]; then echo -e "\n$udev_rule found, copying as well...\n" sudo cp $udev_rule $dname/50-tty.rules fi echo -e "\nFixing permissions in $dname...\n" sudo chown -R $username:$username $dname sudo chmod 775 $dname sudo chmod 664 $dname/* echo "Compressing up and deleting $dname to $dname.tar.gz..." tar czf $dname.tar.gz $dname rm -rf $dname echo "dump_configs complete" >> $status_log } # reconfigure from dir reconfigure_full () { # make sure dir works if [ -z $1 ] || [ ! -d "$1" ]; then echo "usage reconfigure_full /path/to/config/dir" exit 1 fi # new conf file paths gpsd_new="$1/gpsd" chrony_new="$1/chrony.conf" grafana_new="$1/grafana.ini" influxdb_new="$1/influxdb.conf" telegraf_new="$1/telegraf.conf" udev_new="$1/50-tty.rules" bootfirmwareconfig_new="$1/boot-firmware-config.txt" crontab_new="$1/root-crontab" sudoers_new="$1/sudoers" # hwclockset_new="$1/hwclock-set" # stop da services services_cmd stop dump_configs # replace dem by truncation echo -e "\nPlacing the new config files by truncation..." echo -e "\tConfiguring gpsd" sudo bash -c "cat $gpsd_new > $gpsd" echo -e "\tConfiguring chrony" sudo bash -c "cat $chrony_new > $chrony" echo -e "\tConfiguring grafana" sudo bash -c "cat $grafana_new > $grafana" echo -e "\tConfiguring influxdb" sudo bash -c "cat $influxdb_new > $influxdb" echo -e "\tConfiguring telegraf" sudo bash -c "cat $telegraf_new > $telegraf" echo -e "\tConfiguring udev\n" sudo bash -c "cat $udev_new > $udev_rule" # setup and install root crontabs echo -e "\nInstalling root cronjobs\n" echo -e "\nJUST SAVE AND EXIT NO EDITS\n" hold_for_enter sudo crontab -e (sudo crontab -l 2>/dev/null && sudo cat $crontab_new) | sudo crontab - # set up passwordless sudo ## backup first sudo cp $sudoers "$sudoers.bak" ## replace sudoers with mine sudo bash -c "cat $sudoers_new > $sudoers" ## test it sudo visudo -c # config hwclockset # echo -e "\tConfiguring hwclockset" # sudo bash -c "cat $hwclockset_new > $hwclockset" # check if /boot/firmware/config.txt is configured yet sudo rg -q "GPS PPS signals" $bootfirmwareconfig grepconfig=$? # configure the overlay if [ $grepconfig -eq 0 ]; then # if config exists, skip echo "$bootfirmwareconfig already updated, skipping..." else # APPEND to /boot/firmware/config.txt echo "Appending configs to $bootfirmwareconfig" sudo bash -c "cat $bootfirmwareconfig_new >> $bootfirmwareconfig" echo $? fi # finish the log echo "reconfigure_full complete" >> $status_log # start da services services_cmd start } phase_one () { echo -e "\n\nStarting 1/5\n\n" long_sleep # updoot echo -e "\nUpdating Software Lists\n" sudo apt update # install get for next step echo -e "\nInstalling git\n" sudo bash -c "apt install -y $first_install" # download da thing echo -e "\nCloning Repo\n" git clone https://github.com/PrincessPi3/Precision-Timekeeping-Fuckery.git $git_dir # makin scripts executable chmod +x $git_dir/*.sh # update the log echo -e "START AT $(date +%s) time_fuckery.sh\ncomplete 1/5" >> $status_log # update the running file echo 1 > $installer_status # done echo -e "\n\nStage 1/5 Complet\n\n" run_reboot } phase_two () { echo -e "\n\nStarting 2/5\n\n" long_sleep # rpi-update echo -e "\nUpdating Raspberry Pi firmware... DO NOT REBOOT\n" sudo rpi-update short_sleep # run da raspberry pi config script clear echo -e "\nConfigure Raspberry Pi... DO NOT REBOOT\n" echo -e "\nUpdate\n\nEnable I2C Support in raspi-config\n\tInterface Options->I2C->\n\t Would you like the ARM I2C interface to be enabled? \n\nInterface Options->Serial Port\n\tWould you like a login shell to be accessible over serial? \n\tWould you like the serial port hardware to be enabled? \n\nAdvanced Options\n\tExpand Filesystem\n\nWould you like to reboot now? " hold_for_enter sudo raspi-config # update the running file echo 2 > $installer_status # update the log echo "phase two complete 2/5" >> $status_log # notify finish echo -e "\n\nPart 2/5 Done!\n\n" run_reboot } phase_three () { echo -e "\n\nStarting 3/5\n\n" long_sleep # full distribution upgrade echo -e "\nFully upgrading, this may take a while...\n" sudo apt dist-upgrade -y short_sleep # cleanup # moved to phase five # echo -e "\nCleaning up...\n" # sudo apt autoremove -y # update the running file echo 3 > $installer_status # notify finish echo -e "\n\nPart 3/5 Done!\n\n" # update the log echo "phase three complete 3/5" >> $status_log run_reboot } phase_four () { echo -e "\nStarting 4/5\n" long_sleep # grafana repo and install echo -e "\nAdd Grafana repo...\n" sudo mkdir -p /etc/apt/keyrings/ wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg >/dev/null # otherwisse get some stupid binary output to terminal echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list >/dev/null # telegraf repo and install echo -e "\nAdd Telegraf repo...\n" curl --silent --location -O \ https://repos.influxdata.com/influxdata-archive.key \ && echo "943666881a1b8d9b849b74caebf02d3465d6beb716510d86a39f6c8e8dac7515 influxdata-archive.key" \ | sha256sum -c - && cat influxdata-archive.key \ | gpg --dearmor \ | sudo tee /etc/apt/trusted.gpg.d/influxdata-archive.gpg >/dev/null \ && echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main' \ | sudo tee /etc/apt/sources.list.d/influxdata.list >/dev/null # remove dat key file thing if [ -f /home/$username/influxdata-archive.key ]; then echo -e "\nRemoving /home/$username/influxdata-archive.key...\n" rm -f /home/$username/influxdata-archive.key else echo -e "\n/home/$username/influxdata-archive.key not found, skipping delete...\n" fi # updoot echo -e "\nGetting new software lists...\n" sudo apt update short_sleep # clean up echo -e "\nDisabling unneeded junk..\n" sudo systemctl disable bluetooth # sudo systemctl disable fake-hwclock sudo update-rc.d -f fake-hwclock remove # install da packages echo -e "\nInstalling packages, this may take a while...\n" sudo bash -c "apt install -y $packages" short_sleep # check if pps-gpio is in /etc/modules already rg -q "pps-gpio" /etc/modules gerppps=$? # add pps-gpio to modules if [ $gerppps -eq 0 ]; then echo -e "\npps-gpio already in /etc/modules, skipping..\n" else echo -e "\nAdding pps-gpio to /etc/modules...\n" sudo bash -c "echo pps-gpio >> /etc/modules" fi # short_sleep # cleanup # moved to phase 5 # echo -e "\nCleaning up...\n" # sudo apt autoremove -y # handle users serial shit ## self echo -e "\nGiving $username the right permissions...\n" sudo usermod -aG dialout $username sudo usermod -a -G i2c $username sudo usermod -a -G tty $username ## service users echo -e "\nGiving service users the right permissions...\n" sudo usermod -aG dialout gpsd sudo usermod -aG dialout _chrony sudo usermod -aG i2c _chrony sudo usermod -aG i2c gpsd sudo usermod -aG tty _chrony sudo usermod -aG tty gpsd short_sleep # installing ble.sh echo -e "\nInstalling BLE.sh\n" bashrc="/home/$username/.bashrc" git clone --recursive --depth 1 --shallow-submodules https://github.com/akinomyoga/ble.sh.git /tmp/ble.sh make -C /tmp/ble.sh install PREFIX=/home/$username/.local echo -e "\n# ble.sh" >> $bashrc echo "source -- /home/$username/.local/share/blesh/ble.sh" >> $bashrc short_sleep # update the running file echo 4 > $installer_status # general-scripts-and-system-ssssssetup echo -e "\nInstalling general-scripts-and-system-ssssssetup\n" curl -s https://raw.githubusercontent.com/PrincessPi3/general-scripts-and-system-ssssssetup/refs/heads/main/customscripts/install_script.sh?nocache=$RANDOM | sudo "$SHELL" && bash /usr/share/customscripts/configure_webhook.sh # update the log echo "phase 4 complete 4/5" >> $status_log # finish echo -e "\n\nPart 4/5 Done\n\n" run_reboot } phase_five () { echo -e "\n\nStarting part 5/5\n\n" long_sleep # reconfigure to normal mode echo -e "\nStarting configurAation\n" # info level # bash ./reconfig_full.sh ./reconfig_full.sh ./conf-level-warn # running (warn level) # bash ./reconfig_full.sh ./conf-level-debug # debug/dev mode reconfigure_full "$git_dir/conf-level-info" # enable services echo -e "\nEnabling Services..." services_cmd enable # purging da junk # dont actually think this is at worth the space savings echo -e "\nPurging unneeded junk...\n" sudo bash -c "apt purge -y $purge_packages" short_sleep sudo apt autoremove -y # unclear if this is needed # edit dis ## comment out and add note ## # commented out manually to use rtc ## # if [ -e /run/systemd/system ] ; then ## # exit 0 ## # fi ## Also comment out the two lines ## # /sbin/hwclock --rtc=$dev --systz --badyear ## and ## # /sbin/hwclock --rtc=$dev --systz # echo "Editing hwclock-set file" # sudo nano /lib/udev/hwclock-set # update the log echo "phase 5 done 5/5\nCOMPLETE AT $(date +%s)" >> $status_log # finish the tmp file echo "installed" > $installer_status # finish echo -e "\nPart 5/5 Done! Yaay! Done!\n" run_reboot } # updoot repo any time the repo is downloaded updoot_repo () { echo -e "\nUpdating\n" git -C $git_dir pull ret=$? if [ $ret -ne 0 ]; then echo -e "\n\nSCRIPT UPDATED! RE-RUN\n\n" exit 1 # explicit fail fi } show_running_configs () { sudo less $gpsd sudo less $chrony sudo less $grafana sudo less $influxdb sudo less $telegraf sudo less $udev_rule sudo less $bootfirmwareconfig sudo crontab -l } test () { # status of services services_cmd status # test pps ## pps0 echo "Testing PPS0" sudo ppstest /dev/pps0 ## pps1 # echo "Testing PPS1" # sudo ppstest /dev/pps1 # check gps echo "Checking Normal GPS" sudo cgps # check gpsmon echo "Checking Timekeeping GPS" gpsmon --nmea # do same with watch echo "Watching chronyc sources" watch chronyc sources # track echo "Watching chronyc tracking" watch chronyc tracking # i2c clear echo -e "Detecting I2C Devices\n" sudo i2cdetect -y 1 hold_for_enter # devices ## tty devices clear echo "tty devices" ls -lh /dev/tty* | sort -k9 hold_for_enter ## pps devices clear echo "pps devices" ls -lh /dev/pps* | sort -k9 hold_for_enter # i2c devices clear echo "i2c devices" ls -lh /dev/i2c* | sort -k9 hold_for_enter # rtc devices clear echo "rtc devices" ls -lh /dev/rtc* | sort -k9 hold_for_enter # rtc clear echo -e "Reading from hardware RTC\n" sudo hwclock -r hold_for_enter # hwclock status clear echo "hwclock status" sudo hwclock --verbose hold_for_enter # root crontab clear echo "root crontab" sudo crontab -l hold_for_enter show_running_configs # clean up clear } uninstall () { services_cmd stop services_cmd disable nuke_logs cleanup sudo apt purge -y telegraf grafana influxdb gpsd gpsd-clients chrony syslog-ng sudo apt install -y raspi-config cd ~ rm -rf ~/Precision-Timekeeping-Fuckery run_reboot } function backup_logs () { # make log backup dir with unix timestamp dname="./log_backup_$(date +%s)" mkdir $dname # copy em sudo cp $chrony_tracking_log $dname/chrony_tracking.log sudo cp $chrony_statistics_log $dname/chrony_statistics.log sudo cp $chrony_measurements_log $dname/chrony_measurements.log sudo cp $telegraf_log $dname/telegraf.log sudo cp $grafana_log $dname/grafana.log sudo cp $syslog_log $dname/syslog sudo cp $rootcrontab_log $dname/root-crontab.log # fix permissions sudo chown -R $USER:$USER $dname chmod 775 $dname chmod 664 $dname/* # compress logs tar fczvv $dname.tar.gz $dname # cleanup rm -rf $dname } function clear_logs() { # truncate logs to empty files sudo bash -c "echo '' > $chrony_tracking_log" sudo bash -c "echo '' > $chrony_statistics_log" sudo bash -c "echo '' > $chrony_measurements_log" sudo bash -c "echo '' > $telegraf_log" sudo bash -c "echo '' > $grafana_log" sudo bash -c " echo '' > $rootcrontab_log" sudo bash -c "echo '' > $syslog_log" } cleanup() { echo "Nuking all those stupid files" rm -f $git_dir/influxdata-archive.key 2>/dev/null rm -f $git_dir/status.txt 2>/dev/null rm -f $git_dir/*.tar.gz 2>/dev/null rm -f $git_dir/*.log 2>/dev/null rm -f $git_dir/*.bak* 2>/dev/null rm -f $git_dir/*.~ 2>/dev/null echo "Cleanup done!" } # usage chrony_statistics [int number of logs to process] # measure_offset chrony_statistics () { numlogs=$1 tmp_log=$git_dir/chrony_statistics.log sudo tail -n $numlogs /var/log/chrony/statistics.log > $tmp_log sudo chown $USER:$USER $tmp_log echo "$(wc -l $tmp_log) logs entered" python $git_dir/chrony_statistics.py rm -f $tmp_log } # always run echo -e "\n\nPrecision Timekeeping Fuckery :3\n\n" # test mode if [[ "$1" =~ ^[tT]{1} ]]; then test exit 0 # reconfigure mode elif [[ "$1" =~ ^[rR]{1} ]]; then if [ -z "$2" ]; then default_conf=$git_dir/conf-level-info else default_conf=$git_dir/$2 fi reconfigure_full $default_conf # nuke logs mode elif [[ "$1" =~ ^[nN]{1} ]]; then cleanup backup_logs clear_logs # uninstall modde elif [[ "$1" =~ ^[uU]{1} ]]; then uninstall # measure offset (chrony_statustics.sh) elif [[ "$1" =~ ^[mM]{1} ]]; then if [ -z "$2" ]; then default_numlogs=500 else default_numlogs=$2 fi chrony_statistics $default_numlogs # services modde elif [[ "$1" =~ ^[sS]{1} ]]; then if [ -z "$2" ]; then default_service_action=status else default_service_action=$2 fi services_cmd $default_service_action else # do da install # if da file is there if [ -f $status_log ]; then updoot_repo if [[ "$(cat $installer_status)" =~ 1 ]]; then phase_two elif [[ "$(cat $installer_status)" =~ 2 ]]; then phase_three elif [[ "$(cat $installer_status)" =~ 3 ]]; then phase_four elif [[ "$(cat $installer_status)" =~ 4 ]]; then phase_five else echo -e "\nAlready installed!\n\tUsage: time_fuckery.sh test" exit 0 fi # if da file is not there else phase_one fi fi