diff options
Diffstat (limited to 'rescue/Flash')
-rwxr-xr-x | rescue/Flash/scripts/backup_systemloop | 106 | ||||
-rwxr-xr-x | rescue/Flash/scripts/clear_systemloop | 87 | ||||
-rw-r--r-- | rescue/Flash/scripts/rescue_common | 146 | ||||
-rwxr-xr-x | rescue/Flash/scripts/reset_rootpass | 100 | ||||
-rwxr-xr-x | rescue/Flash/scripts/reset_userpass | 111 | ||||
-rwxr-xr-x | rescue/Flash/scripts/restore_systemloop | 167 | ||||
-rwxr-xr-x | rescue/Flash/scripts/test_badblocks | 69 | ||||
-rwxr-xr-x | rescue/Flash/scripts/upgrade | 196 | ||||
-rwxr-xr-x | rescue/Flash/scripts/upgrade.merge-users | 52 |
9 files changed, 1034 insertions, 0 deletions
diff --git a/rescue/Flash/scripts/backup_systemloop b/rescue/Flash/scripts/backup_systemloop new file mode 100755 index 000000000..65c3185e6 --- /dev/null +++ b/rescue/Flash/scripts/backup_systemloop @@ -0,0 +1,106 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + +function prepare() { + + mkdir -p $rootdir + + if ! mount_usbroot $rootdir; then + return 1 + fi + + if [ x"$version" = x"1.0" ]; then + mkdir -p $tmpdir/shared + if ! mount_sharedroot $tmpdir/shared; then + return 1 + fi + fi + + if [ ! -d $dir ]; then + mkdir $dir + fi + + return 0 +} + +function doit() { + + clear + echo + echo -n 'Creating backup file. This can take some time: ' + + bzip2 -c $loop > $target 2> /tmp/rescue-backup.err & + + sleep 2 + + while ps | grep -q bzip2; do + progress + done + + sync + + echo + echo + + errsize=$(ls -la /tmp/rescue-backup.err | cut -d' ' -f5) + if [ $errsize -ne 0 ]; then + echo "Error compressing user files into $target" + return 1 + else + echo 'Backup file created!' + fi + + echo + + return 0 +} + +function cleanup() { + + if [ x"$version" = x"1.0" ]; then + umount $tmpdir/shared > /dev/null 2>&1 + rmdir $tmpdir/shared + fi + + umount $rootdir > /dev/null 2>&1 + rmdir $rootdir $tmpdir 2> /dev/null + + return 0 +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if [ x"$version" = x"1.0" ]; then + dir="$tmpdir/shared/backup" + loop="$rootdir/loopbacks/system.loop" +else + dir="$rootdir/backup" + loop="$rootdir/.loopbacks/system.loop" +fi + +file="backup-$(date +%Y%m%d).bz2" +target="$dir/$file" + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup +exit 0 diff --git a/rescue/Flash/scripts/clear_systemloop b/rescue/Flash/scripts/clear_systemloop new file mode 100755 index 000000000..f218d0987 --- /dev/null +++ b/rescue/Flash/scripts/clear_systemloop @@ -0,0 +1,87 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + +function prepare() { + + mkdir -p $rootdir + + if ! mount_usbroot $rootdir; then + return 1 + fi + + return 0 +} + +function doit() { + + clear + echo + echo "WARNING!" + echo + echo "Mandriva Flash will be reseted to factory defaults!" + echo -n "All user files, customizations and new packages installed " + echo "will be removed." + echo + echo -n "Do you want to continue? [N/y] " + read confirm + + if [ x"$confirm" = x"y" -o x"$confirm" = x"Y" ]; then + + if [ ! -f $loop ]; then + dd if=/dev/zero of=$loop bs=4000000 count=100 + fi + + if [ x"$version" = x"1.0" ]; then + /sbin/mkfs.ext2 -q -F $loop + fi + + echo + if [ $? -ne 0 ]; then + echo 'Error reseting device to factory defaults' + return 1 + else + echo 'Mandriva Flash was restored to factory defaults!' + fi + fi + + echo + + return 0 +} + +function cleanup() { + + umount $rootdir > /dev/null 2>&1 + rmdir $rootdir $tmpdir 2> /dev/null +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if [ x"$version" = x"1.0" ]; then + loop="$rootdir/loopbacks/system.loop" +else + loop="$rootdir/.loopbacks/system.loop" +fi + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup diff --git a/rescue/Flash/scripts/rescue_common b/rescue/Flash/scripts/rescue_common new file mode 100644 index 000000000..d09a3de1c --- /dev/null +++ b/rescue/Flash/scripts/rescue_common @@ -0,0 +1,146 @@ +#!/bin/bash + +function detect_version() { + + _tmpdir="/tmp/$$" + + mkdir -p $_tmpdir + + nash --force > /dev/null 2>&1 <<EOF +mount -t vfat LABEL=Share $_tmpdir +EOF + if [ $? -eq 0 ]; then + version="1.0" + else + version="1.05" + fi + + umount $_tmpdir 2> /dev/null + rmdir $_tmpdir 2> /dev/null +} + +function check_vendor() { + + # list of supported vendors/models + + # mandriva flash 1.0 (france) + vendors[0]="13fe" + models[0]="1a00" + # mandriva flash 1.0 (brazil) + vendors[1]="0930" + models[1]="653e" + # mandriva flash 4GB (france) + vendors[2]="13fe" + models[2]="1d00" + + rc=1 + + mount -t usbfs none /proc/bus/usb + + i=0 + while [ ! -z "${vendors[$i]}" ]; do + + grep "P:" /proc/bus/usb/devices | grep -q \ + "Vendor=${vendors[$i]} ProdID=${models[$i]}" + if [ $? -eq 0 ]; then + rc=0 + break + fi + + let i++ + done + + umount /proc/bus/usb + + return $rc +} + +function insert_pendrive() { + + _tmpdir="/tmp/rescue-temp" + mkdir -p $_tmpdir + + modprobe usb-storage > /dev/null 2>&1 + modprobe vfat > /dev/null 2>&1 + + echo + echo -n 'Please insert your Mandriva Flash pen drive and press ENTER when ready: ' + read READY + echo + echo -n 'Detecting pen drive: ' + + for ((i=0; $i <= 15 ; i++)); do + nash --force > /dev/null 2>&1 <<EOF +mount -t vfat LABEL=MDVUSBROOT $_tmpdir +EOF + if [ $? -ne 0 ]; then + echo -n '.' + sleep 1 + else + echo -n ' found!' + + if ! check_vendor; then + echo + echo "This is not an official Mandriva Flash key!" + echo + fi + + cat /proc/mounts | grep $_tmpdir | cut -d' ' -f1 | \ + sed 's/[0-9]*$//g' > /tmp/rescue-device + umount $_tmpdir + rmdir $_tmpdir 2> /dev/null + + detect_version + + return 0 + fi + done + + rmdir $_tmpdir 2> /dev/null + + echo + echo + echo "Couldn't detect Mandriva Flash pen drive!" + echo + + return 1 +} + +function mount_usbroot() { + + nash --force > /dev/null 2>&1 <<EOF +mount -t vfat LABEL=MDVUSBROOT $1 +EOF + if [ $? -ne 0 ]; then + echo "Error mounting device labeled MDVUSBROOT" + return 1 + fi + + return 0 +} + +function mount_sharedroot() { + + nash --force > /dev/null 2>&1 <<EOF +mount -t vfat LABEL=Share $1 +EOF + if [ $? -ne 0 ]; then + echo "Error mounting device labeled Share" + return 1 + fi + + return 0 +} + +function progress() { + + echo -ne '\b|' + usleep 100000 + echo -ne '\b/' + usleep 100000 + echo -ne '\b-' + usleep 100000 + echo -ne '\b\\' + usleep 100000 +} + diff --git a/rescue/Flash/scripts/reset_rootpass b/rescue/Flash/scripts/reset_rootpass new file mode 100755 index 000000000..c0a505f21 --- /dev/null +++ b/rescue/Flash/scripts/reset_rootpass @@ -0,0 +1,100 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + +function prepare() { + + modprobe unionfs > /dev/null 2>&1 + modprobe squashfs > /dev/null 2>&1 + modprobe loop > /dev/null 2>&1 + + mkdir -p $rootdir + mkdir -p $tmpdir/squash + mkdir -p $tmpdir/user + mkdir -p $tmpdir/union + + if ! mount_usbroot $rootdir; then + return 1 + fi + + mount -t squashfs -o loop $sfs_loop $tmpdir/squash > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting distrib.sqfs" + return 1 + fi + + mount -t ext2 -o loop $sys_loop $tmpdir/user > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting system.loop" + return 1 + fi + + mount -t unionfs -o dirs=$tmpdir/user=rw:$tmpdir/squash=ro \ + none $tmpdir/union + if [ $? -ne 0 ]; then + echo "Error creating union of distrib.sqfs and system.loop" + return 1 + fi + + chroot $tmpdir/union /etc/init.d/keytable start &> /dev/null + chroot $tmpdir/union /usr/bin/unicode_start + + return 0 +} + +function doit() { + + clear + echo + chroot $tmpdir/union passwd root + echo + echo + + return 0 +} + +function cleanup() { + + chroot $tmpdir/union /usr/bin/unicode_stop + + umount $tmpdir/union > /dev/null 2>&1 + umount $tmpdir/user > /dev/null 2>&1 + umount $tmpdir/squash > /dev/null 2>&1 + umount $rootdir > /dev/null 2>&1 + + rmdir $tmpdir/union $tmpdir/user $tmpdir/squash 2> /dev/null + rmdir $rootdir $tmpdir 2> /dev/null +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if [ x"$version" = x"1.0" ]; then + sys_loop="$rootdir/loopbacks/system.loop" + sfs_loop="$rootdir/loopbacks/distrib.sqfs" +else + sys_loop="$rootdir/.loopbacks/system.loop" + sfs_loop="$rootdir/.loopbacks/distrib.sqfs" +fi + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup +exit 0 diff --git a/rescue/Flash/scripts/reset_userpass b/rescue/Flash/scripts/reset_userpass new file mode 100755 index 000000000..d34b629bf --- /dev/null +++ b/rescue/Flash/scripts/reset_userpass @@ -0,0 +1,111 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + +function prepare() { + + modprobe unionfs > /dev/null 2>&1 + modprobe squashfs > /dev/null 2>&1 + modprobe loop > /dev/null 2>&1 + + mkdir -p $rootdir + mkdir -p $tmpdir/squash + mkdir -p $tmpdir/user + mkdir -p $tmpdir/union + + if ! mount_usbroot $rootdir; then + return 1 + fi + + mount -t squashfs -o loop $sfs_loop $tmpdir/squash > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting distrib.sqfs" + return 1 + fi + + mount -t ext2 -o loop $sys_loop $tmpdir/user > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting system.loop" + return 1 + fi + + mount -t unionfs -o dirs=$tmpdir/user=rw:$tmpdir/squash=ro \ + none $tmpdir/union > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error creating union of distrib.sqfs and system.loop" + return 1 + fi + + chroot $tmpdir/union /etc/init.d/keytable start &> /dev/null + chroot $tmpdir/union /usr/bin/unicode_start + + return 0 +} + +function doit() { + + username=$(tail -1 $tmpdir/union/etc/passwd | cut -d ':' -f1) + + clear + echo + echo -n "What is your username? [$username] " + read name + + if [ -z "$name" ]; then + name="$username" + fi + + echo + echo + chroot $tmpdir/union passwd $name + echo + echo + + return 0 +} + +function cleanup() { + + chroot $tmpdir/union /usr/bin/unicode_stop + + umount $tmpdir/union > /dev/null 2>&1 + umount $tmpdir/user > /dev/null 2>&1 + umount $tmpdir/squash > /dev/null 2>&1 + umount $rootdir > /dev/null 2>&1 + + rmdir $tmpdir/union $tmpdir/user $tmpdir/squash 2> /dev/null + rmdir $rootdir $tmpdir 2> /dev/null +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if [ x"$version" = x"1.0" ]; then + sys_loop="$rootdir/loopbacks/system.loop" + sfs_loop="$rootdir/loopbacks/distrib.sqfs" +else + sys_loop="$rootdir/.loopbacks/system.loop" + sfs_loop="$rootdir/.loopbacks/distrib.sqfs" +fi + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup +exit 0 diff --git a/rescue/Flash/scripts/restore_systemloop b/rescue/Flash/scripts/restore_systemloop new file mode 100755 index 000000000..39c56e030 --- /dev/null +++ b/rescue/Flash/scripts/restore_systemloop @@ -0,0 +1,167 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + +function prepare() { + + mkdir -p $rootdir + + if ! mount_usbroot $rootdir; then + return 1 + fi + + if [ x"$version" = x"1.0" ]; then + mkdir -p $tmpdir/shared + if ! mount_sharedroot $tmpdir/shared; then + return 1 + fi + fi + + return 0 +} + +function doit() { + + if [ ! -d $dir ]; then + echo + echo "Can't find a backup directory in the Share partition" + echo + return 0 + fi + + cd $dir + i=1 + for file in $(ls -c1 backup-*.bz2 2> /dev/null | sort -r | head -10); do + files[$i]="$file" + let i++ + done + cd - > /dev/null + + if [ $i -eq 1 ]; then + echo + echo 'No backup files found!' + echo + return 0 + fi + + while [ true ]; do + + clear + echo + echo "The following backup files were found:" + echo + + i=1 + while [ -n "${files[$i]}" ]; do + echo "[$i] ${files[$i]}" + let i++ + done + let i-- + echo + echo '[0] Cancel / Return to main menu' + + echo + echo 'Select from the list above, the file that you want to restore.' + echo 'The most recent files come first in the list.' + echo + echo -n "What backup file do you want to restore? [1] " + read option + + if [ -z "$option" ]; then + option=1 + fi + if [ x"$option" = x"0" ]; then + return 0 + fi + + if [ ! -f $dir/${files[$option]} ]; then + echo + echo "Error reading backup file ${files[$option]}!" + echo + echo -n 'Do you want to restore another backup file? [N/y] ' + read confirm + + if [ x"$confirm" = x"y" -o x"$confirm" = x"Y" ]; then + continue + else + return 0 + fi + else + + echo + echo -n 'Restoring backup file. This can take some time: ' + + bunzip2 -c $dir/${files[$option]} > $loop \ + 2> /tmp/rescue-backup.err & + + sleep 2 + + while ps | grep -q bunzip2; do + progress + done + + sync + echo + echo + + errsize=$(ls -la /tmp/rescue-backup.err | cut -d' ' -f5) + if [ $errsize -ne 0 ]; then + echo 'Error restoring user files!' + echo + return 1 + else + echo 'Backup file restored!' + echo + break + fi + fi + done + + return 0 +} + +function cleanup() { + + if [ x"$version" = x"1.0" ]; then + umount $tmpdir/shared > /dev/null 2>&1 + rmdir $tmpdir/shared 2> /dev/null + fi + + umount $rootdir > /dev/null 2>&1 + rmdir $rootdir $tmpdir 2> /dev/null + + return 0 +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if [ x"$version" = x"1.0" ]; then + dir="$tmpdir/shared/backup" + loop="$rootdir/loopbacks/system.loop" +else + dir="$rootdir/backup" + loop="$rootdir/.loopbacks/system.loop" +fi + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup +exit 0 diff --git a/rescue/Flash/scripts/test_badblocks b/rescue/Flash/scripts/test_badblocks new file mode 100755 index 000000000..3fb1f34d8 --- /dev/null +++ b/rescue/Flash/scripts/test_badblocks @@ -0,0 +1,69 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + +function prepare() { + + return 0 +} + +function doit() { + + clear + echo + echo "WARNING!" + echo + echo "Searching for bad blocks in Mandriva Flash is a slow process." + echo + echo -n "Do you want to continue? [N/y] " + read confirm + + echo + echo + + device=$(cat /tmp/rescue-device) + + if [ x"$confirm" = x"y" -o x"$confirm" = x"Y" ]; then + + /sbin/badblocks -n -v -s ${device}1 + if [ x"$version" = x"1.0" ]; then + /sbin/badblocks -n -v -s ${device}2 + fi + fi + + echo + echo 'Bad blocks scan completed!' + echo + + return 0 +} + +function cleanup() { + + umount $rootdir > /dev/null 2>&1 + rmdir $rootdir $tmpdir 2> /dev/null +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup diff --git a/rescue/Flash/scripts/upgrade b/rescue/Flash/scripts/upgrade new file mode 100755 index 000000000..a81263c38 --- /dev/null +++ b/rescue/Flash/scripts/upgrade @@ -0,0 +1,196 @@ +#!/bin/bash + +# import functions library +source rescue_common + +tmpdir="/tmp/flash-rescue-root" +rootdir="$tmpdir/pen" + + +config_files_network_scripts="etc/sysconfig/network-scripts/ifcfg-* \ + etc/sysconfig/network-scripts/cellular.d \ + etc/sysconfig/network-scripts/vpn.d \ + etc/sysconfig/network-scripts/wireless.d" + +config_files_users="etc/passwd etc/shadow etc/group etc/gshadow" +config_files_time="etc/localtime etc/ntp etc/ntp.conf" +config_files="etc/sysconfig/* $config_files_users $config_files_time \ + etc/wpa_supplicant.conf etc/shorewall etc/kde \ + etc/udev/rules.d/61-*_config.rules" + +config_files_to_remove="etc/sysconfig/harddrake2" + +function prepare() { + + modprobe unionfs > /dev/null 2>&1 + modprobe squashfs > /dev/null 2>&1 + modprobe loop > /dev/null 2>&1 + + mkdir -p $rootdir + mkdir -p $tmpdir/squash + mkdir -p $tmpdir/user + mkdir -p $tmpdir/union + + if ! mount_usbroot $rootdir; then + return 1 + fi + + mount -t ext2 -o loop $sys_loop $tmpdir/user > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting system.loop" + return 1 + fi + + return 0 +} + +function get_existing_rpms() { + + mount -t squashfs -o loop $sfs_loop $tmpdir/squash > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting distrib.sqfs" + return 1 + fi + + mount -t unionfs -o dirs=$tmpdir/user=rw:$tmpdir/squash=ro \ + none $tmpdir/union + if [ $? -ne 0 ]; then + echo "Error creating union of distrib.sqfs and system.loop" + return 1 + fi + + chroot $tmpdir/squash rpm -qa | sort > /tmp/previous_rpms.list + if [ $? -ne 0 ]; then + echo "Error getting list of vanilla rpms installed on previous key" + fi + + chroot $tmpdir/union rpm -qa | sort > /tmp/existing_rpms.list + if [ $? -ne 0 ]; then + echo "Error getting list of rpms installed prior to upgrade" + fi + + umount $tmpdir/union > /dev/null 2>&1 + umount $tmpdir/squash > /dev/null 2>&1 + + mkdir -p $tmpdir/user/root + diff /tmp/previous_rpms.list /tmp/existing_rpms.list | sed -n 's/^> //p' > $tmpdir/user/root/new_existing_rpms.list + + return 0 +} + +function move_files() { + for i in $*; do + if [ -e $i ]; then + dir=`dirname $i` + [ "$dir" = "." ] || mkdir -p ..keep/$dir + mv $i ..keep/$dir || { echo "Error moving $i"; return 1; } + fi + done + + return 0 +} + +function remove_non_user_nor_config_files() { + + cd $tmpdir/user + + rm -rf $config_files_to_remove + + if [ -e ..keep ]; then + mv ..keep ..keep.bak + fi + if [ -e ..keep ]; then + echo "remove_non_user_nor_config_files can't work with existing temp dir" + return 1 + fi + + mkdir ..keep + + move_files $config_files_network_scripts || return 1 + rm -rf etc/sysconfig/network-scripts + + move_files home root $config_files || return 1 + rm -rf * + rm -rf .[^.]* + + mv ..keep/* . + rmdir ..keep + + cd - > /dev/null + + return 0 +} + +function copy_new_version() { + + return 0 +} + +function merge_config_files() { + + mount -t squashfs -o loop $sfs_loop $tmpdir/squash > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Error mounting distrib.sqfs" + return 1 + fi + + ./upgrade.merge-users $tmpdir/user/etc $tmpdir/squash/etc + + return 0 +} + +function doit() { + + if [ -d $tmpdir/user/var/lib/rpm/Packages ]; then + get_existing_rpms || return 1 + fi + + remove_non_user_nor_config_files || return 1 + + copy_new_version + + merge_config_files || return 1 + + return 0 +} + +function cleanup() { + cd / + + umount $tmpdir/union > /dev/null 2>&1 + umount $tmpdir/user > /dev/null 2>&1 + umount $tmpdir/squash > /dev/null 2>&1 + umount $rootdir > /dev/null 2>&1 + + rmdir $tmpdir/union $tmpdir/user $tmpdir/squash 2> /dev/null + rmdir $rootdir $tmpdir 2> /dev/null +} + +clear +trap cleanup SIGINT + +version="" +if ! insert_pendrive; then + exit 1 +fi + +if [ x"$version" = x"1.0" ]; then + sys_loop="$rootdir/loopbacks/system.loop" + sfs_loop="$rootdir/loopbacks/distrib.sqfs" +else + sys_loop="$rootdir/.loopbacks/system.loop" + sfs_loop="$rootdir/.loopbacks/distrib.sqfs" +fi + +if ! prepare; then + cleanup + exit 1 +fi + +if ! doit; then + cleanup + exit 1 +fi + +cleanup +exit 0 diff --git a/rescue/Flash/scripts/upgrade.merge-users b/rescue/Flash/scripts/upgrade.merge-users new file mode 100755 index 000000000..297960e91 --- /dev/null +++ b/rescue/Flash/scripts/upgrade.merge-users @@ -0,0 +1,52 @@ +#!/usr/bin/perl + +use MDK::Common; + +@ARGV == 2 or die "merge_users <existing files dir> <new files dir>\n"; + +my ($existing_dir, $new_dir) = @ARGV; + +merge('passwd', 'shadow'); +merge('group', 'gshadow'); + +sub merge { + my ($main, $shadow) = @_; + + my @new = cat_("$new_dir/$main"); + my %new_ids = map { (split ':')[2] => $_ } @new; + + my %names_to_have; + foreach (cat_("$existing_dir/$main")) { + my @l = split ':'; + next if $l[0] eq 'nobody' || $l[2] < 500; + if (my $e = $new_ids{$l[2]}) { + $_ eq $e or warn "ERROR: conflicting entries:\n $_ $e"; + } else { + push @new, $_; + $names_to_have{$l[0]} = 1; + } + } + + my @new_shadow = grep { !/^root:/ } cat_("$new_dir/$shadow"); + foreach (cat_("$existing_dir/$shadow")) { + my ($name) = split ':'; + if ($name eq 'root') { + unshift @new_shadow, $_; + } elsif ($names_to_have{$name}) { + push @new_shadow, $_; + } + } + + if (rename "$existing_dir/$main", "$existing_dir/$main.old") { + output("$existing_dir/$main", @new); + } else { + warn "rename $existing_dir/$main failed: $?\n"; + <STDIN>; + } + if (rename "$existing_dir/$shadow", "$existing_dir/$shadow.old") { + output("$existing_dir/$shadow", @new_shadow); + } else { + warn "rename $existing_dir/$shadow failed: $?\n"; + <STDIN>; + } +} |