From c4945bf96b23793f5d2b399ef449fda0793be00c Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Sat, 19 Oct 2024 16:11:38 +0200 Subject: [PATCH] tools: load PerlIO explicitly to avoid odd failures Since commit ef0bcc9 ("tools: file_set_contents: use syswrite instead of print") we're using PerlIO's scalar layer to ensure we encode any potential unicode before passing the data to syswrite, which does not support writing code points above 255. Add an explicit use statement for PerlIO::scalar to avoid some odd failures. Some more background on why this seems odd: After the pve-common version that included this change got moved to public repos we got some reports in our Forum about CTs failing to start [0] due to the lxc-pve-prestart-hook failing with an error message like: > Can't locate PerlIO.pm in @INC [...] at /usr/share/perl5/PVE/Tools.pm line 293. Which points to the recently added `open(my $data_fh, '>', \$data)` line in file_set_contents. The call chain from there upwards was $lxc_setup->ct_file_set_contents <- $lxc_setup->pre_start_hook <- closure <- lxc_hook <- lxc-pve-prestart-hook. This seemed especially odd as we use `file_set_contents` in a lot of other places and there was no all to obvious breakage from the change on our test systems. During evaluation I noticed some additional strange behavior, if one called `file_set_contents` inside the closure before the call to `pre_start_hook`, the error just goes away and one can observer that %INC, which contains all loaded modules, suddenly does have a entry for the PerlIO module, or well, it's scalar layer, which it did not have without that call. So why the PerlIO can get automatically loaded just fine most of the time but not inside the `pre_start_hook` is not really clear yet; still loading PerlIO explicitly makes the issue go away and seems sensible, so go for that and keep a comment to remind more explicitly of this oddity. Once it's explained it can be removed with a commit that mentions the explanation. Further, if the PerlIO scalar layer cannot be loaded, the result is that the passed reference is used as filename, which is far from ideal, see the report in the perl GH [1] and the PR that fixes this [2] by moving PerlIO::scalar into perl core proper, which will be available in Perl v5.40 and thus our next Debian Trixie based major release. This might have well to do with the original symptom that embarked me on this odd (and not 100% finished) quest.. [0]: https://forum.proxmox.com/threads/156188/ [1]: https://github.com/Perl/perl5/issues/21275 [2]: https://github.com/Perl/perl5/pull/21282 Signed-off-by: Thomas Lamprecht --- src/PVE/Tools.pm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm index b354039..d31120f 100644 --- a/src/PVE/Tools.pm +++ b/src/PVE/Tools.pm @@ -290,6 +290,13 @@ sub file_set_contents { } else { # Encode wide characters with print before passing them to syswrite my $unencoded_data = $data; + # Without this we get some "Can't locate PerlIO.pm in @INC" errors _sometimes_, and the + # odd thing about it is that they can be "fixed" by calling file_set_contents in the + # parent methode/code before the method, from another module, is called. + # Anyway, loading PerlIO here should be fine as the in-memory variable writing is in + # fact backed by the PerlIO based "scalar" module. This comment can be removed once the + # odd behavior is really understood. + use PerlIO::scalar; open(my $data_fh, '>', \$data) or die "failed to open in-memory variable - $!\n"; print $data_fh $unencoded_data; close($data_fh);