#!/usr/bin/env ruby
require 'fileutils'
require 'json'
require 'socket'

ctid = ENV.fetch('LXC_NAME', nil)

if ctid.nil?
  warn 'Expected environment variables:'
  warn '  LXC_NAME'
  exit(false)
end

if %r{^/run/osctl/pools/([^/]+)/hooks} !~ $0
  warn "Unable to detect pool name from '#{$0}'"
  exit(false)
end

pool = Regexp.last_match(1)

s = UNIXSocket.new('/run/osctl/user-control/namespaced.sock')
s.puts({ cmd: :ct_autodev, opts: {
  id: ctid,
  pool:
} }.to_json)
ret = JSON.parse(s.readline, symbolize_names: true)
s.close

unless ret[:status]
  warn "Error: #{ret[:message]}"
  exit(false)
end

dst = ENV.fetch('LXC_ROOTFS_MOUNT', nil)

ret[:response][:devices].each do |dev|
  dstdev = File.join(dst, dev[:name])
  devdir = File.dirname(dstdev)
  FileUtils.mkdir_p(devdir)

  begin
    st = File.stat(dstdev)

    if (dev[:type] == 'char' && !st.chardev?) \
       || (dev[:type] == 'block' && !st.blockdev?) \
       || dev[:major] != st.rdev_major.to_s \
       || dev[:minor] != st.rdev_minor.to_s
      # The device is of an incorrect type
      File.unlink(dstdev)

    else
      # Device already exists
      File.chown(0, 0, dstdev)
      File.chmod(dev[:permission], dstdev)
      next
    end
  rescue Errno::ENOENT
    # pass
  end

  unless system("mknod #{dstdev} #{dev[:type_s]} #{dev[:major]} #{dev[:minor]}")
    raise "unable to create device '#{dstdev}'"
  end

  File.chown(0, 0, dstdev)
  File.chmod(dev[:permission], dstdev)
end

exit
