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