From capezotte, 8 Months ago, written in Bash.
Embed Show code
  1. #!/bin/execlineb
  2. #
  3. # This is the turnstile s6-rc backend. It accepts the action as its first
  4. # argument, which is either "ready", "run", or "stop". The backend can be
  5. # written in any language, in this case the shebang is used to run it.
  6. #
  7. # It also serves as an example of how to implement such backend in a non
  8. # shell language.
  9. #
  10. # Arguments for "ready":
  11. #
  12. # live:     the path to s6-rc's live dir; it is the string that is
  13. #           written by dinit into ready_fd for the "run" part of the process
  14. #
  15. # Arguments for "run":
  16. #
  17. # ready_p:  path to named pipe (fifo) that should be poked with a string; this
  18. #           will be passed to the "ready" script of the sequence as its sole
  19. #           argument (here this is the path to s6-rc's live state directory)
  20. # srvdir:   an internal directory that can be used by the service manager
  21. #           for any purpose (usually to keep track of its state)
  22. # confdir:  the path where turnstile's configuration data reside, used
  23. #           to source the configuration file
  24. #
  25. # Arguments for "stop":
  26. #
  27. # pid:      the PID of the service manager to stop (gracefully); it should
  28. #           terminate the services it's running and then stop itself
  29. #
  30. # How the script manages its configuration and so on is up to the script.
  31. #
  32. # Note that the script *must* exec the service manager directly, i.e. the
  33. # service manager must fully replace the shell process for this to work.
  34. #
  35. # Copyright 2024 Carlos Eduardo <carana2099@gmail.com>
  36. # License: BSD-2-Clause
  37. #
  38.  
  39. importas -i directive 1
  40. shift -n 1
  41.  
  42. case $directive {
  43.         run {
  44.                 # source additional arguments.
  45.                 # two subsitution steps are needed because https://skarnet.org/lists/skaware/2049.html
  46.                 multisubstitute {
  47.                         importas -i __confdir 3
  48.                         importas -i __home    HOME
  49.                 }
  50.                 envfile -I -- ${__confdir}/s6-rc.conf
  51.  
  52.                 # despite the above warning, we do want serial substitution on these, so we import it here, before the bigger multisubstitute.
  53.                 multisubstitute {
  54.                         importas -uD "${HOME}/.local/share/s6/compiled" compiled compileddir
  55.                         importas -uD "${statedir}/s6-rc"                live     livestatedir
  56.                         importas -uD "${statedir}/env"                  env      envdir
  57.                 }
  58.                 multisubstitute {
  59.                         importas -i readyfifo 1
  60.                         importas -i statedir 2
  61.                         importas -i confdir 3
  62.                         # not used directly, but might be useful for the config file
  63.                         importas -Si HOME
  64.                         importas -Si USER
  65.                         importas -Si XDG_RUNTIME_DIR
  66.                         importas -Si SHELL
  67.                         importas -Si LOGNAME
  68.                 }
  69.  
  70.                 # Initialize state directory.
  71.                 # confdir/s6 should have the definition for a s6-svscan-log
  72.                 # service that acts as the catch-all loger. See:
  73.                 # /run/service/s6-svscan-log
  74.                 # on a s6-linux-init powered machine for an example.
  75.                 # It should also contain a .s6-svscan/SIGINT file with
  76.                 # foreground { s6-rc -bDa } s6-svscanctl -t .
  77.                 if { cp -a -- ${confdir}/s6 ${statedir}/service }
  78.  
  79.                 pipeline -dw -- {
  80.                         if {
  81.                                 forstdin -x0 _
  82.                                         exit 0
  83.                         }
  84.                         if -nt {
  85.                                 # Create envdir.
  86.                                 if { mkdir -p -- ${env} }
  87.                                 # Init service management layer.
  88.                                 if { s6-rc-init -c $compiled -l $live -- ${statedir}/service }
  89.                                 # Wait for logger to come up.
  90.                                 redirfd -w 2 ${statedir}/service/s6-svscan-log/fifo
  91.                                 # Print string for the ready step.
  92.                                 redirfd -w 1 ${readyfifo}
  93.                                 printf %s $live
  94.                         }
  95.                         # tell s6-svscan to give up if anything goes awry.
  96.                         s6-svscanctl -t -- ${statedir}/service
  97.                 }
  98.                         # turn pipeline output into notification-fd.
  99.                         fdmove -c 3 1
  100.                         # backup stderr for catch-all logger
  101.                         fdmove -c 4 2
  102.                         # fifo trick
  103.                         redirfd -wnb 2 ${statedir}/service/s6-svscan-log/fifo
  104.                         fdmove -c 1 2
  105.                         # avoid leaking script arguments
  106.                         emptyenv -P
  107.                         # export extra info for helper scripts
  108.                         export SVDIR ${statedir}/service
  109.                         export TURNSTILE_S6RC_LIVESTATE_DIR ${live}
  110.                         s6-svscan -d 3 -X 4 -- ${statedir}/service
  111.         }
  112.         ready {
  113.                 importas -i string 1
  114.                 s6-rc -l $string -up change default
  115.         }
  116.         stop {
  117.                 importas -i ! 1
  118.                 # Using INT instead of TERM so the s6-rc -bDa change hook runs
  119.                 kill -s INT $!
  120.         }
  121. }
  122.         exit 32
  123.  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
 
#!/bin/execlineb
#
# This is the turnstile s6-rc backend. It accepts the action as its first
# argument, which is either "ready", "run", or "stop". The backend can be
# written in any language, in this case the shebang is used to run it.
#
# It also serves as an example of how to implement such backend in a non
# shell language.
#
# Arguments for "ready":
#
# live:     the path to s6-rc's live dir; it is the string that is
#           written by dinit into ready_fd for the "run" part of the process
#
# Arguments for "run":
#
# ready_p:  path to named pipe (fifo) that should be poked with a string; this
#           will be passed to the "ready" script of the sequence as its sole
#           argument (here this is the path to s6-rc's live state directory)
# srvdir:   an internal directory that can be used by the service manager
#           for any purpose (usually to keep track of its state)
# confdir:  the path where turnstile's configuration data reside, used
#           to source the configuration file
#
# Arguments for "stop":
#
# pid:      the PID of the service manager to stop (gracefully); it should
#           terminate the services it's running and then stop itself
#
# How the script manages its configuration and so on is up to the script.
#
# Note that the script *must* exec the service manager directly, i.e. the
# service manager must fully replace the shell process for this to work.
#
# Copyright 2024 Carlos Eduardo <>
# License: BSD-2-Clause
#
 
importas -i directive 1
shift -n 1
 
case $directive {
    run {
        # source additional arguments.
        # two subsitution steps are needed because 
        multisubstitute {
            importas -i __confdir 3
            importas -i __home    HOME
        }
        envfile -I -- ${__confdir}/s6-rc.conf
 
        # despite the above warning, we do want serial substitution on these, so we import it here, before the bigger multisubstitute.
        multisubstitute {
            importas -uD "${HOME}/.local/share/s6/compiled" compiled compileddir
            importas -uD "${statedir}/s6-rc"                live     livestatedir
            importas -uD "${statedir}/env"                  env      envdir
        }
        multisubstitute {
            importas -i readyfifo 1
            importas -i statedir 2
            importas -i confdir 3
            # not used directly, but might be useful for the config file
            importas -Si HOME
            importas -Si USER
            importas -Si XDG_RUNTIME_DIR
            importas -Si SHELL
            importas -Si LOGNAME
        }
 
        # Initialize state directory.
        # confdir/s6 should have the definition for a s6-svscan-log
        # service that acts as the catch-all loger. See:
        # /run/service/s6-svscan-log
        # on a s6-linux-init powered machine for an example.
        # It should also contain a .s6-svscan/SIGINT file with
        # foreground { s6-rc -bDa } s6-svscanctl -t .
        if { cp -a -- ${confdir}/s6 ${statedir}/service }
 
        pipeline -dw -- {
            if {
                forstdin -x0 _
                    exit 0
            }
            if -nt {
                # Create envdir.
                if { mkdir -p -- ${env} }
                # Init service management layer.
                if { s6-rc-init -c $compiled -l $live -- ${statedir}/service }
                # Wait for logger to come up.
                redirfd -w 2 ${statedir}/service/s6-svscan-log/fifo
                # Print string for the ready step.
                redirfd -w 1 ${readyfifo}
                printf %s $live
            }
            # tell s6-svscan to give up if anything goes awry.
            s6-svscanctl -t -- ${statedir}/service
        }
            # turn pipeline output into notification-fd.
            fdmove -c 3 1
            # backup stderr for catch-all logger
            fdmove -c 4 2
            # fifo trick
            redirfd -wnb 2 ${statedir}/service/s6-svscan-log/fifo
captcha