diff --git a/test b/test
new file mode 120000
index 000000000..0c272b615
--- /dev/null
+++ b/test
@@ -0,0 +1 @@
+user/apps/tests
\ No newline at end of file
diff --git a/user/apps/tests/README.md b/user/apps/tests/README.md
new file mode 100644
index 000000000..59b7d2535
--- /dev/null
+++ b/user/apps/tests/README.md
@@ -0,0 +1,5 @@
+Test Tookit Overview
+=========================
+
+## Brief Introduction
+This Directory contains all using test toolkit and source for DragonOS, including **compatible test** and **performance benchmarks**.
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/README.md b/user/apps/tests/benchmark/README.md
new file mode 100644
index 000000000..77b51422f
--- /dev/null
+++ b/user/apps/tests/benchmark/README.md
@@ -0,0 +1,2 @@
+Benchmark Overview
+===================
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/alternatives/README b/user/apps/tests/benchmark/lmbench/sysroot/etc/alternatives/README
new file mode 100644
index 000000000..4c4d21567
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/alternatives/README
@@ -0,0 +1,2 @@
+Please read the update-alternatives(1) man page for information on this
+directory and its contents.
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/cron.daily/dpkg b/user/apps/tests/benchmark/lmbench/sysroot/etc/cron.daily/dpkg
new file mode 100755
index 000000000..899572d72
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/cron.daily/dpkg
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Skip if systemd is running.
+if [ -d /run/systemd/system ]; then
+ exit 0
+fi
+
+/usr/libexec/dpkg/dpkg-db-backup
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/dpkg/dpkg.cfg b/user/apps/tests/benchmark/lmbench/sysroot/etc/dpkg/dpkg.cfg
new file mode 100644
index 000000000..ba898ee8b
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/dpkg/dpkg.cfg
@@ -0,0 +1,13 @@
+# dpkg configuration file
+#
+# This file can contain default options for dpkg. All command-line
+# options are allowed. Values can be specified by putting them after
+# the option, separated by whitespace and/or an `=' sign.
+#
+
+# Do not enable debsig-verify by default; since the distribution is not using
+# embedded signatures, debsig-verify would reject all packages.
+no-debsig
+
+# Log status changes and actions to a file.
+log /var/log/dpkg.log
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/gprofng.rc b/user/apps/tests/benchmark/lmbench/sysroot/etc/gprofng.rc
new file mode 100644
index 000000000..188ce7a34
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/gprofng.rc
@@ -0,0 +1,134 @@
+# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# .
+#
+# Specify which classes of compiler commentary will be shown
+# with annotated source.
+scc all
+
+# Specify which classes of compiler commentary will be shown
+# with annotated disassembly
+dcc all:src
+
+# Set the default function-list metrics
+# for heap data, show inclusive leaks and bytes leaked; not allocations
+dmetrics i.heapleakbytes:e!heapleakbytes
+dmetrics i.heapleakcnt:e!heapleakcnt
+dmetrics i.heapallocbytes:e!heapallocbytes
+dmetrics i.heapalloccnt:e!heapalloccnt:
+
+# Clock profiling data
+# Note: use same display order of LMS_* in: er.rc, TimelineVariable.java,
+# Ovw_data.h, BaseMetricTreeNode.cc and Experiment.cc metric registration
+dmetrics i!total:e!.total
+# Show total cpu time
+dmetrics ei%.totalcpu
+dmetrics i!.user:e!.user
+dmetrics i!system:e!.system
+dmetrics i!trap:e!.trap
+dmetrics i!lock:e!.lock
+dmetrics i!datapfault:e!.datapfault
+dmetrics i!textpfault:e!.textpfault
+dmetrics i!kernelpfault:e!.kernelpfault
+dmetrics i!stop:e!.stop
+dmetrics i!wait:e!.wait
+dmetrics i!sleep:e!.sleep
+
+# for kernel clock profiling data, show inclusive and exclusive KCPU
+dmetrics ei.kcpu
+###dmetrics ie.kcpu
+
+# for count data, show exclusive metrics only
+dmetrics i!bit:e.bit
+
+# for er_generic data, show exclusive metrics only
+dmetrics i!icount:e.icount
+
+# Hide implementation hack. Functionmark column only serves
+# to force zero-count functions to be displayed.
+dmetrics e!bit_FM
+
+# for kernel profiles, show inclusive and exclusive kucycles and kcycles
+# (kucycles and kcycles are for 12.3 and older experiments, Obsolete TBR)
+dmetrics ei.kucycles:ei.kcycles
+###dmetrics ie.kucycles:ie.kcycles
+
+# for derived HWC metrics, show exclusive only
+dmetrics i!IPC:e!.IPC
+dmetrics i!CPI:e!.CPI
+dmetrics i!K_IPC:e!.K_IPC
+dmetrics i!K_CPI:e!.K_CPI
+
+# for HWC, show exclusive only
+dmetrics i!hwc:e%.hwc
+
+# for synctrace, show inclusive only
+dmetrics i.sync:e!sync
+dmetrics i.syncn:e!syncn
+
+# Set the default function-list metrics for OMP profiling
+dmetrics i.ompwork:e!ompwork
+dmetrics i.ompwait:e!ompwait
+dmetrics i!.masterthread:e!.masterthread
+
+#set the default function-list metrics for deadlock detection
+dmetrics i!deadlocks:e.deadlocks
+
+# io data
+dmetrics i.ioreadtime:e!ioreadtime
+dmetrics i.iowritetime:e!iowritetime
+dmetrics i.ioothertime:e!ioothertime
+dmetrics i.ioerrortime:e!ioerrortime
+dmetrics i!.ioreadcnt:e!ioreadcnt
+dmetrics i!.ioreadbytes:e!ioreadbytes
+dmetrics i!.iowritecnt:e!iowritecnt
+dmetrics i!.iowritebytes:e!iowritebytes
+dmetrics i!.ioothercnt:e!ioothercnt
+dmetrics i!.ioerrorcnt:e!ioerrorcnt
+
+# for any other unnamed metrics, don't show them
+dmetrics ie!.any
+
+# don't show size or address; show name
+dmetrics !size:!address:name
+
+# Select the default function-list sorting metric
+dsort ei.any:name
+###dsort ie.any:name
+
+# Set function name style
+name long
+
+# Set View mode to user
+viewmode user
+
+# Set compare mode
+compare off
+
+# Set enabling descendants to on
+en_desc on
+
+# Set path where the gprofng libraries are installed
+preload_libdirs ../lib:../lib32:../lib64
+
+# Add search path for annotated source and disasm
+addpath $expts:.
+
+# Add controls for specific load objects
+# object_hide
+
+# gprofng GUI tabs
+tabs dsrc:function:timeline:processes:threads:ctree:callflame:src:dis:leaks:ioactivity:ifreq:callers-callees:header
+
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/ld.so.conf.d/x86_64-linux-gnu.conf b/user/apps/tests/benchmark/lmbench/sysroot/etc/ld.so.conf.d/x86_64-linux-gnu.conf
new file mode 100644
index 000000000..cd691abf2
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/ld.so.conf.d/x86_64-linux-gnu.conf
@@ -0,0 +1,4 @@
+# Multiarch support
+/usr/local/lib/x86_64-linux-gnu
+/lib/x86_64-linux-gnu
+/usr/lib/x86_64-linux-gnu
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/logrotate.d/alternatives b/user/apps/tests/benchmark/lmbench/sysroot/etc/logrotate.d/alternatives
new file mode 100644
index 000000000..41c8a9c0a
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/logrotate.d/alternatives
@@ -0,0 +1,9 @@
+/var/log/alternatives.log {
+ monthly
+ rotate 12
+ compress
+ delaycompress
+ missingok
+ notifempty
+ create 644 root root
+}
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/logrotate.d/dpkg b/user/apps/tests/benchmark/lmbench/sysroot/etc/logrotate.d/dpkg
new file mode 100644
index 000000000..cf36f081f
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/logrotate.d/dpkg
@@ -0,0 +1,9 @@
+/var/log/dpkg.log {
+ monthly
+ rotate 12
+ compress
+ delaycompress
+ missingok
+ notifempty
+ create 644 root root
+}
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/netconfig b/user/apps/tests/benchmark/lmbench/sysroot/etc/netconfig
new file mode 100644
index 000000000..effc67eb0
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/netconfig
@@ -0,0 +1,19 @@
+#
+# The network configuration file. This file is currently only used in
+# conjunction with the TI-RPC code in the libtirpc library.
+#
+# Entries consist of:
+#
+# \
+#
+#
+# The and fields are always empty in this
+# implementation.
+#
+udp tpi_clts v inet udp - -
+tcp tpi_cots_ord v inet tcp - -
+udp6 tpi_clts v inet6 udp - -
+tcp6 tpi_cots_ord v inet6 tcp - -
+rawip tpi_raw - inet - - -
+local tpi_cots_ord - loopback - - -
+unix tpi_cots_ord - loopback - - -
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/perl/Net/libnet.cfg b/user/apps/tests/benchmark/lmbench/sysroot/etc/perl/Net/libnet.cfg
new file mode 100644
index 000000000..293658212
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/perl/Net/libnet.cfg
@@ -0,0 +1,21 @@
+# Prior to perl 5.8.8-7, libnet was a seperate package with a debconf
+# configuration managed config in /etc/libnet.cfg which is used if
+# present. Remove the following line, or the old file before making
+# changes below.
+return do '/etc/libnet.cfg' if -f '/etc/libnet.cfg';
+
+{
+ nntp_hosts => [ qw {} ],
+ snpp_hosts => [ qw {} ],
+ pop3_hosts => [ qw {} ],
+ smtp_hosts => [ qw {} ],
+ ph_hosts => [ qw {} ],
+ daytime_hosts => [ qw {} ],
+ time_hosts => [ qw {} ],
+ inet_domain => undef,
+ ftp_firewall => qq {},
+ ftp_firewall_type => qq {},
+ ftp_ext_passive => 0,
+ ftp_int_passive => 0,
+ local_netmask => qq {},
+}
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/etc/rmt b/user/apps/tests/benchmark/lmbench/sysroot/etc/rmt
new file mode 120000
index 000000000..34d899416
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/etc/rmt
@@ -0,0 +1 @@
+/usr/sbin/rmt
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/addr2line b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/addr2line
new file mode 120000
index 000000000..30b10e062
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/addr2line
@@ -0,0 +1 @@
+x86_64-linux-gnu-addr2line
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/ar b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/ar
new file mode 120000
index 000000000..1837c50b5
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/ar
@@ -0,0 +1 @@
+x86_64-linux-gnu-ar
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/as b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/as
new file mode 120000
index 000000000..db6647454
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/as
@@ -0,0 +1 @@
+x86_64-linux-gnu-as
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c++filt b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c++filt
new file mode 120000
index 000000000..b86713479
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c++filt
@@ -0,0 +1 @@
+x86_64-linux-gnu-c++filt
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c89-gcc b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c89-gcc
new file mode 100755
index 000000000..d0a3c1e63
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c89-gcc
@@ -0,0 +1,23 @@
+#! /bin/sh
+
+# Call the appropriate C compiler with options to accept ANSI/ISO C
+# The following options are the same (as of gcc-2.95):
+# -ansi
+# -std=c89
+# -std=iso9899:1990
+
+extra_flag=-std=c89
+
+for i; do
+ case "$i" in
+ -ansi|-std=c89|-std=iso9899:1990)
+ extra_flag=
+ ;;
+ -std=*)
+ echo >&2 "`basename $0` called with non ANSI/ISO C option $i"
+ exit 1
+ ;;
+ esac
+done
+
+exec gcc $extra_flag ${1+"$@"}
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c99-gcc b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c99-gcc
new file mode 100755
index 000000000..046d30b75
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/c99-gcc
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+# Call the appropriate C compiler with options to accept ANSI/ISO C
+# The following options are the same (as of gcc-3.3):
+# -std=c99
+# -std=c9x
+# -std=iso9899:1999
+# -std=iso9899:199x
+
+extra_flag=-std=c99
+
+for i; do
+ case "$i" in
+ -std=c9[9x]|-std=iso9899:199[9x])
+ extra_flag=
+ ;;
+ -std=*|-ansi)
+ echo >&2 "`basename $0` called with non ISO C99 option $i"
+ exit 1
+ ;;
+ esac
+done
+
+exec gcc $extra_flag ${1+"$@"}
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/corelist b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/corelist
new file mode 100755
index 000000000..0765892b7
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/corelist
@@ -0,0 +1,577 @@
+#!/usr/bin/perl
+ eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0; # ^ Run only under a shell
+#!/usr/bin/perl
+
+=head1 NAME
+
+corelist - a commandline frontend to Module::CoreList
+
+=head1 DESCRIPTION
+
+See L for one.
+
+=head1 SYNOPSIS
+
+ corelist -v
+ corelist [-a|-d] | // [] ...
+ corelist [-v ] [ | // ] ...
+ corelist [-r ] ...
+ corelist --utils [-d] [] ...
+ corelist --utils -v
+ corelist --feature [] ...
+ corelist --diff PerlVersion PerlVersion
+ corelist --upstream
+
+=head1 OPTIONS
+
+=over
+
+=item -a
+
+lists all versions of the given module (or the matching modules, in case you
+used a module regexp) in the perls Module::CoreList knows about.
+
+ corelist -a Unicode
+
+ Unicode was first released with perl v5.6.2
+ v5.6.2 3.0.1
+ v5.8.0 3.2.0
+ v5.8.1 4.0.0
+ v5.8.2 4.0.0
+ v5.8.3 4.0.0
+ v5.8.4 4.0.1
+ v5.8.5 4.0.1
+ v5.8.6 4.0.1
+ v5.8.7 4.1.0
+ v5.8.8 4.1.0
+ v5.8.9 5.1.0
+ v5.9.0 4.0.0
+ v5.9.1 4.0.0
+ v5.9.2 4.0.1
+ v5.9.3 4.1.0
+ v5.9.4 4.1.0
+ v5.9.5 5.0.0
+ v5.10.0 5.0.0
+ v5.10.1 5.1.0
+ v5.11.0 5.1.0
+ v5.11.1 5.1.0
+ v5.11.2 5.1.0
+ v5.11.3 5.2.0
+ v5.11.4 5.2.0
+ v5.11.5 5.2.0
+ v5.12.0 5.2.0
+ v5.12.1 5.2.0
+ v5.12.2 5.2.0
+ v5.12.3 5.2.0
+ v5.12.4 5.2.0
+ v5.13.0 5.2.0
+ v5.13.1 5.2.0
+ v5.13.2 5.2.0
+ v5.13.3 5.2.0
+ v5.13.4 5.2.0
+ v5.13.5 5.2.0
+ v5.13.6 5.2.0
+ v5.13.7 6.0.0
+ v5.13.8 6.0.0
+ v5.13.9 6.0.0
+ v5.13.10 6.0.0
+ v5.13.11 6.0.0
+ v5.14.0 6.0.0
+ v5.14.1 6.0.0
+ v5.15.0 6.0.0
+
+=item -d
+
+finds the first perl version where a module has been released by
+date, and not by version number (as is the default).
+
+=item --diff
+
+Given two versions of perl, this prints a human-readable table of all module
+changes between the two. The output format may change in the future, and is
+meant for I, not programs. For programs, use the L
+API.
+
+=item -? or -help
+
+help! help! help! to see more help, try --man.
+
+=item -man
+
+all of the help
+
+=item -v
+
+lists all of the perl release versions we got the CoreList for.
+
+If you pass a version argument (value of C<$]>, like C<5.00503> or C<5.008008>),
+you get a list of all the modules and their respective versions.
+(If you have the C module, you can also use new-style version numbers,
+like C<5.8.8>.)
+
+In module filtering context, it can be used as Perl version filter.
+
+=item -r
+
+lists all of the perl releases and when they were released
+
+If you pass a perl version you get the release date for that version only.
+
+=item --utils
+
+lists the first version of perl each named utility program was released with
+
+May be used with -d to modify the first release criteria.
+
+If used with -v then all utilities released with that version of perl
+are listed, and any utility programs named on the command line are ignored.
+
+=item --feature, -f
+
+lists the first version bundle of each named feature given
+
+=item --upstream, -u
+
+Shows if the given module is primarily maintained in perl core or on CPAN
+and bug tracker URL.
+
+=back
+
+As a special case, if you specify the module name C, you'll get
+the version number of the Unicode Character Database bundled with the
+requested perl versions.
+
+=cut
+
+BEGIN { pop @INC if $INC[-1] eq '.' }
+use Module::CoreList;
+use Getopt::Long qw(:config no_ignore_case);
+use Pod::Usage;
+use strict;
+use warnings;
+use List::Util qw/maxstr/;
+
+my %Opts;
+
+GetOptions(
+ \%Opts,
+ qw[ help|?! man! r|release:s v|version:s a! d diff|D utils feature|f u|upstream ]
+);
+
+pod2usage(1) if $Opts{help};
+pod2usage(-verbose=>2) if $Opts{man};
+
+if(exists $Opts{r} ){
+ if ( !$Opts{r} ) {
+ print "\nModule::CoreList has release info for the following perl versions:\n";
+ my $versions = { };
+ my $max_ver_len = max_mod_len(\%Module::CoreList::released);
+ for my $ver ( grep !/0[01]0$/, sort keys %Module::CoreList::released ) {
+ printf "%-${max_ver_len}s %s\n", format_perl_version($ver), $Module::CoreList::released{$ver};
+ }
+ print "\n";
+ exit 0;
+ }
+
+ my $num_r = numify_version( $Opts{r} );
+ my $version_hash = Module::CoreList->find_version($num_r);
+
+ if( !$version_hash ) {
+ print "\nModule::CoreList has no info on perl $Opts{r}\n\n";
+ exit 1;
+ }
+
+ printf "Perl %s was released on %s\n\n", format_perl_version($num_r), $Module::CoreList::released{$num_r};
+ exit 0;
+}
+
+if(exists $Opts{v} ){
+ if( !$Opts{v} ) {
+ print "\nModule::CoreList has info on the following perl versions:\n";
+ print format_perl_version($_)."\n" for grep !/0[01]0$/, sort keys %Module::CoreList::version;
+ print "\n";
+ exit 0;
+ }
+
+ my $num_v = numify_version( $Opts{v} );
+
+ if ($Opts{utils}) {
+ utilities_in_version($num_v);
+ exit 0;
+ }
+
+ my $version_hash = Module::CoreList->find_version($num_v);
+
+ if( !$version_hash ) {
+ print "\nModule::CoreList has no info on perl $Opts{v}\n\n";
+ exit 1;
+ }
+
+ if ( !@ARGV ) {
+ print "\nThe following modules were in perl $Opts{v} CORE\n";
+ my $max_mod_len = max_mod_len($version_hash);
+ for my $mod ( sort keys %$version_hash ) {
+ printf "%-${max_mod_len}s %s\n", $mod, $version_hash->{$mod} || "";
+ }
+ print "\n";
+ exit 0;
+ }
+}
+
+if ($Opts{diff}) {
+ if(@ARGV != 2) {
+ die "\nprovide exactly two perl core versions to diff with --diff\n";
+ }
+
+ my ($old_ver, $new_ver) = @ARGV;
+
+ my $old = numify_version($old_ver);
+ if ( !Module::CoreList->find_version($old) ) {
+ print "\nModule::CoreList has no info on perl $old_ver\n\n";
+ exit 1;
+ }
+ my $new = numify_version($new_ver);
+ if ( !Module::CoreList->find_version($new) ) {
+ print "\nModule::CoreList has no info on perl $new_ver\n\n";
+ exit 1;
+ }
+
+ my %diff = Module::CoreList::changes_between($old, $new);
+
+ for my $lib (sort keys %diff) {
+ my $diff = $diff{$lib};
+
+ my $was = ! exists $diff->{left} ? '(absent)'
+ : ! defined $diff->{left} ? '(undef)'
+ : $diff->{left};
+
+ my $now = ! exists $diff->{right} ? '(absent)'
+ : ! defined $diff->{right} ? '(undef)'
+ : $diff->{right};
+
+ printf "%-35s %10s %10s\n", $lib, $was, $now;
+ }
+ exit(0);
+}
+
+if ($Opts{utils}) {
+ die "\n--utils only available with perl v5.19.1 or greater\n"
+ if $] < 5.019001;
+
+ die "\nprovide at least one utility name to --utils\n"
+ unless @ARGV;
+
+ warn "\n-a has no effect when --utils is used\n" if $Opts{a};
+ warn "\n--diff has no effect when --utils is used\n" if $Opts{diff};
+ warn "\n--upstream, or -u, has no effect when --utils is used\n" if $Opts{u};
+
+ my $when = maxstr(values %Module::CoreList::released);
+ print "\n","Data for $when\n";
+
+ utility_version($_) for @ARGV;
+
+ exit(0);
+}
+
+if ($Opts{feature}) {
+ die "\n--feature is only available with perl v5.16.0 or greater\n"
+ if $] < 5.016;
+
+ die "\nprovide at least one feature name to --feature\n"
+ unless @ARGV;
+
+ no warnings 'once';
+ require feature;
+
+ my %feature2version;
+ my @bundles = map { $_->[0] }
+ sort { $b->[1] <=> $a->[1] }
+ map { [$_, numify_version($_)] }
+ grep { not /[^0-9.]/ }
+ keys %feature::feature_bundle;
+
+ for my $version (@bundles) {
+ $feature2version{$_} = $version =~ /^\d\.\d+$/ ? "$version.0" : $version
+ for @{ $feature::feature_bundle{$version} };
+ }
+
+ # allow internal feature names, just in case someone gives us __SUB__
+ # instead of current_sub.
+ while (my ($name, $internal) = each %feature::feature) {
+ $internal =~ s/^feature_//;
+ $feature2version{$internal} = $feature2version{$name}
+ if $feature2version{$name};
+ }
+
+ my $when = maxstr(values %Module::CoreList::released);
+ print "\n","Data for $when\n";
+
+ for my $feature (@ARGV) {
+ print "feature \"$feature\" ",
+ exists $feature2version{$feature}
+ ? "was first released with the perl "
+ . format_perl_version(numify_version($feature2version{$feature}))
+ . " feature bundle\n"
+ : "doesn't exist (or so I think)\n";
+ }
+ exit(0);
+}
+
+if ( !@ARGV ) {
+ pod2usage(0);
+}
+
+while (@ARGV) {
+ my ($mod, $ver);
+ if ($ARGV[0] =~ /=/) {
+ ($mod, $ver) = split /=/, shift @ARGV;
+ } else {
+ $mod = shift @ARGV;
+ $ver = (@ARGV && $ARGV[0] =~ /^\d/) ? shift @ARGV : "";
+ }
+
+ if ($mod !~ m|^/(.*)/([imosx]*)$|) { # not a regex
+ module_version($mod,$ver);
+ } else {
+ my $re;
+ eval { $re = $2 ? qr/(?$2)($1)/ : qr/$1/; }; # trap exceptions while building regex
+ if ($@) {
+ # regex errors are usually like 'Quantifier follow nothing in regex; marked by ...'
+ # then we drop text after ';' to shorten message
+ my $errmsg = $@ =~ /(.*);/ ? $1 : $@;
+ warn "\n$mod is a bad regex: $errmsg\n";
+ next;
+ }
+ my @mod = Module::CoreList->find_modules($re);
+ if (@mod) {
+ module_version($_, $ver) for @mod;
+ } else {
+ $ver |= '';
+ print "\n$mod $ver has no match in CORE (or so I think)\n";
+ }
+
+ }
+}
+
+exit();
+
+sub module_version {
+ my($mod,$ver) = @_;
+
+ if ( $Opts{v} ) {
+ my $numeric_v = numify_version($Opts{v});
+ my $version_hash = Module::CoreList->find_version($numeric_v);
+ if ($version_hash) {
+ print $mod, " ", $version_hash->{$mod} || 'undef', "\n";
+ return;
+ }
+ else { die "Shouldn't happen" }
+ }
+
+ my $ret = $Opts{d}
+ ? Module::CoreList->first_release_by_date(@_)
+ : Module::CoreList->first_release(@_);
+ my $msg = $mod;
+ $msg .= " $ver" if $ver;
+
+ my $rem = $Opts{d}
+ ? Module::CoreList->removed_from_by_date($mod)
+ : Module::CoreList->removed_from($mod);
+
+ my $when = maxstr(values %Module::CoreList::released);
+ print "\n","Data for $when\n";
+
+ if( defined $ret ) {
+ my $deprecated = Module::CoreList->deprecated_in($mod);
+ $msg .= " was ";
+ $msg .= "first " unless $ver;
+ $msg .= "released with perl " . format_perl_version($ret);
+ $msg .= ( $rem ? ',' : ' and' ) . " deprecated (will be CPAN-only) in " . format_perl_version($deprecated) if $deprecated;
+ $msg .= " and removed from " . format_perl_version($rem) if $rem;
+ } else {
+ $msg .= " was not in CORE (or so I think)";
+ }
+
+ print $msg,"\n";
+
+ if( defined $ret and exists $Opts{u} ) {
+ my $upstream = $Module::CoreList::upstream{$mod};
+ $upstream = 'undef' unless $upstream;
+ print "upstream: $upstream\n";
+ if ( $upstream ne 'blead' ) {
+ my $bugtracker = $Module::CoreList::bug_tracker{$mod};
+ $bugtracker = 'unknown' unless $bugtracker;
+ print "bug tracker: $bugtracker\n";
+ }
+ }
+
+ if(defined $ret and exists $Opts{a} and $Opts{a}){
+ display_a($mod);
+ }
+}
+
+sub utility_version {
+ my ($utility) = @_;
+
+ require Module::CoreList::Utils;
+
+ my $released = $Opts{d}
+ ? Module::CoreList::Utils->first_release_by_date($utility)
+ : Module::CoreList::Utils->first_release($utility);
+
+ my $removed = $Opts{d}
+ ? Module::CoreList::Utils->removed_from_by_date($utility)
+ : Module::CoreList::Utils->removed_from($utility);
+
+ if ($released) {
+ print "$utility was first released with perl ", format_perl_version($released);
+ print " and later removed in ", format_perl_version($removed)
+ if $removed;
+ print "\n";
+ } else {
+ print "$utility was not in CORE (or so I think)\n";
+ }
+}
+
+sub utilities_in_version {
+ my ($version) = @_;
+
+ require Module::CoreList::Utils;
+
+ my @utilities = Module::CoreList::Utils->utilities($version);
+
+ if (not @utilities) {
+ print "\nModule::CoreList::Utils has no info on perl $version\n\n";
+ exit 1;
+ }
+
+ print "\nThe following utilities were in perl ",
+ format_perl_version($version), " CORE\n";
+ print "$_\n" for sort { lc($a) cmp lc($b) } @utilities;
+ print "\n";
+}
+
+
+sub max_mod_len {
+ my $versions = shift;
+ my $max = 0;
+ for my $mod (keys %$versions) {
+ $max = max($max, length $mod);
+ }
+
+ return $max;
+}
+
+sub max {
+ my($this, $that) = @_;
+ return $this if $this > $that;
+ return $that;
+}
+
+sub display_a {
+ my $mod = shift;
+
+ for my $v (grep !/0[01]0$/, sort keys %Module::CoreList::version ) {
+ next unless exists $Module::CoreList::version{$v}{$mod};
+
+ my $mod_v = $Module::CoreList::version{$v}{$mod} || 'undef';
+ printf " %-10s %-10s\n", format_perl_version($v), $mod_v;
+ }
+ print "\n";
+}
+
+
+{
+ my $have_version_pm;
+ sub have_version_pm {
+ return $have_version_pm if defined $have_version_pm;
+ return $have_version_pm = eval { require version; 1 };
+ }
+}
+
+
+sub format_perl_version {
+ my $v = shift;
+ return $v if $v < 5.006 or !have_version_pm;
+ return version->new($v)->normal;
+}
+
+
+sub numify_version {
+ my $ver = shift;
+ if ($ver =~ /\..+\./) {
+ have_version_pm()
+ or die "You need to install version.pm to use dotted version numbers\n";
+ $ver = version->new($ver)->numify;
+ }
+ $ver += 0;
+ return $ver;
+}
+
+=head1 EXAMPLES
+
+ $ corelist File::Spec
+
+ File::Spec was first released with perl 5.005
+
+ $ corelist File::Spec 0.83
+
+ File::Spec 0.83 was released with perl 5.007003
+
+ $ corelist File::Spec 0.89
+
+ File::Spec 0.89 was not in CORE (or so I think)
+
+ $ corelist File::Spec::Aliens
+
+ File::Spec::Aliens was not in CORE (or so I think)
+
+ $ corelist /IPC::Open/
+
+ IPC::Open2 was first released with perl 5
+
+ IPC::Open3 was first released with perl 5
+
+ $ corelist /MANIFEST/i
+
+ ExtUtils::Manifest was first released with perl 5.001
+
+ $ corelist /Template/
+
+ /Template/ has no match in CORE (or so I think)
+
+ $ corelist -v 5.8.8 B
+
+ B 1.09_01
+
+ $ corelist -v 5.8.8 /^B::/
+
+ B::Asmdata 1.01
+ B::Assembler 0.07
+ B::Bblock 1.02_01
+ B::Bytecode 1.01_01
+ B::C 1.04_01
+ B::CC 1.00_01
+ B::Concise 0.66
+ B::Debug 1.02_01
+ B::Deparse 0.71
+ B::Disassembler 1.05
+ B::Lint 1.03
+ B::O 1.00
+ B::Showlex 1.02
+ B::Stackobj 1.00
+ B::Stash 1.00
+ B::Terse 1.03_01
+ B::Xref 1.01
+
+=head1 COPYRIGHT
+
+Copyright (c) 2002-2007 by D.H. aka PodMaster
+
+Currently maintained by the perl 5 porters Eperl5-porters@perl.orgE.
+
+This program is distributed under the same terms as perl itself.
+See http://perl.org/ or http://cpan.org/ for more info on that.
+
+=cut
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpan b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpan
new file mode 100755
index 000000000..5e54f7f07
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpan
@@ -0,0 +1,352 @@
+#!/usr/bin/perl
+ eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0; # ^ Run only under a shell
+#!/usr/local/bin/perl
+
+BEGIN { pop @INC if $INC[-1] eq '.' }
+use strict;
+use vars qw($VERSION);
+
+use App::Cpan;
+use CPAN::Version;
+my $minver = '1.64';
+if ( CPAN::Version->vlt($App::Cpan::VERSION, $minver) ) {
+ warn "WARNING: your version of App::Cpan is $App::Cpan::VERSION while we would expect at least $minver";
+}
+$VERSION = '1.64';
+
+my $rc = App::Cpan->run( @ARGV );
+
+# will this work under Strawberry Perl?
+exit( $rc || 0 );
+
+=head1 NAME
+
+cpan - easily interact with CPAN from the command line
+
+=head1 SYNOPSIS
+
+ # with arguments and no switches, installs specified modules
+ cpan module_name [ module_name ... ]
+
+ # with switches, installs modules with extra behavior
+ cpan [-cfFimtTw] module_name [ module_name ... ]
+
+ # use local::lib
+ cpan -I module_name [ module_name ... ]
+
+ # one time mirror override for faster mirrors
+ cpan -p ...
+
+ # with just the dot, install from the distribution in the
+ # current directory
+ cpan .
+
+ # without arguments, starts CPAN.pm shell
+ cpan
+
+ # without arguments, but some switches
+ cpan [-ahpruvACDLOPX]
+
+=head1 DESCRIPTION
+
+This script provides a command interface (not a shell) to CPAN. At the
+moment it uses CPAN.pm to do the work, but it is not a one-shot command
+runner for CPAN.pm.
+
+=head2 Options
+
+=over 4
+
+=item -a
+
+Creates a CPAN.pm autobundle with CPAN::Shell->autobundle.
+
+=item -A module [ module ... ]
+
+Shows the primary maintainers for the specified modules.
+
+=item -c module
+
+Runs a `make clean` in the specified module's directories.
+
+=item -C module [ module ... ]
+
+Show the F files for the specified modules
+
+=item -D module [ module ... ]
+
+Show the module details. This prints one line for each out-of-date module
+(meaning, modules locally installed but have newer versions on CPAN).
+Each line has three columns: module name, local version, and CPAN
+version.
+
+=item -f
+
+Force the specified action, when it normally would have failed. Use this
+to install a module even if its tests fail. When you use this option,
+-i is not optional for installing a module when you need to force it:
+
+ % cpan -f -i Module::Foo
+
+=item -F
+
+Turn off CPAN.pm's attempts to lock anything. You should be careful with
+this since you might end up with multiple scripts trying to muck in the
+same directory. This isn't so much of a concern if you're loading a special
+config with C<-j>, and that config sets up its own work directories.
+
+=item -g module [ module ... ]
+
+Downloads to the current directory the latest distribution of the module.
+
+=item -G module [ module ... ]
+
+UNIMPLEMENTED
+
+Download to the current directory the latest distribution of the
+modules, unpack each distribution, and create a git repository for each
+distribution.
+
+If you want this feature, check out Yanick Champoux's C
+distribution.
+
+=item -h
+
+Print a help message and exit. When you specify C<-h>, it ignores all
+of the other options and arguments.
+
+=item -i module [ module ... ]
+
+Install the specified modules. With no other switches, this switch
+is implied.
+
+=item -I
+
+Load C (think like C<-I> for loading lib paths). Too bad
+C<-l> was already taken.
+
+=item -j Config.pm
+
+Load the file that has the CPAN configuration data. This should have the
+same format as the standard F file, which defines
+C<$CPAN::Config> as an anonymous hash.
+
+=item -J
+
+Dump the configuration in the same format that CPAN.pm uses. This is useful
+for checking the configuration as well as using the dump as a starting point
+for a new, custom configuration.
+
+=item -l
+
+List all installed modules with their versions
+
+=item -L author [ author ... ]
+
+List the modules by the specified authors.
+
+=item -m
+
+Make the specified modules.
+
+=item -M mirror1,mirror2,...
+
+A comma-separated list of mirrors to use for just this run. The C<-P>
+option can find them for you automatically.
+
+=item -n
+
+Do a dry run, but don't actually install anything. (unimplemented)
+
+=item -O
+
+Show the out-of-date modules.
+
+=item -p
+
+Ping the configured mirrors and print a report
+
+=item -P
+
+Find the best mirrors you could be using and use them for the current
+session.
+
+=item -r
+
+Recompiles dynamically loaded modules with CPAN::Shell->recompile.
+
+=item -s
+
+Drop in the CPAN.pm shell. This command does this automatically if you don't
+specify any arguments.
+
+=item -t module [ module ... ]
+
+Run a `make test` on the specified modules.
+
+=item -T
+
+Do not test modules. Simply install them.
+
+=item -u
+
+Upgrade all installed modules. Blindly doing this can really break things,
+so keep a backup.
+
+=item -v
+
+Print the script version and CPAN.pm version then exit.
+
+=item -V
+
+Print detailed information about the cpan client.
+
+=item -w
+
+UNIMPLEMENTED
+
+Turn on cpan warnings. This checks various things, like directory permissions,
+and tells you about problems you might have.
+
+=item -x module [ module ... ]
+
+Find close matches to the named modules that you think you might have
+mistyped. This requires the optional installation of Text::Levenshtein or
+Text::Levenshtein::Damerau.
+
+=item -X
+
+Dump all the namespaces to standard output.
+
+=back
+
+=head2 Examples
+
+ # print a help message
+ cpan -h
+
+ # print the version numbers
+ cpan -v
+
+ # create an autobundle
+ cpan -a
+
+ # recompile modules
+ cpan -r
+
+ # upgrade all installed modules
+ cpan -u
+
+ # install modules ( sole -i is optional )
+ cpan -i Netscape::Booksmarks Business::ISBN
+
+ # force install modules ( must use -i )
+ cpan -fi CGI::Minimal URI
+
+ # install modules but without testing them
+ cpan -Ti CGI::Minimal URI
+
+=head2 Environment variables
+
+There are several components in CPAN.pm that use environment variables.
+The build tools, L and L use some,
+while others matter to the levels above them. Some of these are specified
+by the Perl Toolchain Gang:
+
+Lancaster Consensus: L
+
+Oslo Consensus: L
+
+=over 4
+
+=item NONINTERACTIVE_TESTING
+
+Assume no one is paying attention and skips prompts for distributions
+that do that correctly. C sets this to C<1> unless it already
+has a value (even if that value is false).
+
+=item PERL_MM_USE_DEFAULT
+
+Use the default answer for a prompted questions. C sets this
+to C<1> unless it already has a value (even if that value is false).
+
+=item CPAN_OPTS
+
+As with C, a string of additional C options to
+add to those you specify on the command line.
+
+=item CPANSCRIPT_LOGLEVEL
+
+The log level to use, with either the embedded, minimal logger or
+L if it is installed. Possible values are the same as
+the C levels: C, C, C, C,
+C, and C. The default is C.
+
+=item GIT_COMMAND
+
+The path to the C binary to use for the Git features. The default
+is C.
+
+=back
+
+=head1 EXIT VALUES
+
+The script exits with zero if it thinks that everything worked, or a
+positive number if it thinks that something failed. Note, however, that
+in some cases it has to divine a failure by the output of things it does
+not control. For now, the exit codes are vague:
+
+ 1 An unknown error
+
+ 2 The was an external problem
+
+ 4 There was an internal problem with the script
+
+ 8 A module failed to install
+
+=head1 TO DO
+
+* one shot configuration values from the command line
+
+=head1 BUGS
+
+* none noted
+
+=head1 SEE ALSO
+
+Most behaviour, including environment variables and configuration,
+comes directly from CPAN.pm.
+
+=head1 SOURCE AVAILABILITY
+
+This code is in Github in the CPAN.pm repository:
+
+ https://github.com/andk/cpanpm
+
+The source used to be tracked separately in another GitHub repo,
+but the canonical source is now in the above repo.
+
+=head1 CREDITS
+
+Japheth Cleaver added the bits to allow a forced install (-f).
+
+Jim Brandt suggest and provided the initial implementation for the
+up-to-date and Changes features.
+
+Adam Kennedy pointed out that exit() causes problems on Windows
+where this script ends up with a .bat extension
+
+=head1 AUTHOR
+
+brian d foy, C<< >>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2001-2015, brian d foy, All Rights Reserved.
+
+You may redistribute this under the same terms as Perl itself.
+
+=cut
+
+1;
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpp b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpp
new file mode 120000
index 000000000..6b69a4e43
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpp
@@ -0,0 +1 @@
+cpp-13
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpp-13 b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpp-13
new file mode 120000
index 000000000..ee2d7be73
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/cpp-13
@@ -0,0 +1 @@
+x86_64-linux-gnu-cpp-13
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg
new file mode 100755
index 000000000..c493b7df0
Binary files /dev/null and b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg differ
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-deb b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-deb
new file mode 100755
index 000000000..f125775f7
Binary files /dev/null and b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-deb differ
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-divert b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-divert
new file mode 100755
index 000000000..b5f19ec0c
Binary files /dev/null and b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-divert differ
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-maintscript-helper b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-maintscript-helper
new file mode 100755
index 000000000..9c52264b3
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-maintscript-helper
@@ -0,0 +1,667 @@
+#!/bin/sh
+#
+# Copyright © 2007, 2011-2015 Guillem Jover
+# Copyright © 2010 Raphaël Hertzog
+# Copyright © 2008 Joey Hess
+# Copyright © 2005 Scott James Remnant (original implementation on www.dpkg.org)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# The conffile related functions are inspired by
+# https://wiki.debian.org/DpkgConffileHandling
+
+# This script is documented in dpkg-maintscript-helper(1)
+
+##
+## Functions to remove an obsolete conffile during upgrade
+##
+rm_conffile() {
+ local CONFFILE="$1"
+ local LASTVERSION="$2"
+ local PACKAGE="$3"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$PACKAGE" ] || error "couldn't identify the package"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ "${CONFFILE}" != "${CONFFILE#/}" ] || \
+ error "conffile '$CONFFILE' is not an absolute path"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 rm_conffile in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "CONFFILE=$CONFFILE PACKAGE=$PACKAGE" \
+ "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ prepare_rm_conffile "$CONFFILE" "$PACKAGE"
+ fi
+ ;;
+ postinst)
+ if [ "$1" = "configure" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ finish_rm_conffile "$CONFFILE"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "purge" ]; then
+ rm -f "$DPKG_ROOT$CONFFILE.dpkg-bak" \
+ "$DPKG_ROOT$CONFFILE.dpkg-remove" \
+ "$DPKG_ROOT$CONFFILE.dpkg-backup"
+ fi
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ abort_rm_conffile "$CONFFILE" "$PACKAGE"
+ fi
+ ;;
+ *)
+ debug "$0 rm_conffile not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+prepare_rm_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ [ -e "$DPKG_ROOT$CONFFILE" ] || return 0
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ local md5sum old_md5sum
+ md5sum="$(md5sum "$DPKG_ROOT$CONFFILE" | sed -e 's/ .*//')"
+ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$PACKAGE" | \
+ sed -n -e "\\'^ $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+ if [ "$md5sum" != "$old_md5sum" ]; then
+ mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-backup"
+ else
+ mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-remove"
+ fi
+}
+
+finish_rm_conffile() {
+ local CONFFILE="$1"
+
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-backup" ]; then
+ echo "Obsolete conffile $DPKG_ROOT$CONFFILE has been modified by you."
+ echo "Saving as $DPKG_ROOT$CONFFILE.dpkg-bak ..."
+ mv -f "$DPKG_ROOT$CONFFILE.dpkg-backup" "$DPKG_ROOT$CONFFILE.dpkg-bak"
+ fi
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then
+ echo "Removing obsolete conffile $DPKG_ROOT$CONFFILE ..."
+ rm -f "$DPKG_ROOT$CONFFILE.dpkg-remove"
+ fi
+}
+
+abort_rm_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then
+ echo "Reinstalling $DPKG_ROOT$CONFFILE that was moved away"
+ mv "$DPKG_ROOT$CONFFILE.dpkg-remove" "$DPKG_ROOT$CONFFILE"
+ fi
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-backup" ]; then
+ echo "Reinstalling $DPKG_ROOT$CONFFILE that was backed-up"
+ mv "$DPKG_ROOT$CONFFILE.dpkg-backup" "$DPKG_ROOT$CONFFILE"
+ fi
+}
+
+##
+## Functions to rename a conffile during upgrade
+##
+mv_conffile() {
+ local OLDCONFFILE="$1"
+ local NEWCONFFILE="$2"
+ local LASTVERSION="$3"
+ local PACKAGE="$4"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$PACKAGE" ] || error "couldn't identify the package"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ "${OLDCONFFILE}" != "${OLDCONFFILE#/}" ] || \
+ error "old-conffile '$OLDCONFFILE' is not an absolute path"
+ [ "${NEWCONFFILE}" != "${NEWCONFFILE#/}" ] || \
+ error "new-conffile '$NEWCONFFILE' is not an absolute path"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 mv_conffile in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "CONFFILE=$OLDCONFFILE -> $NEWCONFFILE PACKAGE=$PACKAGE" \
+ "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ prepare_mv_conffile "$OLDCONFFILE" "$PACKAGE"
+ fi
+ ;;
+ postinst)
+ if [ "$1" = "configure" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ finish_mv_conffile "$OLDCONFFILE" "$NEWCONFFILE" "$PACKAGE"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ abort_mv_conffile "$OLDCONFFILE" "$PACKAGE"
+ fi
+ ;;
+ *)
+ debug "$0 mv_conffile not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+prepare_mv_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ [ -e "$DPKG_ROOT$CONFFILE" ] || return 0
+
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ local md5sum old_md5sum
+ md5sum="$(md5sum "$DPKG_ROOT$CONFFILE" | sed -e 's/ .*//')"
+ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$PACKAGE" | \
+ sed -n -e "\\'^ $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+ if [ "$md5sum" = "$old_md5sum" ]; then
+ mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-remove"
+ fi
+}
+
+finish_mv_conffile() {
+ local OLDCONFFILE="$1"
+ local NEWCONFFILE="$2"
+ local PACKAGE="$3"
+
+ rm -f "$DPKG_ROOT$OLDCONFFILE.dpkg-remove"
+
+ [ -e "$DPKG_ROOT$OLDCONFFILE" ] || return 0
+ ensure_package_owns_file "$PACKAGE" "$OLDCONFFILE" || return 0
+
+ echo "Preserving user changes to $DPKG_ROOT$NEWCONFFILE (renamed from $DPKG_ROOT$OLDCONFFILE)..."
+ if [ -e "$DPKG_ROOT$NEWCONFFILE" ]; then
+ mv -f "$DPKG_ROOT$NEWCONFFILE" "$DPKG_ROOT$NEWCONFFILE.dpkg-new"
+ fi
+ mv -f "$DPKG_ROOT$OLDCONFFILE" "$DPKG_ROOT$NEWCONFFILE"
+}
+
+abort_mv_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then
+ echo "Reinstalling $DPKG_ROOT$CONFFILE that was moved away"
+ mv "$DPKG_ROOT$CONFFILE.dpkg-remove" "$DPKG_ROOT$CONFFILE"
+ fi
+}
+
+##
+## Functions to replace a symlink with a directory
+##
+symlink_to_dir() {
+ local SYMLINK="$1"
+ local SYMLINK_TARGET="$2"
+ local LASTVERSION="$3"
+ local PACKAGE="$4"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ -n "$PACKAGE" ] || error "cannot identify the package"
+ [ -n "$SYMLINK" ] || error "symlink parameter is missing"
+ [ "${SYMLINK#/}" = "$SYMLINK" ] && \
+ error "symlink pathname is not an absolute path"
+ [ "${SYMLINK%/}" = "$SYMLINK" ] || \
+ error "symlink pathname ends with a slash"
+ [ -n "$SYMLINK_TARGET" ] || error "original symlink target is missing"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 symlink_to_dir in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "SYMLINK=$SYMLINK -> $SYMLINK_TARGET PACKAGE=$PACKAGE" \
+ "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+ [ -n "$2" ] && [ -h "$DPKG_ROOT$SYMLINK" ] &&
+ symlink_match "$SYMLINK" "$SYMLINK_TARGET" &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ mv -f "$DPKG_ROOT$SYMLINK" "$DPKG_ROOT${SYMLINK}.dpkg-backup"
+ fi
+ ;;
+ postinst)
+ # We cannot bail depending on the version, as here we only
+ # know what was the last configured version, and we might
+ # have been unpacked, then upgraded with an unpack and thus
+ # never been configured before.
+ if [ "$1" = "configure" ] &&
+ [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ] &&
+ symlink_match "${SYMLINK}.dpkg-backup" "$SYMLINK_TARGET"
+ then
+ rm -f "$DPKG_ROOT${SYMLINK}.dpkg-backup"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "purge" ] && [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ]; then
+ rm -f "$DPKG_ROOT${SYMLINK}.dpkg-backup"
+ fi
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ [ ! -e "$DPKG_ROOT$SYMLINK" ] &&
+ [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ] &&
+ symlink_match "${SYMLINK}.dpkg-backup" "$SYMLINK_TARGET" &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ echo "Restoring backup of $DPKG_ROOT$SYMLINK ..."
+ mv "$DPKG_ROOT${SYMLINK}.dpkg-backup" "$DPKG_ROOT$SYMLINK"
+ fi
+ ;;
+ *)
+ debug "$0 symlink_to_dir not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+##
+## Functions to replace a directory with a symlink
+##
+dir_to_symlink() {
+ local PATHNAME="${1%/}"
+ local SYMLINK_TARGET="$2"
+ local LASTVERSION="$3"
+ local PACKAGE="$4"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ -n "$PACKAGE" ] || error "cannot identify the package"
+ [ -n "$PATHNAME" ] || error "directory parameter is missing"
+ [ "${PATHNAME#/}" = "$PATHNAME" ] && \
+ error "directory parameter is not an absolute path"
+ [ -n "$SYMLINK_TARGET" ] || error "new symlink target is missing"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 dir_to_symlink in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "PATHNAME=$PATHNAME SYMLINK_TARGET=$SYMLINK_TARGET" \
+ "PACKAGE=$PACKAGE LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+ [ -n "$2" ] &&
+ [ ! -h "$DPKG_ROOT$PATHNAME" ] &&
+ [ -d "$DPKG_ROOT$PATHNAME" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ prepare_dir_to_symlink "$PACKAGE" "$PATHNAME"
+ fi
+ ;;
+ postinst)
+ # We cannot bail depending on the version, as here we only
+ # know what was the last configured version, and we might
+ # have been unpacked, then upgraded with an unpack and thus
+ # never been configured before.
+ if [ "$1" = "configure" ] &&
+ [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ] &&
+ [ ! -h "$DPKG_ROOT$PATHNAME" ] &&
+ [ -d "$DPKG_ROOT$PATHNAME" ] &&
+ [ -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" ]; then
+ finish_dir_to_symlink "$PATHNAME" "$SYMLINK_TARGET"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "purge" ] &&
+ [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ]; then
+ rm -rf "$DPKG_ROOT${PATHNAME}.dpkg-backup"
+ fi
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ] &&
+ [ \( ! -h "$DPKG_ROOT$PATHNAME" -a \
+ -d "$DPKG_ROOT$PATHNAME" -a \
+ -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" \) -o \
+ \( -h "$DPKG_ROOT$PATHNAME" -a \
+ \( "$(readlink "$DPKG_ROOT$PATHNAME")" = "$SYMLINK_TARGET" -o \
+ "$(dpkg-realpath "$PATHNAME")" = "$SYMLINK_TARGET" \) \) ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ abort_dir_to_symlink "$PATHNAME"
+ fi
+ ;;
+ *)
+ debug "$0 dir_to_symlink not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+prepare_dir_to_symlink()
+{
+ local PACKAGE="$1"
+ local PATHNAME="$2"
+
+ local LINE
+ # If there are conffiles we should not perform the switch.
+ dpkg-query -W -f='${Conffiles}\n' "$PACKAGE" | while read -r LINE; do
+ case "$LINE" in
+ "$PATHNAME"/*)
+ error "directory '$PATHNAME' contains conffiles," \
+ "cannot switch to symlink"
+ ;;
+ esac
+ done
+
+ # If there are locally created files or files owned by another package
+ # we should not perform the switch.
+ export DPKG_MAINTSCRIPT_HELPER_INTERNAL_API="$version"
+ find "$DPKG_ROOT$PATHNAME" -print0 | \
+ xargs -0 -n1 "$0" _internal_pkg_must_own_file "$PACKAGE" || \
+ error "directory '$PATHNAME' contains files not owned by" \
+ "package $PACKAGE, cannot switch to symlink"
+ unset DPKG_MAINTSCRIPT_HELPER_INTERNAL_API
+
+ # At this point, we know that the directory either contains no files,
+ # or only non-conffiles owned by the package.
+ #
+ # To do the switch we cannot simply replace it with the final symlink
+ # just yet, because dpkg needs to remove any file present in the old
+ # package that have disappeared in the new one, and we do not want to
+ # lose files resolving to the same pathname in the symlink target.
+ #
+ # We cannot replace the directory with a staging symlink either,
+ # because dpkg will update symlinks to their new target.
+ #
+ # So we need to create a staging directory, to avoid removing files
+ # from other packages, and to trap any new files in the directory
+ # to move them to their correct place later on.
+ mv -f "$DPKG_ROOT$PATHNAME" "$DPKG_ROOT${PATHNAME}.dpkg-backup"
+ mkdir "$DPKG_ROOT$PATHNAME"
+
+ # Mark it as a staging directory, so that we can track things.
+ touch "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir"
+}
+
+finish_dir_to_symlink()
+{
+ local PATHNAME="$1"
+ local SYMLINK_TARGET="$2"
+
+ # Move the contents of the staging directory to the symlink target,
+ # as those are all new files installed between this package being
+ # unpacked and configured.
+ local ABS_SYMLINK_TARGET
+ if [ "${SYMLINK_TARGET#/}" = "$SYMLINK_TARGET" ]; then
+ ABS_SYMLINK_TARGET="$(dirname "$PATHNAME")/$SYMLINK_TARGET"
+ else
+ ABS_SYMLINK_TARGET="$SYMLINK_TARGET"
+ fi
+ rm "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir"
+ find "$DPKG_ROOT$PATHNAME" -mindepth 1 -maxdepth 1 -print0 | \
+ xargs -0 -I% mv -f "%" "$DPKG_ROOT$ABS_SYMLINK_TARGET/"
+
+ # Remove the staging directory.
+ rmdir "$DPKG_ROOT$PATHNAME"
+
+ # Do the actual switch.
+ ln -s "$SYMLINK_TARGET" "$DPKG_ROOT$PATHNAME"
+
+ # We are left behind the old files owned by this package in the backup
+ # directory, just remove it.
+ rm -rf "$DPKG_ROOT${PATHNAME}.dpkg-backup"
+}
+
+abort_dir_to_symlink()
+{
+ local PATHNAME="$1"
+
+ echo "Restoring backup of $DPKG_ROOT$PATHNAME ..."
+ if [ -h "$DPKG_ROOT$PATHNAME" ]; then
+ rm -f "$DPKG_ROOT$PATHNAME"
+ else
+ # The staging directory must be empty, as no other package
+ # should have been unpacked in between.
+ rm -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir"
+ rmdir "$DPKG_ROOT$PATHNAME"
+ fi
+
+ mv "$DPKG_ROOT${PATHNAME}.dpkg-backup" "$DPKG_ROOT$PATHNAME"
+}
+
+# Common functions
+validate_optional_version() {
+ local VERSION="$1"
+
+ if [ -z "$VERSION" ]; then
+ return
+ fi
+
+ if ! VERSIONCHECK=$(dpkg --validate-version -- "$VERSION" 2>&1); then
+ error "$VERSIONCHECK"
+ fi
+}
+
+ensure_package_owns_file() {
+ local PACKAGE="$1"
+ local FILE="$2"
+
+ if ! dpkg-query -L "$PACKAGE" | grep -F -q -x "$FILE"; then
+ debug "File '$FILE' not owned by package " \
+ "'$PACKAGE', skipping $command"
+ return 1
+ fi
+ return 0
+}
+
+internal_pkg_must_own_file()
+{
+ local PACKAGE="$1"
+ local FILE="${2##"$DPKG_ROOT"}"
+
+ if [ "$DPKG_MAINTSCRIPT_HELPER_INTERNAL_API" != "$version" ]; then
+ error "internal API used by external command"
+ fi
+
+ if ! ensure_package_owns_file "$PACKAGE" "$FILE"; then
+ error "file '$FILE' not owned by package '$PACKAGE'"
+ fi
+ return 0
+}
+
+symlink_match()
+{
+ local SYMLINK="$1"
+ local SYMLINK_TARGET="$2"
+
+ [ "$(readlink "$DPKG_ROOT$SYMLINK")" = "$SYMLINK_TARGET" ] || \
+ [ "$(dpkg-realpath "$SYMLINK")" = "$SYMLINK_TARGET" ]
+}
+
+usage() {
+ cat < ... -- ...
+
+Commands:
+ supports
+ Returns 0 (success) if the given command is supported, 1 otherwise.
+ rm_conffile [ []]
+ Remove obsolete conffile. Must be called in preinst, postinst and
+ postrm.
+ mv_conffile [ []]
+ Rename a conffile. Must be called in preinst, postinst and postrm.
+ symlink_to_dir [ []]
+ Replace a symlink with a directory. Must be called in preinst,
+ postinst and postrm.
+ dir_to_symlink [ []]
+ Replace a directory with a symlink. Must be called in preinst,
+ postinst and postrm.
+ help
+ -?, --help
+ Show this help message.
+ --version
+ Show the version.
+END
+}
+
+# Main code
+set -e
+
+PROGNAME=$(basename "$0")
+version="1.22.6"
+DPKG_ROOT=${DPKG_ROOT:+$(realpath "$DPKG_ROOT")}
+# Remove default root dir.
+if [ "$DPKG_ROOT" = "/" ]; then
+ DPKG_ROOT=""
+fi
+export DPKG_ROOT
+
+PKGDATADIR_DEFAULT='/usr/share/dpkg'
+PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}"
+
+# shellcheck source=src/sh/dpkg-error.sh
+. "$PKGDATADIR/sh/dpkg-error.sh"
+
+setup_colors
+
+command="$1"
+[ $# -gt 0 ] || badusage "missing command"
+shift
+
+case "$command" in
+supports)
+ case "$1" in
+ rm_conffile|mv_conffile|symlink_to_dir|dir_to_symlink)
+ code=0
+ ;;
+ *)
+ code=1
+ ;;
+ esac
+ if [ -z "$DPKG_MAINTSCRIPT_NAME" ]; then
+ warning "environment variable DPKG_MAINTSCRIPT_NAME missing"
+ code=1
+ fi
+ if [ -z "$DPKG_MAINTSCRIPT_PACKAGE" ]; then
+ warning "environment variable DPKG_MAINTSCRIPT_PACKAGE missing"
+ code=1
+ fi
+ exit $code
+ ;;
+rm_conffile)
+ rm_conffile "$@"
+ ;;
+mv_conffile)
+ mv_conffile "$@"
+ ;;
+symlink_to_dir)
+ symlink_to_dir "$@"
+ ;;
+dir_to_symlink)
+ dir_to_symlink "$@"
+ ;;
+_internal_pkg_must_own_file)
+ # This is an internal command, must not be used outside this program.
+ internal_pkg_must_own_file "$@"
+ ;;
+--help|help|-?)
+ usage
+ ;;
+--version)
+ cat <
+# Copyright © 2020 Guillem Jover
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+set -e
+
+PROGNAME=$(basename "$0")
+version="1.22.6"
+EOL="\n"
+
+PKGDATADIR_DEFAULT='/usr/share/dpkg'
+PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}"
+
+# shellcheck source=src/sh/dpkg-error.sh
+. "$PKGDATADIR/sh/dpkg-error.sh"
+
+show_version()
+{
+ cat <...]
+
+Options:
+ -z, --zero end output line with NUL, not newline.
+ --instdir set the root directory.
+ --root set the root directory.
+ --version show the version.
+ -?, --help show this help message.
+END
+}
+
+canonicalize() {
+ local src="$1"
+ local root="$DPKG_ROOT"
+ local loop=0
+ local result="$root"
+ local dst
+
+ # Check whether the path is relative and make it absolute otherwise.
+ if [ "$src" = "${src#/}" ]; then
+ src="$(pwd)/$src"
+ src="${src#"$root"}"
+ fi
+
+ # Remove prefixed slashes.
+ while [ "$src" != "${src#/}" ]; do
+ src=${src#/}
+ done
+ while [ -n "$src" ]; do
+ # Get the first directory component.
+ prefix=${src%%/*}
+ # Remove the first directory component from src.
+ src=${src#"$prefix"}
+ # Remove prefixed slashes.
+ while [ "$src" != "${src#/}" ]; do
+ src=${src#/}
+ done
+ # Resolve the first directory component.
+ if [ "$prefix" = . ]; then
+ # Ignore, stay at the same directory.
+ :
+ elif [ "$prefix" = .. ]; then
+ # Go up one directory.
+ result=${result%/*}
+ if [ -n "$root" ] && [ "${result#"$root"}" = "$result" ]; then
+ result="$root"
+ fi
+ elif [ -h "$result/$prefix" ]; then
+ loop=$((loop + 1))
+ if [ "$loop" -gt 25 ]; then
+ error "too many levels of symbolic links"
+ fi
+ # Resolve the symlink within $result.
+ dst=$(readlink "$result/$prefix")
+ case "$dst" in
+ /*)
+ # Absolute pathname, reset result back to $root.
+ result=$root
+ src="$dst${src:+/$src}"
+ # Remove prefixed slashes.
+ while [ "$src" != "${src#/}" ]; do
+ src=${src#/}
+ done
+ ;;
+ *)
+ # Relative pathname.
+ src="$dst${src:+/$src}"
+ ;;
+ esac
+ else
+ # Otherwise append the prefix.
+ result="$result/$prefix"
+ fi
+ done
+ # We are done, print the resolved pathname, w/o $root.
+ result="${result#"$root"}"
+ printf "%s$EOL" "${result:-/}"
+}
+
+setup_colors
+
+DPKG_ROOT="${DPKG_ROOT:-}"
+export DPKG_ROOT
+
+while [ $# -ne 0 ]; do
+ case "$1" in
+ -z|--zero)
+ EOL="\0"
+ ;;
+ --instdir|--root)
+ shift
+ DPKG_ROOT=$1
+ ;;
+ --instdir=*)
+ DPKG_ROOT="${1#--instdir=}"
+ ;;
+ --root=*)
+ DPKG_ROOT="${1#--root=}"
+ ;;
+ --version)
+ show_version
+ exit 0
+ ;;
+ --help|-\?)
+ show_usage
+ exit 0
+ ;;
+ --)
+ shift
+ pathname="$1"
+ ;;
+ -*)
+ badusage "unknown option: $1"
+ ;;
+ *)
+ pathname="$1"
+ ;;
+ esac
+ shift
+done
+
+# Normalize root directory.
+DPKG_ROOT="${DPKG_ROOT:+$(realpath "$DPKG_ROOT")}"
+# Remove default root dir.
+if [ "$DPKG_ROOT" = "/" ]; then
+ DPKG_ROOT=""
+fi
+
+[ -n "$pathname" ] || badusage "missing pathname"
+if [ "${pathname#"$DPKG_ROOT"}" != "$pathname" ]; then
+ error "link '$pathname' includes root prefix '$DPKG_ROOT'"
+fi
+
+canonicalize "$pathname"
+
+exit 0
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-split b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-split
new file mode 100755
index 000000000..446d043d0
Binary files /dev/null and b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-split differ
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-statoverride b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-statoverride
new file mode 100755
index 000000000..85c34333e
Binary files /dev/null and b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-statoverride differ
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-trigger b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-trigger
new file mode 100755
index 000000000..9818f6295
Binary files /dev/null and b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dpkg-trigger differ
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dwp b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dwp
new file mode 120000
index 000000000..516b03d6b
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/dwp
@@ -0,0 +1 @@
+x86_64-linux-gnu-dwp
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/elfedit b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/elfedit
new file mode 120000
index 000000000..674841da4
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/elfedit
@@ -0,0 +1 @@
+x86_64-linux-gnu-elfedit
\ No newline at end of file
diff --git a/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/enc2xs b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/enc2xs
new file mode 100755
index 000000000..4a4f8b67a
--- /dev/null
+++ b/user/apps/tests/benchmark/lmbench/sysroot/usr/bin/enc2xs
@@ -0,0 +1,1484 @@
+#!/usr/bin/perl
+ eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ if 0; # ^ Run only under a shell
+#!./perl
+BEGIN {
+ # @INC poking no longer needed w/ new MakeMaker and Makefile.PL's
+ # with $ENV{PERL_CORE} set
+ # In case we need it in future...
+ require Config; import Config;
+ pop @INC if $INC[-1] eq '.';
+}
+use strict;
+use warnings;
+use Getopt::Std;
+use Config;
+my @orig_ARGV = @ARGV;
+our $VERSION = do { my @r = (q$Revision: 2.24 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
+
+# These may get re-ordered.
+# RAW is a do_now as inserted by &enter
+# AGG is an aggregated do_now, as built up by &process
+
+use constant {
+ RAW_NEXT => 0,
+ RAW_IN_LEN => 1,
+ RAW_OUT_BYTES => 2,
+ RAW_FALLBACK => 3,
+
+ AGG_MIN_IN => 0,
+ AGG_MAX_IN => 1,
+ AGG_OUT_BYTES => 2,
+ AGG_NEXT => 3,
+ AGG_IN_LEN => 4,
+ AGG_OUT_LEN => 5,
+ AGG_FALLBACK => 6,
+};
+
+# (See the algorithm in encengine.c - we're building structures for it)
+
+# There are two sorts of structures.
+# "do_now" (an array, two variants of what needs storing) is whatever we need
+# to do now we've read an input byte.
+# It's housed in a "do_next" (which is how we got to it), and in turn points
+# to a "do_next" which contains all the "do_now"s for the next input byte.
+
+# There will be a "do_next" which is the start state.
+# For a single byte encoding it's the only "do_next" - each "do_now" points
+# back to it, and each "do_now" will cause bytes. There is no state.
+
+# For a multi-byte encoding where all characters in the input are the same
+# length, then there will be a tree of "do_now"->"do_next"->"do_now"
+# branching out from the start state, one step for each input byte.
+# The leaf "do_now"s will all be at the same distance from the start state,
+# only the leaf "do_now"s cause output bytes, and they in turn point back to
+# the start state.
+
+# For an encoding where there are variable length input byte sequences, you
+# will encounter a leaf "do_now" sooner for the shorter input sequences, but
+# as before the leaves will point back to the start state.
+
+# The system will cope with escape encodings (imagine them as a mostly
+# self-contained tree for each escape state, and cross links between trees
+# at the state-switching characters) but so far no input format defines these.
+
+# The system will also cope with having output "leaves" in the middle of
+# the bifurcating branches, not just at the extremities, but again no
+# input format does this yet.
+
+# There are two variants of the "do_now" structure. The first, smaller variant
+# is generated by &enter as the input file is read. There is one structure
+# for each input byte. Say we are mapping a single byte encoding to a
+# single byte encoding, with "ABCD" going "abcd". There will be
+# 4 "do_now"s, {"A" => [...,"a",...], "B" => [...,"b",...], "C"=>..., "D"=>...}
+
+# &process then walks the tree, building aggregate "do_now" structures for
+# adjacent bytes where possible. The aggregate is for a contiguous range of
+# bytes which each produce the same length of output, each move to the
+# same next state, and each have the same fallback flag.
+# So our 4 RAW "do_now"s above become replaced by a single structure
+# containing:
+# ["A", "D", "abcd", 1, ...]
+# ie, for an input byte $_ in "A".."D", output 1 byte, found as
+# substr ("abcd", (ord $_ - ord "A") * 1, 1)
+# which maps very nicely into pointer arithmetic in C for encengine.c
+
+sub encode_U
+{
+ # UTF-8 encode long hand - only covers part of perl's range
+ ## my $uv = shift;
+ # chr() works in native space so convert value from table
+ # into that space before using chr().
+ my $ch = chr(utf8::unicode_to_native($_[0]));
+ # Now get core perl to encode that the way it likes.
+ utf8::encode($ch);
+ return $ch;
+}
+
+sub encode_S
+{
+ # encode single byte
+ ## my ($ch,$page) = @_; return chr($ch);
+ return chr $_[0];
+}
+
+sub encode_D
+{
+ # encode double byte MS byte first
+ ## my ($ch,$page) = @_; return chr($page).chr($ch);
+ return chr ($_[1]) . chr $_[0];
+}
+
+sub encode_M
+{
+ # encode Multi-byte - single for 0..255 otherwise double
+ ## my ($ch,$page) = @_;
+ ## return &encode_D if $page;
+ ## return &encode_S;
+ return chr ($_[1]) . chr $_[0] if $_[1];
+ return chr $_[0];
+}
+
+my %encode_types = (U => \&encode_U,
+ S => \&encode_S,
+ D => \&encode_D,
+ M => \&encode_M,
+ );
+
+# Win32 does not expand globs on command line
+if ($^O eq 'MSWin32' and !$ENV{PERL_CORE}) {
+ eval "\@ARGV = map(glob(\$_),\@ARGV)";
+ @ARGV = @orig_ARGV unless @ARGV;
+}
+
+my %opt;
+# I think these are:
+# -Q to disable the duplicate codepoint test
+# -S make mapping errors fatal
+# -q to remove comments written to output files
+# -O to enable the (brute force) substring optimiser
+# -o