[Pkg-shadow-devel] [Git][debian/adduser][wip/feature-system-locks] 11 commits: add some basic tests
Marc Haber (@zugschlus)
gitlab at salsa.debian.org
Sun Jan 4 17:17:24 GMT 2026
Marc Haber pushed to branch wip/feature-system-locks at Debian / adduser
Commits:
c9a84b64 by Matt Barry at 2026-01-04T18:10:25+01:00
add some basic tests
- - - - -
124ab1ea by Marc Haber at 2026-01-04T18:10:25+01:00
improve log level handling
Thanks: Matt Barry
Git-Dch: ignore
- - - - -
9941e3e3 by Marc Haber at 2026-01-04T18:10:25+01:00
add new constants for password handling
Git-Dch: ignore
Thanks: Matt Barry
- - - - -
60adaf5e by Marc Haber at 2026-01-04T18:10:25+01:00
introduce password handling logic
Git-Dch: ignore
Thanks: Matt Barry
- - - - -
ac024314 by Marc Haber at 2026-01-04T18:10:25+01:00
introduce new function existing_value_desc
Git-Dch: ignore
Thanks: Matt Barry
- - - - -
a8cfffb1 by Marc Haber at 2026-01-04T18:10:25+01:00
use existing_value_desc
Thanks: Matt Barry
Git-Dch: ignore
- - - - -
b58cf801 by Matt Barry at 2026-01-04T18:10:25+01:00
locked.account.tests
- - - - -
81f6390d by Marc Haber at 2026-01-04T18:10:25+01:00
prepare AdduserTestsCommon for the new tests
Git-Dch: ignore
- - - - -
e8454ada by Matt Barry at 2026-01-04T18:10:25+01:00
user locked account tests
Git-Dch: ignore
- - - - -
adf54cae by Marc Haber at 2026-01-04T18:10:25+01:00
fix testsuite warning in test08.pl
Git-Dch: ignore
- - - - -
64b8e779 by Marc Haber at 2026-01-04T18:10:25+01:00
run upstream testsuite with redirected stdin
otherwise tests might hang invisibly when the software
goes interactive
Git-Dch: ignore
- - - - -
7 changed files:
- AdduserCommon.pm
- adduser
- + debian/tests/f/account_locks.t
- debian/tests/lib/AdduserTestsCommon.pm
- testsuite/runsuite.sh
- testsuite/test08.pl
- + testsuite/test10.pl
Changes:
=====================================
AdduserCommon.pm
=====================================
@@ -102,6 +102,17 @@ use constant {
EXISTING_ID_MISMATCH => 4,
EXISTING_LOCKED => 8,
EXISTING_HAS_PASSWORD => 16,
+ EXISTING_DISABLED_PASS => 40, # 32 | EXISTING_LOCKED
+ EXISTING_INVALID_PASS => 72, # 64 | EXISTING_LOCKED
+ EXISTING_EXPIRED => 136, # 128 | EXISTING_LOCKED
+ EXISTING_NOLOGIN => 264, # 256 | EXISTING_LOCKED
+ EXISTING_PASSWORDLESS => 512,
+};
+
+use constant {
+ STDOUTDEFLEVEL => "warn",
+ STDERRDEFLEVEL => "warn",
+ LOGMSGDEFLEVEL => "info",
};
@EXPORT = (
@@ -138,6 +149,14 @@ use constant {
'EXISTING_ID_MISMATCH',
'EXISTING_LOCKED',
'EXISTING_HAS_PASSWORD',
+ 'EXISTING_DISABLED_PASS',
+ 'EXISTING_INVALID_PASS',
+ 'EXISTING_EXPIRED',
+ 'EXISTING_NOLOGIN',
+ 'EXISTING_PASSWORDLESS',
+ 'STDOUTDEFLEVEL',
+ 'STDERRDEFLEVEL',
+ 'LOGMSGDEFLEVEL',
'existing_user_status',
'existing_group_status',
);
@@ -598,16 +617,18 @@ END {
# EXISTING_ID_MISMATCH => 4
# EXISTING_LOCKED => 8
# EXISTING_HAS_PASSWORD => 16
-# e.g. if the requested account name exists as a locked system user,
-# return 8|2|1 == 11
+# EXISTING_DISABLED_PASS => 32
+# EXISTING_INVALID_PASS => 64
+# EXISTING_NOLOGIN => 128
+# EXISTING_EXPIRED => 256
+# EXISTING_PASSWORDLESS => 512
sub existing_user_status {
my ($config, $new_name,$new_uid) = @_;
- my ($dummy1,$pw,$uid);
my $ret = EXISTING_NOT_FOUND;
log_trace( "existing_user_status called with new_name %s, new_uid %s, first_system_uid %s, last_system_uid %s", $new_name, $new_uid, $config->{"first_system_uid"}, $config->{"last_system_uid"} );
- if (($dummy1,$pw,$uid) = egetpwnam($new_name)) {
+ if (my (undef,$pw,$uid,undef,undef,$home,$shell) = egetpwnam($new_name)) {
# user with the name exists
- log_trace( "egetpwnam(%s) returns %s, %s, %s", $new_name, $dummy1, $pw, $uid );
+ log_trace( "egetpwnam(%s) returns %s, %s, %s, %s", $new_name, $pw, $uid, $home, $shell );
$ret |= EXISTING_FOUND;
$ret |= EXISTING_ID_MISMATCH if (defined($new_uid) && $uid != $new_uid);
$ret |= EXISTING_SYSTEM if
@@ -615,11 +636,22 @@ sub existing_user_status {
$ret |= EXISTING_HAS_PASSWORD if
(defined $pw && $pw ne '' && $pw ne '!' && $pw !~ /^\*/);
$ret |= EXISTING_LOCKED if (substr($pw,0,1) eq "!"); # TODO: also check expiry?
+
+ # Note: the following conditions will also be true against EXISTING_LOCKED
+ # iow, if $x & EXISTING_INVALID_PASS, then $x & EXISTING_LOCKED
+ $ret |= EXISTING_DISABLED_PASS if (substr($pw,0,1) eq "!");
+ $ret |= EXISTING_INVALID_PASS if (substr($pw,0,1) eq "*");
+ $ret |= EXISTING_PASSWORDLESS if ($pw eq '!');
+ $ret |= EXISTING_NOLOGIN if ($shell =~ /bin\/nologin/);
+
+ my $age = `chage -l $new_name`;
+ $ret |= EXISTING_EXPIRED if ($age =~ /password must be changed/);
+
} elsif (defined($new_uid) && getpwuid($new_uid)) {
# user with the uid exists
$ret |= EXISTING_ID_MISMATCH;
}
- log_trace( "existing_user_status( %s, %s ) returns %s", $new_name, $new_uid, $ret );
+ log_trace( "existing_user_status( %s, %s ) returns %s (%s)", $new_name, $new_uid, $ret, existing_value_desc($ret) );
return $ret;
}
@@ -635,10 +667,10 @@ sub existing_user_status {
# EXISTING_ID_MISMATCH => 4
sub existing_group_status {
my ($config, $new_name,$new_gid) = @_;
- my ($dummy1,$dummy2,$gid);
+ my ($gid);
my $ret = EXISTING_NOT_FOUND;
log_trace( "existing_group_status called with new_name %s, new_gid %s", $new_name, $new_gid );
- if (($dummy1,$dummy2,$gid) = egetgrnam($new_name)) {
+ if ((undef,undef,$gid) = egetgrnam($new_name)) {
# group with the name exists
log_trace("egetgrnam %s returned successfully, gid = %s", $new_name, $gid);
$ret |= EXISTING_FOUND;
@@ -648,10 +680,26 @@ sub existing_group_status {
} elsif (defined($new_gid) && getgrgid($new_gid)) {
$ret |= EXISTING_ID_MISMATCH;
}
- log_trace( "existing_group_status( %s, %s ) returns %s", $new_name, $new_gid, $ret );
+ log_trace( "existing_group_status( %s, %s ) returns %s (%s)", $new_name, $new_gid, $ret, existing_value_desc($ret) );
return $ret;
}
+sub existing_value_desc {
+ my ($val) = @_;
+ my @flags = ();
+ push @flags, "found" if ($val & EXISTING_FOUND);
+ push @flags, "wrongid" if $val & EXISTING_ID_MISMATCH;
+ push @flags, "system" if ($val & EXISTING_SYSTEM);
+ push @flags, "locked" if $val & EXISTING_LOCKED;
+ push @flags, "haspass" if $val & EXISTING_HAS_PASSWORD;
+ push @flags, "badpass" if $val & EXISTING_INVALID_PASS;
+ push @flags, "disabled" if $val & EXISTING_DISABLED_PASS;
+ push @flags, "nologin" if $val & EXISTING_NOLOGIN;
+ push @flags, "expired" if $val & EXISTING_EXPIRED;
+ push @flags, "notfound" unless $#flags > 0;
+ return join '|', at flags
+}
+
1;
# Local Variables:
=====================================
adduser
=====================================
@@ -103,9 +103,9 @@ $0 =~ s+.*/++;
our $action;
our $verbose; # should we be verbose?
my $name_check_level = 0; # should we allow bad names?
-our $stdoutmsglevel = "warn";
-our $stderrmsglevel = "warn";
-our $logmsglevel = "info";
+our $stdoutmsglevel = undef;
+our $stderrmsglevel = undef;
+our $logmsglevel = undef;
my $allow_badname = 0; # should we allow bad names?
my $ask_passwd = 1; # ask for a passwd?
my $disabled_login = 0; # leave the new account disabled?
@@ -201,10 +201,11 @@ if (!@configfiles) {
# make sure that message levels apply for reading configuration
# this will be overridden again after reading configuration
-$stdoutmsglevel = sanitize_string($stdoutmsglevel);
-$stderrmsglevel = sanitize_string($stderrmsglevel);
-$logmsglevel = sanitize_string($logmsglevel);
-set_msglevel( $stderrmsglevel, $stdoutmsglevel, $logmsglevel );
+set_msglevel(
+ sanitize_string($stderrmsglevel or STDERRDEFLEVEL),
+ sanitize_string($stdoutmsglevel or STDOUTDEFLEVEL),
+ sanitize_string($logmsglevel or LOGMSGDEFLEVEL),
+);
log_trace("ARGV %s", join(@ARGV,"-"));
log_trace("special_home %s", $special_home);
log_trace("special_home %s", encode($charset, $special_home));
@@ -225,8 +226,13 @@ if( $> != 0) {
log_fatal( mtx("Only root may add a user or group to the system.") );
exit( RET_ROOT_NEEDED );
}
-
-# TODO: Handle configuration file input, allow bare input there.
+# ARGV > adduser.conf > (default)
+$stdoutmsglevel //= $config{'stdoutmsglevel'};
+$stdoutmsglevel //= STDOUTDEFLEVEL;
+$stderrmsglevel //= $config{'stderrmsglevel'};
+$stderrmsglevel //= STDERRDEFLEVEL;
+$logmsglevel //= $config{'logmsglevel'};
+$logmsglevel //= LOGMSGDEFLEVEL;
$stdoutmsglevel = sanitize_string($stdoutmsglevel);
$stderrmsglevel = sanitize_string($stderrmsglevel);
$logmsglevel = sanitize_string($logmsglevel);
@@ -237,6 +243,7 @@ if( defined $verbose ) {
} elsif( $verbose == 1 ) {
set_msglevel( $stderrmsglevel, "info", $logmsglevel );
} elsif( $verbose == 2 ) {
+ set_msglevel( $stdoutmsglevel, "debug", $logmsglevel );
set_msglevel( $stderrmsglevel, "debug", $logmsglevel );
}
}
=====================================
debian/tests/f/account_locks.t
=====================================
@@ -0,0 +1,109 @@
+#! /usr/bin/perl -Idebian/tests/lib
+
+# Ref: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=701110
+
+
+use diagnostics;
+use strict;
+use warnings;
+
+use AdduserTestsCommon;
+
+my $prefix = "lockedtest";
+my $un;
+
+END {
+ remove_tree("/home/$prefix-user");
+ remove_tree("/var/mail/$prefix-user");
+}
+
+## system user
+
+$un = "${prefix}-sys";
+
+assert_user_does_not_exist($un);
+assert_command_success('/usr/sbin/adduser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--disabled-password',
+ '--system',
+ $un);
+assert_user_exists($un);
+assert_command_success('/usr/sbin/deluser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--system', "--lock",
+ $un);
+assert_user_exists($un);
+assert_user_is_locked($un);
+assert_user_is_disabled($un);
+assert_user_is_invalid($un);
+assert_user_is_expired($un);
+assert_user_is_nologin($un);
+assert_command_success('/usr/sbin/deluser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--system', "--lock",
+ $un);
+assert_user_exists($un);
+assert_command_success('/usr/sbin/adduser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--system',
+ $un);
+assert_user_exists($un);
+assert_user_is_not_locked($un);
+assert_user_is_not_disabled($un);
+assert_user_is_not_invalid($un);
+assert_user_is_not_expired($un);
+assert_user_is_not_nologin($un);
+assert_command_success('/usr/sbin/deluser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--system', '--force-delete',
+ $un);
+assert_user_does_not_exist($un);
+
+## normal user
+
+$un = "${prefix}-user";
+
+assert_user_does_not_exist($un);
+assert_command_success('/usr/sbin/adduser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--disabled-password',
+ $un);
+assert_user_exists($un);
+assert_command_success('/usr/sbin/deluser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ "--lock",
+ $un);
+assert_user_exists($un);
+assert_user_is_locked($un);
+assert_user_is_disabled($un);
+assert_user_is_invalid($un);
+assert_user_is_expired($un);
+assert_user_is_nologin($un);
+assert_command_success('/usr/sbin/deluser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ "--lock",
+ $un);
+assert_user_exists($un);
+assert_command_failure('/usr/sbin/adduser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ $un);
+assert_user_exists($un);
+assert_user_is_locked($un);
+assert_command_success('/usr/sbin/adduser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--unlock',
+ $un);
+assert_user_exists($un);
+assert_user_is_not_locked($un);
+assert_user_is_not_disabled($un);
+assert_user_is_not_invalid($un);
+assert_user_is_not_expired($un);
+assert_user_is_not_nologin($un);
+assert_command_success('/usr/sbin/deluser',
+ '--stdoutmsglevel=error', '--stderrmsglevel=error',
+ '--system', '--force-delete', '--remove-home',
+ $un);
+assert_user_does_not_exist($un);
+
+
+# vim: tabstop=4 shiftwidth=4 expandtab
=====================================
debian/tests/lib/AdduserTestsCommon.pm
=====================================
@@ -30,6 +30,22 @@ END {
if (-f '/var/cache/adduser/tests/state.tar');
}
+use constant {
+ EXISTING_NOT_FOUND => 0,
+ EXISTING_FOUND => 1,
+ EXISTING_SYSTEM => 2,
+ EXISTING_ID_MISMATCH => 4,
+ EXISTING_LOCKED => 8,
+ EXISTING_DISABLED_PASS => 24, # 16 | EXISTING_LOCKED
+ EXISTING_INVALID_PASS => 40, # 32 | EXISTING_LOCKED
+ EXISTING_EXPIRED => 72, # 64 | EXISTING_LOCKED
+ EXISTING_NOLOGIN => 136, # 128 | EXISTING_LOCKED
+ SYS_MIN => 100,
+ SYS_MAX => 999,
+ USER_MIN => 1000,
+ USER_MAX => 9999,
+};
+
my $charset = langinfo(CODESET);
binmode(STDOUT, ":encoding($charset)");
binmode(STDERR, ":encoding($charset)");
@@ -291,11 +307,6 @@ sub assert_path_has_ownership {
is(sprintf('%s:%s', $user, $group), $ownership, $name);
}
-sub assert_path_is_a_file {
- my $path = shift;
- ok(-f $path, "path is a file $path");
-}
-
sub assert_path_is_a_directory {
my $path = shift;
ok(-d $path, "path is a directory: $path");
@@ -387,6 +398,7 @@ sub assert_user_has_home_directory {
sub assert_user_has_comment {
my ($user, $comment) = @_;
+ $comment .= ',,,';
is((egetpwnam($user))[6], $comment, "user has comment: ~$user is $comment");
}
@@ -459,6 +471,65 @@ sub apply_config_hash {
close(CONF);
}
+sub assert_user_is_locked {
+ return existing_user_status($1) & EXISTING_LOCKED;
+}
+sub assert_user_is_disabled {
+ return (existing_user_status($1) & EXISTING_DISABLED_PASS)==EXISTING_DISABLED_PASS;
+}
+sub assert_user_is_invalid {
+ return (existing_user_status($1) & EXISTING_INVALID_PASS)==EXISTING_INVALID_PASS;
+}
+sub assert_user_is_nologin {
+ return (existing_user_status($1) & EXISTING_NOLOGIN)==EXISTING_NOLOGIN;
+}
+sub assert_user_is_expired {
+ return (existing_user_status($1) & EXISTING_EXPIRED)==EXISTING_EXPIRED;
+}
+sub assert_user_is_not_locked { return !assert_user_is_locked($1) }
+sub assert_user_is_not_disabled { return !assert_user_is_disabled($1) }
+sub assert_user_is_not_invalid { return !assert_user_is_invalid($1) }
+sub assert_user_is_not_nologin { return !assert_user_is_nologin($1) }
+sub assert_user_is_not_expired { return !assert_user_is_expired($1) }
+
+sub existing_user_status {
+ my ($new_name,$new_uid) = @_;
+ my $ret = EXISTING_NOT_FOUND;
+ if (my (undef,$pw,$uid,undef,undef,$home,$shell) = egetpwnam($new_name)) {
+ $ret |= EXISTING_FOUND;
+ $ret |= EXISTING_ID_MISMATCH if (defined($new_uid) && $uid != $new_uid);
+ $ret |= EXISTING_SYSTEM if \
+ ($uid >= SYS_MIN && $uid <= SYS_MAX);
+
+ # Note: the following conditions will also be true against EXISTING_LOCKED
+ # iow, if $x & EXISTING_INVALID_PASS, then $x & EXISTING_LOCKED
+ $ret |= EXISTING_DISABLED_PASS if (substr($pw,0,1) eq "!");
+ $ret |= EXISTING_INVALID_PASS if (substr($pw,0,1) eq "*");
+ $ret |= EXISTING_NOLOGIN if ($shell =~ /bin\/nologin/);
+
+ my $age = `chage -l $new_name`;
+ $ret |= EXISTING_EXPIRED if ($age =~ /password must be changed/);
+ } elsif ($new_uid && getpwuid($new_uid)) {
+ $ret |= EXISTING_ID_MISMATCH;
+ }
+ return $ret;
+}
+
+sub existing_group_status {
+ my ($new_name,$new_gid) = @_;
+ my $gid;
+ my $ret = EXISTING_NOT_FOUND;
+ if ((undef,undef,$gid) = egetgrnam($new_name)) {
+ $ret |= EXISTING_FOUND;
+ $ret |= EXISTING_ID_MISMATCH if (defined($new_gid) && $gid != $new_gid);
+ $ret |= EXISTING_SYSTEM if \
+ ($gid >= SYS_MIN && $gid <= SYS_MAX);
+ } elsif ($new_gid && getgrgid($new_gid)) {
+ $ret |= EXISTING_ID_MISMATCH;
+ }
+ return $ret;
+}
+
1;
# vim: tabstop=4 shiftwidth=4 expandtab
=====================================
testsuite/runsuite.sh
=====================================
@@ -20,7 +20,7 @@ for a in on; do
fi
echo
echo "Starting $i (shadow $a)"
- /usr/bin/perl -I. $i
+ < /dev/null /usr/bin/perl -I. $i
if [ "$?" != "0" ]; then
FAILED="$FAILED $i($a)"
fi
=====================================
testsuite/test08.pl
=====================================
@@ -91,7 +91,7 @@ unless (!defined getgrnam($newgroup)) {
print "ok\n";
}
-my $newgroup = find_unused_name();
+$newgroup = find_unused_name();
$cmd = "adduser --group $newgroup";
unless (defined getgrnam($newgroup)) {
=====================================
testsuite/test10.pl
=====================================
@@ -0,0 +1,144 @@
+#!/usr/bin/perl -w
+
+# expect:
+# - a new non-system group $groupname
+# - reading the group fails
+# - reading the group as a system group fails
+# - a new system group $groupname
+# - reading the group succeeds
+# - reading the group as a non-system group fails
+
+use strict;
+
+use lib_test;
+
+my $error;
+my $output;
+
+my $cmd;
+my $username;
+my $num;
+
+$username = find_unused_name();
+$num = 0;
+
+# unlock a non-existing account
+$cmd = "adduser --unlock $username";
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if (!$error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# add the account
+$cmd = "adduser --no-create-home --comment '' --disabled-password $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if ($error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# lock the account
+$cmd = "deluser --lock $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if ($error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# add the account (should fail)
+$cmd = "adduser --no-create-home --comment '' --disabled-password $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if (!$error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# unlock the account
+$cmd = "adduser --unlock $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if ($error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# system
+$username = find_unused_name();
+
+# add system account
+$cmd = "adduser --system $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+print "Testing (10.1) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if ($error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# lock the account
+$cmd = "deluser --system --lock $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if ($error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# re-enable via add
+$cmd = "adduser --system $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if ($error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
+
+# unlock already-unlocked
+$cmd = "adduser --unlock $username";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+$num ++ && print "Testing (10.$num) $cmd... ";
+$output=`$cmd 2>&1`;
+$error = ($?>>8);
+if (!$error) {
+ print "failed\n $cmd returned errorcode ($error)\n $output\n";
+ exit 1;
+}
+print "ok\n";
View it on GitLab: https://salsa.debian.org/debian/adduser/-/compare/6b5fe312198cab513a7197d6dd518c675a3832a0...64b8e77924dce922bbad50b06a37ed22a16a1094
--
View it on GitLab: https://salsa.debian.org/debian/adduser/-/compare/6b5fe312198cab513a7197d6dd518c675a3832a0...64b8e77924dce922bbad50b06a37ed22a16a1094
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-shadow-devel/attachments/20260104/30bd3f15/attachment-0001.htm>
More information about the Pkg-shadow-devel
mailing list