Although I have already written quite some customized services in the past I feel there's a lack of guides on how to efficiently write the @ execute field in the frontend file of a custom service.
This is apparently due to the fact that this field needs to be written in the s6 format of execline script. This is easy for one liners but how about a service where I want to test for two or more things to be existent in the system and only afterwards fire several commands? What are my choices? What would be best practice?

Requirements
  1. Check for requirements of the service, can include more than only one command
  2. If a requirement is not met then try to satisfy it
  3. Once that is done execute several commands for the service itself
  4. If anything goes wrong echo an error message to the boot log and prevent stalling of the boot process
Especially the last point here is something I have stumbled upon quite frequently in the past and still do. Whenever I write a custom service and fk up the syntax the boot process will stall and prompt for the emergency maintenance mode (CTRL+D to continue). This is very frustrating and destructive, just to play around with a custom service and debug it. Also there's no verbosity involved here as long as I don't create the service frontend file execute field in a way that it would log to some place. I see this as a pretty deep rabbit hole as most users won't search this information and even if they did, the docs on this matter are pretty complex and hard to get your head around.

Approaches
  1. Ignore the requirements and make one service file for each command. Highly ineffective and unnecessarily complex. Creates service clutter.
  2. Check the requirements in one service file and execute anything necessary, make separate services for the commands and make them depend on the first. The developer approach, overly complex and unnecessarily overthought. Creates flexibility and service clutter.
  3. Check the requirements and fire all commands in the same service file. The lazy user approach. Highly cringed upon by any developer. Complex but effective and useful in everyday use. Reduces flexibility and service clutter.
Example
VMware Workstation needs a few modules loaded and command lines to be executed to have USB hand-over, networking etc. working.
This is rather simple and quickly done from the shell but apparently services are meant to automate this for me. The requirements and steps are as follows:
  1. Have the following kernel modules loaded: vmmon vmnet vmw_vmci
  2. For networking: ’vmware-networks --postinstall vmware-workstation,0,1’ and then ’vmware-networks --start’
  3. For USB hand-over: ’vmware-usbarbitrator’
So that is three modules that need to be checked and loaded if they weren't already and then three command lines. I suppose the easiest and fastest way for the system would be to just modprobe these anyways, even if they were already loaded by something else (the vmware kernel package loads vmmon and vmw_vmci by itself it seems).
[main]
@ type = oneshot
@ name = vmware
@ description = "starts vmware modules"
@ user = ( root )

[start]
@ build = auto
@ execute =
(
        if { modprobe vmw_vmci }
        if { modprobe vmmon }
        if { modprobe vmnet }
        if { vmware-networks --postinstall vmware-workstation,0,1 }
        if { vmware-networks --start }
        vmware-usbarbitrator
)
This misses any fail-safe approach though and logging is also not thought of. What's your approach in such a situation?
First you are not forced to use execline syntax to write your script. Execline is perfect for simple script but can be useless on complex one.
"Yeah, Eric, i saw that, but what the solution?"
You can use ANY languages that you want for your script. Bash, Python,Csh,Ash,Ruby WHATEVER :).

@ build field allow you to change this behavior. If you pick "auto" the script is considered as an execline one. If you pick custom you will be able to define the program to use to read the @ execute field.
So the syntax is
@ build = custom
@ shebang = "/usr/bin/foo"
@ execute = ( my list of command, my call of a script, what i need to do, what i want to do,.... )
So in your case
@ build = custom
@ shebang = "/usr/bin/bash -c"
@ execute =
(
exec 2>&1
for i in vmw_vmci vmmon vmnet; do
   modprobe $i || echo modprobe failed && exit 0
done
vmware-networks --postinstall vmware-workstation,0,1
vmware-networks --start
vmware-usbarbitrator
)
Ok, now a little explanation. As you see the shebang give a -c options to bash. This is because you use it on oneshot (see https://skarnet.org/software/s6-rc/s6-rc-compile.html oneshot section"). On longrun/classic the shebang would be "/usr/bin/bash".
So the shebang allow you to determine the program to use to interpret the syntax of the @ execute field.
The redirection made at the first line of the @ execute field allow you to send the error(stderr) to the standard output (stdout). This is done automatically when you use execline but you need to do it by yourself in other case.

But you can do some stuff like this
@ build = auto
@ execute = ( /home/marianarlt/myscript.sh )
This is really simple, make your complex script, make it executable and call it :)

Now, strictly speaking about your needs. You can use the /etc/modules-load.d directory to load modules. The modules-system service will parse this directory at boot time and it loads every modules found on a file.
For example create the file /etc/modules-load.d/vmware.conf containing this
vmw_vmci 
vmmon 
vmnet
and write a oneshot service like this
[main]
@ type = oneshot
@ name = vmware
@ description = "starts vmware modules"
@ user = ( root )

[start]
@ build = auto
@ execute =
(
ifelse { 
	if { vmware-networks --postinstall } 
        if { vmware-networks --start }
	vmware-usbarbitrator
}
{ 66-echo vmware configured successfully }
if { 66-echo vmware unable to configure vmware }
exit 0
)
Or write your @ execute field with other interpreter :)

You have right, the boot process should not fail as far as the boot service set is finished successfully. Every followed tree (like root) should not crash the boot if something go wrong on it. I think from a little while now about it and i think i found the solution, be patient please , this behavior will change and the near future.

Powered by Obarun