Help with massive uid/gid change.
Tom Christiansen
tchrist at convex.COM
Sat Dec 1 08:36:05 AEST 1990
In article <2365 at taurus.BITNET> <ofer%math.tau.ac.il at CUNYVM.CUNY.EDU> writes:
>Hello
>I have to change the uid/gid numbers for all the users on a system
>I'd like to do it doing one pass over the file system and not by
>doing n times 'find ....' for n=the number of users.
>I have an old /etc/passwd file and a new one and wish to use them
>as the base for this number swapping process.
>I have perl and all standard unix available.
I believe that UofCO has a compiled version of this kind of thing that's
quite quick by going under the file system, which may or may not bother
you. I don't have a copy though, so wrote my own.
This is how it works. You make a file, called "howtomv" by default.
In it you put new mappings, for example:
#comment
user jimbob 10002 # more comment
user stevebob 854
group bobbros 200
user daemon 1854
user notes 1
Then you run the script. It will give you a passwd.new and a group.new
file that you can inspect, and it won't really do the work if you use -n.
I've checked for a lot of blunders, but not all. One thing I don't check
for is if userid A wants to move to userid B and B is occupied, it won't
let you. It should really check to see whether B is moving and leaving a
vacancy, but it doesn't. By all means inspect the code closely first, run
with -n to see what it wants to do, and keep a backup of your disk. No
warranties, etc etc. Still, it worked well enough for me when I needed it.
--tom
#!/usr/bin/perl
#
# mvids - "moves" uids and gids
# Tom Christiansen <tchrist at convex.com>
#
# usage: mvids [-n] [-f howtomvfile] [starting-dir]
#
# Takes list of new user and group ids.
# Fixes passwd and group files.
# Traverses local file system starting with starting-dir
# updating all changed ids
#
# -n means don't really change anything
# -f is if you don't like the default description file name of howtomv
# read descriptions from howtomv file with format:
# type name number
# e.g.:
# user tom 1023
# group staff 200
$| = 1;
$oops = 0;
require 'getopts.pl';
do Getopts('dnf:');
$FILE = $opt_f || "howtomv";
$DIR = $opt_d ? "." : "/etc";
$topdir = shift || '/';
die "usage: $0 [-n] [-f howtomv] [starting-dir]\n" if $#ARGV > -1;
die "$topdir: Not a directory" unless -d $topdir;
open FILE || die "Can't open directions file \"$FILE\": $!\n";
while (<FILE>) {
s/\s*#.*//;
next if /^$/;
unless (/^(user|group)\s+(\w+)\s+(\d+)/) {
print STDERR "malformed line at line $. of $FILE: $_";
$oops++; next;
}
if ($3 > 32000) {
print STDERR "$1 $2 has id that's too big ($3)\n";
$oops++; next;
}
if ($3 == 0) {
print STDERR "Too dangerous to move $1 $2 to 0\n";
$oops++; next;
}
if ($2 eq 'root') {
print STDERR "You don't really want to move root\n";
$oops++; $next;
}
if ($1 eq 'user') {
if (defined $n_pwn2i{$2}) {
print STDERR "Saw user $2 again at line $. of $FILE\n";
$oops++; next;
}
if (defined $n_pwi2n{$3}) {
print STDERR "Saw uid $3 again at line $. of $FILE\n";
$oops++; next;
}
$uids++;
$n_pwn2i{$2} = $3;
$n_pwi2n{$3} = $2;
} else {
if (defined $n_grn2i{$2}) {
print STDERR "Saw group $2 again at line $. of $FILE\n";
$oops++; next;
}
if (defined $n_gri2n{$3}) {
print STDERR "Saw gid $3 again at line $. of $FILE\n";
$oops++; next;
}
$gids++;
$n_grn2i{$2} = $3;
$n_gri2n{$3} = $2;
}
}
$PWD = "$DIR/passwd";
$NPWD = "$PWD.new";
if ($uids) {
open PWD || die "Can't open $PWD: $!\n";
open (NPWD, ">$NPWD") || die "Can't create $NPWD: $!\n";
while (<PWD>) {
((($name,$uid) = /^(\w+):[^:]*:(\d+):/))
|| die "Bad passwd entry at line $.\n";
if (defined $n_pwi2n{$uid} && !defined $n_pwn2i{$name}) {
printf STDERR "Can't move user %s to uid %d -- %s already has it\n",
$n_pwi2n{$uid}, $uid, $name;
$oops++;
next;
}
$pwn2i{$name} = $uid;
s/:$uid:/:$n_pwn2i{$name}:/ if defined $n_pwn2i{$name};
print NPWD;
}
close PWD;
close NPWD;
foreach $user (keys %pwnam) {
unless (defined $pwn2i{$user}) {
print STDERR "Can't move non-existent user $user\n";
$oops++;
}
}
}
if ($gids) {
$GRP = "$DIR/group";
$NGRP = "$GRP.new";
open GRP || die "Can't open $GRP: $!\n";
open (NGRP , ">$NGRP") || die "Can't create $NGRP: $!\n";
while (<GRP>) {
((($name,$gid) = /^(\w+):[^:]*:(\d+):/))
|| die "Bad group entry at line $.\n";
if (defined $n_gri2n{$gid} && !defined $n_grn2i{$name}) {
printf STDERR "Can't move gid %s to %d -- %s already has it\n",
$n_gri2n{$gid}, $gid, $name;
$oops++;
next;
}
$grn2i{$name} = $gid;
s/:$gid:/:$n_grn2i{$name}:/ if defined $n_grn2i{$name};
print NGRP;
}
close GRP;
close NGRP;
foreach $group (keys %grnam) {
unless (defined $grn2i{$group}) {
print STDERR "Can't move non-existent group $group\n";
$oops++;
}
}
}
die "$0: $oops error" . ($oops > 1 ? "s" : "").
" in remapping directions.\n" if $oops;
die "$0: no ids to move\n" unless $uids || $gids;
# ok, now do it
open(FIND, "find $topdir \\( -fstype nfs -prune \\) -o -ls |")
|| die "Can't open find pipe";
while (<FIND>) {
split;
$uid = $gid = -1;
($file, $user, $group) = ($_[11], $_[5], $_[6]);
if (defined $n_pwn2i{$user}) {
$uid = $n_pwn2i{$user};
print "changing owner $user of $file from ",
"$pwn2i{$user} to $n_pwn2i{$user}\n";
}
if (defined $n_grn2i{$group}) {
$gid = $n_grn2i{$group};
print "changing group $group of $file from ",
"$grn2i{$group} to $n_grn2i{$group}\n";
}
if (!$opt_n && ($uid != -1 || $gid != -1)) {
if (!chown $uid, $gid, $file) {
printf STDERR "couldn't chown $file to $uid.$gid: $!\n";
$oops++;
}
}
}
unless ($opt_n) {
if ($uids) {
rename($PWD, "$PWD.bak")
|| die "Can't mv $PWD to $PWD.bak: $!\n";
rename($NPWD, $PWD)
|| die "Can't mv $NPWD to $PWD: $!\n";
}
if ($gids) {
rename($GRP, "$GRP.bak")
|| die "Can't mv $GRP to $GRP.bak: $!\n";
rename($NGRP, $GRP)
|| die "Can't mv $NGRP to $GRP: $!\n";
}
}
exit ($oops != 0);
More information about the Comp.unix.questions
mailing list