#!/bin/bash
# Copyright 2010-2020 Chad Lemmen http://www.lemmen.com

# Make sure user is root so we can create a user and set file permissions
if [ `id -u` != "0" ]; then
  echo "This script must be run as root"
  exit
fi

# which does not give absolute path on Debian when run in pwd
#ssdir=$(dirname `which $0`)
ssdir=$(dirname `realpath $0`)
vers=7.26


spin()
{
  printf "Installing Informix... This may take a while "
  local pid=$1
  local cycle='|/-\'
  local substr=1

  while [ "$(ps -ef | awk '{print $2}' | grep $pid)" ]; do
    local prtstr=`echo "$cycle" | cut -c$substr`
    echo -ne "$prtstr" "\b\b"
    sleep .5
    substr=$(($substr+1))
    if [ $substr -eq 4 ]; then
      substr=1
    fi
  done

  echo -e "\r"
}

getstate() {
  onstat -  >/dev/null 2>&1
  engine_state=$?
}

create_user()
{
# Create user stansoft
if ! id stansoft > /dev/null 2>&1; then
  echo
  echo "Creating user stansoft, this is the database administrator account."
  # useradd will fail if -U/--user-group is specified and the group already
  # exists, so add the group first.
  groupadd -f stansoft > /dev/null 2>&1
  useradd -g stansoft -m -s /bin/bash stansoft
  passwd stansoft
fi

touch "$ssdir"/etc/postgres.local
touch "$ssdir"/etc/stansoft.local
# Set permissions, for rpm installs the spec file will handle this
chmod 775 "$ssdir"
chown -R stansoft:stansoft "$ssdir"
}


setport() {
  # Assign and add port to /etc/services
  portnum=$1
  servicename=$2
  maxport=65535

  if ! grep -q "$servicename" /etc/services; then
    while [ $portnum -le $maxport ]; do
      # Check if port exists in services and not bound
      if grep -q $portnum /etc/services || lsof -i:"$portnum" >/dev/null; then
        portnum=$(($portnum+1))
        continue
      else
        echo -e "$servicename\t$portnum/tcp" >> /etc/services
        break
      fi
    done
  else # use port already set in services
    portnum=$(grep ^$servicename /etc/services | grep -o '[0-9]*')
  fi

  if ! grep -q "$servicename" /etc/services; then
    echo "Could not find open tcp port... exiting"
    exit 1
  fi
  # Add the port to SELinux policy
  semanage port -a -t postgresql_port_t "$portnum" -p tcp 2>/dev/null
}


install_informix()
{
echo
read -p "Enter the path to the Informix installation media: " ifxmedia

if ! [ -f "$ifxmedia"/ids_install ]; then
  echo "Informix installation media not found."
  exit
fi

# Create user informix
if ! id informix > /dev/null 2>&1; then
  echo
  echo "Creating user informix, this is the database administrator account."
  useradd -s /bin/bash -N -m informix
  passwd informix

  # Add group
  groupadd -f informix
  # Set informix to group informix
  usermod informix -g informix > /dev/null 2>&1
fi

# Prompt for INFORMIXDIR, ids_install will install to this location.
echo
defaultpath="/opt/informix"
read -p "Enter installation directory for Informix [$defaultpath]: " ifxpath
ifxpath="${ifxpath:-$defaultpath}"
export INFORMIXDIR="$ifxpath"

if [ -z "$INFORMIXDIR" ]; then
  echo "You must set INFORMIXDIR"
  echo "Example: export INFORMIXDIR=/opt/informix"
  exit
fi


#
# Install Informix
#

# This will install to $INFORMIXDIR
# Can omit -DCHOSEN_FEATURE_LIST to install default features
"$ifxmedia"/ids_install -i silent -DLICENSE_ACCEPTED=TRUE \
-DLEGACY=TRUE &
#-DIDS_SERVER_INSTANCE_BOOLEAN_1=0 \
#-DIDS_DRDA_BOOLEAN_1=0 \
#-DCHOSEN_FEATURE_LIST=IDS,IDS-SVR,IDS-LOAD,IDS-LOAD-ONL,\
#IDS-LOAD-DBL,IDS-LOAD-HPL,IDS-BAR,IDS-BAR-CHK,IDS-BAR-ONBAR,\
#IDS-ADM,IDS-ADM-PERF,IDS-ADM-MON,IDS-ADM-ADT,IDS-ADM-IMPEXP,\
#SDK,SDK-ESQL,GLS,GLS-WEURAM &

pid=$!
spin $pid
# Set the exit status from the ids_install process
wait $pid

# ids_install returns 0 on first successful install and 244 if run again.
if [[ ! -d "$ifxpath" || ($? -ne 0 && $? -ne 244) ]]; then
  echo "An error occurred during installation of Informix, aborting install."
  exit
fi

# LEGACY install doesn't create forms dir
mkdir -p "$INFORMIXDIR"/forms
# In case ksh is not installed. This is run during database initialization. 
sed -i 's%/bin/ksh%/bin/bash%' $INFORMIXDIR/etc/alarmprogram.sh

# Must be run from inside $INFORMIXDIR
cd "$INFORMIXDIR"
echo "Setting INFORMIXDIR permissions..."
"$INFORMIXDIR"/RUNasroot.installserver

ifxserver=ol_informix
instancepath="$INFORMIXDIR/dbspaces/$ifxserver"

# Create database storage spaces
if [ ! -d "$instancepath" ]; then
  mkdir -p "$instancepath"
  touch "$instancepath"/datadbs
  touch "$instancepath"/llogdbs
  touch "$instancepath"/plogdbs
  touch "$instancepath"/rootdbs
  touch "$instancepath"/sbspace
  touch "$instancepath"/tempdbs
  chmod 660 "$instancepath"/*
  chown -R informix:informix "$INFORMIXDIR"/dbspaces
fi

# Create new onconfig for instance
onconfig="$INFORMIXDIR"/etc/onconfig."$ifxserver"
if [ ! -f "$onconfig" ]; then 
  cp "$INFORMIXDIR"/etc/onconfig.std "$onconfig"
  chown informix:informix "$onconfig"
  sed -i "s%^\(ROOTPATH\).*%\1 $instancepath/rootdbs%g" "$onconfig"
  sed -i "s%^\(MSGPATH\).*%\1 $INFORMIXDIR/$ifxserver.log%g" "$onconfig"
  sed -i "s%^\(DBSERVERNAME\).*%\1 $ifxserver%g" "$onconfig"
  # Disable logical logs
  sed -i "s%^\(LTAPEDEV\).*%\1 /dev/null%g" "$onconfig"
  # PDQ functionality is not supported in IDS Innovator-C Edition.
  # The value of MAX_PDQPRIORITY cannot be set to 100. It is reset to 0.
  # To avoid the warning message change the value to 0
  sed -i "s%^\(MAX_PDQPRIORITY\).*%\1 0%g" "$onconfig"
  # Change the value of SP_THRESHOLD from 0 to 5 which will
  # trigger the chunks to expand when there is 5% free space left
  sed -i "s%^\(SP_THRESHOLD\).*%\1 5%g" "$onconfig"
fi

# For Informix use port 9088 if available
setport 9088 "$ifxserver"

# Create sqlhosts file
sqlhosts="$INFORMIXDIR/etc/sqlhosts.$ifxserver"
if [ ! -f "$sqlhosts" ]; then
  #echo "$ifxserver onsoctcp `hostname` $ifxserver" > "$sqlhosts"
  # Using localhost instead so the hostname can be changed, but this
  # means remote connections are not allowed.
  echo "$ifxserver onsoctcp localhost $ifxserver" > "$sqlhosts"
  chown informix:informix "$sqlhosts"
fi

# Create environment variable file
envfile="$INFORMIXDIR/$ifxserver.sh"
if [ ! -f "$envfile" ]; then
  echo "INFORMIXDIR=$INFORMIXDIR"      > "$envfile"
  echo "INFORMIXSERVER=$ifxserver"    >> "$envfile"
  echo "ONCONFIG=onconfig.$ifxserver" >> "$envfile"
  echo "INFORMIXSQLHOSTS=$sqlhosts"   >> "$envfile"
  echo "PATH=\${INFORMIXDIR}/bin:\${INFORMIXDIR}/extend/krakatoa/jre/bin:\${PATH}" >> "$envfile"
  echo "export INFORMIXDIR INFORMIXSERVER ONCONFIG INFORMIXSQLHOSTS PATH" >> "$envfile"
fi

setenv="$envfile"

echo
echo "Installing Stansoft..."

# Create user stansoft
create_user

# Set the Informix environment
if [ -f "$setenv" ]; then
  . "$setenv"
else
  echo "First install the Informix database server then re-run this script"
  exit
fi

# Make sure the database instance does not exist, before initializing.
echo
echo "Checking database..."
getstate
if [ $engine_state == 5 ]; then
  # Database server is up, check if stansoft database exists.
  oncheck -cd -q stansoft:systables > /dev/null 2>&1
  if [ $? == 0 ]; then
    # Database exists
    exit
  fi
else
  # Initialize the database instance
  echo
  echo "Initializing the database instance..."
  oninit -i
fi

#engine_up=$(onstat - | grep "Up" | wc -l)
getstate
if [ $engine_state != 5 ]; then
  echo "Informix engine must be up to execute commands, aborting installation."
  exit
fi

(
# Add spaces to the database instance
onspaces -c -d plogdbs -p "$instancepath"/plogdbs -o 0 -s 50176
onspaces -c -d llogdbs -p "$instancepath"/llogdbs -o 0 -s 61440
onspaces -c -d datadbs -p "$instancepath"/datadbs -o 0 -s 51200
# -S to create as a SBLOBspace
onspaces -c -S sbspace -p "$instancepath"/sbspace -o 0 -s 32768
onspaces -c -d tempdbs -p "$instancepath"/tempdbs -o 0 -s 51200
) > "$ssdir"/dbinstall.log

# After a database initialization, it may take about 20 seconds
# before the sysadmin database is accessible, even after the
# instance is up.  So check before selecting this database.  
dbup=false
timenow=$(date +%s)
timelater=$(($timenow + 4*60)) # Timeout after 4 min.
echo
echo "Checking state of database..."
while [ $(date +%s) -lt $timelater ]; do
  oncheck -cd -q sysadmin:systables  >/dev/null 2>&1
  if [ $? == 0 ]; then
    # Database exists
    dbup=true
    break
  fi
done

if [ $dbup == false ]; then
  echo "There was a problem accessing the sysadmin database, aborting..."
  exit
fi

# Run as user informix so the database owner is informix.
echo
echo "Creating database and database menus..."
su informix << eod >> "$ssdir"/dbinstall.log 2>&1 # created above so append here
. "$setenv"
# So the load files are found if the script wasn't run from the stansoft dir...
cd "$ssdir"/newdb

dbaccess - <<- sql
  -- Mark chunks as extenable.
  -- The chunk numbers can be found by doing onstat -d.
  database sysadmin;
  execute function task("modify chunk extendable", "4"); -- datadbs
  execute function task("modify chunk extendable", "6"); -- tempdbs

  execute function task("storagepool add", "$INFORMIXDIR/tmp",
                        "0", "0", "10000", "2"); -- adds a storage pool

  -- Create new database
  `cat "$ssdir"/newdb/newdb.sql`

  -- Load table data
  `cat "$ssdir"/bin/menu.sql`
  `cat "$ssdir"/newdb/newdbload.sql`

  -- Set version number
  update sys_parm set parm_field = "$vers" where parm_nbr = 1
sql
eod
}

install_postgres()
{
dbname=stansoft

# Create user stansoft
create_user

echo
echo "Installing Stansoft..."

# For Postgres use port 7770 if available
setport 7770 "$dbname"

tmpfile=$(mktemp)
chown stansoft:stansoft "$tmpfile"
cleanup() {
  rm -f "$tmpfile"
}
trap cleanup EXIT


# Start up the database server as user stansoft
# The su '-' option is needed to avoid permission denied errors if
# user stansoft cannot access the PWD.
su - stansoft << EOD
  # Set the PostgreSQL environment, any environment variable explicitly 
  # used inside this here document needs the '$' escaped with a backslash. 
  . "$ssdir"/etc/postgres.sh

  # Make sure $PGDATA is writeable by user stansoft, check the top directory
  # since data has not been created yet. An rpm install will have correct
  # permissions, this check is mainly for other installs.
  if ! [ -w "\${PGDATA%/*}" ]; then
    echo "User stansoft cannot write to \$PGDATA"
    echo "Move the installation directory somewhere writable,"
    echo "such as /opt/stansoft then re-run the install."
    exit 1
  fi

  initdb -D "\$PGDATA"
  # Enable the Postgres Log rotation
  sed -i 's/#logging_collector = off/logging_collector = on/' "\$PGDATA"/postgresql.conf
  # Set socket directory, Fedora has built in /tmp and /var/run/postgresql,
  # which user stansoft cannot write to. The RPM adds environment variable
  # PGHOST=/tmp for connecting, but at startup postgresql.conf is used.
  sed -i "/unix_socket_directories/a unix_socket_directories = '/tmp'" "\$PGDATA"/postgresql.conf
  # Using the -D option so PGDATA is shown by /bin/ps
  postgres -D "\$PGDATA" &

  # Give database time to fully come up or createdb will fail
  sleep 5

  # Make sure the database server is running
  # Because of the subshell created by the su command, the exit status
  # cannot be evaluated here. Instead redirect stderr to a file.
  # pg_isready has no stderr messages, use psql
  psql -l >/dev/null 2>"$tmpfile"

  if [ -s "$tmpfile" ]; then
    echo "The database is not running. To start it..."
    echo "Set the PostgreSQL environment (make sure to include the dot space):"
    echo ". $ssdir/etc/postgres.sh"
    echo "Start the database:"
    echo "$ssdir/etc/rc.postgresql start"
    echo "Then re-run the install."
    exit 1
  fi

  psql -l "$dbname" >/dev/null 2>"$tmpfile"
  if ! [ -s "$tmpfile" ]; then
    echo "Database already exists, exiting..."
    exit 1
  fi
 
  # Create the database as user stansoft so the database owner is stansoft
  echo
  echo -n "Creating database... "
  createdb "$dbname"
EOD

# This is the exit status of the subshell from su
if [ $? -ne 0 ]; then
  exit
fi

# Set the PostgreSQL environment
. "$ssdir"/etc/postgres.sh
dblog="$PGDATA"/dbinstall.log

#
# Load database schema and tables and log the output
#
su - stansoft << EOD > "$dblog" 2>&1

# Set the PostgreSQL environment, any environment variable explicitly
# used inside this here document needs the '$' escaped with a backslash.
. "$ssdir"/etc/postgres.sh

# The copy command needs $SSDIR
export SSDIR="$ssdir"

psql "$dbname" <<- SQL
  -- Create new database
  `cat "$ssdir"/newdb/newdbpg.sql`

  -- Load table data
  `cat "$ssdir"/newdb/menupg.sql`
  `cat "$ssdir"/newdb/newdbcopy.sql`

  -- Set version number
  update sys_parm set parm_field = '$vers' where parm_nbr = 1
SQL

  # Since this is a database function being imported and not
  # individual SQL lines it needs to be done like this.
  psql "$dbname" < "$ssdir"/newdb/matches.sql
EOD

echo "done"
}

echo
db=1
read -p "Enter database to use: 1=PostgreSQL 2=Informix [$db]: " dbsel
dbsel="${dbsel:-$db}"

if [ $dbsel -eq 2 ]; then
  install_informix 
else
  install_postgres 
fi

echo
echo "Installation of Stansoft complete."
echo 
echo "To start the program run $ssdir/stansoft as user stansoft." 

