We often need to convert between file sizes, for formatting output,
but also code-internal. Some methods expect kilobytes, some gigabytes
and sometimes we need bytes.
While conversion from smaller to bigger units can be simply done with
a left-shift, the opposite conversion may need more attention -
depending on the used context.
If we allocate disks this is quite critical. For example, if we need
to allocate a disk with size 1023 bytes using the
PVE::Storage::vdisk_alloc method (which expects kilobytes) a
right shift by 10 (<=> division by 1024) would result in "0", which
obviously fails.
Thus we round up the converted value if a remainder was lost on the
transformation in this new method. This behaviour is opt-out, to be
on the safe side.
The method can be used in a clear way, as it gives information about
the source and target unit size, unlike "$var *= 1024", which doesn't
gives direct information at all, if not commented or derived
somewhere from its context.
For example:
> my $size = convert_unit($value, 'gb' => 'kb');
is more clear than:
> my $size = $value*1024*1024;
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
perls 'local' must be either used in front of each $SIG{...}
assignments or they must be put in a list, else it affects only the
first variable and the rest are *not* in local context.
This may cause weird behaviour where daemons seemingly do not get
terminating signals delivered correctly and thus may not shutdown
gracefully anymore.
As we only send SIGINT to processes if a manual stop action gets
triggered just catch this one here.
As this is a general method which allows to pass an arbitrary code
payload we cannot sanely handle all signals here, so remove trapping
all other besides SIGINT, if those need to be trapped that should be
done by the caller on a case by case basis.
Fixes: #1495
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
We run into problems where this method returned to early, even if the
port wasn't actually ready yet. The reason for this is that we
checked /proc/net/tcp which does not guarantees and always up to date
state of only those ports which are actuall available, i.e. a port
could linger around (time-wait state) or appear even if it wasn't
accepting connections yet (as stated in the kernel docs:
/proc/net/tcp is seen as obsolete by the kernel devs).
Use the `ss` tool from the iproute2 package, it uses netlink to get
the current state and has switches where we can direct it to really
only get the state of those sockets which interest us currently.
I.e., we tell it to get only listening TCP sockets from the requested
port.
The only drawback is that we loop on a run_command, which is slower
than just reading a file. A single loop needs about 1ms here vs the
60µs on the /proc/net/tcp read. But this isn't a api call which is
used highly frequently but rather once per noVNC console open.
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Otherwise perl tries to bind+listen on a UDP socket if the
TCP socket fails - which is a waste since we're looking for
TCP ports.
Additionall since UDP doesn't support listen(), perl will
return EOPNOTSUPP instead of, say, EADDRINUSE. (We don't
care about the error in this code though.)
While it should be impossible to bind to a wildcard address
when the port is in use by any other address there's one
case where this is allowed, and that's when the port is in
use by an ipv6 address while trying to bind to an ipv4
wildcard.
This currently happens when qemu finds ::1 for the
'localhost' we pass to qemu's spice address while we're
resolving the local nodename via IPv4.
Raw syscall numbers were not platform independent, so replace them
with the helpers provided from the syscall.ph perl bits helper.
This makes reading the code easier as a nice side effect.
As syscall.ph is not an ordinary module and makes problems when it is
required by multiple modules we make a own module PVE::Syscall which
loads it and allows to export the necessary constants in a sane way.
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Previously an external exception (eg. caused by a SIGARLM in a code
which is already inside a run_with_timeout() call) could happen in
various places where we did not properly this situation.
For instance after calling $lock_func() but before reaching the cleanup
code. In this case a lock was leaked.
Additionally the code was broken in that it used perl's automatic hash
creation side effect ($a->{x}->{y} implicitly initializing $a->{x} with
an empty hash when it did not exist). The effect was that if our own
time out was triggered after the initial check for an existing file
handle inside $lock_func() happened (extremely rare since perl would have
to be running insanely slow), the cleanup did:
if (my $fh = $lock_handles->{$$}->{$filename}->{fh}) {
This recreated $lock_handles->{$$}->{$filename} as an empty hash.
A subsequent call to lock_file_full() will think a file descriptor
already exists because the check simply used:
if (!$lock_handles->{$$}->{$filename}) {
While this could have been a one-line fix for this one particular case,
we'd still not be taking external timeouts into account causing the
first issue described above.
When the child process running the command got an signal or failed
to execute exitcode was still undefined as we extract it just only
after the signal/failed to execute check.
This led to:
> Use of uninitialized value in numeric ne (!=) at
> /usr/share/perl5/PVE/API2/Qemu.pm line 1433.
errors if we used run_commands `noerr` param and checked for the
commands exit code.
So just default the exit code to -1 for such cases.
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
since the "lang" param has not worked, introduce a "keeplocale"
parameter instead.
the default behaviour is the same (set LC_ALL to 'C'), but we can use
the parameter to keep the locale from the host (eg. for the vncshell)
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
when reserving ports, we use lock_file to lock the
reservation file, but then use file_set_content which
writes a new file and renames it, making the lock invalid
and different processes waiting for the lock get inconsistent
data
instead we use a designated lock file for the lock, so that we don't
lose the lock when writing the reservation file
this should fix the problem that sometimes multiple vms get the
same vnc/spice port
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Commit de9a267 introduced vec() to optimize the generation
by using binary operations instead of converting back and
forth between hex and strings, but forgot to switch over to
the binary sha1 method. This resulted in only the first 6
hex digits of the output string making up the address.
This essentially performas the task of systemd-run while
also waiting for the job to finish.
With the systemd-run version in jessie we run into a race
condition where the executed process can start forking child
processes before the systemd daemon is done setting up the
scope's cgroups, causing the children to NOT be included in
the cgroups. This means the child processes (in our case
qemu) will not adhere to the limits we want to apply to it
via cgroups.
enter_systemd_scope() performs the setup task of systemd-run
and waits for the job to finish, after this we can spawn the
qemu process without systemd-run.
This was already implemented in PVE::LXC::lock_aquire() and
lock_release(). Enabling refcounting in the general
PVE::Tools::lock_file() and lock_file_full() methods allows
us to use one code base for flocking.
Furthermore, we could get rid of various xx_no_lock methods
that were required because the old non-refcounting version
did not support nested flocks (the inner most flock would
close the file handle and thus release the flock).
If we can't acquire the lock in lock_file_full and get interrupted
by a signal inqeual to EINTR (e.g. SIGTERM), output also it's name
in the error message to allow better debugging.
Also fix a typo.
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Allow to return the exit code of the executed command.
And as we do not reach the return of the exit code if it was not 0,
a noerr parameter is also needed so we can suppress the 'command
failed' die in case of an exit code unequal to 0.
This is required as some programs return another value than 0 when
they succeed, For example `systemctl list-jobs` returns a value
>= 0 on a successful execution, normally 1.
Without this patch a run_command call to `systemctl list-jobs` gets
marked as failed although it was successful.
This does not break current behaviour in any way as setting the
noerr parameter is required to return something other than 0 or
undef, which are equal in a boolean comparison.
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Most syscall wrappers in perl return 1 on success and our
current use of Tools::unshare isn't using the return value
(yet), so let's fix this while we can.
Also it seems to make sense to use prototyping on syscalls
to add some compile-time argument checking.
In an alternation /a|b|c/ the first match matches, so while
'1.1.1.121' matches /^$IPV4RE$/ (note the ^ and $ anchors),
parsing a line like /nameserver ($IPV4RE)/ would only
extract '1.1.1.12', ignoring the last '1' due to the /[1-9]/
alternative matching before the /1[0-9]/ one.
Passing an array of arrays to run_command will cause each
array to be treated like a command piped to the following
command. Each argument is shell-quoted unless its passed by
reference.
The following situations could lead to the 'unknown error':
1) As commented, when the alarm triggered after the first
signal handler was installed and before the new alarm was
installed. In this case the $signalcount was increased,
and worse: the original signal handler was never called.
2) When $code died, since the call itself wasn't in an eval
block, we'd leave the eval block containing the inner alarm
signal handler. Then there's a time window from leaving the
signal block (and with that restoring the first installed
only-counting signal-handler) and reaching the code to
restore the previous alarm where the counting alarm handler
could get triggered by our own alarm set before running
$code. In this case at least the the old alarm would be
restored, but we'd still trigger the 'unknown error'.
The new code starts off by suspending the original alarm
before installing any signal handler, then installing the
timeout handler inside the first eval block. The $code is
then run inside another eval block to make sure we reach the
alarm(0) statement before restoring the old signal handler
and alarm timeout.
Added a generic function to split a host+port string to the
host and port part supporting the two most common ipv6
notations beside domains and ipv4: with brackets for the
address or a dot as port separator.
perl's IO::Socket::IP passes AI_ADDRCONFIG if no GetAddrInfoFlags are passed,
which is often useful but also causes it to error when explicitly trying to
bind to 127.0.0.1 when there are no _other_ IPv4 addresses present.
Instead of assuming a local address of 0.0.0.0, the next_*_port family
of functions now takes an optional packet family argument (AF_INET/AF_INET6),
used for ipv6 support.