#!/usr/bin/ruby

#############################################################################
## This probes a random destination and the ::1 address in all routed IPv6
## prefixes on an ongoing basis.
##
## $Id: v6-prober,v 1.45 2023/06/12 00:43:26 mjl Exp $
#############################################################################

$0 = "ark-v6-prober"

require 'rubygems'
require 'ostruct'
require 'optparse'
require 'syslog'
require 'fileutils'

require 'arkutil/fileutils'
require 'arkutil/generalutils'
require 'arkutil/logging'

$options = OpenStruct.new

opts = OptionParser.new

# real options the wrapper cares about

opts.on("--syslog", TrueClass,
        "use Syslog instead of StderrLogger") do |v|
  $options.syslog = v
end


# dummy options that only the worker cares about
opts.on("--cycle-duration", "=NUM", Integer,
	"min duration (secs) for a cycle (#{$options.cycle_duration})") do |v|
end

opts.on("-m", "--monitor", "=MONITOR", "canonical monitor name") do |v|
end

opts.on("-s", "--scamper-port", "=NUM", Integer,
	"control socket port (#{$options.scamper_port})") do |v|
end

opts.on("--[no-]notify-collector", TrueClass,
        "notify ark-collector of finished files (true)") do |v|
end

opts.on("--collector", "=ADDR", String, "collector server to report to") do |v|
end

opts.on("-v", "--[no-]verbose", TrueClass,  "show detailed progress") do |v|
  $options.verbose = v
end

begin
  opts.parse(*ARGV)
rescue OptionParser::ParseError
  $stderr.puts "ERROR: " + $!.to_s
  $stderr.puts opts
  exit 1
end

$activity = "topo-v6"
$root = "/var/lib/ark/activity/#{$activity}"
$finished_dir = $root + "/finished"
$ramdisk = "/ramdisk"

if File.symlink? $root and not File.directory? $root
  # this block of code will run if a symlink exists, but the directory
  # underlying the symlink does not exist.
  x = File.readlink $root
  begin
    FileUtils.mkpath x
  rescue
    $stderr.puts "Could not mkpath #{$x}"
    exit 1
  end
elsif File.directory? $ramdisk and not File.directory? $root
  # if we have /ramdisk available, use it -- create /ramdisk/topo-v6
  # and symlink /var/lib/ark/activity/topo-v6 to it.
  begin
    FileUtils.mkpath "#{$ramdisk}/#{$activity}"
  rescue
    $stderr.puts "Could not mkpath #{$ramdisk}/#{$activity}"
    exit 1
  end
  begin
    FileUtils.ln_s("#{$ramdisk}/#{$activity}", $root)
  rescue
    $stderr.puts "Could not symlink #{$ramdisk}/#{$activity} to #{$root}"
    exit 1
  end
elsif not File.directory? $root
  # we do not have /ramdisk available, so just create
  # /var/lib/ark/activity/topo-v6
  begin
    FileUtils.mkpath $root
  rescue
    $stderr.puts "Could not mkpath #{$root}"
    exit 1
  end
end

# make sure the root directory exists, before going any further
unless File.directory? $root
  $stderr.printf "ERROR: missing activity directory '%s'\n", $root
  exit 1
end

# create the finished directory if it does not exist.
begin
  FileUtils.mkpath $finished_dir
rescue
  $stderr.puts "Could not mkpath #{$finished_dir}"
  exit 1
end

#===========================================================================

if $options.syslog
  syslog_options = Syslog::LOG_PID
  syslog_options |= Syslog::LOG_PERROR unless $options.detach
  $log = Syslog.open("v6-prober", syslog_options, Syslog::LOG_LOCAL0)
  Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_DEBUG) if $options.verbose
else
  $log = ArkUtil::StderrLogger.new
end

Signal.trap("TERM") do
  $log.info "exiting on SIGTERM"
  exit 2
end

Signal.trap("INT")  do
  $log.info "exiting on SIGINT"
  exit 2
end

def sh(command)
  puts command
  unless system command
    $stderr.printf "ERROR: couldn't execute command: %s\n", command
    exit 1
  end
end

#############################################################################
# MAIN
#############################################################################

$next_run = Time.now

while 1 == 1
  # if we've been told to stop probing while probing, then exit now
  if(File.file?($root + "/stop-probing"))
    $log.info "found stop-probing file; exiting"
    break
  end

  # make sure we only do one loop per 24 hours
  now = Time.now
  if(now.to_i < $next_run.to_i)
    gap = $next_run.to_i - now.to_i;
    sleep gap
  end
  $next_run = now + (24 * 60 * 60)

  # if we've been told to stop probing while sleeping, then exit now
  if(File.file?($root + "/stop-probing"))
    $log.info "found stop-probing file; exiting"
    break
  end

  # call the worker
  command = "ark-v6-prober-worker " + ARGV.join(" ")
  sh command
end
