# Best Practice Advice - Install script and config variables



## Allan (Mar 21, 2020)

I'm attempting to script (bash) the post installation settings of FreeBSD.

I'm trying to programmatically write the settings to  /etc/rc.conf, /boot/loader.conf, /etc/sysctl.conf, /etc/devfs.conf, etc. just to name a few.  I'm even trying to programmatically create .profile and other skeleton files.  Currently, I'm storing my values to be written in arrays, but as I build out these arrays, I'm finding that I have (right now) 12 arrays with a couple having at least 25 elements all in the bash script file.

Is there a better way to do this?

Is there a way to store settings for an install type that can be parsed as needed that's more efficient than arrays in a script?  Any best practice advice anyone has on this topic is much appreciated.


----------



## unitrunker (Mar 21, 2020)

Don't use bash for your post-install script. bash isn't part of base. Use sh(1). It's not that far from bash anyways and is far more portable.

If you must use bash - be sure to use the correct shebang.

```
#!/bin/env bash
```
and not

```
#!/bin/bash
```
Thinking out loud - could some of the skeleton files be done as "here is" documents?





__





						UNIX Shell Quotes - a simple tutorial
					





					www.grymoire.com


----------



## unitrunker (Mar 22, 2020)

I forgot to add ...

sysrc(8) might be an easier way to edit the system configs from a script.


----------



## Allan (Mar 24, 2020)

unitrunker said:


> Don't use bash for your post-install script. bash isn't part of base. Use sh(1). It's not that far from bash anyways and is far more portable.
> 
> If you must use bash - be sure to use the correct shebang.



That was part of my conundrum.  I'm using bash because I needed to use arrays which isn't found in sh.  I have my script broken into two parts:  a pre-install script that runs entirely in sh.  It checks for the existance of bash and if it doesn't exist, it installs it.  It writes a temp file that after reboot if that file exists, it continues with the second script in bash.




unitrunker said:


> sysrc(8) might be an easier way to edit the system configs from a script.



I'm going to look into this tonight!


----------



## ralphbsz (Mar 24, 2020)

I think you are using bash way out of its comfort zone. Shells are designed primarily for interactive use, and their scripts intended for "short" tasks. If you are doing something complex (for example, which requires arrays), you should probably use different tools.

Note I'm not saying what other tool you should use. Personally, I would go with Python, or awk, or a preprocessing language like m4, but to each their own.


----------



## tommiie (Mar 24, 2020)

I agree that if you need to install a different tool (in your case bash) you are better off installing e.g. Python instead which gives you the added bonus of being able to use Ansible, just to give an example.

I'm curious about awk(1) or m4(1) as I would not have considered awk(1) suitable for this task and I've never even heard of m4(1).


----------



## unitrunker (Mar 24, 2020)

m4 is what made sendmail so notorious.


----------



## Allan (Mar 24, 2020)

My bash script is actually fairly small.  There are simple functions that edits config files, installs fonts, installs packages, etc.  There's really not much too it _logically._ A majority now is array declarations/assignments because there are just so many config items to store.  

However, I want to get this back on track...I'm not looking to implement a new language like Python or Perl because I'll be right back in the same boat:  *what is the best practice for handling config values?  *Because, I'm facing the exact same dilemma of them being in separate files or array values so switching to another language doesn't solve my problem.


----------



## tommiie (Mar 24, 2020)

Could you share a code snippet so we can have a better idea of what you are currently doing?


----------



## unitrunker (Mar 24, 2020)

It sounds like your script is a whole application to its own.


----------



## Allan (Mar 24, 2020)

Here's a small piece of code that writes values to the different files:


```
printArrValues() {
# Parses through property array(s) and writes config files
# takes two values:
#  array of properties
#  filename to write
    declare -a argArray=("${!1}")
    echo $2
  for i in "${argArray[@]}"
do
    local str=$( echo ${i} | cut -d '=' -f1 )
    if ! grep ${str} $_file
    then
      if [ ${str:0:1} = "#" ]   # If it's a comment add a blank line
      then
          echo >> $_file
      fi
      echo  $i >> $_file
    else
        #if the line already exists, rewite it
        # 1) check if is a coment, then ignore
        # 2) rewrite the line as a comment
        # 3) add new line
        echo 'nothing here.'
    fi
done
}

setValues() {
# Function that parses through all of the values that needs to be set
# takes one value:
#  - Platform (svr=server, dsk=desktop)

platform=${1}


# Assign proper arrays depending on platform
case ${platform} in

  dsk) sysctl_props=("${sysctl_props_dsk[@]}")
       loader_props=("${loader_props_dsk[@]}")
       rc_props=("${rc_props_dsk[@]}")
       devfs_props=("${devfs_props_dsk[@]}")
       ;;
  svr)
       sysctl_props=("${sysctl_props_svr[@]}")
       loader_props=("${loader_props_svr[@]}")
       rc_props=("${rc_props_svr[@]}")
       devfs_props=("${devfs_props_svr[@]}")
       ;;
    *) echo 'No platform specified.  Making no changes.'
       ;;
esac


fnames=("/etc/sysctl.conf" "/boot/loader.conf" "/etc/rc.conf" "/etc/devfs.conf")

for file in "${fnames[@]}"
do
  printArrValues props_all[@] ${file}
done

}
```

And, here is just a sampling of how I use arrays to hold the config values:


```
# /etc/rc.conf Properties
# rc_props_all+=( '' );

rc_props_all+=( '# Synchronize system time' );
rc_props_all+=( 'ntpd_enable="YES"' );
rc_props_all+=( '# Let ntpd make time jumps larger than 1000sec' );
rc_props_all+=( 'ntpd_flags="-g"' );
rc_props_all+=( '# Remote logins' );
rc_props_all+=( 'sshd_enable="YES"' );
rc_props_all+=( '# Auto Update MOTD' );
rc_props_all+=( 'update_motd="YES"');
```

*Please keep in mind that this is a work in progress so there's some unfinished code.*  I'm not having any issues with the code, it's the logic of whether to use arrays in this manner (which are getting huge) or find a different way to attack this.


----------



## unitrunker (Mar 24, 2020)

You could have one file or function that uses sysrc to set the "dsk" profile, another for "srv" profile and a menu to choose between the two.


----------



## gpw928 (Mar 24, 2020)

tommiie said:


> I've never even heard of m4(1).


It's a derivative of Strachey's General Purpose Macrogenerator.


----------



## gpw928 (Mar 24, 2020)

tommiie said:


> ...being able to use Ansible, just to give an example.


Good point.  I know this was posed as a programming problem, but there's a whole raft of configuration management tools like puppet and chef which you are re-inventing.


----------



## tommiie (Mar 24, 2020)

I would look at Ansible and jinja2 template files. I'm not sure it will be able to solve everything you're trying to do, but perhaps most of it and you will only need a few small scripts or better yet, only a few commands to be sent with Ansible (e.g. Ansible has a module that can restart services etc).


----------



## Allan (Mar 24, 2020)

gpw928 said:


> there's a whole raft of configuration management tools like puppet and chef which you are re-inventing.





tommiie said:


> I would look at Ansible and jinja2 template files.




I do appreciate the product recommendations - they're now on the list to evaluate.  However, and I'm kicking myself for being remiss and not stating this earlier:

*I'm taking this approach to better learn FreeBSD and to sharpen my scripting skills.   *

I have no doubt that the recommend products would speed me through this, but this is more of a personal self teaching project.


----------



## Allan (Mar 24, 2020)

pyret said:


> yaml_parser.md



I'm not sure how this applies.  Perhaps you could expand?


----------



## tommiie (Jun 17, 2020)

Hey Allan, I was curious, did you make any progress with this project?


----------



## Mjölnir (Jun 17, 2020)

I have a _conversation_ on that very same topic and I'd like you to join.  Maybe I should start a new thread on that? I see the need and that 1000's of people are doing very similar tasks after/during each installation.  This should be automated, and colaborated.  Let's come together and join our forces!
It is here: FreeBSD CE (Community Edition), or you go into my user profile.


----------



## Mjölnir (Jun 17, 2020)

and do not use bash(1), instead use a portable sh(1) syntax.  Added benefit: it can be used w/o any ports to be installed. This is another task you script might want to do, right?


----------

