1d7ab7c04Sdownsj#!/usr/bin/perl 2d7ab7c04Sdownsj# -*- perl -*- 3d7ab7c04Sdownsj# 4*b69faa6cSmillert# $OpenBSD: rmuser.perl,v 1.7 2005/06/07 05:07:54 millert Exp $ 5d7ab7c04Sdownsj# 6d7ab7c04Sdownsj# Copyright 1995, 1996 Guy Helmer, Madison, South Dakota 57042. 7d7ab7c04Sdownsj# All rights reserved. 8d7ab7c04Sdownsj# 9d7ab7c04Sdownsj# Redistribution and use in source and binary forms, with or without 10d7ab7c04Sdownsj# modification, are permitted provided that the following conditions 11d7ab7c04Sdownsj# are met: 12d7ab7c04Sdownsj# 1. Redistributions of source code must retain the above copyright 13d7ab7c04Sdownsj# notice, this list of conditions and the following disclaimer as 14d7ab7c04Sdownsj# the first lines of this file unmodified. 15d7ab7c04Sdownsj# 2. Redistributions in binary form must reproduce the above copyright 16d7ab7c04Sdownsj# notice, this list of conditions and the following disclaimer in the 17d7ab7c04Sdownsj# documentation and/or other materials provided with the distribution. 18d7ab7c04Sdownsj# 3. The name of the author may not be used to endorse or promote products 19d7ab7c04Sdownsj# derived from this software without specific prior written permission. 20d7ab7c04Sdownsj# 21d7ab7c04Sdownsj# THIS SOFTWARE IS PROVIDED BY GUY HELMER ``AS IS'' AND ANY EXPRESS OR 22d7ab7c04Sdownsj# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23d7ab7c04Sdownsj# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24d7ab7c04Sdownsj# IN NO EVENT SHALL GUY HELMER BE LIABLE FOR ANY DIRECT, INDIRECT, 25d7ab7c04Sdownsj# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26d7ab7c04Sdownsj# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27d7ab7c04Sdownsj# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28d7ab7c04Sdownsj# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29d7ab7c04Sdownsj# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30d7ab7c04Sdownsj# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31d7ab7c04Sdownsj# 32d7ab7c04Sdownsj# rmuser - Perl script to remove users 33d7ab7c04Sdownsj# 34d7ab7c04Sdownsj# Guy Helmer <ghelmer@alpha.dsu.edu>, 07/17/96 35d7ab7c04Sdownsj# 36d7ab7c04Sdownsj# $From: rmuser.perl,v 1.2 1996/12/07 21:25:12 ache Exp $ 37d7ab7c04Sdownsj 3827250d79Smillertuse Fcntl qw(:DEFAULT :flock); 39d7ab7c04Sdownsj 40d7ab7c04Sdownsj$ENV{"PATH"} = "/bin:/sbin:/usr/bin:/usr/sbin"; 41d7ab7c04Sdownsjumask(022); 42d7ab7c04Sdownsj$whoami = $0; 43d7ab7c04Sdownsj$passwd_file = "/etc/master.passwd"; 4427250d79Smillert$passwd_tmp = "/etc/ptmp"; 45d7ab7c04Sdownsj$group_file = "/etc/group"; 46d7ab7c04Sdownsj$new_group_file = "${group_file}.new.$$"; 47d7ab7c04Sdownsj$mail_dir = "/var/mail"; 48d7ab7c04Sdownsj$crontab_dir = "/var/cron/tabs"; 49d7ab7c04Sdownsj$atjob_dir = "/var/at/jobs"; 50d7ab7c04Sdownsj 51d7ab7c04Sdownsj#$debug = 1; 52d7ab7c04Sdownsj 5327250d79SmillertEND { 549eacfc3dSmillert if (-e $passwd_tmp && defined(fileno(NEW_PW))) { 5527250d79Smillert unlink($passwd_tmp) || 5627250d79Smillert warn "\n${whoami}: warning: couldn't unlink $passwd_tmp ($!)\n\tPlease investigate, as this file should not be left in the filesystem\n"; 5727250d79Smillert } 5827250d79Smillert} 5927250d79Smillert 60d7ab7c04Sdownsjsub cleanup { 61d7ab7c04Sdownsj local($sig) = @_; 62d7ab7c04Sdownsj 63d7ab7c04Sdownsj print STDERR "Caught signal SIG$sig -- cleaning up.\n"; 64d7ab7c04Sdownsj exit(0); 65d7ab7c04Sdownsj} 66d7ab7c04Sdownsj 6727250d79Smillertsub open_files { 6827250d79Smillert open(GROUP, $group_file) || 6927250d79Smillert die "\n${whoami}: Error: couldn't open ${group_file}: $!\n"; 7027250d79Smillert if (!flock(GROUP, LOCK_EX|LOCK_NB)) { 7127250d79Smillert print STDERR "\n${whoami}: Error: couldn't lock ${group_file}: $!\n"; 7227250d79Smillert exit 1; 7327250d79Smillert } 7427250d79Smillert 7527250d79Smillert sysopen(NEW_PW, $passwd_tmp, O_RDWR|O_CREAT|O_EXCL, 0600) || 7627250d79Smillert die "\n${whoami}: Error: Password file busy\n"; 7727250d79Smillert 7827250d79Smillert if (!open(MASTER_PW, $passwd_file)) { 79d7ab7c04Sdownsj print STDERR "${whoami}: Error: Couldn't open ${passwd_file}: $!\n"; 80d7ab7c04Sdownsj exit(1); 81d7ab7c04Sdownsj } 82d7ab7c04Sdownsj} 83d7ab7c04Sdownsj 84d7ab7c04Sdownsj$SIG{'INT'} = 'cleanup'; 85d7ab7c04Sdownsj$SIG{'QUIT'} = 'cleanup'; 86d7ab7c04Sdownsj$SIG{'HUP'} = 'cleanup'; 87d7ab7c04Sdownsj$SIG{'TERM'} = 'cleanup'; 88d7ab7c04Sdownsj 89d7ab7c04Sdownsjif ($#ARGV > 0) { 90d7ab7c04Sdownsj print STDERR "usage: ${whoami} [username]\n"; 91d7ab7c04Sdownsj exit(1); 92d7ab7c04Sdownsj} 93d7ab7c04Sdownsj 94d7ab7c04Sdownsjif ($< != 0) { 95d7ab7c04Sdownsj print STDERR "${whoami}: Error: you must be root to use ${whoami}\n"; 96d7ab7c04Sdownsj exit(1); 97d7ab7c04Sdownsj} 98d7ab7c04Sdownsj 9927250d79Smillert&open_files; 100d7ab7c04Sdownsj 101d7ab7c04Sdownsjif ($#ARGV == 0) { 102d7ab7c04Sdownsj # Username was given as a parameter 103d7ab7c04Sdownsj $login_name = pop(@ARGV); 104d7ab7c04Sdownsj} else { 105d7ab7c04Sdownsj # Get the user name from the user 106d7ab7c04Sdownsj $login_name = &get_login_name; 107d7ab7c04Sdownsj} 108d7ab7c04Sdownsj 109d7ab7c04Sdownsjif (($pw_ent = &check_login_name($login_name)) eq '0') { 110d7ab7c04Sdownsj print STDERR "${whoami}: Error: User ${login_name} not in password database\n"; 111d7ab7c04Sdownsj exit 1; 112d7ab7c04Sdownsj} 113d7ab7c04Sdownsj 114d7ab7c04Sdownsj($name, $password, $uid, $gid, $class, $change, $expire, $gecos, $home_dir, 115d7ab7c04Sdownsj $shell) = split(/:/, $pw_ent); 116d7ab7c04Sdownsj 117d7ab7c04Sdownsjif ($uid == 0) { 118d7ab7c04Sdownsj print "${whoami}: Sorry, I'd rather not remove a user with a uid of 0.\n"; 119d7ab7c04Sdownsj exit 1; 120d7ab7c04Sdownsj} 121d7ab7c04Sdownsj 122d7ab7c04Sdownsjprint "Matching password entry:\n\n$pw_ent\n\n"; 123d7ab7c04Sdownsj 124d7ab7c04Sdownsj$ans = &get_yn("Is this the entry you wish to remove? "); 125d7ab7c04Sdownsj 126d7ab7c04Sdownsjif ($ans eq 'N') { 127d7ab7c04Sdownsj print "User ${login_name} not removed.\n"; 128d7ab7c04Sdownsj exit 0; 129d7ab7c04Sdownsj} 130d7ab7c04Sdownsj 131d7ab7c04Sdownsj# 132d7ab7c04Sdownsj# Get owner of user's home directory; don't remove home dir if not 133d7ab7c04Sdownsj# owned by $login_name 134d7ab7c04Sdownsj 135d7ab7c04Sdownsj$remove_directory = 1; 136d7ab7c04Sdownsj 137d7ab7c04Sdownsjif (-l $home_dir) { 138d7ab7c04Sdownsj $real_home_dir = &resolvelink($home_dir); 139d7ab7c04Sdownsj} else { 140d7ab7c04Sdownsj $real_home_dir = $home_dir; 141d7ab7c04Sdownsj} 142d7ab7c04Sdownsj 143d7ab7c04Sdownsj# 144d7ab7c04Sdownsj# If home_dir is a symlink and points to something that isn't a directory, 145d7ab7c04Sdownsj# or if home_dir is not a symlink and is not a directory, don't remove 146d7ab7c04Sdownsj# home_dir -- seems like a good thing to do, but probably isn't necessary... 147d7ab7c04Sdownsjif (((-l $home_dir) && ((-e $real_home_dir) && !(-d $real_home_dir))) || 148d7ab7c04Sdownsj (!(-l $home_dir) && !(-d $home_dir))) { 149d7ab7c04Sdownsj print STDERR "${whoami}: Home ${home_dir} is not a directory, so it won't be removed\n"; 150d7ab7c04Sdownsj $remove_directory = 0; 151d7ab7c04Sdownsj} 152d7ab7c04Sdownsj 153d7ab7c04Sdownsjif (length($real_home_dir) && -d $real_home_dir) { 154d7ab7c04Sdownsj $dir_owner = (stat($real_home_dir))[4]; # UID 155d7ab7c04Sdownsj if ($dir_owner != $uid) { 156d7ab7c04Sdownsj print STDERR "${whoami}: Home dir ${real_home_dir} is not owned by ${login_name} (uid ${dir_owner})\n"; 157d7ab7c04Sdownsj $remove_directory = 0; 158d7ab7c04Sdownsj } 159d7ab7c04Sdownsj} 160d7ab7c04Sdownsj 161d7ab7c04Sdownsjif ($remove_directory) { 162d7ab7c04Sdownsj $ans = &get_yn("Remove user's home directory ($home_dir)? "); 163d7ab7c04Sdownsj if ($ans eq 'N') { 164d7ab7c04Sdownsj $remove_directory = 0; 165d7ab7c04Sdownsj } 166d7ab7c04Sdownsj} 167d7ab7c04Sdownsj 168d7ab7c04Sdownsj#exit 0 if $debug; 169d7ab7c04Sdownsj 170d7ab7c04Sdownsj# 171d7ab7c04Sdownsj# Remove the user's crontab, if there is one 172d7ab7c04Sdownsj# (probably needs to be done before password databases are updated) 173d7ab7c04Sdownsj 174d7ab7c04Sdownsjif (-e "$crontab_dir/$login_name") { 175d7ab7c04Sdownsj print STDERR "Removing user's crontab:"; 176d7ab7c04Sdownsj system('/usr/bin/crontab', '-u', $login_name, '-r'); 177d7ab7c04Sdownsj print STDERR " done.\n"; 178d7ab7c04Sdownsj} 179d7ab7c04Sdownsj 180d7ab7c04Sdownsj# 181d7ab7c04Sdownsj# Remove the user's at jobs, if any 182d7ab7c04Sdownsj# (probably also needs to be done before password databases are updated) 183d7ab7c04Sdownsj 184d7ab7c04Sdownsj&remove_at_jobs($login_name, $uid); 185d7ab7c04Sdownsj 186d7ab7c04Sdownsj# 187d7ab7c04Sdownsj# Copy master password file to new file less removed user's entry 188d7ab7c04Sdownsj 189d7ab7c04Sdownsj&update_passwd_file; 190d7ab7c04Sdownsj 191d7ab7c04Sdownsj# 192d7ab7c04Sdownsj# Remove the user from all groups in /etc/group 193d7ab7c04Sdownsj 194d7ab7c04Sdownsj&update_group_file($login_name); 195d7ab7c04Sdownsj 196d7ab7c04Sdownsj# 197d7ab7c04Sdownsj# Remove the user's home directory 198d7ab7c04Sdownsj 199d7ab7c04Sdownsjif ($remove_directory) { 200d7ab7c04Sdownsj print STDERR "Removing user's home directory ($home_dir):"; 201d7ab7c04Sdownsj &remove_dir($home_dir); 202d7ab7c04Sdownsj print STDERR " done.\n"; 203d7ab7c04Sdownsj} 204d7ab7c04Sdownsj 205d7ab7c04Sdownsj# 206d7ab7c04Sdownsj# Remove the user's incoming mail file 207d7ab7c04Sdownsj 208d7ab7c04Sdownsjif (-e "$mail_dir/$login_name" || -l "$mail_dir/$login_name") { 209d7ab7c04Sdownsj print STDERR "Removing user's incoming mail file ($mail_dir/$login_name):"; 210d7ab7c04Sdownsj unlink "$mail_dir/$login_name" || 211d7ab7c04Sdownsj print STDERR "\n${whoami}: warning: unlink on $mail_dir/$login_name failed ($!) - continuing\n"; 212d7ab7c04Sdownsj print STDERR " done.\n"; 213d7ab7c04Sdownsj} 214d7ab7c04Sdownsj 215d7ab7c04Sdownsj# 216d7ab7c04Sdownsj# All done! 217d7ab7c04Sdownsj 218d7ab7c04Sdownsjexit 0; 219d7ab7c04Sdownsj 220d7ab7c04Sdownsjsub get_login_name { 221d7ab7c04Sdownsj # 222d7ab7c04Sdownsj # Get new user's name 223*b69faa6cSmillert local($login_name); 224d7ab7c04Sdownsj 225d7ab7c04Sdownsj print "Enter login name for user to remove: "; 226d7ab7c04Sdownsj $login_name = <>; 22727250d79Smillert chomp $login_name; 228d7ab7c04Sdownsj 229d7ab7c04Sdownsj print "User name is ${login_name}\n" if $debug; 230d7ab7c04Sdownsj return($login_name); 231d7ab7c04Sdownsj} 232d7ab7c04Sdownsj 233d7ab7c04Sdownsjsub check_login_name { 234d7ab7c04Sdownsj # 235d7ab7c04Sdownsj # Check to see whether login name is in password file 236d7ab7c04Sdownsj local($login_name) = @_; 237d7ab7c04Sdownsj local($Mname, $Mpassword, $Muid, $Mgid, $Mclass, $Mchange, $Mexpire, 238d7ab7c04Sdownsj $Mgecos, $Mhome_dir, $Mshell); 239d7ab7c04Sdownsj local($i); 240d7ab7c04Sdownsj 241d7ab7c04Sdownsj seek(MASTER_PW, 0, 0); 242d7ab7c04Sdownsj while ($i = <MASTER_PW>) { 24327250d79Smillert chomp $i; 244d7ab7c04Sdownsj ($Mname, $Mpassword, $Muid, $Mgid, $Mclass, $Mchange, $Mexpire, 245d7ab7c04Sdownsj $Mgecos, $Mhome_dir, $Mshell) = split(/:/, $i); 246d7ab7c04Sdownsj if ($Mname eq $login_name) { 247d7ab7c04Sdownsj seek(MASTER_PW, 0, 0); 248d7ab7c04Sdownsj return($i); # User is in password database 249d7ab7c04Sdownsj } 250d7ab7c04Sdownsj } 251d7ab7c04Sdownsj seek(MASTER_PW, 0, 0); 252d7ab7c04Sdownsj 253d7ab7c04Sdownsj return '0'; # User wasn't found 254d7ab7c04Sdownsj} 255d7ab7c04Sdownsj 256d7ab7c04Sdownsjsub get_yn { 257d7ab7c04Sdownsj # 258d7ab7c04Sdownsj # Get a yes or no answer; return 'Y' or 'N' 259d7ab7c04Sdownsj local($prompt) = @_; 260d7ab7c04Sdownsj local($done, $ans); 261d7ab7c04Sdownsj 262d7ab7c04Sdownsj for ($done = 0; ! $done; ) { 263d7ab7c04Sdownsj print $prompt; 264d7ab7c04Sdownsj $ans = <>; 26527250d79Smillert chomp $ans; 266d7ab7c04Sdownsj $ans =~ tr/a-z/A-Z/; 267d7ab7c04Sdownsj if (!($ans =~ /^[YN]/)) { 268d7ab7c04Sdownsj print STDERR "Please answer (y)es or (n)o.\n"; 269d7ab7c04Sdownsj } else { 270d7ab7c04Sdownsj $done = 1; 271d7ab7c04Sdownsj } 272d7ab7c04Sdownsj } 273d7ab7c04Sdownsj 274d7ab7c04Sdownsj return(substr($ans, 0, 1)); 275d7ab7c04Sdownsj} 276d7ab7c04Sdownsj 277d7ab7c04Sdownsjsub update_passwd_file { 278d7ab7c04Sdownsj local($skipped, $i); 279d7ab7c04Sdownsj 280d7ab7c04Sdownsj print STDERR "Updating password file,"; 281d7ab7c04Sdownsj seek(MASTER_PW, 0, 0); 282d7ab7c04Sdownsj $skipped = 0; 283d7ab7c04Sdownsj while ($i = <MASTER_PW>) { 28427250d79Smillert chomp($i); 285d7ab7c04Sdownsj if ($i ne $pw_ent) { 286d7ab7c04Sdownsj print NEW_PW "$i\n"; 287d7ab7c04Sdownsj } else { 288d7ab7c04Sdownsj print STDERR "Dropped entry for $login_name\n" if $debug; 289d7ab7c04Sdownsj $skipped = 1; 290d7ab7c04Sdownsj } 291d7ab7c04Sdownsj } 292d7ab7c04Sdownsj close(NEW_PW); 293d7ab7c04Sdownsj seek(MASTER_PW, 0, 0); 294d7ab7c04Sdownsj 295d7ab7c04Sdownsj if ($skipped == 0) { 296d7ab7c04Sdownsj print STDERR "\n${whoami}: Whoops! Didn't find ${login_name}'s entry second time around!\n"; 297d7ab7c04Sdownsj exit 1; 298d7ab7c04Sdownsj } 299d7ab7c04Sdownsj 300d7ab7c04Sdownsj # 301d7ab7c04Sdownsj # Run pwd_mkdb to install the updated password files and databases 302d7ab7c04Sdownsj 303d7ab7c04Sdownsj print STDERR " updating databases,"; 30427250d79Smillert system('/usr/sbin/pwd_mkdb', '-p', ${passwd_tmp}); 305d7ab7c04Sdownsj print STDERR " done.\n"; 306d7ab7c04Sdownsj 307d7ab7c04Sdownsj close(MASTER_PW); # Not useful anymore 308d7ab7c04Sdownsj} 309d7ab7c04Sdownsj 310d7ab7c04Sdownsjsub update_group_file { 311d7ab7c04Sdownsj local($login_name) = @_; 312d7ab7c04Sdownsj 313d7ab7c04Sdownsj local($i, $j, $grmember_list, $new_grent); 314d7ab7c04Sdownsj local($grname, $grpass, $grgid, $grmember_list, @grmembers); 315d7ab7c04Sdownsj 316d7ab7c04Sdownsj print STDERR "Updating group file:"; 317d7ab7c04Sdownsj local($group_perms, $group_uid, $group_gid) = 318d7ab7c04Sdownsj (stat(GROUP))[2, 4, 5]; # File Mode, uid, gid 319d7ab7c04Sdownsj open(NEW_GROUP, ">$new_group_file") || 320d7ab7c04Sdownsj die "\n${whoami}: Error: couldn't open ${new_group_file}: $!\n"; 321d7ab7c04Sdownsj chmod($group_perms, $new_group_file) || 322d7ab7c04Sdownsj printf STDERR "\n${whoami}: warning: could not set permissions of new group file to %o ($!)\n\tContinuing, but please check permissions of $group_file!\n", $group_perms; 323d7ab7c04Sdownsj chown($group_uid, $group_gid, $new_group_file) || 324d7ab7c04Sdownsj print STDERR "\n${whoami}: warning: could not set owner/group of new group file to ${group_uid}/${group_gid} ($!)\n\rContinuing, but please check ownership of $group_file!\n"; 325d7ab7c04Sdownsj while ($i = <GROUP>) { 326d7ab7c04Sdownsj if (!($i =~ /$login_name/)) { 327d7ab7c04Sdownsj # Line doesn't contain any references to the user, so just add it 328d7ab7c04Sdownsj # to the new file 329d7ab7c04Sdownsj print NEW_GROUP $i; 330d7ab7c04Sdownsj } else { 331d7ab7c04Sdownsj # 332d7ab7c04Sdownsj # Remove the user from the group 33327250d79Smillert chomp $i; 334d7ab7c04Sdownsj ($grname, $grpass, $grgid, $grmember_list) = split(/:/, $i); 335d7ab7c04Sdownsj @grmembers = split(/,/, $grmember_list); 336d7ab7c04Sdownsj undef @new_grmembers; 337d7ab7c04Sdownsj local(@new_grmembers); 338d7ab7c04Sdownsj foreach $j (@grmembers) { 339d7ab7c04Sdownsj if ($j ne $login_name) { 34027250d79Smillert push(@new_grmembers, $j); 341d7ab7c04Sdownsj } elsif ($debug) { 342d7ab7c04Sdownsj print STDERR "Removing $login_name from group $grname\n"; 343d7ab7c04Sdownsj } 344d7ab7c04Sdownsj } 345d7ab7c04Sdownsj if ($grname eq $login_name && $#new_grmembers == -1) { 346d7ab7c04Sdownsj # Remove a user's personal group if empty 347d7ab7c04Sdownsj print STDERR "Removing group $grname -- personal group is empty\n"; 348d7ab7c04Sdownsj } else { 349d7ab7c04Sdownsj $grmember_list = join(',', @new_grmembers); 350d7ab7c04Sdownsj $new_grent = join(':', $grname, $grpass, $grgid, $grmember_list); 351d7ab7c04Sdownsj print NEW_GROUP "$new_grent\n"; 352d7ab7c04Sdownsj } 353d7ab7c04Sdownsj } 354d7ab7c04Sdownsj } 355d7ab7c04Sdownsj close(NEW_GROUP); 356d7ab7c04Sdownsj rename($new_group_file, $group_file) || # Replace old group file with new 357d7ab7c04Sdownsj die "\n${whoami}: error: couldn't rename $new_group_file to $group_file ($!)\n"; 358d7ab7c04Sdownsj close(GROUP); # File handle is worthless now 359d7ab7c04Sdownsj print STDERR " done.\n"; 360d7ab7c04Sdownsj} 361d7ab7c04Sdownsj 362d7ab7c04Sdownsjsub remove_dir { 363d7ab7c04Sdownsj # Remove the user's home directory 364d7ab7c04Sdownsj local($dir) = @_; 365d7ab7c04Sdownsj local($linkdir); 366d7ab7c04Sdownsj 367d7ab7c04Sdownsj if (-l $dir) { 368d7ab7c04Sdownsj $linkdir = &resolvelink($dir); 369d7ab7c04Sdownsj # Remove the symbolic link 370d7ab7c04Sdownsj unlink($dir) || 371d7ab7c04Sdownsj warn "${whoami}: Warning: could not unlink symlink $dir: $!\n"; 372d7ab7c04Sdownsj if (!(-e $linkdir)) { 373d7ab7c04Sdownsj # 374d7ab7c04Sdownsj # Dangling symlink - just return now 375d7ab7c04Sdownsj return; 376d7ab7c04Sdownsj } 377d7ab7c04Sdownsj # Set dir to be the resolved pathname 378d7ab7c04Sdownsj $dir = $linkdir; 379d7ab7c04Sdownsj } 380d7ab7c04Sdownsj if (!(-d $dir)) { 381d7ab7c04Sdownsj print STDERR "${whoami}: Warning: $dir is not a directory\n"; 382d7ab7c04Sdownsj unlink($dir) || warn "${whoami}: Warning: could not unlink $dir: $!\n"; 383d7ab7c04Sdownsj return; 384d7ab7c04Sdownsj } 385d7ab7c04Sdownsj system('/bin/rm', '-rf', $dir); 386d7ab7c04Sdownsj} 387d7ab7c04Sdownsj 388d7ab7c04Sdownsjsub remove_at_jobs { 389d7ab7c04Sdownsj local($login_name, $uid) = @_; 390d7ab7c04Sdownsj local($i, $owner, $found); 391d7ab7c04Sdownsj 392d7ab7c04Sdownsj $found = 0; 393d7ab7c04Sdownsj opendir(ATDIR, $atjob_dir) || return; 394d7ab7c04Sdownsj while ($i = readdir(ATDIR)) { 395d7ab7c04Sdownsj next if $i eq '.'; 396d7ab7c04Sdownsj next if $i eq '..'; 397d7ab7c04Sdownsj next if $i eq '.lockfile'; 398d7ab7c04Sdownsj 399d7ab7c04Sdownsj $owner = (stat("$atjob_dir/$i"))[4]; # UID 400d7ab7c04Sdownsj if ($uid == $owner) { 401d7ab7c04Sdownsj if (!$found) { 402d7ab7c04Sdownsj print STDERR "Removing user's at jobs:"; 403d7ab7c04Sdownsj $found = 1; 404d7ab7c04Sdownsj } 405d7ab7c04Sdownsj # Use atrm to remove the job 406d7ab7c04Sdownsj print STDERR " $i"; 407d7ab7c04Sdownsj system('/usr/bin/atrm', $i); 408d7ab7c04Sdownsj } 409d7ab7c04Sdownsj } 410d7ab7c04Sdownsj closedir(ATDIR); 411d7ab7c04Sdownsj if ($found) { 412d7ab7c04Sdownsj print STDERR " done.\n"; 413d7ab7c04Sdownsj } 414d7ab7c04Sdownsj} 415d7ab7c04Sdownsj 416d7ab7c04Sdownsjsub resolvelink { 417d7ab7c04Sdownsj local($path) = @_; 418d7ab7c04Sdownsj local($l); 419d7ab7c04Sdownsj 420d7ab7c04Sdownsj while (-l $path && -e $path) { 421d7ab7c04Sdownsj if (!defined($l = readlink($path))) { 422d7ab7c04Sdownsj die "${whoami}: readlink on $path failed (but it should have worked!): $!\n"; 423d7ab7c04Sdownsj } 424d7ab7c04Sdownsj if ($l =~ /^\//) { 425d7ab7c04Sdownsj # Absolute link 426d7ab7c04Sdownsj $path = $l; 427d7ab7c04Sdownsj } else { 428d7ab7c04Sdownsj # Relative link 429d7ab7c04Sdownsj $path =~ s/\/[^\/]+\/?$/\/$l/; # Replace last component of path 430d7ab7c04Sdownsj } 431d7ab7c04Sdownsj } 432d7ab7c04Sdownsj return $path; 433d7ab7c04Sdownsj} 434