Commit Graph

203 Commits

Author SHA1 Message Date
Michal Privoznik
79c613ec8a virsh: fflush(stdout) after fputs()
We are not guaranteed that the string we are printing onto stdout
contains '\n' and thus that the stdout is flushed. In fact, I've
met this problem when virsh asked me whether I want to edit the
domain XML again (vshAskReedit()) but the prompt wasn't displayed
(as it does not contain a newline character) and virsh just sat
there waiting for my input, I sat there waiting for virsh's
output. Flush stdout after all fputs()-s  which do not flush
stdout.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2022-03-10 08:57:31 +01:00
Peter Krempa
8c35dcf9fc vsh: Add helper for auto-removing temporary file
The vsh helpers for user-editing of contents use temporary files.
Introduce 'vshTempFile' type which automatically removes the file.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2022-03-03 11:06:56 +01:00
Tim Wiederhake
883cd98498 tools: Use automatic mutex management
Signed-off-by: Tim Wiederhake <twiederh@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2022-02-11 16:03:29 +01:00
Michal Privoznik
87a43a907f lib: Use g_clear_pointer() more
This change was generated using the following spatch:

  @ rule1 @
  expression a;
  identifier f;
  @@
    <...
  - f(*a);
    ... when != a;
  - *a = NULL;
  + g_clear_pointer(a, f);
    ...>

  @ rule2 @
  expression a;
  identifier f;
  @@
    <...
  - f(a);
    ... when != a;
  - a = NULL;
  + g_clear_pointer(&a, f);
    ...>

Then, I left some of the changes out, like tools/nss/ (which
doesn't link with glib) and put back a comment in
qemuBlockJobProcessEventCompletedActiveCommit() which coccinelle
decided to remove (I have no idea why).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2022-02-08 08:42:07 +01:00
Michal Privoznik
364cf32e57 virsh: Remove needless labels
There are few places where a cleanup label contains nothing but a
return statement. Drop such labels and return directly.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2022-01-17 09:53:45 +01:00
Michal Privoznik
7c2a4e84b7 Prefer g_auto(GStrv) over g_strfreev()
There are a few cases where a string list is freed by an explicit
call of g_strfreev(), but the same result can be achieved by
g_atuo(GStrv).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Tim Wiederhake <twiederh@redhat.com>
2021-11-11 16:16:17 +01:00
Michal Privoznik
1b2e06b1bf virsh: Use VIR_AUTOCLOSE more
There are few places where we can replace explicit
VIR_FORCE_CLOSE() with VIR_AUTOCLOSE annotation.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-10-06 09:28:19 +02:00
Tim Wiederhake
4ad3c95f4b vshCmddefCheckInternals: Fix typo
Signed-off-by: Tim Wiederhake <twiederh@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-10-01 13:12:23 +02:00
Michal Privoznik
bf9074c6a8 vsh: Don't check for OOM in vshGetTypedParamValue()
Both function description and function itself mention check for
OOM which can't happen really. There was a bug in glib where
g_strdup_*() might have not aborted on OOM, but we have our own
implementation when dealing with broken glib (see
vir_g_strdup_printf()). Therefore, checking for OOM is redundant
and can never be true.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-09-24 12:40:48 +02:00
Michal Privoznik
b480a5cb5c vsh: Ensure that bool --options don't have completer
Let's check whether a boolean --option doesn't have completer or
completer_flags set. These options are just flags and don't
accept any value, thus they can't have any completer.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-09-21 10:20:41 +02:00
Michal Privoznik
a1a22b0b1c vsh: Extend checks for aliased commands
If a command is an alias, then it can only have .name, .flags and
.alias set and .flags should contain just VSH_CMD_FLAG_ALIAS.
Check if that's the case in self-test.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-09-21 10:20:41 +02:00
Peter Krempa
9d26af5e5b vsh: Move 'vshReadlineOptionsGenerator' out of '#if WITH_READLINE'
It's now also used in vshCompleteHelpCommand which is outside of the
conditionally compiled code.

Fixes: 80f70c74a7
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
2021-09-17 11:00:13 +02:00
Peter Krempa
80f70c74a7 vsh: Add completer for '--command' of 'help' command
Wrap 'vshReadlineCommandGenerator' into a function with proper prototype
to provide a completer for the help command.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-09-17 09:40:46 +02:00
Peter Krempa
8f5b8fac33 vsh: Introduce '--completers-missing' for 'self-test' command
Make it simple to spot which options of which commands are missing
autocompletion functions by introducing this hidden option.

In the future when we'll have completers for everything this can be also
used as a hard fail so that completers are always added.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-09-17 09:40:46 +02:00
Peter Krempa
7f72ed0707 vshCmddefCheckInternals: Sanitize command alias validation
We don't need to validate the real command twice, but it's better to
check that the real command name exists and it's not an alias to prevent
loops.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-09-17 09:40:46 +02:00
Peter Krempa
1726c572a2 virsh: Remove hack using 'VSH_CMD_FLAG_ALIAS' to hide virsh commands
Introduce a proper flag 'VSH_CMD_FLAG_HIDDEN' for hiding commands from
output so that we can validate that there aren't any loops or
misconfigured commands.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-09-17 09:40:46 +02:00
Peter Krempa
8efd949c8b vshStringToArray: Rewrite using 'g_strsplit'
Use 'g_strsplit' to split the strings and then concatenate back when the
escape sequence (',,') is used.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-08-18 11:07:25 +02:00
Peter Krempa
4db8ffeb2e virsh: Add testing for vshStringToArray
Add a '--split' switch for the 'virsh echo' command and add few test
cases to the virshtest.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-08-18 11:07:25 +02:00
Peter Krempa
31fa241b46 virsh: cmdEcho: Rewrite with new buffer helpers
Remove the need for temporary strings by filling the output buffer
directly.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-08-18 11:07:25 +02:00
Peter Krempa
86de16b317 virsh: cmdEcho: Make '--xml' and '--shell' mutually exclusive
Initialize the flags earlier and use VSH_EXCLUSIVE_OPTIONS_VAR to
declare the conflicting options as exclusive.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-08-18 11:07:25 +02:00
Peter Krempa
a52a201c22 virsh: Un-document 'virsh echo'
Note that it's for internal testing use and remove the manpage entry.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-08-18 11:07:25 +02:00
Ján Tomko
bd1f40fe7d tools: virsh: remove redundant labels
Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2021-08-16 13:10:34 +02:00
Ján Tomko
4de7ccc4d8 vsh: steal pointer in vshEditWriteToTempFile
Fixes: 13896b5ad1
Signed-off-by: Ján Tomko <jtomko@redhat.com>
2021-08-12 11:45:21 +02:00
Ján Tomko
a6488fd3a2 vsh: use g_clear_pointer
Replace remaining uses of VIR_FREE with g_clear_pointer.

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2021-08-11 10:52:58 +02:00
Ján Tomko
4d64c850c4 vsh: remove pointless cleanup labels
Remove cleanup sections that are no longer needed, as well
as unnecessary 'ret' variables.

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2021-08-11 10:52:58 +02:00
Ján Tomko
13896b5ad1 vsh: use g_auto where possible
Excluding vshCommandParse.

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2021-08-11 10:52:58 +02:00
Ján Tomko
f78e2495e5 vsh: cmdEcho: use separate variable for argument
Do not use 'arg' which is later used for an allocated string.

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2021-08-11 10:52:58 +02:00
Ján Tomko
2cbc686d66 vsh: do not cast away const
Instead of using the same variable to store either a const pointer
or an allocated string, always make a copy.

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2021-08-11 10:52:58 +02:00
Peter Krempa
92a3eddd03 Remove static analysis assertions
None of them are currently needed to pass our upstream CI, most were
either for ancient clang versions or coverity for silencing false
positives.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-05-24 20:26:20 +02:00
Michal Privoznik
c8238579fb lib: Drop internal virXXXPtr typedefs
Historically, we declared pointer type to our types:

  typedef struct _virXXX virXXX;
  typedef virXXX *virXXXPtr;

But usefulness of such declaration is questionable, at best.
Unfortunately, we can't drop every such declaration - we have to
carry some over, because they are part of public API (e.g.
virDomainPtr). But for internal types - we can do drop them and
use what every other C project uses 'virXXX *'.

This change was generated by a very ugly shell script that
generated sed script which was then called over each file in the
repository. For the shell script refer to the cover letter:

https://listman.redhat.com/archives/libvir-list/2021-March/msg00537.html

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2021-04-13 17:00:38 +02:00
Ján Tomko
a131b8b517 vsh: fix memory leak in vshCommandParse
One of the error branches used a plain free where vshCommandFree
was required.

https://bugzilla.redhat.com/show_bug.cgi?id=1943415

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Erik Skultety <eskultet@redhat.com>
2021-04-09 13:07:30 +02:00
Michal Privoznik
0c30e7221c lib: Use g_steal_pointer() more
Generated by the following spatch:

  @@
  expression a, b;
  @@

  + b = g_steal_pointer(&a);
  - b = a;
    ... when != a
  - a = NULL;

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Erik Skultety <eskultet@redhat.com>
2021-03-24 13:57:51 +01:00
Jiri Denemark
1107c0b9c3 Do not check return value of VIR_REALLOC_N
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Reviewed-by: Erik Skultety <eskultet@redhat.com>
2021-03-22 12:44:18 +01:00
Michal Privoznik
b1e3728dec lib: Replace virFileMakePathWithMode() with g_mkdir_with_parents()
These functions are identical. Made using this spatch:

  @@
  expression path, mode;
  @@
  - virFileMakePathWithMode(path, mode)
  + g_mkdir_with_parents(path, mode)

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-03-04 20:52:23 +01:00
Peter Krempa
dcd547aec1 Replace virStringListLength by g_strv_length
The glib implementation doesn't tolerate NULL but in most cases we check
before anyways. The rest of the callers adds a NULL check.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-02-11 17:05:34 +01:00
Michal Privoznik
7415e72e68 vsh: Drop unused @text arg from readline generators
After previous patches neither vshReadlineCommandGenerator() nor
vshReadlineOptionsGenerator() use prefix that user wants to
complete. The argument is marked as unused in both functions.
Drop it then.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
72636ed86d vsh: Rework vshReadlineCommandGenerator()
Firstly, move variable declarations into the inner most block
they are used. Secondly, use for() loop instead of while so that
we don't have to advance loop counter explicitly on 'continue'.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
9b005b1967 vsh: Simplify condition for calling completer callback
The way we currently call completer callbacks is that if we've
found --option that user wants to complete value for and it has
callback set then the callback is called.

And just before that, if no --option to have the value completed
is found or is found and is of boolean type then a list of
--option is generated (for given command).

But these two conditions can never be true at the same time
because boolean type of --options do not accept values. Therefore
the calling of completer callback can be promoted onto the same
level as the --option list generation.

This means that merging of two lists can be dropped to and
completer callback can store its retval directly into @list (but
as shown earlier one of the string lists to merge is always
empty).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
b1eab47c2d vsh: Deduplicate filtering in vshReadlineCommandGenerator()
Completer callbacks generate all possible outputs ignoring any partial
input (e.g. prefix of a domain name) and then use vshCompleterFilter() to
filter out those strings which don't fit the partial input (prefix).

In contrast, vshReadlineCommandGenerator() does some internal filtering and
only generates completions that match a given prefix. Rather than treating
these scenarios differently, simply generate all possible options and
filter them all at the end.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
c3ea585e18 vsh: Deduplicate filtering in vshReadlineOptionsGenerator()
Completer callbacks generate all possible outputs ignoring any partial
input (e.g. prefix of a domain name) and then use vshCompleterFilter() to
filter out those strings which don't fit the partial input (prefix).

In contrast, vshReadlineOptionsGenerator() does some internal filtering and
only generates completions that match a given prefix. Rather than treating
these scenarios differently, simply generate all possible options and
filter them all at the end.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
3cc6572fab vsh: Rewrite opt->type check in vshReadlineParse()
The vshReadlineParse() function is called whenever user hits
<TAB><TAB>. If there is no command (or a partially written one),
then a list of possible commands is printed to the user. But, if
there is a command then its --options are generated. But
obviously, we can not generate --options if there already is an
--option that's expecting a value. For instance, consider:

  virsh # start --domain <TAB><TAB>

In this case we want to call completer for --domain option, but
that's a different story.

Anyway, the way that we currently check whether --options list
should be generated is checking the type of the last --option. If
it isn't DATA, STRING, INT, or ARGV (all these expect a value),
then we can generate --option list. Well, writing the condition
this way is needlessly verbose and also prone to errors (see
d9a320bf97 for example).

We know that boolean type does not require a value. This leaves
us with the only type that was not mentioned yet - VSH_OT_ALIAS.
This is a special type for backwards compatibility and it refers
to another --option which can be just any type.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
9ad2cb6e73 vsh: Use g_auto() for string lists returned in readline command/options generators
There are two functions that are used to generate completion
lists: vshReadlineCommandGenerator() for command names and
vshReadlineOptionsGenerator() for --options for given command.
Both return a string list, but may also fail while constructing
it. For that case, they call g_strfreev() explicitly, which is
needless since we have g_auto(GStrv).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
eac14234c8 vsh: Prefer g_strdup_printf() over g_snprintf() in vshReadlineOptionsGenerator()
The vshReadlineOptionsGenerator() function returns a string list
of all --options for given command. But the way that individual
items on the list are allocated can be written better.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
6ba61373b7 vsh: Accept NULL @list in vshCompleterFilter()
The aim of vshCompleterFilter() is to take a string list and a
prefix and remove all strings from the list that don't have the
desired prefix. The function is used to filter out those strings
returned by a completer callback that don't correspond with
user's (partial) input. For instance, domain name completer
virshDomainNameCompleter() returns all domain names and then
vshCompleterFilter() refines the list so that only domains with
correct prefix of their name are offered to user. This was a
design choice - it allows us to have shorter completers as they
do not have to copy the list filtering over and over.

Having said all of that, it may happen that a completer does not
return anything (e.g. there is no domain in requested state,
virsh is not connected and thus completer exited early, etc.). In
that case, the string list is NULL and vshCompleterFilter() can
simply return early.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
268f16293c vsh: Use g_auto(GStrv) to free string list returned by completer callback
This saves us explicit call of g_strfreev() in error path.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
58aeebe096 vsh: Don't put VSH_OT_ALIAS onto list of completions
We've invented VSH_OT_ALIAS type for --option so that we can
rewrite some --options (e.g. fix spelling). For instance
blkdeviotune command uses this feature heavily:
--options-with-dash are preferred over old
--options_with_underscore. Both versions are supported but only
the new ones (not aliased) are documented and reported in --help.

Except for options completer, which happily put also aliased
versions in front of user's eyes.

Note, there is a second (gross) way we use aliases: to rewrite
options from --oldoption to --newoption=value (for instance
--shareable option of attach-disk is an alias of
--mode=shareable). And just like with the previous group - don't
generate them into the list of possible options.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Michal Privoznik
d3b2d5158a lib: Substitute some STREQLEN with STRPREFIX
There are few cases where STREQLEN() is called like this:

  STREQLEN(var, string, strlen(string))

which is the same as STRPREFIX(var, string). Use STRPREFIX()
because it is more obvious what the check is doing.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2021-02-10 11:51:59 +01:00
Laine Stump
6b1595317c tools: replace VIR_FREE with g_free in all vir*Free() functions
Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
2021-02-05 00:20:45 -05:00
Michal Privoznik
aad2262b9e vsh: Allow double quotes imbalance for auto completion in vshCommandStringGetArg()
If user is trying to auto complete a value that contains a space,
they have two options: use backslash to escape space or use
quotes, like this:

  virsh # start --domain "domain with space<TAB>

However, in this case our tokenizer sees imbalance in (double)
quotes: there is a starting one that's missing its companion.
Well, that's obvious - user is still in process of writing the
command. What we need to do in this case is to ignore the
imbalance and return success (from the tokenizer) - readline will
handle closing the quote properly.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-01-26 16:46:41 +01:00
Michal Privoznik
22904b5702 vsh: Rework how option to complete is found
The way that auto completion works currently is that user's input
is parsed, and then we try to find the first --option (in the
parsed structure) that has the same value as user's input around
where <TAB> was pressed. For instance, for the following input:

  virsh # command --arg1 hello --arg2 world<TAB>

we will see "world" as text that user is trying to autocomplete
(this is affected by rl_basic_word_break_characters which
readline uses internally to break user's input into individual
words) and find that it is --arg2 that user is trying to
autocomplete. So far so good, for this naive approach. But
consider the following example:

  virsh # command --arg1 world --arg2 world<TAB>

Here, both arguments have the same value and because we see
"world" as text that user is trying to autocomplete we would
think that it is --arg1 that user wants to autocomplete. This is
obviously wrong.

Fortunately, readline stores the current position of cursor (into
rl_point) and we can use that when parsing user's input: whenever
we reach a position that matches the cursor then we know that
that is the place where <TAB> was pressed and hence that is the
--option that user wants to autocomplete. Readline stores the
cursor position as offset (numbered from 1) from the beginning of
user's input. We store this input into @parser->pos initially,
but then advance it as we tokenize it. Therefore, what we need is
to store the original position too.

Thanks to Martin who helped me with this.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-01-26 16:46:41 +01:00