+#!/usr/bin/ruby
+
+require 'socket'
+
+
+def do_cmd(*cmd)
+ ctl = UNIXSocket.open('/run/initctl')
+ ctl.puts(cmd.join(' '))
+ puts(ctl.readline.chomp)
+ exit
+end
+
+
+# If we're not PID 1, parse & send commands to /run/initctl
+
+if $$ != 1
+ case ARGV[0]
+ when 'poweroff', 'restart', 'halt'
+ do_cmd(ARGV[0].to_sym)
+ when 'status'
+ do_cmd(ARGV.shift.to_sym, *ARGV)
+ when 'test'
+ map = { poweroff: 0x4321fedc, restart: 0x01234567, halt: 0xcdef0123 }
+ # 169 == SYS_reboot
+ syscall(169, 0xfee1dead, 0x20112000, map[:poweroff])
+ else
+ puts('I know the following commands: poweroff, restart, halt, status, test')
+ exit 1
+ end
+end
+
+
+# These are hashes
+
+$daemons = {}
+$daemonCmds = {}
+
+# Needed to prevent respawning during a reboot...
+
+$shuttingDown = false
+
+# Here we do some process monitoring...
+
+Signal.trap(:SIGCHLD) do
+ loop do
+ begin
+ pid = Process.wait(-1, Process::WNOHANG)
+ key = $daemons.key(pid)
+
+ if key
+ cmd = $daemonCmds[key]
+ $daemons.delete(key)
+ $daemonCmds.delete(key)
+
+ # Respawn any processes that exit...
+ if key != 'openrc' && !$shuttingDown
+ launch(key, cmd)
+ end
+ end
+
+ break if pid == nil
+ rescue Errno::ECHILD
+ break
+ end
+ end
+end
+
+
+def action(name)
+ print(name)
+ begin
+ yield
+ rescue => e
+ print(' (error: %s)' % e)
+ end
+ puts
+end
+
+
+def launch(id, cmd)
+ puts('Starting %s...' % id)
+ pid = fork do
+ Process.setsid()
+ exec(*cmd)
+ end
+ $daemons[id] = pid
+ $daemonCmds[id] = cmd
+end
+
+
+def init
+ puts('*** init-ng v1.0.0 starting...')
+
+ launch('openrc', %w[/sbin/rc sysinit])
+ Process.wait($daemons['openrc'])
+
+ launch('openrc', %w[/sbin/rc boot])
+ Process.wait($daemons['openrc'])
+
+ launch('openrc', %w[/sbin/rc default])
+ Process.wait($daemons['openrc'])
+
+end
+
+
+def shutdown
+
+ $shuttingDown = true
+ launch('openrc', %w[/sbin/rc reboot])
+ Process.wait($daemons['openrc'])
+
+ sys_sync()
+
+end
+
+
+init
+
+ARGV.each do |e|
+ case e
+ when 'emergency'
+ $emergency = true
+ end
+end
+
+if $emergency
+ launch('agetty1', %w[/sbin/agetty tty1 --noclear --autologin root])
+else
+ # Launch TTYs...
+ (1..5).each do |n|
+ launch("agetty#{n}", %W[/sbin/agetty tty#{n} --noclear])
+ end
+end
+
+
+# This shows the one of the hazards of coding this in Ruby...
+
+def sys_reboot(cmd)
+ # LINUX_REBOOT_CMD_POWER_OFF == 0x4321FEDC
+ # LINUX_REBOOT_CMD_RESTART == 0x01234567
+ # LINUX_REBOOT_CMD_HALT == 0xCDEF0123
+ map = { poweroff: 0x4321fedc, restart: 0x01234567, halt: 0xcdef0123 }
+ # 169 == SYS_reboot
+ # LINUX_REBOOT_MAGIC1 == 0xfee1dead
+ # LINUX_REBOOT_MAGIC2C == 0x20112000
+ syscall(169, 0xfee1dead, 0x20112000, map[cmd])
+end
+
+
+def sys_sync
+ # 162 == SYS_sync
+ syscall(162)
+end
+
+
+begin
+ server = UNIXServer.open('/run/initctl')
+rescue Errno::EADDRINUSE
+ File.delete('/run/initctl')
+ retry
+end
+
+loop do
+ ctl = server.accept
+ args = ctl.readline.chomp.split
+ cmd = args.shift.to_sym
+ case cmd
+ when :poweroff, :restart, :halt
+ shutdown
+ sys_reboot(cmd)
+ when :status
+# ctl.puts($daemons[args.first] ? 'ok' : 'dead')
+ # This is NFG. It only shows on the main console, not on the socket, so
+ # you get nothing if you're ssh'ed in...
+ $daemons.each { |key, value| puts(key + ': ' + (value ? '[OK]' : '[!!]') + ' (' + value.to_s + ')') }
+ ctl.puts
+ end
+end
+