#!/opt/bin/perl # ######################################################################### # # # Programm zur systematischen Umstellung von User- und Group-ID-Nummern # # # ######################################################################### # # # Version 1.0 - Written 28.03.95 by Steffen Beyer # # Version 1.0.1 - Written 29.03.95 by Steffen Beyer # # Version 1.1 - Written 30.03.95 by Steffen Beyer # # Version 1.1.1 - Written 30.03.95 by Steffen Beyer # # Version 1.1.2 - Written 31.03.95 by Steffen Beyer # # Version 1.1.3 - Written 02.04.95 by Steffen Beyer # # Version 1.2 - Written 15.04.95 by Steffen Beyer # # Version 1.2.1 - Written 04.05.95 by Steffen Beyer # # Version 1.3 - Written 01.03.96 by Steffen Beyer # # # ######################################################################### # # # Copyright (C) 1995 by software design & management GmbH & Co. KG # # # ######################################################################### # # Einige wichtige Defaulteinstellungen: # $version = 'version 1.3'; # $self = $0; $self =~ s!^.*/!!; # $startdir = `pwd`; chop($startdir); # $UID_FILE = '/g/sysadm/uid.uid'; $GID_FILE = '/g/sysadm/gid.gid'; # $uid_file = $UID_FILE; $gid_file = $GID_FILE; # # Unterprogrammdefinitionen: # require "find.pl"; # sub numerically { $a <=> $b } # # Aufruf ohne Parameter ==> Hilfe ausgeben: # if (@ARGV == 0) { $help = 1; } # # Optionen aus der Kommandozeile ueberpruefen und uebernehmen: # while (@ARGV) { $_ = shift; if (/^-d$/) { $startdir = shift; } elsif (/^-u$/) { $uid_file = shift; } elsif (/^-g$/) { $gid_file = shift; } elsif (/^-d(\S+)$/) { $startdir = $1; } elsif (/^-u(\S+)$/) { $uid_file = $1; } elsif (/^-g(\S+)$/) { $gid_file = $1; } elsif (/^-m$/) { $merge = 1; } elsif (/^-\?$/) { $help = 1; } elsif (/^-h$/) { $help = 1; } elsif (/^-t$/) { $test = 1; } elsif (/^-v$/) { $verbose = 1; } else { $error = 1; unless (defined $option) { $option = $_; } } } # # Hilfe gewuenscht? # if ($help) { print <<"@@"; Usage: $self [ ]* where is one of the following: -d Explicitly specifies the starting directory (default is '.') -u Explicitly specifies the user id's parameter file (default is '$UID_FILE') -g Explicitly specifies the group id's parameter file (default is '$GID_FILE') (white space between option letter and directory or file name is optional) -m Allows merging of multiple users/groups to a single ID number -t Initiates test mode: every action is reported but not executed -v Initiates verbose mode: all parameters and actions are listed @@ exit; } # # Unbekannte Option gefunden? # if ($error) { die "Error: Unknown option '$option' encountered!\nEnter '$self -h' for help.\n"; } # # Sind die Angaben des Startverzeichnisses und der id-Dateien sinnvoll? # unless (($startdir ne "") && (-d $startdir)) { die "Error: Can't find starting directory '$startdir'!\n"; } # unless (($uid_file ne "") && (-f $uid_file)) { die "Error: Can't find user id's parameter file '$uid_file'!\n"; } # unless (($gid_file ne "") && (-f $gid_file)) { die "Error: Can't find group id's parameter file '$gid_file'!\n"; } # # Ausgabe der aktiven Parameter: # if ($verbose) { printf("\n'%s' %s active parameters:\n\n", $self, $version); printf("Starting directory = '%s'\n", $startdir); printf("User id's parameter file = '%s'\n", $uid_file); printf("Group id's parameter file = '%s'\n", $gid_file); printf("Merge mode = %s\n", $merge ? "ON" : "off"); printf("Test mode = %s\n", $test ? "ON" : "off"); printf("Verbose mode = %s\n", $verbose ? "ON" : "off"); } # # Erste Parameterdatei einlesen, ueberpruefen und in Tabelle(n) ablegen: # open(UID, "<$uid_file") || die "Can't open '$uid_file': $!\n"; # while () { chop; if (/^\s*([A-Za-z_][A-Za-z0-9_-]*)\s+(\d+)\s*$/) { $user = $1; $uid = $2; if ($user_uid{$uid} ne "") { if ($merge) { $user_uid{$uid} .= ", " . $user; warn "Warning: Parameter user id '$uid' is not unique!\n"; } else { die "Error: Parameter user id '$uid' is not unique!\n"; } } else { $user_uid{$uid} = $user; } if ($uid_user{$user} ne "") { if ($uid_user{$user} == $uid) { warn "Warning: Parameter user name '$user' is not unique!\n"; } else { die "Error: Parameter user name '$user' is not unique!\n"; } } else { $uid_user{$user} = $uid; } } else { die "Syntax error in '$uid_file' at line #$.!\n"; } } # close(UID); # # Liste der user und uid's nach uid sortiert ausgeben: # if ($verbose) { $i = 0; printf("\n'%s' %s user id table sorted by user id's:\n\n", $self, $version); foreach $uid (sort numerically keys(%user_uid)) { printf("%5d %6d %s\n", ++$i, $uid, $user_uid{$uid}); } } # # Liste der user und uid's nach user sortiert ausgeben: # if ($verbose) { $i = 0; printf("\n'%s' %s user id table sorted by user names:\n\n", $self, $version); foreach $user (sort keys(%uid_user)) { printf("%5d %8s %6d\n", ++$i, $user, $uid_user{$user}); } } # # Zweite Parameterdatei einlesen, ueberpruefen und in Tabelle(n) ablegen: # open(GID, "<$gid_file") || die "Can't open '$gid_file': $!\n"; # while () { chop; if (/^\s*([A-Za-z_][A-Za-z0-9_-]*)\s+(\d+)\s*$/) { $group = $1; $gid = $2; if ($group_gid{$gid} ne "") { if ($merge) { $group_gid{$gid} .= ", " . $group; warn "Warning: Parameter group id '$gid' is not unique!\n"; } else { die "Error: Parameter group id '$gid' is not unique!\n"; } } else { $group_gid{$gid} = $group; } if ($gid_group{$group} ne "") { if ($gid_group{$group} == $gid) { warn "Warning: Parameter group name '$group' is not unique!\n"; } else { die "Error: Parameter group name '$group' is not unique!\n"; } } else { $gid_group{$group} = $gid; } } else { die "Syntax error in '$gid_file' at line #$.!\n"; } } # close(GID); # # Liste der groups und gid's nach gid sortiert ausgeben: # if ($verbose) { $i = 0; printf("\n'%s' %s group id table sorted by group id's:\n\n", $self, $version); foreach $gid (sort numerically keys(%group_gid)) { printf("%5d %6d %s\n", ++$i, $gid, $group_gid{$gid}); } } # # Liste der groups und gid's nach group sortiert ausgeben: # if ($verbose) { $i = 0; printf("\n'%s' %s group id table sorted by group names:\n\n", $self, $version); foreach $group (sort keys(%gid_group)) { printf("%5d %8s %6d\n", ++$i, $group, $gid_group{$group}); } } # # Nur zur Eindeutigkeitspruefung (und Ausgabe) benoetigte Tabellen loeschen: # undef %user_uid; undef %group_gid; # # Aktuelle (alte!) Passwort- und Gruppendatei einlesen (slurp): # setpwent; # while (($user, $passwd, $uid) = getpwent) { if ($user_uid{$uid} ne "") { $user_uid{$uid} .= ", " . $user; warn "Warning: System user id '$uid' is not unique!\n"; } else { $user_uid{$uid} = $user; } } # endpwent; # setgrent; # while (($group, $passwd, $gid) = getgrent) { if ($group_gid{$gid} ne "") { $group_gid{$gid} .= ", " . $group; warn "Warning: System group id '$gid' is not unique!\n"; } else { $group_gid{$gid} = $group; } } # endgrent; # # Pruefe die Umsetzungstabellen auf Eindeutigkeit: # foreach $uid (keys(%user_uid)) { undef $map; undef $name; undef @users; @users = split(/, /, $user_uid{$uid}); foreach $user (@users) { $new = $uid_user{$user}; if ($new ne "") { if ($map ne "") { if ($map != $new) { die "Error: Mapping for system user id '$uid' is ambiguous!\n", "'$uid' --> '$name' --> '$map'\n", "'$uid' --> '$user' --> '$new'\n"; } } else { $map = $new; $name = $user; } } } } # foreach $gid (keys(%group_gid)) { undef $map; undef $name; undef @groups; @groups = split(/, /, $group_gid{$gid}); foreach $group (@groups) { $new = $gid_group{$group}; if ($new ne "") { if ($map ne "") { if ($map != $new) { die "Error: Mapping for system group id '$gid' is ambiguous!\n", "'$gid' --> '$name' --> '$map'\n", "'$gid' --> '$group' --> '$new'\n"; } } else { $map = $new; $name = $group; } } } } # # Aktuelle passwd-Datei nach uid's sortiert ausgeben: # if ($verbose) { $i = 0; printf("\n'%s' %s actual system passwd file sorted by user id's:\n\n", $self, $version); foreach $uid (sort numerically keys(%user_uid)) { printf("%5d %6d %s\n", ++$i, $uid, $user_uid{$uid}); } } # # Aktuelle group-Datei nach gid's sortiert ausgeben: # if ($verbose) { $i = 0; printf("\n'%s' %s actual system group file sorted by group id's:\n\n", $self, $version); foreach $gid (sort numerically keys(%group_gid)) { printf("%5d %6d %s\n", ++$i, $gid, $group_gid{$gid}); } } # # Gehe ins Startverzeichnis (der Pfad koennte ein Symbolic Link enthalten!): # chdir("$startdir") || die "Can't change to directory '$startdir': $!\n"; # # Device-Nr. der Platte des Startverzeichnisses ermitteln: # unless (($device) = lstat($startdir)) { die "Can't determine device # of directory '$startdir'!\n"; } # # Ueberschrift ausgeben: # if ($verbose) { printf("\n'%s' %s actions performed:\n\n", $self, $version); } # # Hauptschleife ueber alle gefundenen Verzeichnisse, Dateien und Links: # $start = time; # &find('.'); # $stop = time; # # Fertig: # if (($verbose) || ($test)) { ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($stop - $start); $year -= 70; printf ( "\nElapsed time: %d year%s %d day%s %d hour%s %d minute%s %d second%s.\n\n", $year, ($year!=1)?"s":"", $yday, ($yday!=1)?"s":"", $hour, ($hour!=1)?"s":"", $min, ($min!=1)?"s":"", $sec, ($sec!=1)?"s":"" ); } # exit; # # Die eigentliche Aktion erfolgt im folgenden Unterprogramm: # sub wanted { if (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) { if ($dev != $device) { $prune = 1; warn "Pruning at '$name' with device $dev (should be $device)\n" if ($verbose); } elsif ((-f _) || (-d _) || (-l _)) { undef $do_it; if ($user_uid{$uid} ne "") { undef @users; @users = split(/, /, $user_uid{$uid}); foreach $user (@users) { $new = $uid_user{$user}; if ($new ne "") { if ($uid != $new) { $uid = $new; $do_it = 1; } last; # immer abbrechen wenn ($new ne "") gefunden } # da Eindeutigkeit von '$new' garantiert ist } } if ($group_gid{$gid} ne "") { undef @groups; @groups = split(/, /, $group_gid{$gid}); foreach $group (@groups) { $new = $gid_group{$group}; if ($new ne "") { if ($gid != $new) { $gid = $new; $do_it = 1; } last; # immer abbrechen wenn ($new ne "") gefunden } # da Eindeutigkeit von '$new' garantiert ist } } if ($do_it) { if (($verbose) || ($test)) { print "chown $uid.$gid $name\n"; } unless ($test) { if (chown($uid, $gid, $_) != 1) { warn "Can't chown $uid.$gid '$name'!\n"; } } # unless test } # do it! } # file type = f, d, l else { } } # 'lstat' successful else { warn "Can't lstat '$name': $!\n"; } } # sub wanted # # Fertig. #