#!/usr/bin/env ruby
require 'fiddle'
require 'fiddle/import'
require 'json'
require 'socket'

module Sys
  MS_MGC_VAL = 0xc0ed0000
  MS_BIND = 4096

  module Int
    extend Fiddle::Importer
    dlload Fiddle.dlopen(nil)

    extern 'int mount(const char *source, const char *target,           ' \
           'const char *filesystemtype, unsigned long mountflags,           ' \
           'const void *data)'
  end

  def self.bind_mount(src, dst)
    ret = Int.mount(src, dst, 0, MS_MGC_VAL | MS_BIND, 0)
    raise SystemCallError, Fiddle.last_error if ret != 0

    ret
  end
end

class CtPostMount
  def initialize(pool, ctid, rootfs)
    @pool = pool
    @ctid = ctid
    @rootfs = File.absolute_path(rootfs)
  end

  def run
    call_osctld!
  end

  protected

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

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

    ret
  end
end

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)

hook = CtPostMount.new(pool, ctid, ENV.fetch('LXC_ROOTFS_MOUNT', nil))
hook.run

exit
