#!/bin/bash # install.sh # OpenDRS Online Discrepancy Reporting System # Copyright (C) 2026 Rod Wright # SPDX-License-Identifier: GPL-2.0 APP_NAME="OpenDRS" DEFAULT_DB_NAME="opendrs" APP_VERSION="1.4.6" DOC_ROOT="/var/www" INSTALL_LOC="opendrs" APACHE_CONF_DIR="/etc/apache2/conf-available" BACKUP_DIR="opendrs-previous-installation" LANDING_PAGE="writeups.php" CONFIG_TABLE="config" CONFIG_NAME_COLUMN="name" CONFIG_VALUE_COLUMN="value" CONFIG_DEFAULT_COLUMN="defaultvalue" function privilege_check() { # test for superuser rights if [[ $EUID -ne 0 ]]; then echo "This script must be run with superuser privileges. Try sudo $0" exit 1 fi } function get_new_password() { # Stores new password in the variable $newpassword pwgood=false while ! $pwgood do read -p "New password: " -s -r newpassword echo "" read -p "Re-type new password: " -s -r rnewpw echo "" if [ "$newpassword" = "" -o "$rnewpw" = "" ] then echo "Password cannot be blank. Please try again." echo "" elif [ "$newpassword" != "$rnewpw" ] then echo "Passwords do not match. Please try again." echo "" else pwgood=true fi done } function install_required_packages() { # Positional parameters supplied to this function should be quoted # apt-get installable package names. # Note: Each package supplied to the for loop below can either be a # single package name or a list of alternatives separated by the word "or". # If supplying a list, the last one in the list will be the one that # gets installed. for prereq in "$@" do echo "Checking for $prereq installation..." gpattern="" for pkg_option in $(echo $prereq) do if [ "$pkg_option" != "or" ] then gpattern+=" -e $pkg_option" preferred_pkg=$pkg_option fi done if dpkg -l|grep $gpattern >/dev/null 2>&1 then echo "$prereq is installed. Continuing." else echo "$APP_NAME requires $prereq, but it doesn't seem to be installed. " echo -n "Install $preferred_pkg now? [Y/n]: " read reqinstall if [ "$reqinstall" = "N" -o "$reqinstall" = "n" ] then echo "$APP_NAME requires $prereq, but you have elected not to install it." echo "Installation cannot continue." abort_exit else echo "" echo "Proceeding with $preferred_pkg installation" echo "" sleep 3 apt-get install -y $preferred_pkg echo "" echo "Finished with $preferred_pkg installation" echo "" sleep 3 fi fi done } function clean_exit() { # Re-enable unattended-upgrades if $restart_uu; then systemctl start unattended-upgrades; fi exit 0 } function abort_exit() { # Re-enable unattended-upgrades if $restart_uu; then systemctl start unattended-upgrades; fi exit 1 } function spinner() { local pid="$1" local delay="0.1" local spinstr='|/-\\' local i=0 while ps -p "$pid" > /dev/null; do i=$(( (i+1) % 4 )) printf "\r[%c]" "${spinstr:$i:1}" sleep "$delay" done printf "\r \r" # Clear the spinner line } # test for superuser rights privilege_check echo "" echo "" echo "* * * * * Welcome to $APP_NAME $APP_VERSION Installation * * * * *" echo "" echo "" sleep 3 echo "Preparing for installation. Please wait..." # Prevent unattended-upgrades from interfering restart_uu=false while dpkg -l|grep unattended-upgrades >/dev/null 2>&1 do systemctl stop unattended-upgrades sleep 5 restart_uu=true done apt-get update -qq # Check for prerequisites and prompt to install echo "Checking for required packages..." echo "" install_required_packages "apache2" "php" "mysql-server or mariadb-server" "php-mysql" "uuid-runtime" echo "" echo "Finished required package installation." echo "" # Determine the correct Apache2 user and group APACHE_USER=$(grep APACHE_RUN_USER /etc/apache2/envvars | cut -d= -f2) APACHE_GROUP=$(grep APACHE_RUN_GROUP /etc/apache2/envvars | cut -d= -f2) httpd_user_group="$APACHE_USER:$APACHE_GROUP" sleep 3 # prompt for install location echo "Where would you like to install this version of $APP_NAME? This should" echo "be somewhere the webserver can find it. If you don't know, refer to the" echo "webserver's documentation and check the server's configuration files." echo "Note that this is where the directory containing $APP_NAME's files will be" echo "created." echo -n "Enter the webserver's install location [$DOC_ROOT]:" read doc_root_in echo "" echo -n "Enter name of $APP_NAME installation directory [$INSTALL_LOC] :" read install_loc_in echo "" if [ "$doc_root_in" = "" ] then doc_root_in=$DOC_ROOT fi if [ "$install_loc_in" = "" ] then install_loc_in=$INSTALL_LOC fi install_path="$doc_root_in/$install_loc_in" if [ -d "$install_path" ] then echo "The installation path you chose already exists." # Install path exists. if [ -e "$install_path/db.php" ] then # A db.php file was found in the install path if grep -q -e "$APP_NAME" $install_path/db.php then # the db.php file is part of a previous installation echo "Would you like to upgrade an existing installation or cancel " echo "and restart the install using a new installation location." echo -n "[U]pgrade or [C]ancel? [C] :" read upgrade_choice if [ "$upgrade_choice" = "U" -o "$upgrade_choice" = "u" ] # Upgrade chosen then # proceed with upgrade mkdir -p backups operation="upgraded" curr_dbname=$(grep dbname $install_path/db.php | head -1 | cut -d\" -f2) # create mysql option file with data for this installation mysql_opt_file=$(mktemp --tmpdir=/run/shm/) echo "[client]" > $mysql_opt_file echo "user = $(grep username $install_path/db.php | head -1 | cut -d\" -f2)" >> $mysql_opt_file echo "password = $(grep dbpass $install_path/db.php | head -1 | cut -d\" -f2)" >> $mysql_opt_file echo "" >> $mysql_opt_file echo "[mysql]" > $mysql_opt_file echo "database = $curr_dbname" >> $mysql_opt_file echo "batch" >> $mysql_opt_file echo "disable-column-names" >> $mysql_opt_file # back up existing database echo "Backing up the current database to the package directory." mysqldump --defaults-extra-file=$mysql_opt_file --no-tablespaces $curr_dbname > backups/$curr_dbname-$(date +%Y-%m-%d_%H:%M:%S)-backup.sql # back up existing installation echo "Backing up current installation to the package directory." cp -R $install_path backups/$install_loc_in-`date +%Y-%m-%d_%H:%M:%S`-backup # delete all existing installation files except db.php find $install_path/ -mindepth 1 -not -name 'db.php' -delete echo "Performing database updates. This may take a while..." # apply database updates from sql file (mysql --defaults-extra-file=$mysql_opt_file --force < database-update.sql >/dev/null 2>&1) & task_pid=$! spinner $task_pid # apply database updates via script (bash ./database-update.sh $mysql_opt_file) & task_pid=$! spinner $task_pid echo "... finished with database updates." rm -f $mysql_opt_file # apply updates to other files bash ./files-update.sh $install_path # copy distribution to install location echo "Installing distribution . . ." cp -R distfiles/* $install_path # set symlink for jquery-ui if [ ! -L "$install_path/jquery-ui" ] then ln -s $install_path/jquery-ui* $install_path/jquery-ui fi # set symlink for index.php if [ ! -L "$install_path/index.php" ] then ln -s $install_path/$LANDING_PAGE $install_path/index.php fi # add the local timezone to .htaccess local_tz=$(timedatectl show -p Timezone|cut -d= -f2) echo "Your local timezone is $local_tz" echo "php_value date.timezone \"$local_tz\"">$install_path/.htaccess # set ownership echo "" echo "Setting file ownership . . ." chown -R $httpd_user_group $install_path else echo "Cancelling installation" abort_exit fi else # This was a mistake. Exit now to avoid clobbering another app. echo "The installation directory you chose exists, but no previous installation" echo "of $APP_NAME was found. Please investigate the situation. Aborting now." abort_exit fi else # This was a mistake. Exit now to avoid clobbering another app. echo "The installation directory you chose exists, but no previous installation" echo "of $APP_NAME was found." echo "" echo " CAUTION: If there is anything else in this directory, it will be deleted!" echo "" echo "Would you like to use this location for a fresh installation or quit and" echo "investigate further? It's probably safest to quit and investigate." proceed="" while [[ $proceed != "P" && $proceed != "p" && $proceed != "Q" && $proceed != "q" ]] do read proceed -p "[P]roceed with new install or [Q]uit? : " done if [[ $proceed == "Q" || $proceed == "q" ]] then abort_exit fi fi else # This is a fresh install operation="installed" echo "" echo "What would you like to call this installation of $APP_NAME? If you accept" echo "the default, it will be called $APP_NAME. If you will be running multiple" echo "instances of $APP_NAME on this server, you should choose a distinctive name." echo "This can be changed later in the application itself." echo -n "Installation name [$APP_NAME]: " read new_inst_name if [ "$new_inst_name" = "" ] then new_inst_name="$APP_NAME" fi echo "" # Create initial database db_create_fail=true while $db_create_fail do echo "What would you like to call the database for this installation of $APP_NAME?" echo "If you accept the default, it will be called $DEFAULT_DB_NAME. Again, this is fine" echo "if you will only be running this one instance, but if you will be running" echo "multiple instances of $APP_NAME on this server, you should choose a " echo "distinctive name." echo -n "database name [$DEFAULT_DB_NAME]: " read new_db_name if [ "$new_db_name" = "" ] then new_db_name=$DEFAULT_DB_NAME fi echo "" if mysql -e "create database $new_db_name" then db_create_fail=false else echo "An error was encountered when trying to create the database." echo "This probably means the database already exists." echo -n "Try again with a different database name? [Y/N]: " read dbcreatetry if [ "$dbcreatetry" != "Y" -o "$dbcreatetry" != "y" ] then abort_exit fi fi done # Create user and give rights to database db_user="$new_db_name`date +%Y%m%d%H%M%S`" db_pass=`uuidgen` mysql -e "create user if not exists '$db_user'@'localhost' identified by '$db_pass'" mysql -e "grant all on $new_db_name.* to '$db_user'@'localhost'" mysql -e "flush privileges" # Populate initial database mysql $new_db_name < database-initial.sql # Set the installation name export MYSQL_PWD="$db_pass" mysql -u"$db_user" $new_db_name -e "update $CONFIG_TABLE set $CONFIG_VALUE_COLUMN=\"$new_inst_name\" where $CONFIG_NAME_COLUMN=\"app_name\"" if [ "$CONFIG_DEFAULT_COLUMN" != "" ] then mysql -u"$db_user" $new_db_name -e "update $CONFIG_TABLE set $CONFIG_DEFAULT_COLUMN=\"$new_inst_name\" where $CONFIG_NAME_COLUMN=\"app_name\"" fi # Create install path echo "Creating installation directory . . ." mkdir $install_path # Create db.php if it doesn't exist if [ ! -f "$install_path/db.php" ] then cp db.php.template $install_path/db.php sed -i "s/DBNAME/$new_db_name/g" $install_path/db.php sed -i "s/DBUSER/$db_user/g" $install_path/db.php sed -i "s/DBPASS/$db_pass/g" $install_path/db.php sed -i "s/APPNAME/$APP_NAME/g" $install_path/db.php fi # copy distribution to install location echo "Installing distribution . . ." cp -R distfiles/* $install_path if [ ! -L "$install_path/jquery-ui" ] then ln -s $install_path/jquery-ui* $install_path/jquery-ui fi if [ ! -L "$install_path/index.php" ] then ln -s $install_path/$LANDING_PAGE $install_path/index.php fi # add the local timezone to .htaccess local_tz=$(timedatectl show -p Timezone|cut -d= -f2) echo "Your local timezone is $local_tz" echo "php_value date.timezone \"$local_tz\"">$install_path/.htaccess # set ownership echo "" echo "Setting file ownership . . ." chown -R $httpd_user_group $install_path fi echo "" # tell user to launch web browser to continue echo "" echo "" echo "" echo "$APP_NAME has been $operation." base_url=$install_loc_in if [ "$operation" = "installed" ] then echo "# $APP_NAME default Apache configuration" > $APACHE_CONF_DIR/$base_url.conf echo "" >> $APACHE_CONF_DIR/$base_url.conf echo "Alias /$base_url $doc_root_in/$base_url" >> $APACHE_CONF_DIR/$base_url.conf echo "" >> $APACHE_CONF_DIR/$base_url.conf echo "" >> $APACHE_CONF_DIR/$base_url.conf echo " AllowOverride Options" >> $APACHE_CONF_DIR/$base_url.conf echo " Options FollowSymLinks" >> $APACHE_CONF_DIR/$base_url.conf echo " DirectoryIndex index.php" >> $APACHE_CONF_DIR/$base_url.conf echo "" >> $APACHE_CONF_DIR/$base_url.conf echo -n "The apache2 $base_url configuration must be enabled. Would you like to do that now? [Y/n] :" read enconf if [ "$enconf" = "" -o "$enconf" = "Y" -o "$enconf" = "y" ] then a2enconf $base_url.conf >/dev/null service apache2 reload echo "You can now point a web browser to $base_url on your web server " echo "to set up and configure $APP_NAME." echo "" echo "IMPORTANT: The default login credentials for the initial admin user are:" echo "" echo "login: drsadmin" echo "password: OpenDRS-1" echo "" echo "Remember these credentials. Otherwise, you will not be able to log in and" echo "configure your new installation." echo "It is highly recommended that you change the initial password to something" echo "secure after logging in for the first time." else echo "You will need to manually enable the configuration by executing:" echo " a2enconf $base_url.conf" echo " systemctl reload apache2" echo "as a superuser before it can be accessed." fi else echo "You can now point a web browser to http://$HOSTNAME/$base_url " echo "to use your upgraded $APP_NAME." fi clean_exit