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