EVERYTHING FROM THE OTHER REPO

This commit is contained in:
2026-07-29 03:36:26 +03:00
parent 6777ea96db
commit 92a6ae42f5
4426 changed files with 1696506 additions and 2 deletions
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh -e
if test $# -eq 0
then
echo "usage: $0 shellname [shellname ...]"
exit 1
fi
file="$DPKG_ROOT/etc/shells"
# I want this to be GUARANTEED to be on the same filesystem as $file
tmpfile="${file}.tmp"
set -o noclobber
cleanup() {
rm -f "$tmpfile"
}
trap cleanup EXIT
if ! cat "$file" > "$tmpfile"
then
cat 1>&2 <<EOF
Either another instance of $0 is running, or it was previously interrupted.
Please examine ${tmpfile} to see if it should be moved onto ${file}.
EOF
exit 1
fi
for i
do
REALDIR="$(dirname "$(realpath -m "$i")")/$(basename "$i")"
for j in "$i" "$REALDIR"
do
if ! grep -q "^${j}$" "$tmpfile"
then
echo "$j" >> "$tmpfile"
fi
done
done
chmod --reference="${file}" "${tmpfile}" || chmod $(stat -c %a "${file}") "${tmpfile}"
chown --reference="${file}" "${tmpfile}" || chown $(stat -c %U "${file}") "${tmpfile}"
mv -Z "${tmpfile}" "${file}" || mv "${tmpfile}" "${file}"
trap "" EXIT
exit 0
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+190
View File
@@ -0,0 +1,190 @@
#!/usr/bin/perl
# This file was preprocessed, do not edit!
use warnings;
use strict;
BEGIN {
eval qq{
use File::Path qw(make_path remove_tree);
use FileHandle;
use Debconf::Log qw(:all);
use Debconf::Db;
use Debconf::Template;
use Debconf::Config;
use Debconf::AutoSelect qw(:all);
use Debconf::Gettext;
use Debconf::Path;
};
if ($@) {
print STDERR "debconf: Perl may be unconfigured ($@) -- aborting\n";
exit 0;
}
}
if (exists $ENV{DEBCONF_USE_CDEBCONF} and $ENV{DEBCONF_USE_CDEBCONF} ne '') {
exec "/usr/lib/cdebconf/dpkg-preconfigure", @ARGV;
}
chdir('/');
Debconf::Db->load;
my $apt=0;
Debconf::Config->getopt(
qq{Usage: dpkg-preconfigure [options] [debs]
--apt Apt mode.},
"apt" => \$apt,
);
$|=1;
my @debs=@ARGV;
@ARGV=();
my $have_tty=1;
if ($apt) {
while (<STDIN>) {
chomp;
push @debs, $_ if length $_;
}
exit unless @debs;
$have_tty=0 unless open (STDIN, "<", "/dev/tty");
}
elsif (! @debs) {
print STDERR sprintf("dpkg-preconfigure: ".gettext("must specify some debs to preconfigure")), "\n";
exit(1);
}
my $apt_extracttemplates;
if (-x '/usr/lib/apt/apt-extracttemplates') {
$apt_extracttemplates = '/usr/lib/apt/apt-extracttemplates';
} elsif (Debconf::Path::find('apt-extracttemplates')) {
$apt_extracttemplates = 'apt-extracttemplates';
} else {
warn gettext("delaying package configuration, since apt-utils is not installed");
exit;
}
my $frontend=make_frontend();
if (! $have_tty && $frontend->need_tty) {
print STDERR sprintf("dpkg-preconfigure: ".gettext("unable to re-open stdin: %s"), $!)."\n";
exit 0;
}
my $tempdir='/var/cache/debconf/tmp.ci';
remove_tree($tempdir, { safe => 1, keep_root => 1 });
make_path($tempdir);
my ($package, $version, $template, $config);
pipe(my $info_reader, my $info_writer) or die "debconf: pipe failed: $!";
my $pid = fork();
defined $pid or die "fork failed: $!";
unless ($pid) {
close($info_reader);
my $command_max=20000; # LINUX SPECIFIC!!
my $static_len=length($apt_extracttemplates);
my $len=$static_len;
my @collect;
my $progress=0;
my $show_progress=($apt && @debs > 30 && -t STDERR);
sub apt_extracttemplates {
my $apt_extracttemplates_pid = fork();
my $error;
if (not defined $apt_extracttemplates_pid) {
$error = $!;
} elsif (not $apt_extracttemplates_pid) {
open(STDOUT, ">&", $info_writer)
or die "debconf: redirect stdout failed: $!";
exec($apt_extracttemplates, "--tempdir", $tempdir, @collect)
or die "debconf: exec $apt_extracttemplates failed: $!";
} else {
my $child = waitpid($apt_extracttemplates_pid, 0);
if ($child == -1) {
$error = $!;
} elsif ($?) {
$error = $?;
}
}
print STDERR sprintf("debconf: ".gettext("apt-extracttemplates failed: %s")."\n", $error) if defined $error;
if ($show_progress) {
$progress += @collect;
printf "\r".gettext("Extracting templates from packages: %d%%"), $progress * 100 / @debs;
}
return;
}
if ($show_progress) {
STDOUT->autoflush(1);
}
foreach my $deb (@debs) {
$len += length($deb) + 1;
if ($len < $command_max && @collect < 30) {
push @collect, $deb;
}
else {
apt_extracttemplates();
@collect=($deb);
$len=$static_len + length($deb) + 1;
}
}
apt_extracttemplates();
print "\n" if $show_progress;
exit;
}
close($info_writer);
my @buffer=<$info_reader>;
if ($apt && @buffer) {
print gettext("Preconfiguring packages ...\n");
}
foreach my $line (@buffer) {
($package, $version, $template, $config)=split /\s/, $line;
if (defined $template && length $template) {
eval {
Debconf::Template->load($template, $package)
};
unlink $template;
if ($@) {
print STDERR "$package ".sprintf(gettext("template parse error: %s"), $@)."\n";
unlink $config;
next;
}
}
}
foreach my $line (@buffer) {
($package, $version, $template, $config)=split /\s/, $line;
if (defined $config && length $config && -e $config) {
debug user => sprintf("preconfiguring %s (%s)",$package,$version);
chmod(0755, $config) or
die sprintf(gettext("debconf: can't chmod: %s"), $!);
$frontend->default_title($package);
$frontend->info(undef);
my $confmodule=make_confmodule($config, 'configure', $version);
$confmodule->owner($package);
1 while ($confmodule->communicate);
if ($confmodule->exitcode > 0) {
print STDERR sprintf(
gettext("%s failed to preconfigure, with exit status %s"),
$package, $confmodule->exitcode)."\n";
}
unlink $config;
}
}
$frontend->shutdown;
Debconf::Db->save;
remove_tree($tempdir, { safe => 1, keep_root => 1 });
+201
View File
@@ -0,0 +1,201 @@
#!/usr/bin/perl
# This file was preprocessed, do not edit!
use warnings;
use strict;
if (exists $ENV{DEBCONF_USE_CDEBCONF} and $ENV{DEBCONF_USE_CDEBCONF} ne '') {
exec "/usr/lib/cdebconf/dpkg-reconfigure", @ARGV;
}
use Cwd;
use Debconf::Db;
use Debconf::Gettext;
use Debconf::Template;
use Debconf::Config;
use Debconf::AutoSelect qw(:all);
use Debconf::Log qw(:all);
Debconf::Config->priority('low');
my $unseen_only=0;
my $force=0;
my $default_priority=0;
my $reload=1;
Debconf::Config->getopt(
gettext(qq{Usage: dpkg-reconfigure [options] packages
-u, --unseen-only Show only not yet seen questions.
--default-priority Use default priority instead of low.
--force Force reconfiguration of broken packages.
--no-reload Do not reload templates. (Use with caution.)}),
"unseen-only|u" => \$unseen_only,
"default-priority" => \$default_priority,
"force" => \$force,
"reload!" => \$reload,
);
if ($> != 0) {
print STDERR sprintf(gettext("%s must be run as root"), $0)."\n";
exit 1;
}
Debconf::Db->load;
if ($default_priority) {
Debconf::Config->priority(Debconf::Question->get('debconf/priority')->value);
}
if (lc Debconf::Config->frontend eq 'noninteractive' &&
! Debconf::Config->frontend_forced) {
Debconf::Config->frontend('dialog');
}
my $frontend=make_frontend();
unless ($unseen_only) {
Debconf::Config->reshow(1);
}
my @packages=@ARGV;
if (! @packages) {
print STDERR "$0: ".gettext("please specify a package to reconfigure")."\n";
exit 1;
}
$ENV{DEBCONF_RECONFIGURE}=1;
my %initial_triggers=map { $_ => 1 } triggers_pending();
my $original_cwd=getcwd();
foreach my $pkg (@packages) {
$frontend->default_title($pkg);
$frontend->info(undef);
$_=`dpkg --status $pkg`;
my ($version)=m/Version: (.*)\n/;
my ($status)=m/Status: (.*)\n/;
my ($package)=m/Package: (.*)\n/;
my ($arch)=m/Architecture: (.*)\n/;
if (! $force) {
if (! defined $status || $status =~ m/not-installed$/) {
print STDERR "$0: ".sprintf(gettext("%s is not installed"), $pkg)."\n";
exit 1;
}
if ($status !~ m/ ok installed$/) {
print STDERR "$0: ".sprintf(gettext("%s is broken or not fully installed"), $pkg)."\n";
exit 1;
}
}
my @control_paths=`dpkg-query --control-path $pkg`;
map { my $line = $_; chomp $line; $line } @control_paths;
my $control_path = sub {
my $file = shift;
my $path = (grep { /\.\Q$file\E$/ } @control_paths)[0];
chomp($path) if defined $path;
return $path;
};
if ($reload) {
my $templates=$control_path->('templates');
if ($templates and -e $templates) {
Debconf::Template->load($templates, $pkg);
}
}
foreach my $info (['prerm', 'upgrade', $version],
['preinst', 'upgrade', $version],
['config', 'reconfigure', $version],
['postinst', 'configure', $version]) {
my $script=shift @$info;
my $path_script=$control_path->($script);
next unless $path_script and -x $path_script;
my $is_confmodule='';
$ENV{DPKG_MAINTSCRIPT_PACKAGE}=$package;
$ENV{DPKG_MAINTSCRIPT_ARCH}=$arch;
$ENV{DPKG_MAINTSCRIPT_NAME}=$script;
if ($script ne 'config') {
open (my $in, "<", $path_script);
while (<$in>) {
if (/confmodule/i) {
$is_confmodule=1;
last;
}
}
close $in;
}
chdir('/');
if ($script eq 'config' || $is_confmodule) {
my $confmodule=make_confmodule($path_script, @$info);
$confmodule->owner($pkg);
1 while ($confmodule->communicate);
exit $confmodule->exitcode if $confmodule->exitcode > 0;
}
else {
run_external($path_script, @$info);
}
chdir($original_cwd);
}
}
my @new_triggers;
do {
@new_triggers=();
foreach my $trigpend (triggers_pending()) {
push @new_triggers, $trigpend
if not exists $initial_triggers{$trigpend};
}
if (@new_triggers) {
chdir('/');
run_external("dpkg", "--configure", @new_triggers);
chdir($original_cwd);
}
} while (@new_triggers);
$frontend->shutdown;
Debconf::Db->save;
sub run_external {
Debconf::Db->save;
delete $ENV{DEBIAN_HAS_FRONTEND};
my $ret=system(@_);
if (int($ret / 256) != 0) {
exit int($ret / 256);
}
$ENV{DEBIAN_HAS_FRONTEND}=1;
Debconf::Db->load;
}
sub triggers_pending {
my @ret;
local $_;
open (my $query, '-|', 'dpkg-query', '-W',
'-f', '${Package} ${binary:Package}\t${Triggers-Pending}\n');
while (<$query>) {
chomp;
my ($pkgnames, $triggers) = split /\t/;
if (length $triggers) {
my ($pkg, $binpkg) = split ' ', $pkgnames;
push @ret, (length $binpkg ? $binpkg : $pkg);
}
}
close $query;
return @ret;
}
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
agetty
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+92
View File
@@ -0,0 +1,92 @@
#!/bin/sh
#
# Copyright (C) 1995 - 1998, Ian A. Murdock <imurdock@debian.org>
# Copyright (C) 1998, 1999, Guy Maor
# Copyright (C) 2002, Matthew Wilcox
# Copyright (C) 2002, 2004, 2005, 2007, 2009 Clint Adams
# Copyright (C) 2009 Manoj Srivasta
#
# Install the kernel on a Debian Linux system.
#
# This script is called from /usr/src/linux/arch/i386/boot/install.sh.
# If you install it as /sbin/installkernel, you can do a "make install"
# from a generic kernel source tree, and the image will be installed to
# the proper place for Debian GNU/Linux.
set -e
# Parse the command line options. Of course, powerpc has to be all
# different, and passes in a fifth argument, just because it is
# "special". We ignore the fifth argument, and do not flag is as an
# error, which it would be for any arch apart from powerpc
if [ $# -eq 3 ] || [ $# -eq 4 ] || [ $# -eq 5 ] ; then
img="$2"
map="$3"
ver="$1"
if [ $# -ge 4 ] && [ -n "$4" ] ; then
dir="$4"
else
dir="/boot"
fi
else
echo "Usage: installkernel <version> <image> <System.map> <directory>"
exit 1
fi
# Create backups of older versions before installing
updatever () {
if [ -f "$dir/$1-$ver" ] ; then
mv "$dir/$1-$ver" "$dir/$1-$ver.old"
fi
cat "$2" > "$dir/$1-$ver"
# This section is for backwards compatibility only
if test -f "$dir/$1" || test -h "$dir/$1" ; then
# The presence of "$dir/$1" is unusual in modern intallations, and
# the results are mostly unused. So only recreate them if they
# already existed.
if test -L "$dir/$1" ; then
# If we were using links, continue to use links, updating if
# we need to.
if [ "$(readlink -f ${dir}/${1})" = "${dir}/${1}-${ver}" ]; then
# Yup, we need to change
ln -sf "$1-$ver.old" "$dir/$1.old"
else
mv "$dir/$1" "$dir/$1.old"
fi
ln -sf "$1-$ver" "$dir/$1"
else # No links
mv "$dir/$1" "$dir/$1.old"
cat "$2" > "$dir/$1"
fi
fi
}
case "$(basename $img)" in
"vmlinux"|"Image")
img_dest=vmlinux
;;
*)
img_dest=vmlinuz
;;
esac
updatever $img_dest "$img"
updatever System.map "$map"
config=$(dirname "$map")
config="${config}/.config"
if [ -f "$config" ] ; then
updatever config "$config"
fi
# If installing in the usual directory, run the same scripts that hook
# into kernel package installation. Also make sure the PATH includes
# /usr/sbin and /sbin, just as dpkg would.
if [ "$dir" = "/boot" ]; then
PATH="$PATH:/usr/sbin:/sbin" \
run-parts --verbose --exit-on-error --arg="$ver" --arg="$dir/$img_dest-$ver" \
/etc/kernel/postinst.d /usr/share/kernel/postinst.d
fi
exit 0
+574
View File
@@ -0,0 +1,574 @@
#!/bin/sh
# vim: ft=sh
#
# invoke-rc.d.sysvinit - Executes initscript actions
#
# SysVinit /etc/rc?.d version for Debian's sysvinit package
#
# Copyright (C) 2000,2001 Henrique de Moraes Holschuh <hmh@debian.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, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
# Constants
RUNLEVELHELPER=/sbin/runlevel
POLICYHELPER=$DPKG_ROOT/usr/sbin/policy-rc.d
INITDPREFIX=/etc/init.d/
RCDPREFIX=/etc/rc
# Options
BEQUIET=
MODE=
ACTION=
FALLBACK=
NOFALLBACK=
FORCE=
RETRY=
RETURNFAILURE=
RC=
is_systemd=
is_openrc=
SKIP_SYSTEMD_NATIVE=
# Shell options
set +e
dohelp () {
#
# outputs help and usage
#
cat <<EOF
invoke-rc.d, Debian/SysVinit (/etc/rc?.d) initscript subsystem.
Copyright (c) 2000,2001 Henrique de Moraes Holschuh <hmh@debian.org>
Usage:
invoke-rc.d [options] <basename> <action> [extra parameters]
basename - Initscript ID, as per update-rc.d(8)
action - Initscript action. Known actions are:
start, [force-]stop, [try-]restart,
[force-]reload, status
WARNING: not all initscripts implement all of the above actions.
extra parameters are passed as is to the initscript, following
the action (first initscript parameter).
Options:
--quiet
Quiet mode, no error messages are generated.
--force
Try to run the initscript regardless of policy and subsystem
non-fatal errors.
--try-anyway
Try to run init script even if a non-fatal error is found.
--disclose-deny
Return status code 101 instead of status code 0 if
initscript action is denied by local policy rules or
runlevel constrains.
--query
Returns one of status codes 100-106, does not run
the initscript. Implies --disclose-deny and --no-fallback.
--no-fallback
Ignores any fallback action requests by the policy layer.
Warning: this is usually a very *bad* idea for any actions
other than "start".
--skip-systemd-native
Exits before doing anything if a systemd environment is detected
and the requested service is a native systemd unit.
This is useful for maintainer scripts that want to defer systemd
actions to deb-systemd-invoke
--help
Outputs help message to stdout
EOF
}
printerror () {
#
# prints an error message
# $* - error message
#
if test x${BEQUIET} = x ; then
echo `basename $0`: "$*" >&2
fi
}
formataction () {
#
# formats a list in $* into $printaction
# for human-friendly printing to stderr
# and sets $naction to action or actions
#
printaction=`echo $* | sed 's/ /, /g'`
if test $# -eq 1 ; then
naction=action
else
naction=actions
fi
}
querypolicy () {
#
# queries policy database
# returns: $RC = 104 - ok, run
# $RC = 101 - ok, do not run
# other - exit with status $RC, maybe run if $RETRY
# initial status of $RC is taken into account.
#
policyaction="${ACTION}"
if test x${RC} = "x101" ; then
if test "${ACTION}" = "start" || test "${ACTION}" = "restart" || test "${ACTION}" = "try-restart"; then
policyaction="(${ACTION})"
fi
fi
if test "x${POLICYHELPER}" != x && test -x "${POLICYHELPER}" ; then
FALLBACK=`${POLICYHELPER} ${BEQUIET} ${INITSCRIPTID} "${policyaction}" ${RL}`
RC=$?
formataction ${ACTION}
case ${RC} in
0) RC=104
;;
1) RC=105
;;
101) if test x${FORCE} != x ; then
printerror Overriding policy-rc.d denied execution of ${printaction}.
RC=104
else
printerror policy-rc.d denied execution of ${printaction}.
fi
;;
esac
if test x${MODE} != xquery ; then
case ${RC} in
105) printerror policy-rc.d query returned \"behaviour undefined\",
printerror assuming \"${printaction}\" is allowed.
RC=104
;;
106) formataction ${FALLBACK}
if test x${FORCE} = x ; then
if test x${NOFALLBACK} = x ; then
ACTION="${FALLBACK}"
printerror executing ${naction} \"${printaction}\" instead due to policy-rc.d request.
RC=104
else
printerror ignoring policy-rc.d fallback request: ${printaction}.
RC=101
fi
else
printerror ignoring policy-rc.d fallback request: ${printaction}.
RC=104
fi
;;
esac
fi
case ${RC} in
100|101|102|103|104|105|106) ;;
*) printerror WARNING: policy-rc.d returned unexpected error status ${RC}, 102 used instead.
RC=102
;;
esac
else
if test ! -e "/sbin/init" ; then
if test x${FORCE} != x ; then
printerror "WARNING: No init system and policy-rc.d missing, but force specified so proceeding."
else
printerror "WARNING: No init system and policy-rc.d missing! Defaulting to block."
RC=101
fi
fi
if test x${RC} = x ; then
RC=104
fi
fi
return
}
verifyparameter () {
#
# Verifies if $1 is not null, and $# = 1
#
if test $# -eq 0 ; then
printerror syntax error: invalid empty parameter
exit 103
elif test $# -ne 1 ; then
printerror syntax error: embedded blanks are not allowed in \"$*\"
exit 103
fi
return
}
##
## main
##
## Verifies command line arguments
if test $# -eq 0 ; then
printerror syntax error: missing required parameter, --help assumed
dohelp
exit 103
fi
state=I
while test $# -gt 0 && test ${state} != III ; do
case "$1" in
--help) dohelp
exit 0
;;
--quiet) BEQUIET=--quiet
;;
--force) FORCE=yes
RETRY=yes
;;
--try-anyway)
RETRY=yes
;;
--disclose-deny)
RETURNFAILURE=yes
;;
--query) MODE=query
RETURNFAILURE=yes
;;
--no-fallback)
NOFALLBACK=yes
;;
--skip-systemd-native) SKIP_SYSTEMD_NATIVE=yes
;;
--*) printerror syntax error: unknown option \"$1\"
exit 103
;;
*) case ${state} in
I) verifyparameter $1
INITSCRIPTID=$1
;;
II) verifyparameter $1
ACTION=$1
;;
esac
state=${state}I
;;
esac
shift
done
if test ${state} != III ; then
printerror syntax error: missing required parameter
exit 103
fi
#NOTE: It may not be obvious, but "$@" from this point on must expand
#to the extra initscript parameters, except inside functions.
if test -d /run/systemd/system ; then
is_systemd=1
UNIT="${INITSCRIPTID%.sh}.service"
elif test -f /run/openrc/softlevel ; then
is_openrc=1
elif test ! -f "${INITDPREFIX}${INITSCRIPTID}" ; then
## Verifies if the given initscript ID is known
## For sysvinit, this error is critical
printerror unknown initscript, ${INITDPREFIX}${INITSCRIPTID} not found.
fi
## Queries sysvinit for the current runlevel
if [ ! -x ${RUNLEVELHELPER} ] || ! RL=`${RUNLEVELHELPER}`; then
if [ -n "$is_systemd" ] && systemctl is-active --quiet sysinit.target; then
# under systemd, the [2345] runlevels are only set upon reaching them;
# if we are past sysinit.target (roughly equivalent to rcS), consider
# this as runlevel 5 (this is only being used for validating rcN.d
# symlinks, so the precise value does not matter much)
RL=5
else
printerror "could not determine current runlevel"
# this usually fails in schroots etc., ignore failure (#823611)
RL=
fi
fi
# strip off previous runlevel
RL=${RL#* }
## Running ${RUNLEVELHELPER} to get current runlevel do not work in
## the boot runlevel (scripts in /etc/rcS.d/), as /var/run/utmp
## contains runlevel 0 or 6 (written at shutdown) at that point.
if test x${RL} = x0 || test x${RL} = x6 ; then
if ps -fp 1 | grep -q 'init boot' ; then
RL=S
fi
fi
## Handles shutdown sequences VERY safely
## i.e.: forget about policy, and do all we can to run the script.
## BTW, why the heck are we being run in a shutdown runlevel?!
if test x${RL} = x0 || test x${RL} = x6 ; then
FORCE=yes
RETRY=yes
POLICYHELPER=
BEQUIET=
printerror "-----------------------------------------------------"
printerror "WARNING: 'invoke-rc.d ${INITSCRIPTID} ${ACTION}' called"
printerror "during shutdown sequence."
printerror "enabling safe mode: initscript policy layer disabled"
printerror "-----------------------------------------------------"
fi
## Verifies the existance of proper S??initscriptID and K??initscriptID
## *links* in the proper /etc/rc?.d/ directory
verifyrclink () {
#
# verifies if parameters are non-dangling symlinks
# all parameters are verified
#
doexit=
while test $# -gt 0 ; do
if test ! -L "$1" ; then
printerror not a symlink: $1
doexit=102
fi
if test ! -f "$1" ; then
printerror dangling symlink: $1
doexit=102
fi
shift
done
if test x${doexit} != x && test x${RETRY} = x; then
exit ${doexit}
fi
return 0
}
testexec () {
#
# returns true if any of the parameters is
# executable (after following links)
#
while test $# -gt 0 ; do
if test -x "$1" ; then
return 0
fi
shift
done
return 1
}
RC=
###
### LOCAL POLICY: Enforce that the script/unit is enabled. For SysV init
### scripts, this needs a start entry in either runlevel S or current runlevel
### to allow start or restart.
if [ -n "$is_systemd" ]; then
case ${ACTION} in
start|restart|try-restart)
# If a package ships both init script and systemd service file, the
# systemd unit will not be enabled by the time invoke-rc.d is called
# (with current debhelper sequence). This would make systemctl is-enabled
# report the wrong status, and then the service would not be started.
# This check cannot be removed as long as we support not passing --skip-systemd-native
if systemctl --quiet is-enabled "${UNIT}" 2>/dev/null || \
ls ${RCDPREFIX}[S2345].d/S[0-9][0-9]${INITSCRIPTID} >/dev/null 2>&1; then
RC=104
elif systemctl --quiet is-active "${UNIT}" 2>/dev/null; then
RC=104
else
RC=101
fi
;;
esac
else
# we do handle multiple links per runlevel
# but we don't handle embedded blanks in link names :-(
if test x${RL} != x ; then
SLINK=`ls -d -Q ${RCDPREFIX}${RL}.d/S[0-9][0-9]${INITSCRIPTID} 2>/dev/null | xargs`
KLINK=`ls -d -Q ${RCDPREFIX}${RL}.d/K[0-9][0-9]${INITSCRIPTID} 2>/dev/null | xargs`
SSLINK=`ls -d -Q ${RCDPREFIX}S.d/S[0-9][0-9]${INITSCRIPTID} 2>/dev/null | xargs`
verifyrclink ${SLINK} ${KLINK} ${SSLINK}
fi
case ${ACTION} in
start|restart|try-restart)
if testexec ${SLINK} ; then
RC=104
elif testexec ${KLINK} ; then
RC=101
elif testexec ${SSLINK} ; then
RC=104
else
RC=101
fi
;;
esac
fi
# test if /etc/init.d/initscript is actually executable
_executable=
if [ -n "$is_systemd" ]; then
_executable=1
elif testexec "${INITDPREFIX}${INITSCRIPTID}"; then
_executable=1
fi
if [ "$_executable" = "1" ]; then
if test x${RC} = x && test x${MODE} = xquery ; then
RC=105
fi
# call policy layer
querypolicy
case ${RC} in
101|104)
;;
*) if test x${MODE} != xquery ; then
printerror policy-rc.d returned error status ${RC}
if test x${RETRY} = x ; then
exit ${RC}
else
RC=102
fi
fi
;;
esac
else
###
### LOCAL INITSCRIPT POLICY: non-executable initscript; deny exec.
### (this is common sense, actually :^P )
###
RC=101
fi
## Handles --query
if test x${MODE} = xquery ; then
exit ${RC}
fi
setechoactions () {
if test $# -gt 1 ; then
echoaction=true
else
echoaction=
fi
}
getnextaction () {
saction=$1
shift
ACTION="$@"
}
## Executes initscript
## note that $ACTION is a space-separated list of actions
## to be attempted in order until one suceeds.
if test x${FORCE} != x || test ${RC} -eq 104 ; then
if [ -n "$is_systemd" ] || testexec "${INITDPREFIX}${INITSCRIPTID}" ; then
RC=102
setechoactions ${ACTION}
while test ! -z "${ACTION}" ; do
getnextaction ${ACTION}
if test ! -z ${echoaction} ; then
printerror executing initscript action \"${saction}\"...
fi
if [ -n "$is_systemd" ]; then
if [ "$SKIP_SYSTEMD_NATIVE" = yes ] ; then
case $(systemctl show --value --property SourcePath "${UNIT}") in
/etc/init.d/*)
;;
*)
# We were asked to skip native systemd units, and this one was not generated by the sysv generator
# exit cleanly
exit 0
;;
esac
fi
_state=$(systemctl -p LoadState show "${UNIT}" 2>/dev/null)
case $saction in
start|restart|try-restart)
[ "$_state" != "LoadState=masked" ] || exit 0
systemctl $sctl_args "${saction}" "${UNIT}" && exit 0
;;
stop|status)
systemctl $sctl_args "${saction}" "${UNIT}" && exit 0
;;
reload)
[ "$_state" != "LoadState=masked" ] || exit 0
_canreload="$(systemctl -p CanReload show ${UNIT} 2>/dev/null)"
# Don't block on reload requests during bootup and shutdown
# from units/hooks and simply schedule the task.
if ! systemctl --quiet is-system-running; then
sctl_args="--no-block"
fi
if [ "$_canreload" = "CanReload=no" ]; then
"${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0
else
systemctl $sctl_args reload "${UNIT}" && exit 0
fi
;;
force-stop)
systemctl --signal=KILL kill "${UNIT}" && exit 0
;;
force-reload)
[ "$_state" != "LoadState=masked" ] || exit 0
_canreload="$(systemctl -p CanReload show ${UNIT} 2>/dev/null)"
if [ "$_canreload" = "CanReload=no" ]; then
systemctl $sctl_args restart "${UNIT}" && exit 0
else
systemctl $sctl_args reload "${UNIT}" && exit 0
fi
;;
*)
# We try to run non-standard actions by running
# the init script directly.
"${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0
;;
esac
elif [ -n "$is_openrc" ]; then
rc-service "${INITSCRIPTID}" "${saction}" && exit 0
else
"${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0
fi
RC=$?
if test ! -z "${ACTION}" ; then
printerror action \"${saction}\" failed, trying next action...
fi
done
printerror initscript ${INITSCRIPTID}, action \"${saction}\" failed.
if [ -n "$is_systemd" ] && [ "$saction" = start -o "$saction" = restart -o "$saction" = "try-restart" ]; then
systemctl status --full --no-pager "${UNIT}" || true
fi
exit ${RC}
fi
exit 102
fi
## Handles --disclose-deny and denied "status" action (bug #381497)
if test ${RC} -eq 101 && test x${RETURNFAILURE} = x ; then
if test "x${ACTION%% *}" = "xstatus"; then
printerror emulating initscript action \"status\", returning \"unknown\"
RC=4
else
RC=0
fi
else
formataction ${ACTION}
printerror initscript ${naction} \"${printaction}\" not executed.
fi
exit ${RC}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+746
View File
@@ -0,0 +1,746 @@
#!/usr/bin/perl -w
# pam-auth-update: update /etc/pam.d/common-* from /usr/share/pam-configs
#
# Update the /etc/pam.d/common-* files based on the per-package profiles
# provided in /usr/share/pam-configs/ taking into consideration user's
# preferences (as determined via debconf prompting).
#
# Written by Steve Langasek <steve.langasek@canonical.com>
#
# Copyright (C) 2008 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 3 of the GNU General Public License as
# published by the Free Software Foundation.
#
# # 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
# USA.
use strict;
use Debconf::Client::ConfModule ':all';
use IPC::Open2 'open2';
version('2.0');
my $capb=capb('backup escape');
my $inputdir = '/usr/share/pam-configs';
my $template = 'libpam-runtime/profiles';
my $errtemplate = 'libpam-runtime/conflicts';
my $overridetemplate = 'libpam-runtime/override';
my $blanktemplate = 'libpam-runtime/no_profiles_chosen';
my $titletemplate = 'libpam-runtime/title';
my $confdir = '/etc/pam.d';
my $savedir = '/var/lib/pam';
my (%profiles, @sorted, @enabled, @conflicts, @new, %removals, %to_disable, %to_enable);
my $force = 0;
my $package = 0;
my $priority = 'high';
my %md5sums = (
'auth' => ['8d4fe17e66ba25de16a117035d1396aa'],
'account' => ['3c0c362eaf3421848b679d63fd48c3fa'],
'password' => [
'4d5c92d595a46b69cd61f18feb4c0574',
'50fce2113dfda83ac8bdd5a6e706caec',
'4bd7610f2e85f8ddaef79c7db7cb49eb',
'9ba753d0824276b44bcadfee1f87b6bc',
],
'session' => [
'f297c731a467822cbd86e1283263e8a3',
'240fb92986c885b327cdb21dd641da8c',
'4a25673e8b36f1805219027d3be02cd2',
'9e633425b1878897695217ecaf75e204',
],
'session-noninteractive' => [
'ad2b78ce1498dd637ef36469430b6ac6',
'53c1ede0bf4c07879d3582d875917545',
],
);
my @invalid_modules = ('pam_tally');
# use a '--force' arg to specify that /etc/pam.d should be overwritten;
# used only on upgrades where the postinst has already determined that the
# checksums match. Module packages other than libpam-runtime itself must
# NEVER use this option! Document with big skullses and crossboneses! It
# needs to be exposed for libpam-runtime because that's the package that
# decides whether we have a pristine config to be converted, and knows
# whether the version being upgraded from is one for which the conversion
# should be done.
while ($#ARGV >= 0) {
my $opt = shift;
if ($opt eq '--force') {
$force = 1;
} elsif ($opt eq '--package') {
$package = 1;
} elsif ($opt eq '--root') {
my $rootdir = shift @ARGV;
$savedir = "${rootdir}$savedir";
$confdir = "${rootdir}$confdir";
$inputdir = "${rootdir}$inputdir";
} elsif ($opt eq '--remove') {
while ($#ARGV >= 0) {
last if ($ARGV[0] =~ /^--/);
$removals{shift @ARGV} = 1;
}
# --remove implies --package
$package = 1 if (keys(%removals));
} elsif ($opt eq '--disable') {
while ($#ARGV >= 0) {
last if ($ARGV[0] =~ /^--/);
$to_disable{shift @ARGV} = 1;
}
# --disable implies --package
$package = 1 if (keys(%to_disable));
} elsif ($opt eq '--enable') {
while ($#ARGV >= 0) {
last if ($ARGV[0] =~ /^--/);
$to_enable{shift @ARGV} = 1;
}
# --enable implies --package
$package = 1 if (keys(%to_enable));
}
}
opendir(DIR, $inputdir) || die "could not open config directory: $!";
while (my $profile = readdir(DIR)) {
next if ($profile eq '.' || $profile eq '..' || $profile =~ m/~$/ || $profile =~ m/^#.+#$/);
%{$profiles{$profile}} = parse_pam_profile($inputdir . '/' . $profile);
if (defined $profiles{$profile}{'disabled'} and $profiles{$profile}{'disabled'}) {
delete $profiles{$profile};
}
}
closedir DIR;
$priority = 'medium' if ($package);
x_loadtemplatefile('/var/lib/dpkg/info/libpam-runtime.templates','libpam-runtime');
# always sort by priority, so we have consistency and don't have to
# shuffle later
@sorted = sort { $profiles{$b}->{'Priority'} <=> $profiles{$a}->{'Priority'}
|| $b cmp $a }
keys(%profiles);
# If we're being called for package removal, filter out those options here
@sorted = grep { !$removals{$_} } @sorted;
subst($template, 'profile_names', join(', ',@sorted));
subst($template, 'profiles',
join(', ', map { $profiles{$_}->{'Name'} } @sorted));
my $diff = diff_profiles($confdir,$savedir);
if ($diff) {
@enabled = grep { !$removals{$_} } @{$diff->{'mods'}};
} else {
@enabled = split(/, /,get($template));
}
# find out what we've seen, so we can ignore those defaults
my %seen;
if (-e $savedir . '/seen') {
open(SEEN,$savedir . '/seen') or die("open(${savedir}/seen) failed: $!");
while (<SEEN>) {
chomp;
$seen{$_} = 1;
}
close(SEEN);
}
# filter out any options that are no longer available for any reason
@enabled = grep { $profiles{$_} } @enabled;
# add configs to enable
push(@enabled,
grep { $to_enable{$_} } @sorted);
# Disable anything explicitly disabled
@enabled = grep {!$to_disable{$_} } @enabled;
# And we've seen anything we disable
foreach my $i (keys %to_disable) {
$seen{$i} = 1;
}
# an empty module set is an error, so in that case grab all the defaults
if (!@enabled) {
%seen = ();
$priority = 'high' unless ($force);
}
# add any previously-unseen configs
push(@enabled,
grep { $profiles{$_}->{'Default'} eq 'yes' && !$seen{$_} } @sorted);
@enabled = sort { $profiles{$b}->{'Priority'} <=> $profiles{$a}->{'Priority'}
|| $b cmp $a }
@enabled;
my $prev = '';
@enabled = grep { $_ ne $prev && (($prev) = $_) } @enabled;
# Do we have any new options to show? If not, we shouldn't reprompt the
# user, at any priority level, unless explicitly called.
@new = grep { !$seen{$_} } @sorted;
settitle($titletemplate);
# if diff_profiles() fails, and we weren't passed a 'force' argument
# (because this isn't an upgrade from an old version, or the checksum
# didn't match, or we're being called by some other module package), prompt
# the user whether to override. If the user declines (the default), we
# never again manage this config unless manually called with '--force'.
if (!$diff && !$force) {
input('high',$overridetemplate);
go();
$force = 1 if (get($overridetemplate) eq 'true');
}
if (!$diff && !$force) {
print STDERR <<EOF;
pam-auth-update: Local modifications to /etc/pam.d/common-*, not updating.
pam-auth-update: Run pam-auth-update --force to override.
EOF
exit;
}
umask(0022);
do {
@conflicts = ();
if (@new || !$package) {
fset($template,'seen','false');
}
set($template,join(', ', @enabled));
input($priority,$template);
go();
@enabled = split(/, /, get($template));
# in case of conflicts, automatically unset the lower priority
# item of each pair
foreach my $elem (@enabled)
{
for (my $i=$#enabled; $i >= 0; $i--)
{
my $conflict = $enabled[$i];
if ($profiles{$elem}->{'Conflicts'}->{$conflict}) {
splice(@enabled,$i,1);
my $desc = $profiles{$elem}->{'Name'}
. ', ' . $profiles{$conflict}->{'Name'};
push(@conflicts,$desc);
}
}
}
if (@conflicts) {
subst($errtemplate, 'conflicts', join("\\n", @conflicts));
input('high',$errtemplate);
}
set($template, join(', ', @enabled));
if (!@enabled) {
input('high',$blanktemplate);
# we can only end up here by user error, but give them another
# shot at selecting a correct config anyway.
fset($template,'seen','false');
}
} while (@conflicts || !@enabled);
# the decision has been made about what configs to use, so even if
# something fails after this, we shouldn't go munging the default
# options again. Save the list of known configs to /var/lib/pam.
open(SEEN,"> $savedir/seen") or die("open(${savedir}/seen) failed: $!");
for my $i (@sorted) {
print SEEN "$i\n";
}
close(SEEN) or die("close(${savedir}/seen) failed: $!");
# @enabled now contains our list of profiles to use for piecing together
# a config
# we have:
# - templates into which we insert the specialness
# - magic comments denoting the beginning and end of our managed block;
# looking at only the functional config lines would potentially let us
# handle more cases, at the expense of much greater complexity, so
# pass on this at least for the first round
# - a representation of the autogenerated config stored in /var/lib/pam,
# that we can diff against in order to account for changed options or
# manually dropped modules
# - a hash describing the local modifications the user has made to the
# config; these are always preserved unless manually overridden with
# the --force option
write_profiles(\%profiles, \@enabled, $confdir, $savedir, $diff, $force);
# take a single line from a stock config, and merge it with the
# information about local admin edits
sub merge_one_line
{
my ($line,$diff,$count) = @_;
my (@opts,$modline);
my ($adds,$removes);
$line =~ /^((\[[^]]+\]|\w+)\s+\S+)\s*(.*)/;
@opts = split(/\s+/,$3);
$modline = $1;
$modline =~ s/end/$count/g;
if ($diff) {
my $mod = $modline;
$mod =~ s/(\[[^0-9]*)[0-9]+(.*\])/$1$2/g;
$adds = \%{$diff->{'add'}{$mod}};
$removes = \%{$diff->{'remove'}{$mod}};
} else {
$adds = $removes = undef;
}
for (my $i = 0; $i <= $#opts; $i++) {
if ($adds->{$opts[$i]}) {
delete $adds->{$opts[$i]};
}
if ($removes->{$opts[$i]}) {
splice(@opts,$i,1);
$i--;
}
}
return $modline . " " . join(' ',@opts,sort keys(%{$adds})) . "\n";
}
# return the lines for a given config name, type, and position in the stack
sub lines_for_module_and_type
{
my ($profiles, $mod, $type, $modpos) = @_;
if ($modpos == 0 && $profiles->{$mod}{$type . '-Initial'}) {
return $profiles->{$mod}{$type . '-Initial'};
}
return $profiles->{$mod}{$type};
}
# create a single PAM config from the indicated template and selections,
# writing to a new file
sub create_from_template
{
my($template,$dest,$profiles,$enabled,$diff,$type) = @_;
my $state = 0;
my $uctype = ucfirst($type);
$type =~ s/-noninteractive//;
open(INPUT,$template) || return 0;
open(OUTPUT,">$dest") || return 0;
while (<INPUT>) {
if ($state == 1) {
if (/^# here's the fallback if no module succeeds/) {
print OUTPUT;
$state++;
}
next;
}
if ($state == 3) {
if (/^# end of pam-auth-update config/) {
print OUTPUT;
$state++;
}
next;
}
print OUTPUT;
my ($pattern,$val);
if ($state == 0) {
$pattern = '^# here are the per-package modules \(the "Primary" block\)';
$val = 'Primary';
} elsif ($state == 2) {
$pattern = '^# and here are more per-package modules \(the "Additional" block\)';
$val = 'Additional';
} else {
next;
}
if (/$pattern/) {
my $i = 0;
my $count = 0;
# first we need to get a count of lines that we're
# going to output, so we can fix up the jumps correctly
for my $mod (@{$enabled}) {
my $output;
next if (!$profiles->{$mod}{$uctype . '-Type'});
next if $profiles->{$mod}{$uctype . '-Type'} ne $val;
$output = lines_for_module_and_type($profiles, $mod, $uctype, $i++);
# bypasses a perl warning about @_, sigh
my @tmparr = split("\n+",$output);
$count += @tmparr;
}
# in case anything tries to jump in the 'additional'
# block, let's try not to jump off the stack...
$count-- if ($val eq 'Additional');
# no primary block, so output a stock pam_permit line
# to keep the stack intact
if ($val eq 'Primary' && $count == 0)
{
print OUTPUT "$type\t[default=1]\t\t\tpam_permit.so\n";
}
$i = 0;
for my $mod (@{$enabled}) {
my $output;
my @output;
next if (!$profiles->{$mod}{$uctype . '-Type'});
next if $profiles->{$mod}{$uctype . '-Type'} ne $val;
$output = lines_for_module_and_type($profiles, $mod, $uctype, $i++);
for my $line (split("\n",$output)) {
$line = merge_one_line($line,$diff,
$count);
print OUTPUT "$type\t$line";
$count--;
}
}
$state++;
}
}
close(INPUT);
close(OUTPUT) or die("close($dest) failed: $!");
if ($state < 4) {
unlink($dest);
return 0;
}
return 1;
}
# take a template file, strip out everything between the markers, and
# return the md5sum of the remaining contents. Used for testing for
# local modifications of the boilerplate.
sub get_template_md5sum
{
my($template) = @_;
my $state = 0;
open(INPUT,$template) || return '';
my($md5sum_fd,$output_fd);
my $pid = open2($md5sum_fd, $output_fd, 'md5sum');
return '' if (!$pid);
while (<INPUT>) {
if ($state == 1) {
if (/^# here's the fallback if no module succeeds/) {
print $output_fd $_;
$state++;
}
next;
}
if ($state == 3) {
if (/^# end of pam-auth-update config/) {
print $output_fd $_;
$state++;
}
next;
}
print $output_fd $_;
my ($pattern,$val);
if ($state == 0) {
$pattern = '^# here are the per-package modules \(the "Primary" block\)';
} elsif ($state == 2) {
$pattern = '^# and here are more per-package modules \(the "Additional" block\)';
} else {
next;
}
if (/$pattern/) {
$state++;
}
}
close(INPUT);
close($output_fd);
my $md5sum = <$md5sum_fd>;
close($md5sum_fd);
waitpid $pid, 0;
$md5sum = (split(/\s+/,$md5sum))[0];
return $md5sum;
}
# merge a set of module declarations into a set of new config files,
# using the information returned from diff_profiles().
sub write_profiles
{
my($profiles,$enabled,$confdir,$savedir,$diff,$force) = @_;
if (! -d $savedir) {
mkdir($savedir);
}
# because we can't atomically replace both /var/lib/pam/$foo and
# /etc/pam.d/common-$foo at the same time, take steps to make this
# somewhat robust
for my $type ('auth','account','password','session',
'session-noninteractive')
{
my $target = $confdir . '/common-' . $type;
my $template = $target;
my $dest = $template . '.pam-new';
my $diff = $diff;
if ($diff) {
$diff = \%{$diff->{$type}};
}
# Detect if the template is unmodified, and if so, use
# the version from /usr/share. Depends on knowing the
# md5sums of the originals.
my $md5sum = get_template_md5sum($template);
for my $i (@{$md5sums{$type}}) {
if ($md5sum eq $i) {
$template = '/usr/share/pam/common-' . $type;
last;
}
}
# first, write out the new config
if (!create_from_template($template,$dest,$profiles,$enabled,
$diff,$type))
{
if (!$force) {
return 0;
}
$template = '/usr/share/pam/common-' . $type;
if (!create_from_template($template,$dest,$profiles,
$enabled,$diff,$type))
{
return 0;
}
}
# then write out the saved config
if (!open(OUTPUT, "> $savedir/$type.new")) {
unlink($dest);
return 0;
}
my $i = 0;
my $uctype = ucfirst($type);
for my $mod (@{$enabled}) {
my $output;
next if (!$profiles->{$mod}{$uctype . '-Type'});
next if ($profiles->{$mod}{$uctype . '-Type'} eq 'Additional');
$output = lines_for_module_and_type($profiles, $mod, $uctype, $i++);
if ($output) {
print OUTPUT "Module: $mod\n";
print OUTPUT $output . "\n";
}
}
# no primary block, so output a stock pam_permit line
if ($i == 0)
{
print OUTPUT "Module: null\n";
print OUTPUT "[default=1]\t\t\tpam_permit.so\n";
}
$i = 0;
for my $mod (@{$enabled}) {
my $output;
next if (!$profiles->{$mod}{$uctype . '-Type'});
next if ($profiles->{$mod}{$uctype . '-Type'} eq 'Primary');
$output = lines_for_module_and_type($profiles, $mod, $uctype, $i++);
if ($output) {
print OUTPUT "Module: $mod\n";
print OUTPUT $output . "\n";
}
}
close(OUTPUT) or die("close($dest) failed: $!");
# then do the renames, back-to-back
# we have to use system because File::Copy is in
# perl-modules, not perl-base
if (-e $target && $force) {
system('cp','-f',$target,$target . '.pam-old') == 0
or die("cp -f ${target} ${target}.pam.old failed");
}
rename($dest,$target)
or die("rename($dest, $target) failed: $!");
rename("$savedir/${type}.new","$savedir/$type")
or die("rename(${savedir}/${type}.new, ${savedir}/${type}) failed: $!");
}
# at the end of a successful write, reset the 'seen' flag and the
# value of the debconf override question.
fset($overridetemplate,'seen','false');
set($overridetemplate,'false');
}
# reconcile the current config in /etc/pam.d with the saved ones in
# /var/lib/pam; returns a hash of profile names and the corresponding
# options that should be added/removed relative to the stock config.
# returns false if any of the markers are missing that permit a merge,
# or on any other failure.
sub diff_profiles
{
my ($sourcedir,$savedir) = @_;
my (%diff);
@{$diff{'mods'}} = ();
# Load the saved config from /var/lib/pam, then iterate through all
# lines in the current config that are in the managed block.
# If anything fails here, just return immediately since we then
# have nothing to merge; instead, the caller will decide later
# whether to force an overwrite.
for my $type ('auth','account','password','session',
'session-noninteractive')
{
my (@saved,$modname);
open(SAVED,$savedir . '/' . $type) || return 0;
while (<SAVED>) {
if (/^Module: (.*)/) {
$modname = $1;
next;
}
chomp;
# trim out the destination of any jumps; this saves
# us from having to re-parse everything just to fix
# up the jump lengths, when changes to these will
# already show up as inconsistencies elsewhere
s/(\[[^0-9]*)[0-9]+(.*\])/$1$2/g;
s/(\[.*)end(.*\])/$1$2/g;
my (@temp) = ($modname,$_);
push(@saved,\@temp);
}
close(SAVED);
my $state = 0;
my (@prev_opts,$curmod);
my $realtype = $type;
$realtype =~ s/-noninteractive//;
open(CURRENT,$sourcedir . '/common-' . $type) || return 0;
while (<CURRENT>) {
if ($state == 0) {
$state = 1
if (/^# here are the per-package modules \(the "Primary" block\)/);
next;
}
if ($state == 1) {
s/^$realtype\s+//;
if (/^# here's the fallback if no module succeeds/) {
$state = 2;
next;
}
}
if ($state == 2) {
$state = 3
if (/^# and here are more per-package modules \(the "Additional" block\)/);
next;
}
if ($state == 3) {
last if (/^# end of pam-auth-update config/);
s/^$realtype\s+//;
}
my $found = 0;
my $curopts;
while (!$found && $#saved >= 0) {
my $line;
($modname,$line) = @{$saved[0]};
shift(@saved);
$line =~ /^((\[[^]]+\]|\w+)\s+\S+)\s*(.*)/;
@prev_opts = split(/\s+/,$3);
$curmod = $1;
# FIXME: the key isn't derived from the config
# name, so collisions are possible if more
# than one config references the same module
$_ =~ s/(\[[^0-9]*)[0-9]+(.*\])/$1$2/g;
# check if this is a match for the current line
if ($_ =~ /^\Q$curmod\E\s*(.*)$/) {
$found = 1;
$curopts = $1;
push(@{$diff{'mods'}},$modname);
}
}
# there's a line in the live config that doesn't
# correspond to anything from the saved config.
# treat this as a failure; it's very error-prone
# to decide what to do with an added line that
# didn't come from a package.
return 0 if (!$found);
for my $opt (split(/\s+/,$curopts)) {
my $found = 0;
for (my $i = 0; $i <= $#prev_opts; $i++) {
if ($prev_opts[$i] eq $opt) {
$found = 1;
splice(@prev_opts,$i,1);
}
}
$diff{$type}{'add'}{$curmod}{$opt} = 1 if (!$found);
}
for my $opt (@prev_opts) {
$diff{$type}{'remove'}{$curmod}{$opt} = 1;
}
}
close(CURRENT);
# we couldn't parse the config, so the merge fails
return 0 if ($state < 3);
}
return \%diff;
}
# simple function to parse a provided config file, in pseudo-RFC822
# format,
sub parse_pam_profile
{
my ($profile) = $_[0];
my $fieldname;
my %profile;
open(PROFILE, $profile) || die "could not read profile $profile: $!";
while (<PROFILE>) {
if (/^(\S+):\s+(.*)\s*$/) {
$fieldname = $1;
# compatibility with the first implementation round;
# "Auth-Final" is now just called "Auth"
$fieldname =~ s/-Final$//;
if ($fieldname eq 'Conflicts') {
foreach my $elem (split(/, /, $2)) {
$profile{'Conflicts'}->{$elem} = 1;
}
} else {
$profile{$fieldname} = $2;
}
} else {
chomp;
s/^\s+//;
s/\s+$//;
$profile{$fieldname} .= "\n$_" if ($_);
if (grep { $profile{$fieldname} =~ /$_/} @invalid_modules) {
$profile{'disabled'} = 1;
}
$profile{$fieldname} =~ s/^[\n\s]+//;
}
}
close(PROFILE);
if (!defined($profile{'Session-Interactive-Only'}) or $profile{'Session-Interactive-Only'} ne 'yes') {
$profile{'Session-noninteractive-Type'} = $profile{'Session-Type'};
$profile{'Session-noninteractive'} = $profile{'Session'};
$profile{'Session-noninteractive-Initial'} = $profile{'Session-Initial'};
}
return %profile;
}
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/perl -w
=head1 NAME
pam_getenv - get environment variables from /etc/environment
=head1 SYNOPSIS
pam_getenv B<[-l] [-s]> I<env_var>
=head1 DESCRIPTION
This tool will print out the value of I<env_var> from F</etc/environment>. It will attempt to expand environment variable references in the definition of I<env_var> but will fail if PAM items are expanded.
The B<-l> option indicates the script should return an environment variable related to default locale information.
The B<-s> option indicates that the script should return an
system default environment variable.
Currently neither the B<-l> or B<-s> options do anything. They are
included because future versions of Debian may have a separate
repository for the initial environment used by init scripts and for
system locale information. These options will allow this script to be
a stable interface even in that environment.
=cut
# Copyright 2004 by Sam Hartman
# This script may be copied under the terms of the GNU GPL
# version 2, or at your option any later version.
use strict;
use vars qw(*CONFIGFILE *ENVFILE);
sub read_line($) {
my $fh = shift;
my $line;
local $_;
line: while (<$fh>) {
chomp;
s/^\s+//;
s/\#.*$//;
next if $_ eq "";
if (s/\\\s*$//) {
$line .= $_;
next line;
}
$line .= $_;
last;
}
$line;
}
sub parse_line($) {
my $var;
my (%x, @x);
local $_ = shift;
return undef unless defined $_ and s/(\S+)\s//;
$var->{Name} = $1;
s/^\s*//;
@x = split(/=([^"\s]\S*|"[^"]*")\s*/, $_);
unless (scalar(@x)%2 == 0) {
push @x, undef;
}
%x = @x;
@{$var}{"Default", "Override"} =
@x{"DEFAULT", "OVERRIDE"};
$var;
}
sub expand_val($) {
my ($val) = @_;
return undef unless $val;
die "Cannot handle PAM items\n" if /(?<!\\)\@/;
$val =~ s/(?<!\\)\$\{([^}]+)\}/$ENV{$1}||""/eg;
return $val;
}
my $lookup;
while ($_ = shift) {
next if $_ eq "-s";
next if $_ eq "-l";
$lookup = $_;
last;
}
unless (defined $lookup) {
die "Usage: pam_getenv [-l] [-s] env_var\n";
}
my %allvars;
open (CONFIGFILE, "/etc/security/pam_env.conf")
or die "Cannot open environment file: $!\n";
while (my $var = parse_line(read_line(\*CONFIGFILE))) {
my $val;
unless ($val = expand_val($var->{Override})) {
$val = expand_val($var->{Default});
}
$allvars{$var->{Name}} = $val;
}
if (open (ENVFILE, "/etc/environment")) {
while (my $line = read_line(\*ENVFILE)) {
$line =~ s/^export //;
$line =~ /(.*?)=(.+)/ or next;
my ($var, $val) = ($1, $2);
# This is bizarre logic (" and ' match each other, quotes are only
# significant at the start and end of the string, and the trailing quote
# may be omitted), but it's what pam_env does.
$val =~ s/^["'](.*?)["']?$/$1/;
$allvars{$var} = $val;
}
}
if (exists $allvars{$lookup}) {
print $allvars{$lookup}, "\n";
exit(0);
}
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
CONF=/etc/security/namespace.conf
# Match logic of process_line(), except lines with $HOME are ignored
# skip the leading white space, rip off the comments, ignore empty lines
sed -e 's/^[ ]*//g' -e 's/#.*//g' -e '/.*\$HOME.*/d' -e '/^$/d' < $CONF | \
while read polydir instance_prefix method uids; do
if [ ! -e "$instance_prefix" ]; then
echo "mkdir $instance_prefix"
mkdir --parents --mode=0 -Z "$instance_prefix"
fi
done
exit 0
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh -e
if test $# -eq 0
then
echo "usage: $0 shellname [shellname ...]" 1>&2
exit 1
fi
file="$DPKG_ROOT/etc/shells"
# I want this to be GUARANTEED to be on the same filesystem as $file
tmpfile="${file}.tmp"
otmpfile="${file}.tmp2"
set -o noclobber
cleanup() {
rm -f "$tmpfile" "$otmpfile"
}
trap cleanup EXIT
if ! cat "$file" > "$tmpfile"
then
cat 1>&2 <<EOF
Either another instance of $0 is running, or it was previously interrupted.
Please examine ${tmpfile} to see if it should be moved onto ${file}.
EOF
exit 1
fi
# this is supposed to be reliable, not pretty
for i
do
REALDIR="$(dirname "$(realpath -m "$i")")/$(basename "$i")"
for j in "$i" "$REALDIR"
do
grep -v "^${j}$" "$tmpfile" > "$otmpfile" || true
mv "$otmpfile" "$tmpfile"
done
done
chmod --reference="${file}" "${tmpfile}" || chmod $(stat -c %a "${file}") "${tmpfile}"
chown --reference="${file}" "${tmpfile}" || chown $(stat -c %U "${file}") "${tmpfile}"
mv -Z "${tmpfile}" "${file}" || mv "${tmpfile}" "${file}"
trap "" EXIT
exit 0
Binary file not shown.
Binary file not shown.
Binary file not shown.
+219
View File
@@ -0,0 +1,219 @@
#!/bin/sh
###########################################################################
# /usr/bin/service
#
# A convenient wrapper for the /etc/init.d init scripts.
#
# This script is a modified version of the /sbin/service utility found on
# Red Hat/Fedora systems (licensed GPLv2+).
#
# Copyright (C) 2006 Red Hat, Inc. All rights reserved.
# Copyright (C) 2008 Canonical Ltd.
# * August 2008 - Dustin Kirkland <kirkland@canonical.com>
# Copyright (C) 2013 Michael Stapelberg <stapelberg@debian.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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# On Debian GNU/Linux systems, the complete text of the GNU General
# Public License can be found in `/usr/share/common-licenses/GPL-2'.
###########################################################################
is_ignored_file() {
case "$1" in
skeleton | README | *.dpkg-dist | *.dpkg-old | rc | rcS | single | reboot | bootclean.sh)
return 0
;;
esac
return 1
}
VERSION="`basename $0` ver. 1.69~deb13u1"
USAGE="Usage: `basename $0` < option > | --status-all | \
[ service_name [ command | --full-restart ] ]"
SERVICE=
ACTION=
SERVICEDIR="/etc/init.d"
OPTIONS=
is_systemd=
if [ $# -eq 0 ]; then
echo "${USAGE}" >&2
exit 1
fi
if [ -d /run/systemd/system ]; then
is_systemd=1
fi
cd /
while [ $# -gt 0 ]; do
case "${1}" in
--help | -h | --h* )
echo "${USAGE}" >&2
exit 0
;;
--version | -V )
echo "${VERSION}" >&2
exit 0
;;
*)
if [ -z "${SERVICE}" -a $# -eq 1 -a "${1}" = "--status-all" ]; then
cd ${SERVICEDIR}
for SERVICE in * ; do
case "${SERVICE}" in
functions | halt | killall | single| linuxconf| kudzu)
;;
*)
if ! is_ignored_file "${SERVICE}" \
&& [ -x "${SERVICEDIR}/${SERVICE}" ]; then
out=$(env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" status 2>&1)
retval=$?
if echo "$out" | grep -Fiq "usage:"; then
#printf " %s %-60s %s\n" "[?]" "$SERVICE:" "unknown" 1>&2
echo " [ ? ] $SERVICE" 1>&2
continue
else
if [ "$retval" = "0" -a -n "$out" ]; then
#printf " %s %-60s %s\n" "[+]" "$SERVICE:" "running"
echo " [ + ] $SERVICE"
continue
else
#printf " %s %-60s %s\n" "[-]" "$SERVICE:" "NOT running"
echo " [ - ] $SERVICE"
continue
fi
fi
#env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" status
fi
;;
esac
done
exit 0
elif [ $# -eq 2 -a "${2}" = "--full-restart" ]; then
SERVICE="${1}"
# On systems using systemd, we just perform a normal restart:
# A restart with systemd is already a full restart.
if [ -n "$is_systemd" ]; then
ACTION="restart"
else
if [ -x "${SERVICEDIR}/${SERVICE}" ]; then
env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" stop
env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" start
exit $?
fi
fi
elif [ -z "${SERVICE}" ]; then
SERVICE="${1}"
elif [ -z "${ACTION}" ]; then
ACTION="${1}"
else
OPTIONS="${OPTIONS} ${1}"
fi
shift
;;
esac
done
run_via_sysvinit() {
# Otherwise, use the traditional sysvinit
if [ -x "${SERVICEDIR}/${SERVICE}" ]; then
exec env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" ${ACTION} ${OPTIONS}
else
echo "${SERVICE}: unrecognized service" >&2
exit 1
fi
}
update_openrc_started_symlinks() {
# Skip native openrc-run files
grep -q '^#! */\(usr/\)\?sbin/openrc-run' $SERVICEDIR/$SERVICE && return
# maintain the symlinks of /run/openrc/started so that
# rc-status works with the service command as well
if [ -d /run/openrc/started ] ; then
case "${ACTION}" in
start)
if [ ! -h /run/openrc/started/$SERVICE ] ; then
ln -s $SERVICEDIR/$SERVICE /run/openrc/started/$SERVICE || true
fi
;;
stop)
rm /run/openrc/started/$SERVICE || true
;;
esac
fi
}
# When this machine is running systemd, standard service calls are turned into
# systemctl calls.
if [ -n "$is_systemd" ]
then
UNIT="${SERVICE%.sh}.service"
case "${ACTION}" in
restart|status|try-restart)
exec systemctl $sctl_args ${ACTION} ${UNIT}
;;
start|stop)
# Follow the principle of least surprise for SysV people:
# When running "service foo stop" and foo happens to be a service that
# has one or more .socket files, we also stop the .socket units.
# Users who need more control will use systemctl directly.
for unit in $(systemctl list-unit-files --full --type=socket 2>/dev/null | sed -ne 's/\.socket\s*[a-z]*\s*$/.socket/p'); do
if [ "$(systemctl -p Triggers show $unit)" = "Triggers=${UNIT}" ]; then
systemctl $sctl_args ${ACTION} $unit
fi
done
exec systemctl $sctl_args ${ACTION} ${UNIT}
;;
reload)
_canreload="$(systemctl -p CanReload show ${UNIT} 2>/dev/null)"
# Don't block on reload requests during bootup and shutdown
# from units/hooks and simply schedule the task.
if ! systemctl --quiet is-system-running; then
sctl_args="--no-block"
fi
if [ "$_canreload" = "CanReload=no" ]; then
# The reload action falls back to the sysv init script just in case
# the systemd service file does not (yet) support reload for a
# specific service.
run_via_sysvinit
else
exec systemctl $sctl_args reload "${UNIT}"
fi
;;
force-stop)
exec systemctl --signal=KILL kill "${UNIT}"
;;
force-reload)
_canreload="$(systemctl -p CanReload show ${UNIT} 2>/dev/null)"
if [ "$_canreload" = "CanReload=no" ]; then
exec systemctl $sctl_args restart "${UNIT}"
else
exec systemctl $sctl_args reload "${UNIT}"
fi
;;
*)
# We try to run non-standard actions by running
# the init script directly.
run_via_sysvinit
;;
esac
fi
update_openrc_started_symlinks
run_via_sysvinit
+56
View File
@@ -0,0 +1,56 @@
#!/bin/sh
# turn shadow passwords on on a Debian system
set -e
shadowon () {
set -e
if [ -n "$DPKG_ROOT" ] \
&& cmp "${DPKG_ROOT}/etc/passwd" "${DPKG_ROOT}/usr/share/base-passwd/passwd.master" 2>/dev/null \
&& cmp "${DPKG_ROOT}/etc/group" "${DPKG_ROOT}/usr/share/base-passwd/group.master" 2>/dev/null; then
# If dpkg is run with --force-script-chrootless and if /etc/passwd
# and /etc/group are unchanged, we avoid the chroot() call by manually
# processing the files. This produces bit-by-bit identical results
# compared to the normal case as shown by the CI setup at
# https://salsa.debian.org/helmutg/dpkg-root-demo/-/jobs
for f in passwd group; do
cp -a "${DPKG_ROOT}/etc/$f" "${DPKG_ROOT}/etc/$f-"
done
chmod 600 "${DPKG_ROOT}/etc/passwd-"
sed -i 's/^\([^:]\+\):\*:/\1:x:/' "${DPKG_ROOT}/etc/group" "${DPKG_ROOT}/etc/passwd"
[ -n "$SOURCE_DATE_EPOCH" ] && epoch=$SOURCE_DATE_EPOCH || epoch=$(date +%s)
sed "s/^\([^:]\+\):.*/\1:*:$((epoch/60/60/24)):0:99999:7:::/" "${DPKG_ROOT}/etc/passwd" > "${DPKG_ROOT}/etc/shadow"
sed "s/^\([^:]\+\):.*/\1:*::/" "${DPKG_ROOT}/etc/group" > "${DPKG_ROOT}/etc/gshadow"
touch "${DPKG_ROOT}/etc/.pwd.lock"
chmod 600 "${DPKG_ROOT}/etc/.pwd.lock"
else
pwck -q -r
grpck -r
pwconv
grpconv
fi
chown root:root "${DPKG_ROOT}/etc/passwd" "${DPKG_ROOT}/etc/group"
chmod 644 "${DPKG_ROOT}/etc/passwd" "${DPKG_ROOT}/etc/group"
chown root:shadow "${DPKG_ROOT}/etc/shadow" "${DPKG_ROOT}/etc/gshadow"
chmod 640 "${DPKG_ROOT}/etc/shadow" "${DPKG_ROOT}/etc/gshadow"
}
case "$1" in
"on")
if shadowon ; then
echo Shadow passwords are now on.
else
echo Please correct the error and rerun \`$0 on\'
exit 1
fi
;;
"off")
echo E: Turning shadow passwords off is no longer supported.
exit 1
;;
*)
echo Usage: $0 on
;;
esac
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+42
View File
@@ -0,0 +1,42 @@
#! /bin/sh
# Usage: tarcat volume1 volume2 ...
# concatenates a GNU tar multi-volume archive into a single tar archive.
# Author: Bruno Haible <bruno@clisp.org>, Sergey Poznyakoff <gray@gnu.org.ua>
# dump_type FILE [N]
# Print type character from block N (default 0) of tar archive FILE
dump_type() {
dd if="$1" skip=${2:-0} bs=512 count=1 2>/dev/null |
tr '\0' ' ' |
cut -c157
}
case `dump_type "$1"` in
[gx]) PAX=1;;
esac
cat "$1"
shift
for f
do
SKIP=0
T=`dump_type "$f"`
if [ -n "$PAX" ]; then
if [ "$T" = "g" ]; then
# Global extended header.... 2 blocks
# Extended header........... 2 blocks
# Ustar header.............. 1 block
# FIXME: This calculation is will fail for very long file names.
SKIP=5
fi
else
if [ "$T" = "V" ]; then
T=`dump_type "$f" 1`
fi
if [ "$T" = "M" ]; then
SKIP=$(($SKIP + 1))
fi
fi
dd skip=$SKIP if="$f"
done
Binary file not shown.
Binary file not shown.
Binary file not shown.
+543
View File
@@ -0,0 +1,543 @@
#! /usr/bin/perl
# vim: ft=perl
#
# update-rc.d Update the links in /etc/rc[0-9S].d/
#
use strict;
use warnings;
# NB: All Perl modules used here must be in perl-base. Specifically, depending
# on modules in perl-modules is not okay! See bug #716923
my $initd = "/etc/init.d";
my $etcd = "/etc/rc";
my $dpkg_root = $ENV{DPKG_ROOT} // '';
# Print usage message and die.
sub usage {
print STDERR "update-rc.d: error: @_\n" if ($#_ >= 0);
print STDERR <<EOF;
usage: update-rc.d [-f] <basename> remove
update-rc.d [-f] <basename> defaults
update-rc.d [-f] <basename> defaults-disabled
update-rc.d <basename> disable|enable [S|2|3|4|5]
-f: force
The disable|enable API is not stable and might change in the future.
EOF
exit (1);
}
exit main(@ARGV);
sub info {
print STDOUT "update-rc.d: @_\n";
}
sub warning {
print STDERR "update-rc.d: warning: @_\n";
}
sub error {
print STDERR "update-rc.d: error: @_\n";
exit (1);
}
sub error_code {
my $rc = shift;
print STDERR "update-rc.d: error: @_\n";
exit ($rc);
}
sub make_path {
my ($path) = @_;
my @dirs = ();
my @path = split /\//, $path;
map { push @dirs, $_; mkdir join('/', @dirs), 0755; } @path;
}
# Given a script name, return any runlevels except 0 or 6 in which the
# script is enabled. If that gives nothing and the script is not
# explicitly disabled, return 6 if the script is disabled in runlevel
# 0 or 6.
sub script_runlevels {
my ($scriptname) = @_;
my @links=<"$dpkg_root/etc/rc[S12345].d/S[0-9][0-9]$scriptname">;
if (@links) {
return map(substr($_, 7, 1), @links);
} elsif (! <"$dpkg_root/etc/rc[S12345].d/K[0-9][0-9]$scriptname">) {
@links=<"$dpkg_root/etc/rc[06].d/K[0-9][0-9]$scriptname">;
return ("6") if (@links);
} else {
return ;
}
}
# Map the sysvinit runlevel to that of openrc.
sub openrc_rlconv {
my %rl_table = (
"S" => "sysinit",
"1" => "recovery",
"2" => "default",
"3" => "default",
"4" => "default",
"5" => "default",
"6" => "off" );
my %seen; # return unique runlevels
return grep !$seen{$_}++, map($rl_table{$_}, @_);
}
sub systemd_reload {
if (length $ENV{DPKG_ROOT}) {
# if we operate on a chroot from the outside, do not attempt to reload
return;
}
if (-d "/run/systemd/system") {
system("systemctl", "daemon-reload");
}
}
# Creates the necessary links to enable/disable a SysV init script (fallback if
# no insserv/rc-update exists)
sub make_sysv_links {
my ($scriptname, $action) = @_;
# for "remove" we cannot rely on the init script still being present, as
# this gets called in postrm for purging. Just remove all symlinks.
if ("remove" eq $action) { unlink($_) for
glob("$dpkg_root/etc/rc?.d/[SK][0-9][0-9]$scriptname"); return; }
# if the service already has any links, do not touch them
# numbers we don't care about, but enabled/disabled state we do
return if glob("$dpkg_root/etc/rc?.d/[SK][0-9][0-9]$scriptname");
# for "defaults", parse Default-{Start,Stop} and create these links
my ($lsb_start_ref, $lsb_stop_ref) = parse_def_start_stop("$dpkg_root/etc/init.d/$scriptname");
my $start = $action eq "defaults-disabled" ? "K" : "S";
foreach my $lvl (@$lsb_start_ref) {
make_path("$dpkg_root/etc/rc$lvl.d");
my $l = "$dpkg_root/etc/rc$lvl.d/${start}01$scriptname";
symlink("../init.d/$scriptname", $l);
}
foreach my $lvl (@$lsb_stop_ref) {
make_path("$dpkg_root/etc/rc$lvl.d");
my $l = "$dpkg_root/etc/rc$lvl.d/K01$scriptname";
symlink("../init.d/$scriptname", $l);
}
}
# Creates the necessary links to enable/disable the service (equivalent of an
# initscript) in systemd.
sub make_systemd_links {
my ($scriptname, $action) = @_;
# If called by systemctl (via systemd-sysv-install), do nothing to avoid
# an endless loop.
if (defined($ENV{_SKIP_SYSTEMD_NATIVE}) && $ENV{_SKIP_SYSTEMD_NATIVE} == 1) {
return;
}
# If systemctl is available, let's use that to create the symlinks.
if (-x "$dpkg_root/bin/systemctl" || -x "$dpkg_root/usr/bin/systemctl") {
my $systemd_root = '/';
if ($dpkg_root ne '') {
$systemd_root = $dpkg_root;
}
# Set this env var to avoid loop in systemd-sysv-install.
local $ENV{SYSTEMCTL_SKIP_SYSV} = 1;
# Use --quiet to mimic the old update-rc.d behaviour.
system("systemctl", "--root=$systemd_root", "--quiet", "$action", "$scriptname");
return;
}
# In addition to the insserv call we also enable/disable the service
# for systemd by creating the appropriate symlink in case there is a
# native systemd service. In case systemd is not installed we do this
# on our own instead of using systemctl.
my $service_path;
if (-f "/etc/systemd/system/$scriptname.service") {
$service_path = "/etc/systemd/system/$scriptname.service";
} elsif (-f "/lib/systemd/system/$scriptname.service") {
$service_path = "/lib/systemd/system/$scriptname.service";
} elsif (-f "/usr/lib/systemd/system/$scriptname.service") {
$service_path = "/usr/lib/systemd/system/$scriptname.service";
}
if (defined($service_path)) {
my $changed_sth;
open my $fh, '<', $service_path or error("unable to read $service_path");
while (<$fh>) {
chomp;
if (/^\s*WantedBy=(.+)$/i) {
my $wants_dir = "/etc/systemd/system/$1.wants";
my $service_link = "$wants_dir/$scriptname.service";
if ("enable" eq $action) {
make_path($wants_dir);
symlink($service_path, $service_link);
} else {
unlink($service_link) if -e $service_link;
}
}
}
close($fh);
}
}
sub create_sequence {
my $force = (@_);
my $insserv = "$dpkg_root/usr/lib/insserv/insserv";
# Fallback for older insserv package versions [2014-04-16]
$insserv = "/sbin/insserv" if ( -x "$dpkg_root/sbin/insserv");
# If insserv is not configured it is not fully installed
my $insserv_installed = -x "$dpkg_root$insserv" && -e "$dpkg_root/etc/insserv.conf";
my @opts;
push(@opts, '-f') if $force;
# Add force flag if initscripts is not installed
# This enables inistcripts-less systems to not fail when a facility is missing
unshift(@opts, '-f') unless is_initscripts_installed();
if ( $dpkg_root ne '' ) {
push( @opts,
'--path', "$dpkg_root/etc/init.d",
'--override', "$dpkg_root/etc/insserv/overrides/",
'--insserv-dir', "$dpkg_root/etc/init.d",
'--config', "$dpkg_root/etc/insserv.conf" );
}
my $openrc_installed = -x "$dpkg_root/sbin/openrc";
my $sysv_insserv ={};
$sysv_insserv->{remove} = sub {
my ($scriptname) = @_;
if ( -f "$dpkg_root/etc/init.d/$scriptname" ) {
return system($insserv, @opts, "-r", $scriptname) >> 8;
} else {
# insserv removes all dangling symlinks, no need to tell it
# what to look for.
my $rc = system($insserv, @opts) >> 8;
error_code($rc, "insserv rejected the script header") if $rc;
}
};
$sysv_insserv->{defaults} = sub {
my ($scriptname) = @_;
if ( -f "$dpkg_root/etc/init.d/$scriptname" ) {
my $rc = system($insserv, @opts, $scriptname) >> 8;
error_code($rc, "insserv rejected the script header") if $rc;
} else {
error("initscript does not exist: /etc/init.d/$scriptname");
}
};
$sysv_insserv->{defaults_disabled} = sub {
my ($scriptname) = @_;
return if glob("$dpkg_root/etc/rc?.d/[SK][0-9][0-9]$scriptname");
if ( -f "$dpkg_root/etc/init.d/$scriptname" ) {
my $rc = system($insserv, @opts, $scriptname) >> 8;
error_code($rc, "insserv rejected the script header") if $rc;
} else {
error("initscript does not exist: /etc/init.d/$scriptname");
}
sysv_toggle("disable", $scriptname);
};
$sysv_insserv->{toggle} = sub {
my ($action, $scriptname) = (shift, shift);
sysv_toggle($action, $scriptname, @_);
# Call insserv to resequence modified links
my $rc = system($insserv, @opts, $scriptname) >> 8;
error_code($rc, "insserv rejected the script header") if $rc;
};
my $sysv_plain = {};
$sysv_plain->{remove} = sub {
my ($scriptname) = @_;
make_sysv_links($scriptname, "remove");
};
$sysv_plain->{defaults} = sub {
my ($scriptname) = @_;
make_sysv_links($scriptname, "defaults");
};
$sysv_plain->{defaults_disabled} = sub {
my ($scriptname) = @_;
make_sysv_links($scriptname, "defaults-disabled");
};
$sysv_plain->{toggle} = sub {
my ($action, $scriptname) = (shift, shift);
sysv_toggle($action, $scriptname, @_);
};
my $systemd = {};
$systemd->{remove} = sub {
systemd_reload;
};
$systemd->{defaults} = sub {
systemd_reload;
};
$systemd->{defaults_disabled} = sub {
systemd_reload;
};
$systemd->{toggle} = sub {
my ($action, $scriptname) = (shift, shift);
make_systemd_links($scriptname, $action);
systemd_reload;
};
# Should we check exit codeS?
my $openrc = {};
$openrc->{remove} = sub {
my ($scriptname) = @_;
system("rc-update", "-qqa", "delete", $scriptname);
};
$openrc->{defaults} = sub {
my ($scriptname) = @_;
# OpenRC does not distinguish halt and reboot. They are handled
# by /etc/init.d/transit instead.
return if ("halt" eq $scriptname || "reboot" eq $scriptname);
# no need to consider default disabled runlevels
# because everything is disabled by openrc by default
my @rls=script_runlevels($scriptname);
if ( @rls ) {
system("rc-update", "add", $scriptname, openrc_rlconv(@rls));
}
};
$openrc->{defaults_disabled} = sub {
# In openrc everything is disabled by default
};
$openrc->{toggle} = sub {
my ($action, $scriptname) = (shift, shift);
my (@toggle_lvls, $start_lvls, $stop_lvls, @symlinks);
my $lsb_header = lsb_header_for_script($scriptname);
# Extra arguments to disable|enable action are runlevels. If none
# given parse LSB info for Default-Start value.
if ($#_ >= 0) {
@toggle_lvls = @_;
} else {
($start_lvls, $stop_lvls) = parse_def_start_stop($lsb_header);
@toggle_lvls = @$start_lvls;
if ($#toggle_lvls < 0) {
error("$scriptname Default-Start contains no runlevels, aborting.");
}
}
my %openrc_act = ( "disable" => "del", "enable" => "add" );
system("rc-update", $openrc_act{$action}, $scriptname,
openrc_rlconv(@toggle_lvls))
};
my @sequence;
if ($insserv_installed) {
push @sequence, $sysv_insserv;
}
else {
push @sequence, $sysv_plain;
}
# OpenRC has to be after sysv_{insserv,plain} because it depends on them to synchronize
# states.
if ($openrc_installed) {
push @sequence, $openrc;
}
push @sequence, $systemd;
return @sequence;
}
## Dependency based
sub main {
my @args = @_;
my $scriptname;
my $action;
my $force = 0;
while($#args >= 0 && ($_ = $args[0]) =~ /^-/) {
shift @args;
if (/^-f$/) { $force = 1; next }
if (/^-h|--help$/) { usage(); }
usage("unknown option");
}
usage("not enough arguments") if ($#args < 1);
my @sequence = create_sequence($force);
$scriptname = shift @args;
$action = shift @args;
if ("remove" eq $action) {
foreach my $init (@sequence) {
$init->{remove}->($scriptname);
}
} elsif ("defaults" eq $action || "start" eq $action ||
"stop" eq $action) {
# All start/stop/defaults arguments are discarded so emit a
# message if arguments have been given and are in conflict
# with Default-Start/Default-Stop values of LSB comment.
if ("start" eq $action || "stop" eq $action) {
cmp_args_with_defaults($scriptname, $action, @args);
}
foreach my $init (@sequence) {
$init->{defaults}->($scriptname);
}
} elsif ("defaults-disabled" eq $action) {
foreach my $init (@sequence) {
$init->{defaults_disabled}->($scriptname);
}
} elsif ("disable" eq $action || "enable" eq $action) {
foreach my $init (@sequence) {
$init->{toggle}->($action, $scriptname, @args);
}
} else {
usage();
}
}
sub parse_def_start_stop {
my $script = shift;
my (%lsb, @def_start_lvls, @def_stop_lvls);
open my $fh, '<', $script or error("unable to read $script");
while (<$fh>) {
chomp;
if (m/^### BEGIN INIT INFO\s*$/) {
$lsb{'begin'}++;
}
elsif (m/^### END INIT INFO\s*$/) {
$lsb{'end'}++;
last;
}
elsif ($lsb{'begin'} and not $lsb{'end'}) {
if (m/^# Default-Start:\s*(\S?.*)$/) {
@def_start_lvls = split(' ', $1);
}
if (m/^# Default-Stop:\s*(\S?.*)$/) {
@def_stop_lvls = split(' ', $1);
}
}
}
close($fh);
return (\@def_start_lvls, \@def_stop_lvls);
}
sub lsb_header_for_script {
my $name = shift;
foreach my $file ("/etc/insserv/overrides/$name", "/etc/init.d/$name",
"/usr/share/insserv/overrides/$name") {
return $file if -s $file;
}
error("cannot find a LSB script for $name");
}
sub cmp_args_with_defaults {
my ($name, $act) = (shift, shift);
my ($lsb_start_ref, $lsb_stop_ref, $arg_str, $lsb_str);
my (@arg_start_lvls, @arg_stop_lvls, @lsb_start_lvls, @lsb_stop_lvls);
($lsb_start_ref, $lsb_stop_ref) = parse_def_start_stop("/etc/init.d/$name");
@lsb_start_lvls = @$lsb_start_ref;
@lsb_stop_lvls = @$lsb_stop_ref;
return if (!@lsb_start_lvls and !@lsb_stop_lvls);
warning "start and stop actions are no longer supported; falling back to defaults";
my $start = $act eq 'start' ? 1 : 0;
my $stop = $act eq 'stop' ? 1 : 0;
# The legacy part of this program passes arguments starting with
# "start|stop NN x y z ." but the insserv part gives argument list
# starting with sequence number (ie. strips off leading "start|stop")
# Start processing arguments immediately after the first seq number.
my $argi = $_[0] eq $act ? 2 : 1;
while (defined $_[$argi]) {
my $arg = $_[$argi];
# Runlevels 0 and 6 are always stop runlevels
if ($arg eq 0 or $arg eq 6) {
$start = 0; $stop = 1;
} elsif ($arg eq 'start') {
$start = 1; $stop = 0; $argi++; next;
} elsif ($arg eq 'stop') {
$start = 0; $stop = 1; $argi++; next;
} elsif ($arg eq '.') {
next;
}
push(@arg_start_lvls, $arg) if $start;
push(@arg_stop_lvls, $arg) if $stop;
} continue {
$argi++;
}
if ($#arg_start_lvls != $#lsb_start_lvls or
join("\0", sort @arg_start_lvls) ne join("\0", sort @lsb_start_lvls)) {
$arg_str = @arg_start_lvls ? "@arg_start_lvls" : "none";
$lsb_str = @lsb_start_lvls ? "@lsb_start_lvls" : "none";
warning "start runlevel arguments ($arg_str) do not match",
"$name Default-Start values ($lsb_str)";
}
if ($#arg_stop_lvls != $#lsb_stop_lvls or
join("\0", sort @arg_stop_lvls) ne join("\0", sort @lsb_stop_lvls)) {
$arg_str = @arg_stop_lvls ? "@arg_stop_lvls" : "none";
$lsb_str = @lsb_stop_lvls ? "@lsb_stop_lvls" : "none";
warning "stop runlevel arguments ($arg_str) do not match",
"$name Default-Stop values ($lsb_str)";
}
}
sub sysv_toggle {
my ($act, $name) = (shift, shift);
my (@toggle_lvls, $start_lvls, $stop_lvls, @symlinks);
my $lsb_header = lsb_header_for_script($name);
# Extra arguments to disable|enable action are runlevels. If none
# given parse LSB info for Default-Start value.
if ($#_ >= 0) {
@toggle_lvls = @_;
} else {
($start_lvls, $stop_lvls) = parse_def_start_stop($lsb_header);
@toggle_lvls = @$start_lvls;
if ($#toggle_lvls < 0) {
error("$name Default-Start contains no runlevels, aborting.");
}
}
# Find symlinks in rc.d directories. Refuse to modify links in runlevels
# not used for normal system start sequence.
for my $lvl (@toggle_lvls) {
if ($lvl !~ /^[S2345]$/) {
warning("$act action will have no effect on runlevel $lvl");
next;
}
push(@symlinks, $_) for glob("$dpkg_root/etc/rc$lvl.d/[SK][0-9][0-9]$name");
}
if (!@symlinks) {
error("no runlevel symlinks to modify, aborting!");
}
# Toggle S/K bit of script symlink.
for my $cur_lnk (@symlinks) {
my $sk;
my @new_lnk = split(//, $cur_lnk);
if ("disable" eq $act) {
$sk = rindex($cur_lnk, '/S') + 1;
next if $sk < 1;
$new_lnk[$sk] = 'K';
} else {
$sk = rindex($cur_lnk, '/K') + 1;
next if $sk < 1;
$new_lnk[$sk] = 'S';
}
rename($cur_lnk, join('', @new_lnk)) or error($!);
}
}
# Try to determine if initscripts is installed
sub is_initscripts_installed {
# Check if mountkernfs is available. We cannot make inferences
# using the running init system because we may be running in a
# chroot
return glob("$dpkg_root/etc/rcS.d/S??mountkernfs.sh");
}
+156
View File
@@ -0,0 +1,156 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2021 Helmut Grohne <helmut@subdivi.de>
# A "hashset" is a shell variable containing a sequence of elements separated
# and surrounded by hash (#) characters. None of the elements may contain a
# hash character. The character is thus chosen, because it initiates a comment
# in /etc/shells. All variables ending in _SHELLS in this file are hashsets.
set -e
# Check whether hashset $1 contains element $2.
hashset_contains() {
case "$1" in
*"#$2#"*) return 0 ;;
*) return 1 ;;
esac
}
log() {
if [ "$VERBOSE" = 1 ]; then
echo "$*"
fi
}
ROOT=${DPKG_ROOT:-}
VERBOSE=0
NOACT=0
while [ $# -gt 0 ]; do
case "$1" in
--help)
cat <<EOF
usage: $0 [options]
--no-act Do not move the actual update into place
--verbose Be more verbose
--root DIR Operate on the given chroot, defaults to /
EOF
exit 0
;;
--no-act)
NOACT=1
;;
--root)
shift
if [ "$#" -lt 1 ]; then
echo "missing argument to --root" 1>&2
exit 1
fi
ROOT=$1
;;
--verbose)
VERBOSE=1
;;
*)
echo "unrecognized option $1" 1>&2
exit 1
;;
esac
shift
done
PKG_DIR="$ROOT/usr/share/debianutils/shells.d"
STATE_FILE="$ROOT/var/lib/shells.state"
TEMPLATE_ETC_FILE="$ROOT/usr/share/debianutils/shells"
TARGET_ETC_FILE="$ROOT/etc/shells"
SOURCE_ETC_FILE="$TARGET_ETC_FILE"
NEW_ETC_FILE="$TARGET_ETC_FILE.tmp"
NEW_STATE_FILE="$STATE_FILE.tmp"
if ! test -e "$SOURCE_ETC_FILE"; then
SOURCE_ETC_FILE="$TEMPLATE_ETC_FILE"
fi
PKG_SHELLS='#'
LC_COLLATE=C.UTF-8 # glob in reproducible order
for f in "$TEMPLATE_ETC_FILE" "$PKG_DIR/"*; do
test -f "$f" || continue
while IFS='#' read -r line _; do
[ -n "$line" ] || continue
if ! hashset_contains "$PKG_SHELLS" "$line"; then
PKG_SHELLS="$PKG_SHELLS$line#"
fi
realshell=$(dpkg-realpath --root "$ROOT" "$(dirname "$line")")/$(basename "$line")
if ! hashset_contains "$PKG_SHELLS" "$realshell"; then
PKG_SHELLS="$PKG_SHELLS$realshell#"
fi
done < "$f"
done
STATE_SHELLS='#'
if [ -e "$STATE_FILE" ] ; then
while IFS='#' read -r line _; do
[ -n "$line" ] && STATE_SHELLS="$STATE_SHELLS$line#"
done < "$STATE_FILE"
fi
cleanup() {
rm -f "$NEW_ETC_FILE" "$NEW_STATE_FILE"
}
trap cleanup EXIT
: > "$NEW_ETC_FILE"
ETC_SHELLS='#'
while IFS= read -r line; do
shell=${line%%#*}
# copy all comment lines, packaged shells and local additions
if [ -z "$shell" ] ||
hashset_contains "$PKG_SHELLS" "$shell" ||
! hashset_contains "$STATE_SHELLS" "$shell"; then
if [ -z "$shell" ] || ! hashset_contains "$ETC_SHELLS" "$shell"; then
echo "$line" >> "$NEW_ETC_FILE"
ETC_SHELLS="$ETC_SHELLS$shell#"
fi
else
log "removing shell $shell"
fi
done < "$SOURCE_ETC_FILE"
: > "$NEW_STATE_FILE"
saved_IFS=$IFS
IFS='#'
set -f
# shellcheck disable=SC2086 # word splitting intended, globbing disabled
set -- ${PKG_SHELLS###}
set +f
IFS=$saved_IFS
for shell; do
echo "$shell" >> "$NEW_STATE_FILE"
# add shells that are neither already present nor locally removed
if ! hashset_contains "$ETC_SHELLS" "$shell" &&
! hashset_contains "$STATE_SHELLS" "$shell"; then
echo "$shell" >> "$NEW_ETC_FILE"
log "adding shell $shell"
fi
done
if [ "$NOACT" = 0 ]; then
if [ -e "$STATE_FILE" ]; then
chmod --reference="${STATE_FILE}" "${NEW_STATE_FILE}" || chmod $(stat -c %a "${STATE_FILE}") "${NEW_STATE_FILE}"
chown --reference="${STATE_FILE}" "${NEW_STATE_FILE}" || chown $(stat -c %U "${STATE_FILE}") "${NEW_STATE_FILE}"
else
chmod 0644 "$NEW_STATE_FILE"
fi
chmod --reference="${SOURCE_ETC_FILE}" "${NEW_ETC_FILE}" || chmod $(stat -c %a "${SOURCE_ETC_FILE}") "${NEW_ETC_FILE}"
chown --reference="${SOURCE_ETC_FILE}" "${NEW_ETC_FILE}" || chown $(stat -c %U "${SOURCE_ETC_FILE}") "${NEW_ETC_FILE}"
sync -d "$NEW_ETC_FILE" "$NEW_STATE_FILE"
mv -Z "${NEW_ETC_FILE}" "${TARGET_ETC_FILE}" || mv "${NEW_ETC_FILE}" "${TARGET_ETC_FILE}"
sync "$TARGET_ETC_FILE"
sync "$(dirname "$TARGET_ETC_FILE")"
mv "$NEW_STATE_FILE" "$STATE_FILE"
sync "$STATE_FILE"
sync "$(dirname "$STATE_FILE")"
trap "" EXIT
fi
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
vipw
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.