--- recover.qi.pl	2015-07-13 13:36:09.572397781 +0200
+++ recover.qi2.pl	2020-02-05 14:24:34.542077545 +0100
@@ -10,23 +10,32 @@
 use strict;
 use Getopt::Long;
 
-my %opt = ();
-GetOptions(\%opt,"spool|w=s","basename|f=s","digits|d=i","help!");
-if ($opt{help}) {
-  print "Usage:
-\t$0 -w WorkDirectory -f QueueFileName -d 8 > QueueFileName.qi
-";
-  exit;
-}
+my $spool = ".";
+my $digits = 8;
+my $basename;
+
+GetOptions( "spool|w=s"    => \$spool,
+            "basename|f=s" => \$basename,
+            "digits|d=i"   => \$digits,
+          )
+or die "Usage:
+\t$0 -w WorkDirectory -f QueueFileName -d 8";
+
+my $qifile = "$basename.qi";
 
 # runtime/queue.c: qConstructDisk()
-my $iMaxFiles = 10000000; # 0+"1".( "0"x($opt{digits} - 1));
+my $iMaxFiles = 10000000; # 0+"1".( "0"x($digits - 1));
+
+my @qf;
+sub getQueueFiles {
+  # get the list of queue files, spool directory excluded
+  my $re = qr/^\Q$basename\E\.\d{$digits}$/;
+  opendir(DIR, $spool) or die "can’t open spool: $!";
+  @qf = grep { /$re/ && -f "$spool/$_" } readdir(DIR);
+  closedir DIR;
+}
 
-# get the list of queue files, spool directory excluded
-my $re = qr/^\Q$opt{basename}\E\.\d{$opt{digits}}$/;
-opendir(DIR, $opt{spool}) or die "can’t open spool: $!";
-my @qf = grep { /$re/ && -f "$opt{spool}/$_" } readdir(DIR);
-closedir DIR;
+getQueueFiles();
 
 # ensure order and continuity
 @qf = sort @qf;
@@ -35,13 +44,22 @@
 $head += 0;
 $tail += 0;
 if ($tail-$head+1 != @qf || $tail > $iMaxFiles) {
-  die "broken queue: missing file(s) or wrong tail:$tail, head:$head, max:$iMaxFiles, num=$@qf\n";
+  print STDERR "\tbroken queue: missing file(s) or wrong tail:$tail, head:$head, max:$iMaxFiles, num=$@qf\n";
+  print STDERR "\treordering queue files";
+  my $qid = "1";
+  foreach my $file ( @qf ) {
+    my $qsuf = sprintf("%08d", $qid);
+    #print STDERR "$file $basename.$qsuf\n";
+    rename $file, "$basename.$qsuf" or die "Cannot rename $file to $basename.$qsuf: $!";
+    $qid++;
+  }
+  getQueueFiles();
 }
 
 # collect some counters about the queue, assuming all are unprocessed entries.
 my $sizeOnDisk = 0;
 my $iQueueSize = 0;
-chdir($opt{spool}) or die "can't chdir to spool: $!";
+chdir($spool) or die "can't chdir to spool: $!";
 print STDERR "traversing ". @qf ." files, please wait...\n";
 for (@qf) {
   open FH, "<", $_ or die "can't read queue file $_\n";
@@ -70,7 +88,7 @@
 # write to end
 my $strm_Write = Rsyslog::Obj->new("strm",1);
 $strm_Write->property(      "iCurrFNum",  "INT",                     $tail);
-$strm_Write->property(       "pszFName",  "PSZ",            $opt{basename});
+$strm_Write->property(       "pszFName",  "PSZ",                 $basename);
 $strm_Write->property(      "iMaxFiles",  "INT",                $iMaxFiles);
 $strm_Write->property( "bDeleteOnClose",  "INT",                         0);
 $strm_Write->property(          "sType",  "INT", $STREAMTYPE_FILE_CIRCULAR);
@@ -80,7 +98,7 @@
 # read from head
 my $strm_ReadDel = Rsyslog::Obj->new("strm",1);
 $strm_ReadDel->property(      "iCurrFNum",  "INT",                     $head);
-$strm_ReadDel->property(       "pszFName",  "PSZ",            $opt{basename});
+$strm_ReadDel->property(       "pszFName",  "PSZ",                 $basename);
 $strm_ReadDel->property(      "iMaxFiles",  "INT",                $iMaxFiles);
 $strm_ReadDel->property( "bDeleteOnClose",  "INT",                         1);
 $strm_ReadDel->property(          "sType",  "INT", $STREAMTYPE_FILE_CIRCULAR);
@@ -89,9 +107,13 @@
 $strm_ReadDel->property(      "iCurrOffs","INT64",                         0);
 
 # .qi
-print $qqueue->serialize();
-print $strm_Write->serialize();
-print $strm_ReadDel->serialize();
+open(my $fh, '>', $qifile) or die "Could not open file '$qifile' $!";
+
+print $fh $qqueue->serialize();
+print $fh $strm_Write->serialize();
+print $fh $strm_ReadDel->serialize();
+
+close $fh;
 
 exit;
 #-----------------------------------------------------------------------------
