1 package Proxmox
::Install
::RunEnv
;
7 use JSON
qw(from_json to_json);
10 use Proxmox
::Sys
::File
qw(file_read_firstline);
11 use Proxmox
::Sys
::Block
;
12 use Proxmox
::Sys
::Net
;
14 my sub fromjs
: prototype($) {
15 return from_json
($_[0], { utf8
=> 1 });
18 my $mem_total = undef;
19 sub query_total_memory
: prototype() {
20 return $mem_total if defined($mem_total);
22 open (my $MEMINFO, '<', '/proc/meminfo');
24 my $res = 512; # default to 512 if something goes wrong
25 while (my $line = <$MEMINFO>) {
26 if ($line =~ m/^MemTotal:\s+(\d+)\s*kB/i) {
27 $res = int ($1 / 1024);
40 # mac => <mac address>,
44 # family => <inet|inet6>,
45 # address => <mac address>,
50 my sub query_netdevs
: prototype() {
54 # FIXME: not the same as the battle proven way we used in the installer for years?
55 my $interfaces = fromjs
(qx
/ip --json address show/);
57 for my $if (@$interfaces) {
58 my ($index, $name, $state, $mac, $addresses) =
59 $if->@{qw(ifindex ifname operstate address addr_info)};
61 next if $state ne 'UP';
64 for my $addr (@$addresses) {
65 next if $addr->{scope
} eq 'link';
67 my ($family, $addr, $prefix) = $addr->@{qw(family local prefixlen)};
81 addresses
=> \
@valid_addrs,
103 my sub query_routes
: prototype() {
104 my ($gateway4, $gateway6);
106 my $route4 = fromjs
(qx
/ip -4 --json route show/);
107 for my $route (@$route4) {
108 if ($route->{dst
} eq 'default') {
110 dev
=> $route->{dev
},
111 gateway
=> $route->{gateway
},
117 my $route6 = fromjs
(qx
/ip -6 --json route show/);
118 for my $route (@$route6) {
119 if ($route->{dst
} eq 'default') {
121 dev
=> $route->{dev
},
122 gateway
=> $route->{gateway
},
129 $routes->{gateway4
} = $gateway4 if $gateway4;
130 $routes->{gateway6
} = $gateway6 if $gateway6;
135 # If `/etc/resolv.conf` fails to open this returns nothing.
136 # Otherwise it returns a hash:
138 # dns => <first dns entry>,
140 my sub query_dns
: prototype() {
141 open my $fh , '<', '/etc/resolv.conf' or return;
145 while (defined(my $line = <$fh>)) {
146 if ($line =~ /^nameserver\s+(\S+)/) {
148 } elsif (!defined($domain) && $line =~ /^domain\s+(\S+)/) {
155 @dns ?
(dns
=> \
@dns) : (),
159 # Uses `traceroute` and `geoiplookup`/`geoiplookup6` to figure out the current country.
160 # Has a 10s timeout and uses the stops at the first entry found in the geoip database.
161 my sub detect_country_tracing_to
: prototype($$) {
162 my ($ipver, $destination) = @_;
164 print "trying to detect country...\n";
165 open(my $TRACEROUTE_FH, '-|',
166 'traceroute', "-$ipver", '-N', '1', '-q', '1', '-n', $destination)
169 my $geoip_bin = ($ipver == 6) ?
'geoiplookup6' : 'geoiplookup';
173 my $previous_alarm = alarm (10);
175 local $SIG{ALRM
} = sub { die "timed out!\n" };
177 while (defined ($line = <$TRACEROUTE_FH>)) {
178 log_debug
("DC TRACEROUTE: $line");
179 if ($line =~ m/^\s*\d+\s+(\S+)\s/) {
180 my $geoip = qx
/$geoip_bin $1/;
181 log_debug
("DC GEOIP: $geoip");
182 if ($geoip =~ m/GeoIP Country Edition:\s*([A-Z]+),/) {
184 log_info
("DC FOUND: $country\n");
191 alarm ($previous_alarm);
193 close($TRACEROUTE_FH);
196 die "unable to detect country - $err\n";
198 print "detected country: " . uc($country) . "\n";
204 # Returns the entire environment as a hash.
206 # country => <short country>,
207 # disks => <see Proxmox::Sys::Block::hd_list()>,
209 # interfaces => <see query_netdevs()>,
210 # routes => <see query_routes()>,
211 # dns => <see query_dns()>,
214 sub query_installation_environment
: prototype() {
217 my $routes = query_routes
();
219 $output->{disks
} = Proxmox
::Sys
::Block
::get_cached_disks
();
220 $output->{network
} = {
221 interfaces
=> query_netdevs
(),
225 # FIXME: move whatever makes sense over to Proxmox::Sys::Net:: and keep that as single source,
226 # it can then use some different structure just fine (after adapting the GTK GUI to that) but
227 # **never** to (slightly different!) things for the same stuff...
228 $output->{ipconf
} = Proxmox
::Sys
::Net
::get_ip_config
();
230 $output->{kernel_cmdline
} = file_read_firstline
("/proc/cmdline");
231 $output->{total_memory
} = query_total_memory
();
232 $output->{boot_type
} = -d
'/sys/firmware/efi' ?
'efi' : 'bios';
236 if ($routes->{gateway4
}) {
237 $country = eval { detect_country_tracing_to
(4 => '8.8.8.8') };
238 $err = $@ if !$country;
241 if (!$country && $routes->{gateway6
}) {
242 $country = eval { detect_country_tracing_to
(6 => '2001:4860:4860::8888') };
243 $err = $@ if !$country;
246 if (defined($country)) {
247 $output->{country
} = $country;
249 warn ($err // "unable to detect country\n");
258 $_env = query_installation_environment
() if !defined($_env);
259 return defined($k) ?
$_env->{$k} : $_env;