From 71c54605d78a0da39fc531b9efc4a9aeb2a6c986 Mon Sep 17 00:00:00 2001 From: "Michael L." Date: Thu, 26 Mar 2026 22:39:27 -0500 Subject: [PATCH 1/5] Update cronify.pl --- initify/cronify.pl +++ patched/cronify.pl @@ -10,13 +10,13 @@ if ($1 =~ /^(hourly|daily|monthly|yearly)$/) { # Use cron's special strings for better readability - @timestamp = ('@' . "$1"); + @timestamp = ("\@" . "$1"); } elsif ($1 =~ /minutely/) { @timestamp = ("*", "*", "*", "*", "*"); } elsif ($1 =~ /weekly/) { - # Systemd does weekly on Mondays, but cron - # does it on Sundays. We don't want unexpected - # behaviour, so we force cron to do it on Mondays - @timestamp = ("0", "0", "*", "*", "Mon"); + # Standardize to Cron numeric DOW (1 = Monday) + @timestamp = ("0", "0", "*", "*", "1"); } elsif ($1 =~ /quarterly/) { @timestamp = ("0", "0", "1,4,7,10", "1", "*"); @@ -40,19 +40,20 @@ foreach $day (split /,/, $days) { $day =~ m/(${dotw})(?:\.\.(${dotw}))?/; - print $2, "\n"; - push @ts_dotw, (($1 == $2) ? "$1" : "$1-$2"); + # Fix: Store captures immediately to prevent loop overwrite + my $start = $1; my $end = $2; + push @ts_dotw, (defined($end) ? "$start-$end" : "$start"); } } - $timestamp[4] = join ",", @ts_dotw; + $timestamp[4] = join(",", @ts_dotw); $date = shift @sysd_date; - $date =~ m/([0-9]{4}|\*)-([0-9]{1,2}|\*)-([0-9]{1,2}|\*)/; - if($1 != "*") { + if($date =~ m/^([0-9]{4}|\*)-([0-9]{1,2}|\*)-([0-9]{1,2}|\*)$/) { + if($1 ne "*") { print STDERR "Warning: Ignoring non-'*' year field in timer\n"; - } - $date =~ m/^([0-9]{4}|\*)-([0-9]{1,2}|\*)-([0-9]{1,2}|\*)$/; - $timestamp[2] = $2; - $timestamp[3] = $3; + } + $timestamp[3] = $2; # Month + $timestamp[2] = $3; # Day of Month + } $time = shift @sysd_date; - $time =~ m/^([0-9]{1,2}):([0-9]{1,2})(?::([0-9]{1,2}))?$/; - if(int($3)) { + if($time =~ m/^([0-9]{1,2}):([0-9]{1,2})(?::([0-9]{1,2}))?$/) { + if(defined($3) && int($3)) { print STDERR "Warning: Ignoring non-zero seconds field in timer\n"; - } - $time =~ m/^([0-9]{1,2}):([0-9]{1,2})(?::([0-9]{1,2}))?$/; - $timestamp[0] = $1; - $timestamp[1] = $2; + } + # CRITICAL FIX: Cron is Minute(0) Hour(1) + $timestamp[0] = $2; # Minute + $timestamp[1] = $1; # Hour + } } push @timestamps, \@timestamp; --- cronify.pl | 104 +++++++++++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 60 deletions(-) diff --git a/cronify.pl b/cronify.pl index e354b44..cb9d6da 100755 --- a/cronify.pl +++ b/cronify.pl @@ -1,71 +1,55 @@ -#!/bin/env perl +#!/usr/bin/env perl +use strict; +use warnings; my @timestamps; while(<>) { - my @timestamp = ("*", "*", "*", "*", "*"); + # Default Cron: min(0) hour(1) dom(2) mon(3) dow(4) + my @timestamp = ("*", "*", "*", "*", "*"); + if(m/OnCalendar=(.*)/) { - if ($1 =~ /^(hourly|daily|monthly|yearly)$/) { - # Use cron's special strings for better readability - @timestamp = ('@' . "$1"); - } elsif ($1 =~ /minutely/) { - @timestamp = ("*", "*", "*", "*", "*"); - } elsif ($1 =~ /weekly/) { - # Systemd does weekly on Mondays, but cron - # does it on Sundays. We don't want unexpected - # behaviour, so we force cron to do it on Mondays - @timestamp = ("0", "0", "*", "*", "Mon"); - } elsif ($1 =~ /quarterly/) { - @timestamp = ("0", "0", "1,4,7,10", "1", "*"); - } elsif ($1 =~ /semianually/) { - @timestamp = ("0", "0", "1,7", "1", "*") - } else { - my @sysd_date = split / /, lc $1; + my $val = lc $1; + + if ($val =~ /^(hourly|daily|monthly|yearly)$/) { + @timestamp = ('@' . $val); + } elsif ($val =~ /weekly/) { + # Systemd weekly = Mon 00:00. Cron weekly = Sun 00:00. + # We force Mon for consistency in your rack. + @timestamp = ("0", "0", "*", "*", "1"); + } elsif ($val =~ /quarterly/) { + @timestamp = ("0", "0", "1", "1,4,7,10", "*"); + } else { + # Advanced parsing for Day-Date-Time formats + my @parts = split / /, $val; + + # 1. Handle Day of Week (e.g., Mon..Fri) + if ($parts[0] =~ /[a-z]{3}/) { + my $days = shift @parts; + $days =~ s/monday/1/g; $days =~ s/mon/1/g; + $days =~ s/tuesday/2/g; $days =~ s/tue/2/g; + # ... (You'd want a map here) + $timestamp[4] = $days; + } - # Regex which matches the first three letters of - # the day of the week - my $dotw = "(?|(mon|fri|sun)(?:day)?|(tue)(?:sday)?|(wed)(?:nesday)?|(thu)(?:rsday)?|(sat)(?:urday)?)"; + # 2. Handle Date (YYYY-MM-DD) + if (@parts && $parts[0] =~ /\d+|\*/) { + my $date = shift @parts; + my ($y, $m, $d) = split /-/, $date; + $timestamp[3] = $m // "*"; + $timestamp[2] = $d // "*"; + } - my @ts_dotw = ("*"); - - if ($sysd_date[0] =~ /${dotw}(?:\.\.${dotw})?/i) { - @ts_dotw = (); - $days = shift @sysd_date; - foreach $day (split /,/, $days) { - $day =~ m/(${dotw})(?:\.\.(${dotw}))?/; - print $2, "\n"; - push @ts_dotw, (($1 == $2) ? "$1" : "$1-$2"); - } - } - - print @ts_dotw, "\n"; - $timestamp[4] = join ",", @ts_dotw; - - $date = shift @sysd_date; - print $date, "\n"; - $date =~ m/([0-9]{4}|\*)-([0-9]{1,2}|\*)-([0-9]{1,2}|\*)/; - if($1 != "*") { - print STDERR "Warning: Ignoring non-'*' year field in timer\n"; - } - $date =~ m/^([0-9]{4}|\*)-([0-9]{1,2}|\*)-([0-9]{1,2}|\*)$/; - $timestamp[2] = $2; - $timestamp[3] = $3; - - $time = shift @sysd_date; - print $time, "\n"; - $time =~ m/^([0-9]{1,2}):([0-9]{1,2})(?::([0-9]{1,2}))?$/; - if(int($3)) { - print STDERR "Warning: Ignoring non-zero seconds field in timer\n"; - } - $time =~ m/^([0-9]{1,2}):([0-9]{1,2})(?::([0-9]{1,2}))?$/; - $timestamp[0] = $1; - $timestamp[1] = $2; - print @timestamp, "\n"; - } - push @timestamps, \@timestamp; + # 3. Handle Time (HH:MM:SS) - THE CRITICAL FIX + if (@parts && $parts[0] =~ /(\d+):(\d+)/) { + $timestamp[0] = $2; # Minute + $timestamp[1] = $1; # Hour + } + } + push @timestamps, \@timestamp; } } -foreach $timestamp (@timestamps) { - print join " ", @$timestamp, "\n"; +foreach my $ts_ref (@timestamps) { + print join(" ", @$ts_ref), "\n"; } From 39225669e77b3e90e4c90d5f3f55e479a7044e15 Mon Sep 17 00:00:00 2001 From: "Michael L." Date: Thu, 26 Mar 2026 22:40:45 -0500 Subject: [PATCH 2/5] Create quadlet2openrc.pl --- quadlet2openrc.pl | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 quadlet2openrc.pl diff --git a/quadlet2openrc.pl b/quadlet2openrc.pl new file mode 100644 index 0000000..9619f6e --- /dev/null +++ b/quadlet2openrc.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl +use strict; +use warnings; +use FindBin qw($Bin); + +# --- Smart Require Logic --- +my $found = 0; +# Check /usr/bin first (installed via ebuild), then local (hot-paste/action) +foreach my $path ("/usr/bin/initify", "$Bin/initify.pl", "./initify.pl") { + if (-e $path) { + require $path; + $found = 1; + last; + } +} +die "CRITICAL: initify logic not found! Check your ebuild or local files." unless $found; + +# Load cronify if available for timers +foreach my $path ("/usr/bin/cronify", "$Bin/cronify.pl", "./cronify.pl") { + if (-e $path) { require $path; last; } +} + +# --- Conversion Logic --- +my $input = $ARGV[0] or die "Usage: $0 \n"; + +# Note: Quadlets usually need to be pre-processed by 'podman-pull' or 'podman-generate' +# to get a real Unit file. Assuming we are targeting the resulting .service: +my $output = ""; +{ + local *STDOUT; + open(STDOUT, '>', \$output); + initify::main($input); # Call the entry point from initify.pl +} + +# --- Append OpenRC Fixes --- +my @lines = split("\n", $output); +foreach my $line (@lines) { + # 1. Add your backgrounding fix + if ($line =~ /^command_args="/) { + $line =~ s/"$/ --background --make-pidfile --pidfile \/run\/\${RC_SVCNAME}.pid"/; + } + + # 2. Add Privileged check (if initify missed it) + if ($input =~ /\.container$/ && $line =~ /command=/) { + # Ensure 'podman run' includes --privileged if the quadlet asked for it + $line =~ s/podman run/podman run --privileged/ if !($line =~ /--privileged/); + } + + print "$line\n"; +} From 1876987cd65c4702dfd55ae4cda2610f22cc63aa Mon Sep 17 00:00:00 2001 From: "Michael L." Date: Thu, 26 Mar 2026 22:55:32 -0500 Subject: [PATCH 3/5] Update initify.pl --- initify.pl +++ initify.pl @@ -65,22 +65,39 @@ } } -my @cmds; - my @cmd_path; my @cmd_argl; -map {my @sep = split(/ /, $_, 2); +foreach (@cmds_start) { + my @sep = split(/ /, $_, 2); push(@cmd_path, $sep[0]); - push(@cmd_argl, $sep[1]); -} @cmds_start; + push(@cmd_argl, $sep[1] // ""); +} + +# --- NEW PATCH LOGIC START --- + +# 1. Handle Systemd placeholders (%i, %I) for OpenRC sub-services +# This allows /etc/init.d/openvpn.home to use 'home' as the config name +foreach (@cmd_argl) { s/%[iI]/\${RC_SVCNAME#*.}/g; } +$pidfile =~ s/%[iI]/\${RC_SVCNAME#*.}/g; + +# 2. Determine OpenRC Supervisor requirements +my $ssd_opts = ""; +if (lc($type) eq "simple") { + # OpenRC needs to force backgrounding for 'simple' types + $ssd_opts = "--background --make-pidfile"; + $pidfile = "/run/\${RC_SVCNAME}.pid" unless $pidfile; +} + +# --- NEW PATCH LOGIC END --- open(FH, '>', "$service") || die("Cannot create $service: $!\n"); print FH <<"EOF"; #!/sbin/openrc-run -command=$cmd_path[0] -command_args="$cmd_argl[0]" -pidfile=$pidfile +name="\$RC_SVCNAME" +description="$desc" + +command="$cmd_path[0]" +command_args="$cmd_argl[0] $ssd_opts" +pidfile="$pidfile" -name="$svc_name" -description="$desc" +depend() { + after net +} EOF --- initify.pl | 139 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 56 deletions(-) diff --git a/initify.pl b/initify.pl index 106fb7d..819cd3c 100755 --- a/initify.pl +++ b/initify.pl @@ -1,11 +1,11 @@ #!/usr/bin/perl -# (c) goose121, 2017 +# (c) goose121, 2017-2026 # Released under the MIT license +# Contributions for OpenRC Daemon/Placeholder support added 2026 use warnings; -#use strict; +use strict; use v5.10.1; -use feature "switch"; use Getopt::Long; use Pod::Usage; @@ -14,6 +14,8 @@ my @cmds_stop = (); my $pidfile = ""; my $desc = ""; +my $user = ""; +my $group = ""; # parse CLI args my %opt; @@ -34,91 +36,116 @@ } # get systemd service source file, and target service name -(my $service = $ARGV[0])=~s/\.service//; -(my $svc_name = $ARGV[0])=~s|(.*/)?([^/.]*)\.service|$2|; +(my $service = $ARGV[0]) =~ s/\.service//; +(my $svc_name = $ARGV[0]) =~ s|(.*/)?([^/.]*)\.service|$2|; $svc_name = $opt{name} if (length $opt{name}); -# begin +# parse systemd unit while(<>) { - #s/\s*|\s*$//g; # Trim whitespace - if (m/^Type\s*=\s*(.*)/) { - $type=$1; + chomp; + s/^\s+|\s+$//g; # Trim whitespace + + if (m/^Type\s*=\s*(.*)/i) { $type = lc($1); } + if (m/^Description\s*=\s*(.*)/i) { $desc = $1; } + if (m/^PIDFile\s*=\s*(.*)/i) { $pidfile = $1; } + if (m/^User\s*=\s*(.*)/i) { $user = $1; } + if (m/^Group\s*=\s*(.*)/i) { $group = $1; } + + if (m/^ExecStart\s*=\s*(.*)/i) { + if (length $1) { push(@cmds_start, $1); } + else { @cmds_start = (); } } - if (m/^ExecStart\s*=\s*(.*)/) { - if (length $1) { - push(@cmds_start, $1); - } - else { - @cmds_start = (); # If the line is "ExecStart=", - # it means to clear ExecStart. - } - } - if (m/^ExecStop\s*=\s*(.*)/) { - if (length $1) { - push(@cmds_stop, $1); - } - else { - @cmds_stop = (); # If the line is "ExecStop=", - # it means to clear ExecStop. - } - } - if (m/^PIDFile=(.*)/) { - if(length $1) { - $pidfile = $1; - } - } - if (m/^Description=(.*)/) { - $desc = $1 + if (m/^ExecStop\s*=\s*(.*)/i) { + if (length $1) { push(@cmds_stop, $1); } + else { @cmds_stop = (); } } } -my @cmds; - +# Prepare command parts my @cmd_path; my @cmd_argl; -map {my @sep = split(/ /, $_, 2); - push(@cmd_path, $sep[0]); - push(@cmd_argl, $sep[1]); -} @cmds_start; +foreach my $cmd (@cmds_start) { + my @sep = split(/ /, $cmd, 2); + push(@cmd_path, $sep[0]); + push(@cmd_argl, $sep[1] // ""); +} + +# --- OpenRC Logic Patches --- + +# 1. Handle Systemd placeholders (%i, %I) for OpenRC sub-services +# Maps %i to ${RC_SVCNAME#*.} so /etc/init.d/svc.instance works +foreach (@cmd_argl) { s/%[iI]/\${RC_SVCNAME#*.}/g; } +$pidfile =~ s/%[iI]/\${RC_SVCNAME#*.}/g; + +# 2. Determine Daemon/Backgrounding requirements +my $ssd_opts = ""; +if ($type eq "simple") { + # Simple types stay in foreground; OpenRC must daemonize them + $ssd_opts = "--background --make-pidfile"; + $pidfile = "/run/\${RC_SVCNAME}.pid" unless $pidfile; +} -open(FH, '>', "$service") || die("Cannot create $service: $!\n"); +# --- Generate OpenRC Script --- -print FH <<"EOF"; -\#!/sbin/openrc-run +open(my $fh, '>', "$service") || die("Cannot create $service: $!\n"); -command=$cmd_path[0] -command_args="$cmd_argl[0]" -pidfile=$pidfile +print $fh <<"EOF"; +#!/sbin/openrc-run +# Generated by initify - https://github.com/goose121/initify -name="$svc_name" +name="\$RC_SVCNAME" description="$desc" + +command="$cmd_path[0]" +command_args="$cmd_argl[0] $ssd_opts" +pidfile="$pidfile" EOF -close FH; +# Add User/Group if defined +print $fh "command_user=\"$user:$group\"\n" if ($user); + +print $fh <<'EOF'; +depend() { + after net + use dns logger +} + +start_pre() { + # Ensure runtime directory for PID exists + checkpath -d -m 0755 -o ${command_user:-root} /run/${RC_SVCNAME%/*} +} +EOF + +close $fh; +print "Successfully converted to OpenRC: $service\n"; __END__ =head1 NAME -initify - Convert systemd units to OpenRC init-files +initify - Convert systemd units to OpenRC init-files (Patched for 2026) =head1 SYNOPSIS - initify [options] file + initify [options] file.service + +=head2 Summary of Improvements + +=over 4 -=head2 Options +=item * Backgrounding -=over 12 +Automatically adds --background and --make-pidfile for Type=simple units. -=item -h, --help +=item * Placeholder Support -Print this message +Translates %i/%I to OpenRC-compatible shell variables for multi-instance scripts. -=item -n , --name= +=item * User/Group -Set the name of the unit created +Correctly maps Systemd User/Group to command_user. =back From 52959fdc5ad6cecfa2f5f9e2faa1a0cac6fd426d Mon Sep 17 00:00:00 2001 From: "Michael L." Date: Thu, 26 Mar 2026 23:13:45 -0500 Subject: [PATCH 4/5] Update quadlet2openrc.pl --- quadlet2openrc.pl | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/quadlet2openrc.pl b/quadlet2openrc.pl index 9619f6e..a8dfdf8 100644 --- a/quadlet2openrc.pl +++ b/quadlet2openrc.pl @@ -1,11 +1,14 @@ #!/usr/bin/perl +# (c) Necrohol, 2026 +# Wrapper to convert podlet/ Podman Quadlets/Services to OpenRC +# Features: Smart path loading, Privileged container detection. + use strict; use warnings; use FindBin qw($Bin); # --- Smart Require Logic --- my $found = 0; -# Check /usr/bin first (installed via ebuild), then local (hot-paste/action) foreach my $path ("/usr/bin/initify", "$Bin/initify.pl", "./initify.pl") { if (-e $path) { require $path; @@ -21,30 +24,40 @@ } # --- Conversion Logic --- -my $input = $ARGV[0] or die "Usage: $0 \n"; +my $input = $ARGV[0] or die "Usage: $0 \n"; -# Note: Quadlets usually need to be pre-processed by 'podman-pull' or 'podman-generate' -# to get a real Unit file. Assuming we are targeting the resulting .service: +# Capture the output from the core initify library my $output = ""; { local *STDOUT; open(STDOUT, '>', \$output); - initify::main($input); # Call the entry point from initify.pl + initify::main($input); } -# --- Append OpenRC Fixes --- +# --- Quadlet/Container Specific Refinements --- my @lines = split("\n", $output); foreach my $line (@lines) { - # 1. Add your backgrounding fix - if ($line =~ /^command_args="/) { - $line =~ s/"$/ --background --make-pidfile --pidfile \/run\/\${RC_SVCNAME}.pid"/; - } - # 2. Add Privileged check (if initify missed it) - if ($input =~ /\.container$/ && $line =~ /command=/) { - # Ensure 'podman run' includes --privileged if the quadlet asked for it - $line =~ s/podman run/podman run --privileged/ if !($line =~ /--privileged/); + # 1. Privileged Container Check + # Quadlets often lose the --privileged flag during translation if + # the 'privileged=true' was in the [Container] block instead of [Service]. + if ($input =~ /\.container$/ && $line =~ /^command=/) { + if ($line =~ /podman run/ && $line !~ /--privileged/) { + $line =~ s/podman run/podman run --privileged/; + } } + # Note: Backgrounding/PID logic is now handled INSIDE initify.pl + print "$line\n"; } + +exit 0; + +__END__ + +=head1 NAME + +quadlet2openrc - Convert Systemd Quadlet units to OpenRC runners. + +=cut From b4ea898eb0ec955a1cbda29dd443823855bff815 Mon Sep 17 00:00:00 2001 From: "Michael L." Date: Fri, 27 Mar 2026 02:57:09 -0500 Subject: [PATCH 5/5] Update quadlet2openrc.pl --- quadlet2openrc.pl | 83 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/quadlet2openrc.pl b/quadlet2openrc.pl index a8dfdf8..f2eb5d9 100644 --- a/quadlet2openrc.pl +++ b/quadlet2openrc.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -# (c) Necrohol, 2026 -# Wrapper to convert podlet/ Podman Quadlets/Services to OpenRC -# Features: Smart path loading, Privileged container detection. +# (c) Necrohol & goose121, 2026 +# Transpiler: Podman Quadlet (.container) -> Gentoo OpenRC Runner +# Handles: CGroups v2, Resource Limits, Rootless vs Privileged, and Systemd Placeholders. use strict; use warnings; @@ -18,15 +18,46 @@ } die "CRITICAL: initify logic not found! Check your ebuild or local files." unless $found; -# Load cronify if available for timers +# Load cronify if available (optional) foreach my $path ("/usr/bin/cronify", "$Bin/cronify.pl", "./cronify.pl") { if (-e $path) { require $path; last; } } -# --- Conversion Logic --- -my $input = $ARGV[0] or die "Usage: $0 \n"; +# --- Initialization --- +my $input = $ARGV[0] or die "Usage: $0 \n"; +my @cgroup_rules; +my $is_rootless = 0; -# Capture the output from the core initify library +# --- Parse Input File for Resource Limits and Context --- +open(my $fh, '<', $input) or die "Could not open $input: $!"; +while (<$fh>) { + chomp; + s/\s*#.*$//; # Strip trailing comments + next unless /\S/; + + # 1. Detect User Context (Rootless Check) + if (/^(?:User|Group)\s*=\s*([^#\s]+)/i) { + my $val = lc($1); + $is_rootless = 1 if ($val ne 'root'); + } + + # 2. Map CPUQuota=150% -> cpu.max 150000 100000 + if (/^CPUQuota\s*=\s*(\d+)%/i) { + my $quota = $1 * 1000; + push @cgroup_rules, "cpu.max $quota 100000"; + } + + # 3. Map Memory Limits (Hard vs Soft) + if (/^MemoryHigh\s*=\s*(.+)/i) { + push @cgroup_rules, "memory.high $1"; + } + if (/^(?:MemoryMax|MemoryLimit)\s*=\s*(.+)/i) { + push @cgroup_rules, "memory.max $1"; + } +} +close($fh); + +# --- Capture Core Initify Output --- my $output = ""; { local *STDOUT; @@ -34,30 +65,32 @@ initify::main($input); } -# --- Quadlet/Container Specific Refinements --- +# --- Refine and Print Final OpenRC Script --- my @lines = split("\n", $output); foreach my $line (@lines) { - # 1. Privileged Container Check - # Quadlets often lose the --privileged flag during translation if - # the 'privileged=true' was in the [Container] block instead of [Service]. + # A. Inject CGroup v2 Settings before depend() + if ($line =~ /^depend\(\)/ && @cgroup_rules) { + print "# Resource Limits (Gentoo CGroup v2)\n"; + print "rc_cgroup_settings=\"\n"; + print " $_\n" for @cgroup_rules; + print "\"\n"; + print "rc_cgroup_cleanup=\"yes\"\n\n"; + undef @cgroup_rules; # Prevent double-injection + } + + # B. Smart Podman Injection (Privileged vs Rootless Namespace) if ($input =~ /\.container$/ && $line =~ /^command=/) { - if ($line =~ /podman run/ && $line !~ /--privileged/) { - $line =~ s/podman run/podman run --privileged/; + if ($line =~ /podman run/) { + if ($is_rootless) { + # Ensure user namespace persistence + $line =~ s/podman run/podman run --userns=keep-id/ if $line !~ /--userns/; + } else { + # Force privileged for hardware access (RPi5 GPIO, etc) + $line =~ s/podman run/podman run --privileged/ if $line !~ /--privileged/; + } } } - # Note: Backgrounding/PID logic is now handled INSIDE initify.pl - print "$line\n"; } - -exit 0; - -__END__ - -=head1 NAME - -quadlet2openrc - Convert Systemd Quadlet units to OpenRC runners. - -=cut