Xref: utzoo comp.lang.perl:3171 comp.unix.questions:27288 alt.sources:2667 Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!newstop!texsun!convex!convex.COM From: tchrist@convex.COM (Tom Christiansen) Newsgroups: comp.lang.perl,comp.unix.questions,alt.sources Subject: Re: Help with massive uid/gid change. Message-ID: <109616@convex.convex.com> Date: 30 Nov 90 21:36:05 GMT References: <2365@taurus.BITNET> Sender: news@convex.com Reply-To: tchrist@convex.COM (Tom Christiansen) Followup-To: comp.lang.perl Organization: CONVEX Software Development, Richardson, TX Lines: 235 In article <2365@taurus.BITNET> 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 # # 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 () { 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 () { ((($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 () { ((($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 () { 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); Brought to you by Super Global Mega Corp .com