From 3b6073a94958720f0d632aa704446f7261e86a8a Mon Sep 17 00:00:00 2001 From: Philippe PITTOLI Date: Thu, 10 Oct 2019 03:35:21 +0200 Subject: [PATCH] Better CLI. --- src/main.cr | 142 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 29 deletions(-) diff --git a/src/main.cr b/src/main.cr index 7f34264..5ccc88e 100644 --- a/src/main.cr +++ b/src/main.cr @@ -10,9 +10,11 @@ prefered_network_configuration_program = nil prefered_wireless_configuration_program = nil prefered_dhcp_client = nil +root = "/" print_autodetect = false command = "list" +args = Array(String).new OptionParser.parse! do |parser| parser.on "-s", "--simulation", "Export the network configuration." do @@ -35,6 +37,10 @@ OptionParser.parse! do |parser| prefered_dhcp_client = prog end + parser.on "-r root", "--root root", "Root where to search for /etc/hostname.* files." do |optsn| + root = optsn + end + parser.on "-f file", "--file file", "Parse a configuration file." do |optsn| file = optsn end @@ -57,22 +63,22 @@ OptionParser.parse! do |parser| parser.unknown_args do |arg| command = arg.shift + args = arg case command when /^(list)/ - STDERR.puts "TODO: list" unless arg.empty? when /^(up)/ - STDERR.puts "TODO: up" unless arg.empty? when /^(down)/ - STDERR.puts "TODO: down" unless arg.empty? + when /^(scan)/ else STDERR.puts "Command #{command} not understood" - end - - unless arg.empty? - STDERR.puts "unknown arg: #{arg}" exit 1 end + + # unless arg.empty? + # STDERR.puts "unknown arg: #{arg}" + # exit 1 + # end end parser.on "-h", "--help", "Show this help" do @@ -92,6 +98,15 @@ class Do < Process Process.run cmd, params end end + + def self.run(cmd : String, params : Array(String) = nil, &block : Process -> _) + if @@simulation + puts "simulation, do: #{cmd} #{params.join(" ")}" + Process::Status.new 0 + else + Process.run cmd, params, &block + end + end end class NotSetup @@ -109,14 +124,29 @@ end class NetworkCommands class_property cmd_network_configuration : IfconfigCommand.class | IPCommand.class = IfconfigCommand - class_property cmd_wireless_configuration : IWCommand.class | NotSetup.class = NotSetup + class_property cmd_wireless_configuration : IfconfigCommand.class | IWCommand.class | NotSetup.class = NotSetup class_property cmd_dhcp_client : UDHCPCCommand.class | DHClientCommand.class | NotSetup.class = NotSetup class IWCommand - def self.get_ssid(ifname : String, ssid) - unless Do.run(cmd, [ ifname ]).success? - raise "(#{cmd}) dhcp failed on #{ifname}" + # get the available SSID + def self.scan(ifname : String) : Array(String) + ssids = Array(String).new + + Do.run("iw", [ ifname, "scan" ]) do |p| + p.output.each_line do |line| + ssid = /SSID: (?[a-zA-Z0-9_-]+)/.match(line).try &.["ssid"] + + unless ssid.nil? + ssids << ssid + end + end end + + if ssids.empty? + raise "(iw) cannot get ssid list from #{ifname}" + end + + ssids end end @@ -190,6 +220,11 @@ class NetworkCommands raise "(ifconfig) Cannot set down #{name}" end end + + # ifconfig also performs wireless configuration on some OSs + def self.scan(name : String) + puts "TODO: (ifconfig) ifconfig ifname scan | grep SSID" + end end class IPCommand @@ -293,13 +328,13 @@ class NetworkCommands @@cmd_network_configuration.down name end - def self.wireless_list_ssid(ifname : String) + def self.scan(ifname : String) cmd = @@cmd_wireless_configuration case cmd when NotSetup.class puts "no wireless configuration program: cannot list ssid" - when IWCommand.class - cmd.list_ssid ifname + else + cmd.scan ifname end end @@ -308,7 +343,7 @@ class NetworkCommands case cmd when NotSetup.class puts "no wireless configuration program: cannot connect to ssid #{ssid}" - when IWCommand.class + else cmd.list_ssid ifname end end @@ -566,6 +601,15 @@ class InterfaceConfiguration NetworkCommands.flush name NetworkCommands.down name end + + def scan + unless NetworkCommands.interface_exists(@name) + raise "The interface #{@name} doesn't exists or is already down." + end + + ssid_list = NetworkCommands.scan name + pp! ssid_list + end end class NetworkConfigurationParser @@ -819,7 +863,8 @@ possible_dhcp_clients = { # iw = linux possible_wireless_configuration_cmds = { - "iw" => NetworkCommands::IWCommand + "iw" => NetworkCommands::IWCommand, + "ifconfig" => NetworkCommands::IfconfigCommand } key = prefered_network_configuration_program @@ -838,20 +883,59 @@ key = possible_wireless_configuration_cmds.keys.find { |key| Autodetect.which(ke NetworkCommands.cmd_wireless_configuration = possible_wireless_configuration_cmds[key.not_nil!] -if file.nil? - raise "Cannot search for files yet" + +files = Array(String).new +Dir.children("#{root}/etc/").each do |f| + if /^hostname\./.match(f) + files << f + end end -case command -when "list" +interface_files = Array(String).new + +if ! file.nil? + # file passed via the '-f' option # TODO: why having to force "not_nil!" ? Seems like a compiler bug - puts NetworkConfigurationParser.parse_file(file.not_nil!) -when "up" - # TODO: why having to force "not_nil!" ? Seems like a compiler bug - network_configuration = NetworkConfigurationParser.parse_file(file.not_nil!) - network_configuration.execute -when "down" - # TODO: why having to force "not_nil!" ? Seems like a compiler bug - network_configuration = NetworkConfigurationParser.parse_file(file.not_nil!) - network_configuration.down + interface_files << file.not_nil! +elsif args.empty? + # every configured interface + files.each do |f| + interface_files << "#{root}/etc/#{f}" + end +else + # only interfaces in arguments + args.each do |interface| + interface_files << "#{root}/etc/hostname.#{interface}" + end +end + + + +begin + case command + when "list" + interface_files.each do |f| + puts NetworkConfigurationParser.parse_file(f.not_nil!) + end + when "up" + # TODO: why having to force "not_nil!" ? Seems like a compiler bug + interface_files.each do |f| + network_configuration = NetworkConfigurationParser.parse_file(f.not_nil!) + network_configuration.execute + end + when "down" + # TODO: why having to force "not_nil!" ? Seems like a compiler bug + interface_files.each do |f| + network_configuration = NetworkConfigurationParser.parse_file(f.not_nil!) + network_configuration.down + end + when "scan" + # TODO: why having to force "not_nil!" ? Seems like a compiler bug + interface_files.each do |f| + network_configuration = NetworkConfigurationParser.parse_file(f.not_nil!) + network_configuration.scan + end + end +rescue e + STDERR.puts "#{CRED}Exception: #{CRESET}#{e}" end