[Pkg-shadow-devel] [Git][debian/adduser][debian/latest] 7 commits: improve log level handling
Marc Haber (@zugschlus)
gitlab at salsa.debian.org
Sat Jan 17 08:30:30 GMT 2026
Marc Haber pushed to branch debian/latest at Debian / adduser
Commits:
51c81c3e by Marc Haber at 2026-01-16T07:59:20+01:00
improve log level handling
Thanks: Matt Barry
Git-Dch: ignore
- - - - -
b7725726 by Marc Haber at 2026-01-16T07:59:20+01:00
clarify documentation of exit value 31
Git-Dch: ignore
- - - - -
571f8054 by Marc Haber at 2026-01-16T07:59:20+01:00
rename to RET_INVALID_CHARS_IN_INPUT, apply to comment as well
That was RET_INVALID_CHARS_IN_INPUT previously. The check is now
applied to the comment as well and the error message adapted.
Git-Dch: ignore
- - - - -
783d4d09 by Marc Haber at 2026-01-16T07:59:20+01:00
move interactive command loops to a function
This is more streamlined and handles running on no terminal better
- - - - -
8ec9dd8a by Marc Haber at 2026-01-16T07:59:20+01:00
re-work logic around remove-home etc
Git-Dch: ignore
- - - - -
ab1adc30 by Marc Haber at 2026-01-16T07:59:20+01:00
prepare testsuite libraries to properly handle EXISTING_
this brings the simplifications to the test suite libraries
Git-Dch: ignore
- - - - -
67c314d0 by Marc Haber at 2026-01-16T07:59:20+01:00
add assert_path_is_a_file to debian/tests/lib
Git-Dch: ignore
- - - - -
6 changed files:
- AdduserRetvalues.pm
- adduser
- debian/tests/lib/AdduserTestsCommon.pm
- deluser
- doc/adduser.8
- testsuite/lib_test.pm
Changes:
=====================================
AdduserRetvalues.pm
=====================================
@@ -20,7 +20,7 @@ use vars qw(@EXPORT $VAR1);
'RET_ID_IN_USE',
'RET_NO_ID_IN_RANGE',
'RET_NO_PRIMARY_GID',
- 'RET_INVALID_CHARS_IN_NAME',
+ 'RET_INVALID_CHARS_IN_INPUT',
'RET_INVALID_HOME_DIRECTORY',
'RET_INVALID_NAME_FROM_USERADD',
'RET_GROUP_NOT_EMPTY',
@@ -61,8 +61,8 @@ use constant RET_NO_PRIMARY_GID => 23; # requested primary GID does not exist
# object name errors
-use constant RET_INVALID_CHARS_IN_NAME => 31; # the provided name contains invalid characters
-use constant RET_INVALID_HOME_DIRECTORY => 32; # the provided name contains invalid characters
+use constant RET_INVALID_CHARS_IN_INPUT => 31; # provided input (name/comment) contains invalid characters
+use constant RET_INVALID_HOME_DIRECTORY => 32; # the provided home directory is invalid
use constant RET_INVALID_NAME_FROM_USERADD => 32; # useradd returned 19 "invalid user or group name"
# group membership errors
=====================================
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?
@@ -199,10 +199,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));
@@ -223,8 +224,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);
@@ -235,6 +241,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 );
}
}
@@ -364,7 +371,8 @@ if ( defined $comment_tainted ) {
log_trace("check comment %s for unwanted chars", $special_home);
# do not sanitize, can't be done without libperl
if ( $comment_tainted !~ qr/^([^\x00-\x1F\x7F:]*)$/ ) {
- die( "unwanted chars in comment" );
+ log_fatal( mtx("unwanted chars in comment") );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
}
if( defined $special_shell ) {
@@ -403,8 +411,8 @@ if( defined $gid_option ) {
}
if ((defined($special_home)) && ($special_home !~ m+^/+ )) {
- log_fatal( mtx("The home dir must be an absolute path.") );
- exit( RET_INVALID_HOME_DIRECTORY );
+ log_fatal( mtx("The home dir must be an absolute path.") );
+ exit( RET_INVALID_HOME_DIRECTORY );
}
@@ -942,49 +950,20 @@ if ($action eq "adduser") {
create_homedir ($no_copy_skel ? 0 : 1, 0); # copy skeleton data
# useradd without -p has left the account disabled (password string is '!')
- my $yesexpr = langinfo(YESEXPR());
- my $noexpr = langinfo(NOEXPR());
if ($ask_passwd) {
- PASSWD: for (;;) {
- my $passwd = which('passwd');
- my $ok = systemcall_or_warn($passwd, $new_name);
- $ok = $ok >> 8;
- log_debug( "systemcall_or_warn %s %s return value %s", $passwd, $new_name, $ok);
- if ($ok != 0) {
- my $answer;
- # hm, error, should we break now?
- if ($ok == 1) {
- log_warn( mtx("Permission denied"));
- } elsif ($ok == 2) {
- log_warn( mtx("invalid combination of options"));
- } elsif ($ok == 3) {
- log_warn( mtx("unexpected failure, nothing done"));
- } elsif ($ok == 4) {
- log_warn( mtx("unexpected failure, passwd file missing"));
- } elsif ($ok == 5) {
- log_warn( mtx("passwd file busy, try again"));
- } elsif ($ok == 6) {
- log_warn( mtx("invalid argument to option"));
- } elsif ($ok == 10) {
- log_warn( mtx("wrong password given or password retyped incorrectly"));
- } else {
- log_warn( mtx("unexpected return code %s given from passwd"), $ok );
- }
+ my %passwd_errors = (
+ 1 => "Permission denied",
+ 2 => "Invalid combination of options",
+ 3 => "Unexpected failure, nothing done",
+ 4 => "Passwd file missing",
+ 5 => "Passwd file busy, try again",
+ 6 => "Invalid argument to option",
+ 10 => "Wrong password given or retyped incorrectly",
+ );
- # Translators: [y/N] has to be replaced by values defined in your
- # locale. You can see by running "locale noexpr" which regular
- # expression will be checked to find positive answer.
- PROMPT: for (;;) {
- print (gtx("Try again? [y/N] "));
- chop ($answer=<STDIN>);
- last PROMPT if ($answer =~ m/$yesexpr/o);
- last PASSWD if ($answer =~ m/$noexpr/o);
- last PASSWD if (!$answer);
- }
- } else {
- last; ## passwd ok
- }
- }
+ interactive_command_with_confirmation(
+ 'passwd', $new_name, \%passwd_errors
+ );
}
if (defined($comment_tainted)) {
@@ -992,22 +971,14 @@ if ($action eq "adduser") {
} elsif ($uid_pool{$new_name}{'comment'}) {
ch_comment($new_name, $uid_pool{$new_name}{'comment'});
} else {
- my $noexpr = langinfo(NOEXPR());
- my $yesexpr = langinfo(YESEXPR());
- CHFN: for (;;) {
- my $chfn = &which('chfn');
- systemcall($chfn, $new_name);
- # Translators: [y/N] has to be replaced by values defined in your
- # locale. You can see by running "locale yesexpr" which regular
- # expression will be checked to find positive answer.
- PROMPT: for (;;) {
- print (gtx("Is the information correct? [Y/n] "));
- chop (my $answer=<STDIN>);
- last PROMPT if ($answer =~ m/$noexpr/o);
- last CHFN if ($answer =~ m/$yesexpr/o);
- last CHFN if (!$answer);
- }
- }
+ my %chfn_errors = (
+ 1 => "Permission denied",
+ 2 => "Invalid combination of options",
+ );
+
+ interactive_command_with_confirmation(
+ 'chfn', $new_name, \%chfn_errors, 1
+ );
}
if ( ( $add_extra_groups || $config{"add_extra_groups"} ) && defined($config{"extra_groups"}) ) {
@@ -1309,21 +1280,21 @@ sub sanitize_name {
# this check cannot be turned off
log_err( mtx("To avoid ambiguity with numerical UIDs, usernames which" .
"resemble numbers or negative numbers are not allowed.") );
- exit( RET_INVALID_CHARS_IN_NAME );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
log_trace("sanitize_name testing single or double period");
if ( $name =~ qr/^\.\.?$/ ) {
# this check cannot be turned off
log_err( mtx("Usernames must not be a single or a double period.") );
- exit( RET_INVALID_CHARS_IN_NAME );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
log_trace("sanitize_name testing > 32 chars");
if (length( encode($charset, $name) ) > 32) {
# this check cannot be turned off
log_err( mtx("Usernames must be no more than 32 bytes in length.") );
- exit( RET_INVALID_CHARS_IN_NAME );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
log_trace("sanitize_name testing %s against insane chars %s", $name, def_min_regex);
@@ -1333,7 +1304,7 @@ sub sanitize_name {
"dash, plus sign, or tilde, and it must not contain any of the" .
"following: colon, comma, slash, or any whitespace characters" .
"including spaces, tabs, and newlines.") );
- exit( RET_INVALID_CHARS_IN_NAME );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
log_trace("sanitize_name checking %s against %s (%s)", $name, $name_regex, $name_regex_var);
@@ -1350,7 +1321,7 @@ sub sanitize_name {
"compatibility with Samba machine accounts, \$ is also supported" .
"at the end of the username. (Use the `--allow-all-names' option" .
"to bypass this restriction.)") );
- exit( RET_INVALID_CHARS_IN_NAME );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
if ($name_check_level) {
@@ -1360,7 +1331,7 @@ sub sanitize_name {
"configured via the %s configuration variable. Use the" .
"`--allow-bad-names' option to relax this check or reconfigure" .
"%s in configuration."), $name_regex_var, $name_regex_var );
- exit( RET_INVALID_CHARS_IN_NAME );
+ exit( RET_INVALID_CHARS_IN_INPUT );
}
log_trace("sanitize_name checking %s against %s", $name, anynamere);
@@ -1466,6 +1437,64 @@ sub user_is_member {
}
+sub interactive_command_with_confirmation {
+ my ($cmd, $user_name, $error_map, $always_confirm) = @_;
+
+ $always_confirm //= 0; # default to false if not provided
+ return unless -t STDIN; # skip non-interactive
+
+ my $yesexpr = langinfo(YESEXPR);
+ my $noexpr = langinfo(NOEXPR);
+
+ my $retry = 1;
+
+ while ($retry) {
+ $retry = 0;
+
+ my $full_cmd = which($cmd);
+ my $ok = systemcall_or_warn($full_cmd, $user_name);
+ $ok = $ok >> 8; # extract exit code
+
+ log_debug("systemcall_or_warn %s %s return value %s", $full_cmd, $user_name, $ok);
+
+ if ($ok != 0 && $error_map) {
+ if (exists $error_map->{$ok}) {
+ log_warn($error_map->{$ok});
+ } else {
+ log_warn("Unexpected return code %s from %s", $ok, $cmd);
+ }
+ }
+
+ # Prompt for confirmation if requested
+ if ($always_confirm) {
+ my $answer;
+ do {
+ print gtx("Is the information correct? [Y/n] ");
+ $answer = <STDIN>;
+
+ unless (defined $answer) {
+ warn "No input available, assuming 'yes'\n";
+ last;
+ }
+
+ chomp($answer);
+ $answer =~ s/^\s+|\s+$//g;
+
+ if ($answer =~ m/$yesexpr/o || $answer eq '') {
+ $retry = 0; # accepted
+ last;
+ } elsif ($answer =~ m/$noexpr/o) {
+ $retry = 1; # retry command
+ } else {
+ print "Please answer yes or no.\n";
+ $answer = undef; # repeat prompt
+ }
+
+ } while (!defined $answer);
+ }
+ }
+}
+
sub cleanup {
if ($undohome) {
log_info( mtx("Removing directory `%s' ..."), $undohome);
=====================================
debian/tests/lib/AdduserTestsCommon.pm
=====================================
@@ -30,6 +30,21 @@ 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_HAS_PASSWORD => 16,
+ EXISTING_EXPIRED => 32,
+ EXISTING_NOLOGIN => 64,
+ SYS_MIN => 100,
+ SYS_MAX => 999,
+ USER_MIN => 1000,
+ USER_MAX => 9999,
+};
+
my $charset = langinfo(CODESET);
binmode(STDOUT, ":encoding($charset)");
binmode(STDERR, ":encoding($charset)");
@@ -293,7 +308,7 @@ sub assert_path_has_ownership {
sub assert_path_is_a_file {
my $path = shift;
- ok(-f $path, "path is a file $path");
+ ok(-f $path, "path is a file: $path");
}
sub assert_path_is_a_directory {
@@ -459,6 +474,83 @@ sub apply_config_hash {
close(CONF);
}
+sub assert_user_status {
+ my ($username, $mask, $desc, $invert) = @_;
+
+ # Determine inversion from description if it starts with 'NOT '
+ if ($desc =~ /^NOT\s+(.*)/i) {
+ die "Cannot set invert=1 if description starts with NOT" if $invert;
+ $desc = $1; # remove 'NOT ' prefix
+ $invert = 1; # automatically invert
+ }
+
+ $invert //= 0; # default to positive assertion
+
+ my $status = existing_user_status($username);
+ my $ok = ($status & $mask) == $mask;
+ $ok = !$ok if $invert;
+
+ my $message = $invert
+ ? "User '$username' is NOT $desc (status $status)"
+ : "User '$username' $desc (status $status)";
+
+ ok($ok, $message);
+}
+
+
+sub existing_user_status {
+ my ($user_name,$user_uid) = @_;
+ my $ret = EXISTING_NOT_FOUND;
+ my (
+ $egpwn_name, $egpwn_passwd, $egpwn_uid, $egpwn_gid, $egpwn_quota,
+ $egpwn_comment, $egpwn_gcos, $egpwn_dir, $egpwn_shell, $egpwn_expire,
+ $egpwn_rest
+ ) = getpwnam($user_name);
+
+ if (defined $egpwn_uid) {
+ $ret |= EXISTING_FOUND;
+ $ret |= EXISTING_ID_MISMATCH if (defined($user_uid) && $egpwn_uid != $user_uid);
+ $ret |= EXISTING_SYSTEM if \
+ ($egpwn_uid >= SYS_MIN && $egpwn_uid <= SYS_MAX);
+
+ $ret |= EXISTING_NOLOGIN if ($egpwn_shell =~ /bin\/nologin/);
+ $ret |= EXISTING_HAS_PASSWORD if
+ (defined $egpwn_passwd && $egpwn_passwd ne '' && ($egpwn_passwd =~ s/^[!*]+//r ne ''));
+ $ret |= EXISTING_LOCKED if
+ (defined $egpwn_passwd && $egpwn_passwd =~ /^[!*]/);
+
+ my $age = `chage -l $user_name`;
+ if ($age =~ /Account expires\s*:\s*(.+)/i) {
+ my $exp = $1;
+ use POSIX qw(strftime);
+ use Time::Local;
+ if ($exp ne 'never') {
+ my $expiry_epoch = eval { `date -d "$exp" +%s` };
+ my $now = time;
+ $ret |= EXISTING_EXPIRED if ($expiry_epoch < $now);
+ }
+ }
+ } elsif ($user_uid && getpwuid($user_uid)) {
+ $ret |= EXISTING_ID_MISMATCH;
+ }
+ return $ret;
+}
+
+sub existing_group_status {
+ my ($group_name,$group_gid) = @_;
+ my $gid;
+ my $ret = EXISTING_NOT_FOUND;
+ if ((undef,undef,$gid) = egetgrnam($group_name)) {
+ $ret |= EXISTING_FOUND;
+ $ret |= EXISTING_ID_MISMATCH if (defined($group_gid) && $gid != $group_gid);
+ $ret |= EXISTING_SYSTEM if \
+ ($gid >= SYS_MIN && $gid <= SYS_MAX);
+ } elsif ($group_gid && getgrgid($group_gid)) {
+ $ret |= EXISTING_ID_MISMATCH;
+ }
+ return $ret;
+}
+
1;
# vim: tabstop=4 shiftwidth=4 expandtab
=====================================
deluser
=====================================
@@ -265,21 +265,28 @@ if(defined($group)) {
if($action eq "deluser") {
my($name, $passwd, ,$uid, $rest);
+ if (($config{remove_home} || $config{remove_all_files} || $config{backup}) && ($install_more_packages)) {
+ log_warn( mtx("In order to use the --remove-home, --remove-all-files, and --backup features, you need to install the `perl' package. To accomplish that, run apt-get install perl.") );
+ $config{remove_home}=undef;
+ $config{remove_all_files}=undef;
+ $config{backup}=undef;
+ $config{backup_to}=undef;
+ exit ( RET_MORE_PACKAGES) unless( $config{"system"} );
+ }
+
+ my (
+ $egpwn_name, $egpwn_passwd, $egpwn_uid, $egpwn_gid, $egpwn_quota,
+ $egpwn_comment, $egpwn_gcos, $egpwn_dir, $egpwn_shell, $egpwn_expire,
+ $egpwn_rest
+ ) = egetpwnam(encode($charset, $user));
+
# Don't allow a non-system user to be deleted when --system is given
# Also, "user does not exist" is only a warning with --system, but an
# error without --system.
if( $config{"system"} ) {
- if (($config{remove_home} || $config{remove_all_files} || $config{backup}) && ($install_more_packages)) {
- log_warn( mtx("In order to use the --remove-home, --remove-all-files, and --backup features, you need to install the `perl' package. To accomplish that, run apt-get install perl.") );
- $config{remove_home}=undef;
- $config{remove_all_files}=undef;
- $config{backup}=undef;
- $config{backup_to}=undef;
- }
-
- if( ($name, $passwd, $uid, $rest) = egetpwnam(encode($charset, $user)) ) {
- if ( ($uid < $config{"first_system_uid"} ||
- $uid > $config{"last_system_uid" } ) ) {
+ if( defined $egpwn_uid ) {
+ if ( ($egpwn_uid < $config{"first_system_uid"} ||
+ $egpwn_uid > $config{"last_system_uid" } ) ) {
log_warn( mtx("The user `%s' is not a system user. Exiting."), $user);
exit( RET_WRONG_OBJECT_PROPERTIES );
}
@@ -287,14 +294,9 @@ if($action eq "deluser") {
log_info( mtx("The user `%s' does not exist, but --system was given. Exiting."), $user);
exit( RET_OK );
}
- } else {
- if (($config{remove_home} || $config{remove_all_files} || $config{backup}) && ($install_more_packages)) {
- log_fatal( mtx("In order to use the --remove-home, --remove-all-files, and --backup features, you need to install the `perl' package. To accomplish that, run apt-get install perl.") );
- exit( RET_MORE_PACKAGES );
- }
}
- unless(exist_user($user)) {
+ unless(defined $egpwn_uid) {
log_fatal( mtx("The user `%s' does not exist."), $user );
exit( RET_OBJECT_DOES_NOT_EXIST );
}
=====================================
doc/adduser.8
=====================================
@@ -613,8 +613,8 @@ There is no group with the requested GID for the primary group
for a new user.
.TP
.B 31
-The chosen name for a new user or a new group does not conform to
-the selected naming rules.
+The chosen name or comment for a new user or a new group
+does not conform to the selected naming rules.
.TP
.B 32
The home directory of a new user must be an absolute path.
=====================================
testsuite/lib_test.pm
=====================================
@@ -322,6 +322,94 @@ sub check_user_status {
+sub testsuite_existing_user_status {
+ my ($user_name,$user_uid) = @_;
+ my $ret = EXISTING_NOT_FOUND;
+
+ my (
+ $egpwn_name, $egpwn_passwd, $egpwn_uid, $egpwn_gid, $egpwn_quota,
+ $egpwn_comment, $egpwn_gcos, $egpwn_dir, $egpwn_shell, $egpwn_expire,
+ $egpwn_rest
+ ) = getpwnam($user_name);
+
+ if (defined $egpwn_uid) {
+ $ret |= EXISTING_FOUND;
+ $ret |= EXISTING_ID_MISMATCH if (defined($user_uid) && $egpwn_uid != $user_uid);
+ $ret |= EXISTING_SYSTEM if \
+ ($egpwn_uid >= SYS_MIN && $egpwn_uid <= SYS_MAX);
+
+ $ret |= EXISTING_NOLOGIN if ($egpwn_shell =~ /bin\/nologin/);
+ $ret |= EXISTING_HAS_PASSWORD if
+ (defined $egpwn_passwd && $egpwn_passwd ne '' && ($egpwn_passwd =~ s/^[!*]+//r ne ''));
+ $ret |= EXISTING_LOCKED if
+ (defined $egpwn_passwd && $egpwn_passwd =~ /^[!*]/);
+
+ # this is deliberately implemented differently from the actual program
+ my $age = `chage -l $user_name`;
+
+ if ($age =~ /Account expires\s*:\s*(.+)/i) {
+ my $exp = $1;
+ if ($exp ne 'never') {
+ chomp $exp;
+ # Convert to epoch using GNU date
+ my $expiry_epoch = `date -d "$exp" +%s 2>/dev/null`;
+ chomp $expiry_epoch;
+
+ if (defined $expiry_epoch && $expiry_epoch =~ /^\d+$/) {
+ $ret |= EXISTING_EXPIRED if ($expiry_epoch < time);
+ } else {
+ warn "Failed to parse expiry date '$exp' with date command\n";
+ }
+ }
+ }
+ } elsif ($user_uid && getpwuid($user_uid)) {
+ $ret |= EXISTING_ID_MISMATCH;
+ }
+ return $ret;
+}
+
+# Map human-readable status names to bitmask constants
+my %USER_STATUS_MASK = (
+ locked => EXISTING_LOCKED,
+ haspasswd => EXISTING_HAS_PASSWORD,
+ nologin => EXISTING_NOLOGIN,
+ expired => EXISTING_EXPIRED,
+);
+
+sub check_user_status {
+ my ($username, $check, $do_print) = @_;
+ $do_print //= 0;
+
+ my $invert = 0;
+ my $result;
+
+ # Check for negative prefix "not_"
+ if ($check =~ /^not_(.+)$/) {
+ $invert = 1;
+ $check = $1;
+ }
+
+ my $mask = $USER_STATUS_MASK{$check}
+ or die "Unknown user status '$check'";
+
+ my $status = testsuite_existing_user_status($username);
+ # returns 0 if status is as desired so that it can be used in assertion
+ $result = (($status & $mask) == $mask) ? 0 : 1;
+
+ if ($do_print) {
+ my $msg = $result
+ ? "User '$username' $check"
+ : "User '$username' NOT $check";
+ print "$msg";
+ }
+
+ $result = !$result if $invert;
+ print " (status $status, returning ", $result ? 1 : 0, ")\n";
+ return $result;
+}
+
+
+
return 1
# vim: tabstop=4 shiftwidth=4 expandtab
View it on GitLab: https://salsa.debian.org/debian/adduser/-/compare/d8b8b51509b797d0bbd544153c94cf13da1b9838...67c314d0a72efeb4bbc748f1fcd3f2f174aed853
--
View it on GitLab: https://salsa.debian.org/debian/adduser/-/compare/d8b8b51509b797d0bbd544153c94cf13da1b9838...67c314d0a72efeb4bbc748f1fcd3f2f174aed853
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/20260117/b5c39cbc/attachment-0001.htm>
More information about the Pkg-shadow-devel
mailing list