]> Shamusworld >> Repos - init-ng/blob - init-ng.rb
Added version which conforms to openrc coding guidelines.
[init-ng] / init-ng.rb
1 #!/usr/bin/ruby
2
3 require 'socket'
4
5
6 # These are hashes
7 $daemons = {}
8 $daemonCmds = {}
9
10 # Needed to prevent respawning during a reboot...
11 $shuttingDown = false
12
13
14 def launch(id, cmd)
15   puts('Starting %s...' % id)
16   pid = fork do
17     Process.setsid()
18     exec(*cmd)
19   end
20   $daemons[id] = pid
21   $daemonCmds[id] = cmd
22 end
23
24
25 # Here we do some process monitoring...
26 Signal.trap(:SIGCHLD) do
27   loop do
28     begin
29       pid = Process.wait(-1, Process::WNOHANG)
30       key = $daemons.key(pid)
31
32       if key
33         cmd = $daemonCmds[key]
34         $daemons.delete(key)
35         $daemonCmds.delete(key)
36
37         # Respawn any processes that exit...
38         if key != 'openrc' && !$shuttingDown
39           launch(key, cmd)
40         end
41       end
42
43       break if pid == nil
44     rescue Errno::ECHILD
45       break
46     end
47   end
48 end
49
50
51 def init
52   puts('*** init-ng v1.0.0 starting...')
53
54   launch('openrc', %w[/sbin/rc sysinit])
55   Process.wait($daemons['openrc'])
56
57   launch('openrc', %w[/sbin/rc boot])
58   Process.wait($daemons['openrc'])
59
60   launch('openrc', %w[/sbin/rc default])
61   Process.wait($daemons['openrc'])
62
63 end
64
65
66 def shutdown
67
68   $shuttingDown = true
69   launch('openrc', %w[/sbin/rc reboot])
70   Process.wait($daemons['openrc'])
71
72   sys_sync()
73
74 end
75
76
77 def do_cmd(*cmd)
78   ctl = UNIXSocket.open('/run/initctl')
79   ctl.puts(cmd.join(' '))
80   puts(ctl.readline.chomp)
81   exit
82 end
83
84
85 # This shows the one of the hazards of coding this in Ruby...
86 def sys_reboot(cmd)
87   # LINUX_REBOOT_CMD_POWER_OFF == 0x4321FEDC
88   # LINUX_REBOOT_CMD_RESTART   == 0x01234567
89   # LINUX_REBOOT_CMD_HALT      == 0xCDEF0123
90   map = { poweroff: 0x4321fedc, restart: 0x01234567, halt: 0xcdef0123 }
91   # 169 == SYS_reboot
92   # LINUX_REBOOT_MAGIC1  == 0xfee1dead
93   # LINUX_REBOOT_MAGIC2C == 0x20112000
94   syscall(169, 0xfee1dead, 0x20112000, map[cmd])
95 end
96
97
98 def sys_sync
99   # 162 == SYS_sync
100   syscall(162)
101 end
102
103
104 #
105 # Start of the script proper
106 #
107 # If we're not PID 1, parse & send commands to /run/initctl
108 #
109 if $$ != 1
110   case ARGV[0]
111   when 'poweroff', 'restart', 'halt'
112     do_cmd(ARGV[0].to_sym)
113   when 'status'
114     do_cmd(ARGV.shift.to_sym, *ARGV)
115   when 'test'
116     map = { poweroff: 0x4321fedc, restart: 0x01234567, halt: 0xcdef0123 }
117     # 169 == SYS_reboot
118     syscall(169, 0xfee1dead, 0x20112000, map[:poweroff])
119   else
120     puts('I know the following commands: poweroff, restart, halt, status, test')
121     exit 1
122   end
123 end
124
125 init
126
127 ARGV.each do |e|
128   case e
129   when 'emergency'
130     $emergency = true
131   end
132 end
133
134 if $emergency
135   launch('agetty1', %w[/sbin/agetty tty1 --noclear --autologin root])
136 else
137   # Launch TTYs...
138   (1..5).each do |n|
139     launch("agetty#{n}", %W[/sbin/agetty tty#{n} --noclear])
140   end
141 end
142
143 begin
144   server = UNIXServer.open('/run/initctl')
145 rescue Errno::EADDRINUSE
146   File.delete('/run/initctl')
147   retry
148 end
149
150 loop do
151   ctl = server.accept
152   args = ctl.readline.chomp.split
153   cmd = args.shift.to_sym
154   case cmd
155   when :poweroff, :restart, :halt
156     shutdown
157     sys_reboot(cmd)
158   when :status
159 #    ctl.puts($daemons[args.first] ? 'ok' : 'dead')
160     # This is NFG. It only shows on the main console, not on the socket, so
161     # you get nothing if you're ssh'ed in...
162     $daemons.each { |key, value| puts(key + ': ' + (value ? '[OK]' : '[!!]') + ' (' + value.to_s + ')') }
163     ctl.puts
164   when :start
165     puts('Received start msg from s-s-d: ' + args.to_s)
166   when :stop
167     puts('Received stop msg from s-s-d: ' + args.to_s)
168   end
169 end
170