Bug 248865

Summary: rc scripts in /usr/local/etc/rc.d/ may be ignored
Product: Base System Reporter: unitrunker <unitrunker>
Component: confAssignee: Cy Schubert <cy>
Status: Closed Works As Intended    
Severity: Affects Many People CC: cy, jamie, unitrunker
Priority: ---    
Version: Unspecified   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
PROVIDE must be present none

Description unitrunker 2020-08-24 04:23:09 UTC
rc.subr uses grep to look for rc scripts with '^# PROVIDE:'

See "find_local_scripts_new" and "find_local_scripts_old".

RC scripts in /usr/local/etc/rc.d/* without the "# PROVIDE:" clause are ignored by /etc/rc.

I think this is a mistake. Per the docs, the "PROVIDE" clause is optional. This is certainly the case for rc scripts in base (eg. /etc/rc.d/).

To fix this, either ...

1. Update the docs (see bug https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=121440).

Note that an empty "# PROVIDE:" clause will work. Only scripts under /usr/local/etc/rc.d/ are affected by this quirk.

... or ...

2. Update rc.subr to detect scripts that contain ANY of the well-known rc script clauses: PROVIDE, REQUIRE, BEFORE, or KEYWORD (or some other heuristic to detect a valid RC script).

In any case, the documentation should be updated to say that - because /usr may not yet be mounted when /etc/rc first runs, scripts under /usr/local are not visible. Such scripts are run in a second pass made by /etc/rc (after the root file system has been made read-write). This has the same effect as adding ...

# REQUIRE: FILESYSTEMS

... to any RC script under /usr/local/etc/rc.d/

The reason is /etc/rc only runs scripts up to and including FILESYSTEMS in the first pass.
Comment 1 unitrunker 2020-08-24 04:36:20 UTC
To reproduce, paste the following into a file named /usr/local/etc/rc.d/placebo

------------>8 snip 8<---------
#!/bin/sh

. /etc/rc.subr

name=placebo
rcvar=placebo_enable
start_cmd="${name}_start"
stop_cmd="${name}_stop"

placebo_start()
{
  sleep 5
}

placebo_stop()
{
  sleep 5
}

load_rc_config $name
run_rc_command "$1"
------------>8 snip 8<---------

Enable the service in /etc/rc.conf ...

# sysrc placebo="YES"

Verify the service runs ...

# service placebo start
# service placebo stop

... now reboot.

# reboot

The above service is NOT run by /etc/rc because it does not contain a '# PROVIDE: ' clause.
Comment 2 unitrunker 2020-08-24 15:55:05 UTC
Typo fix:
# sysrc placebo_enable="YES"
Comment 3 Cy Schubert freebsd_committer freebsd_triage 2021-02-24 14:37:36 UTC
The rc(8) man page says:

     Each script should contain rcorder(8) keywords, especially an appropriate
     "PROVIDE" entry, and if necessary "REQUIRE" and "BEFORE" keywords.

A scan of rc scripts shows that many of the ports I have installed don't have PROVIDE.

slippy$ grep -c PROVIDE /etc/rc.d/* | grep :0               
slippy$ grep -c PROVIDE /usr/local/etc/rc.d/* | grep :0
/usr/local/etc/rc.d/cvsupd.sh:0
/usr/local/etc/rc.d/fwlogwatch.sh.sample:0
/usr/local/etc/rc.d/racoon2:0
/usr/local/etc/rc.d/ssyncd.init:0
/usr/local/etc/rc.d/tdetect.sh:0
/usr/local/etc/rc.d/vboxtoolinit:0
/usr/local/etc/rc.d/zzz-jail.sh:0
slippy$ 

Note that racoon2 is provided by the upstream software, written by a NetBSD committer. RCNG was a NetBSD idea.

And the scripts with no keywords are either invalid or 

slippy$ egrep -c 'PROVIDE|REQUIRE|BEFORE|KEYWORD' /usr/local/etc/rc.d/* | grep :0
/usr/local/etc/rc.d/cvsupd.sh:0
/usr/local/etc/rc.d/fwlogwatch.sh.sample:0
/usr/local/etc/rc.d/ssyncd.init:0
/usr/local/etc/rc.d/tdetect.sh:0
/usr/local/etc/rc.d/vboxtoolinit:0
/usr/local/etc/rc.d/zzz-jail.sh:0
slippy$ 

Much of this is not provided by the port but the upstream tarball. Now it becomes an issue for the greater community, not just you or me, whether we relax the rules and do no checking whatsoever or enforce some arbitrary rule that each rc script must have at least one keyword.

I think the best path forward is to start a discussion on freebsd-arch because we will have the largest audience there, and point to a phabricator revision with a proposed solution. I'm of the opinion to print out a warning using logger(1) but run or not run the script based on some arbitrary rc.conf setting. This avoids a POLA violation since those scripts were never executed in the first place. But to execute them is also a POLA violation, Both defaults would be a POLA violation but which would be worse?
Comment 4 Cy Schubert freebsd_committer freebsd_triage 2021-02-24 15:30:00 UTC
Having stepped away from this to reconsider, while in the shower but before coffee, making PROVIDES mandatory is the answer. But why?

A scan through the scripts in /usr/local/etc/rc.d without any keywords, some don't have start or stop functions, they implicitly start. One, a virtualbox script is an old-style pre-systemd Red Hat startup script. Executing those would be problematic.

The only other script without a PROVIDES is racoon2 and it has a KEYWORD: nostart (which causes it not to start at boot anyway) because as per the comments in the script it's not to be autostarted but run by hand.

I think we have our answer. I'll update the documentation to say that PROVIDES: is required.

Thoughts?
Comment 5 unitrunker 2021-02-24 15:53:58 UTC
Thanks Cy. This works for me.
Comment 6 Cy Schubert freebsd_committer freebsd_triage 2021-03-11 03:44:54 UTC
Created attachment 223178 [details]
PROVIDE must be present

PROVIDE must be present.
Comment 7 Cy Schubert freebsd_committer freebsd_triage 2021-10-06 14:31:36 UTC
In doc documentation/content/en/books/porters-handbook/special/_index.adoc, it says:

The following key word must be included in all startup scripts as it is required
 by man:rc.subr[8] to "enable" the startup script:
 
* `PROVIDE`: Specifies the services this file provides.

This is already documented.