# rc.d shell scripts: no extension vs. .sh



## ikevin8me (Jul 17, 2021)

I think I asked this question sometime ago, but I can't find the answer when searching for it. Anyway...

First, I think I know the difference for startup shell scripts located in /etc/rc.d and /usr/local/etc/rc.d. The former is for system scripts while the latter is for user-installed scripts. So, therefore, we should always place scripts in the latter, whether it is for the host or inside a jail. (Let me know me if incorrect...)

Here's my real question: Why do I need to specifically change the name to ".sh" for some scripts to make it run? What's the difference for scripts without filename extensions and those that has to append ".sh" to make it run?


----------



## T-Daemon (Jul 17, 2021)

ikevin8me said:


> Why do I need to specifically change the name to ".sh" for some scripts to make it run?



You don't need to specify a .sh extension to a shell script. The extension of a shell script doesn't determine if it can be run or not. The read and execution permissions of the file owner and/or group member and/or others do. chmod(1)

/etc/rc.d

```
-r-xr-xr-x  DAEMON*
-r-xr-xr-x  FILESYSTEMS*
-r-xr-xr-x  LOGIN*
-r-xr-xr-x  NETWORKING*
-r-xr-xr-x  SERVERS*
-r-xr-xr-x  accounting*
-r-xr-xr-x  addswap*
-r-xr-xr-x  adjkerntz*
```

/usr/local/etc/rc.d

```
-r-xr-xr-x  avahi-daemon*
-r-xr-xr-x  avahi-dnsconfd*
-r-xr-xr-x  bandwidthd*
-rwxr-xr-x  bastille*
-rwxr-xr-x  cups_browsed*
-rwxr-xr-x  cupsd*
```


----------



## mer (Jul 17, 2021)

I think another question qould be:
How are you trying to run it?
If from a Desktop Environment somehow (not a term window or console or regular $SHELL), does it try to associate
a file extension with a "how to run"?

In general, T-Daemon is correct, just need to have execute bit set.  Don't forget you can set it for owner, group, other. 
It's also common to put the correct shebang as the first line to force the use of a specific shell.


----------



## ikevin8me (Jul 17, 2021)

It is actually more confusing. I tried it and it didn't work.

I put the file "nginx" and set the permissions to "555" into /etc/rc.d, rebooted, and it didn't work. Then, I placed the same file into /usr/local/etc/rc.d, rebooted, it didn't work as well. After that, I renamed it to "nginx.sh" and left it in /usr/local/etc/rc.d and rebooted, and it worked.

Further strangeness: if the filename is "nginx.sh" and I execute the command "# service nginx start", it won't work. I have to change it back to without extention "nginx" in order to execute said command.

Conclusion:
- to make it execute when it bootup, it has to be with .sh extension
- to execute it by "# service <name> start", it has to be without .sh extension.

Would appreciate if someone could clarify...


----------



## mer (Jul 17, 2021)

where did this file come from?  Was it part of a port or a package?  If so, the install should put at least a almost runnable sample somewhere.
Can you post the file for us to look at?
At bootup, is there something actually trying to call it with the extension?

The fact that "service" doesn't start it, implies to me that it's not a proper rc init file.


----------



## T-Daemon (Jul 17, 2021)

ikevin8me said:


> I put the file "nginx" and set the permissions to "555" into /etc/rc.d, rebooted, and it didn't work. Then, I placed the same file into /usr/local/etc/rc.d, rebooted, it didn't work as well. After that, I renamed it to "nginx.sh" and left it in /usr/local/etc/rc.d and rebooted, and it worked.


There is this excerpt from rc(8):


```
The following key points apply to old-style scripts in
     /usr/local/etc/rc.d/:

     •   Scripts are only executed if their basename(1) matches the shell
         globbing pattern *.sh, and they are executable.  Any other files or
         directories present within the directory are silently ignored.
```



ikevin8me said:


> Further strangeness: if the filename is "nginx.sh" and I execute the command "# *service nginx start*", it won't work.


That can't work. There is no 'nginx' named file but a 'nginx.sh' named file. Execute `service nginx.sh start`.

I suspect this has nothing to do with permission settings or file extensions but with the 'nginx' script itself. It would be best to have a look at it, please put it in your next post as mer suggested.


----------



## ikevin8me (Jul 17, 2021)

mer said:


> where did this file come from?


That is a long script and the machine is not Internet connected. I'll do this next time. (I'm doing testing on that machine)

In the meantime,


T-Daemon said:


> ```
> The following key points apply to old-style scripts in
> /usr/local/etc/rc.d/:
> 
> ...


the above tells me something and I think they have to be .sh file extension. I wonder what is the difference between *old-style and new-style*. Anything doc to read up on this or any info?


----------



## mer (Jul 17, 2021)

I still stand by 
Where did the script come from?
How is it getting called at boot?


----------



## SirDice (Jul 17, 2021)

An rc(8) needs a couple of mandatory headers or else rcorder(8) won't pick them up. If they're not in the list generated by rcorder(8) they're not executed.


----------



## T-Daemon (Jul 17, 2021)

ikevin8me said:


> ... I think they have to be .sh file extension.


A rc(8) script doesn't require a .sh suffix. It that was the case then all other scripts in /usr/local/etc/rc.d would have it too. Also there is no indication in rc(8) for a .sh suffix requirement, only the quoted note .

It's more likely your 'nginx' rc(8) script is faulty.



ikevin8me said:


> I wonder what is the difference between *old-style and new-style*.


Can't help here. 


ikevin8me said:


> Anything doc to read up on this or any info?


The principal documentation for rc(8) scripts are rc(8), rc.subr(8), rcorder(8) and Practical rc.d scripting in BSD.


----------



## ikevin8me (Jul 17, 2021)

mer said:


> I still stand by
> Where did the script come from?
> How is it getting called at boot?



nginx is web server and here is the script (wasn't written by me, but took it from the web):
It is in /usr/local/etc/rc.d/nginx.sh - must be .sh otherwise it won't execute when booted.

```
#!/bin/sh

# if compiled from sources
# place this file inside /usr/local/etc/rc.d
# point _pidfrefix where nginx holds pid file

. /etc/rc.subr

name="nginx"
rcvar=nginx_enable

start_precmd="nginx_precmd"
restart_precmd="nginx_checkconfig"
reload_precmd="nginx_checkconfig"
configtest_cmd="nginx_checkconfig"
gracefulstop_cmd="nginx_gracefulstop"
upgrade_precmd="nginx_checkconfig"
upgrade_cmd="nginx_upgrade"
command="/usr/local/sbin/nginx"
_pidprefix="/usr/local/nginx/logs"
pidfile="${_pidprefix}/${name}.pid"
_tmpprefix="/var/tmp/nginx"
required_files=/usr/local/nginx/conf/nginx.conf
extra_commands="reload configtest upgrade gracefulstop"

[ -z "$nginx_enable" ]        && nginx_enable="NO"
[ -z "$nginxlimits_enable" ]    && nginxlimits_enable="NO"
[ -z "$nginxlimits_args" ]    && nginxlimits_args="-e -U www"

load_rc_config $name

if [ -n "$2" ]; then
    profile="$2"
    if [ "x${nginx_profiles}" != "x" ]; then
        pidfile="${_pidprefix}/${nginx_pid_prefix}${profile}.pid"
        eval nginx_configfile="\${nginx_${profile}_configfile:-}"
        if [ "x${nginx_configfile}" = "x" ]; then
            echo "You must define a configuration file (nginx_${profile}_configfile)"
            exit 1
        fi
        required_files="${nginx_configfile}"
        eval nginx_enable="\${nginx_${profile}_enable:-${nginx_enable}}"
        eval nginx_flags="\${nginx_${profile}_flags:-${nginx_flags}}"
        eval nginxlimits_enable="\${nginxlimits_${profile}_enable:-${nginxlimits_enable}}"
        eval nginxlimits_args="\${nginxlimits_${profile}_args:-${nginxlimits_args}}"
        nginx_flags="-c ${nginx_configfile} -g \"pid ${pidfile};\" ${nginx_flags}"
    else
        echo "$0: extra argument ignored"
    fi
else
    if [ "x${nginx_profiles}" != "x" -a "x$1" != "x" ]; then
        for profile in ${nginx_profiles}; do
            echo "===> nginx profile: ${profile}"
            /usr/local/etc/rc.d/nginx $1 ${profile}
            retcode="$?"
            if [ "0${retcode}" -ne 0 ]; then
                failed="${profile} (${retcode}) ${failed:-}"
            else
                success="${profile} ${success:-}"
            fi
        done
        exit 0
    fi
fi

# tmpfs(5)
nginx_checktmpdir()
{
    if [ ! -d ${_tmpprefix} ] ; then
        install -d -o www -g www -m 755 ${_tmpprefix}
    fi
}

nginx_checkconfig()
{
    nginx_checktmpdir

    echo "Performing sanity check on nginx configuration:"
    eval ${command} ${nginx_flags} -t
}

nginx_gracefulstop()
{
    echo "Performing a graceful stop:"
    sig_stop="QUIT"
    run_rc_command ${rc_prefix}stop $rc_extra_args || return 1
}

nginx_upgrade()
{
    echo "Upgrading nginx binary:"

    reload_precmd=""
    sig_reload="USR2"
    run_rc_command ${rc_prefix}reload $rc_extra_args || return 1

    sleep 1

    echo "Stopping old binary:"

    sig_reload="QUIT"
    pidfile="$pidfile.oldbin"
    run_rc_command ${rc_prefix}reload $rc_extra_args || return 1
}

nginx_precmd()
{
    nginx_checkconfig

    if checkyesno nginxlimits_enable
    then
        eval `/usr/bin/limits ${nginxlimits_args}` 2>/dev/null
    else
        return 0
    fi
}

run_rc_command "$1"
```

It is called by placing `nginx_enable="YES"` in /etc/rc.conf.


----------



## ikevin8me (Jul 17, 2021)

Another of my script which I wrote myself:


```
#!/bin/sh

. /etc/rc.subr

name=rustapps
rcvar=rustapps_enable

start_cmd="${name}_start"
stop_cmd=":"

load_rc_config $name
: ${rustapps_enable:=no}
: ${rustapps_msg="Nothing started."}

rustapps_start()
{
    sleep 10
    rm /var/log/reader.log
    rm /var/log/processor.log
    rm /var/log/generator.log
    sleep 5
    /usr/local/rustapps/everi.news_server/target/release/reader > /var/log/reader.log &
    sleep 5
    /usr/local/rustapps/everi.news_server/target/release/processor > /var/log/processor.log &
    sleep 5
    /usr/local/rustapps/everi.news_server/target/release/generator > /var/log/generator.log &
}

run_rc_command "$1"
```

It is called by placing `rustapps_enable="YES"` in /etc/rc.conf.


----------



## SirDice (Jul 17, 2021)

ikevin8me said:


> nginx is web server and here is the script (wasn't written by me, but took it from the web):


If you install www/nginx it already places a proper /usr/local/etc/rc.d/nginx script. There is no reason to replace it with something else.


----------



## ikevin8me (Jul 17, 2021)

SirDice said:


> If you install www/nginx it already places a proper /usr/local/etc/rc.d/nginx script. There is no reason to replace it with something else.


Yes, that file is the same file if installed by "pkg install nginx". However, that won't work for me because I had to build some custom modules. So, I had to manually download the source code for nginx and pcre, build it, and then just use that "nginx" script file and set the /usr/local/etc/rc.d/ to run it.


----------



## SirDice (Jul 17, 2021)

ikevin8me said:


> However, that won't work for me because I had to build some custom modules.


The port has a bunch of modules, some of them are not enabled by default so the package doesn't have them. Build it from ports, enable the modules you need and work with that. 



ikevin8me said:


> So, I had to manually download the source code for nginx and pcre, build it


Don't do that. Everything you install that way isn't registered in the package database. So you won't be able to keep track of it.


----------



## ikevin8me (Jul 17, 2021)

SirDice said:


> Don't do that. Everything you install that way isn't registered in the package database. So you won't be able to keep track of it.


That's a very good point, thanks!


----------



## ikevin8me (Jul 17, 2021)

I posted two scripts above. Let's focus on the rustapps.sh script since I wrote that myself. Can anyone point out why I have to the .sh file extension so that it would run?


----------



## SirDice (Jul 17, 2021)

ikevin8me said:


> Can anyone point out why I have to the .sh file extension so that it would run?


It's missing the headers required for rcorder(8).


----------



## ikevin8me (Jul 18, 2021)

SirDice said:


> It's missing the headers required for rcorder(8).


Yup. It worked. All needed is just 2 lines:


> # PROVIDE something
> # REQUIRE something


(# BEFORE and # KEYWORD) are not required.

Just a note: there is nowhere this is mentioned in Practical rc.d scripting in BSD.


----------

