Help with UUID replacement in fstab and menu.lst

I am trying to write a small backup application for Linux systems file by file if partitions are created by the user using fdisk. I am facing a problem when I am done with restoring the files. The problem is with UUID mismatch in restored fstab and menu.lst.

Using C I could create a partlist.txt file where I have 3 entries:
device_name, "UUID" mountpoint

Need to restore the following:

  1. UUID in menu.lst by matching UUID of "/" from partlist.txt
  2. Replace correct UUIDs from partlist.txt for all mountpoints in fstab

Also cannot depend on the ordering of lines anywhere.

Attached the sample generated partlist.txt and fstab + menu.lst from Red Hat 6.
I am not an expert in using sed and awk. So any help is really appreciated.

Something like this..

miro@miro-ntb:Downloads$ cat partlist.txt 
/dev/sda1 "f75b104c-678e-4f80-a618-70d4bf4a3ede" /
/dev/sda3 "hsjsd675-678e-4f80-a618-70d4bf4a3ede" /home
/dev/sda2 "psb8767c-678e-4f80-a618-70d4bf4a3ede" /boot
miro@miro-ntb:Downloads$ cat fstab.txt 
#
# /etc/fstab
# Created by anaconda on Mon Feb 14 16:03:26 2011
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/VolGroup-lv_root /                       ext4    defaults        1 1
UUID=10cb97f9-e52e-472b-a20b-c1e90c6d561b /boot                   ext4    defaults        1 2
/dev/mapper/VolGroup-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
HHH     /home  smthn defs 0 0 
miro@miro-ntb:Downloads$ awk '
NR==FNR{a[$3]=$2; next} #store uuids in assoc. array
{ #on each line from fstab
for(i in a) { #loop through array
  if($2==i)  #check whether mountpoint is the same
  {$1="UUID=" a} #replace 1st field with UUID=uuid
}; 
print $0;  #print the whole line
}
' <(sed -e 's/\r//' -e 's/"//g' partlist.txt) fstab.txt  

#
# /etc/fstab
# Created by anaconda on Mon Feb 14 16:03:26 2011
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=f75b104c-678e-4f80-a618-70d4bf4a3ede / ext4 defaults 1 1
UUID=psb8767c-678e-4f80-a618-70d4bf4a3ede /boot ext4 defaults 1 2
/dev/mapper/VolGroup-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
UUID=hsjsd675-678e-4f80-a618-70d4bf4a3ede /home smthn defs 0 0

The sed command gets rid of carriage return and quotes.

Hi mirni,

Thank you so much. I have tried this just now and it works like a charm for the /etc/fstab file.

I need to replace the same in menu.lst file also (attached as menu.txt). Would you please provide the script for that also?

This is the script to modify menu.txt. It modifies the file in-place. It'd be safer to omit sed's '-i' switch in the second line, and let it print out the new version of menu.txt (redirect it into a new file); so that the original is kept untouched.

miro@miro-ntb:Downloads$ cat test.sh
#!/bin/bash

root_uuid=$(sed -n ' s/[^ ]* "// ;/\/[\r]*$/  s/".*//p' partlist.txt) #extract root UUID
sed -i 's/root=[^ ]*/root=UUID='$root_uuid'/' menu.txt #this file will get modified
miro@miro-ntb:Downloads$ cat menu.txt 
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/mapper/VolGroup-lv_root
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux (2.6.32-71.el6.i686)
    root (hd0,0)
    kernel /vmlinuz-2.6.32-71.el6.i686 ro root=/dev/mapper/VolGroup-lv_root rd_LVM_LV=VolGroup/lv_root rd_LVM_LV=VolGroup/lv_swap rd_NO_LUKS rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us crashkernel=auto rhgb quiet
    initrd /initramfs-2.6.32-71.el6.i686.img
miro@miro-ntb:Downloads$ ./test.sh
miro@miro-ntb:Downloads$ cat menu.txt 
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=UUID=f75b104c-678e-4f80-a618-70d4bf4a3ede
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux (2.6.32-71.el6.i686)
    root (hd0,0)
    kernel /vmlinuz-2.6.32-71.el6.i686 ro root=UUID=f75b104c-678e-4f80-a618-70d4bf4a3ede rd_LVM_LV=VolGroup/lv_root rd_LVM_LV=VolGroup/lv_swap rd_NO_LUKS rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us crashkernel=auto rhgb quiet
    initrd /initramfs-2.6.32-71.el6.i686.img

Thanks a lot mirni!

---------- Post updated at 06:15 PM ---------- Previous update was at 06:08 PM ----------

One question mirni...
Is there any way to edit fstab in-place too? Otherwise I need to redirect the lines in a temp file and replace fstab again.

AFAIK awk doesn't support in-place editing. A workaround is needed. If anyone knows how to deal with this with the original "awk < (sed file1) file2" design, please post.

miro@miro-ntb:Downloads$ cat fstab.txt 

#
# /etc/fstab
# Created by anaconda on Mon Feb 14 16:03:26 2011
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/VolGroup-lv_root /                       ext4    defaults        1 1
UUID=10cb97f9-e52e-472b-a20b-c1e90c6d561b /boot                   ext4    defaults        1 2
/dev/mapper/VolGroup-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
miro@miro-ntb:Downloads$ { rm fstab.txt && awk '
BEGIN{while ( (getline < "partlist.txt")>0) { 
gsub(/\r|"/,""); a[$3]=$2;}
}
{
for(i in a) { if($2==i){$1="UUID=" a}}; 
print $0;
}' > fstab.txt; } < fstab.txt
miro@miro-ntb:Downloads$ cat fstab.txt 

#
# /etc/fstab
# Created by anaconda on Mon Feb 14 16:03:26 2011
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=f75b104c-678e-4f80-a618-70d4bf4a3ede / ext4 defaults 1 1
UUID=psb8767c-678e-4f80-a618-70d4bf4a3ede /boot ext4 defaults 1 2
/dev/mapper/VolGroup-lv_swap swap                    swap    defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0

This workaround is adapted from here: sed / awk - inplace or inline edit. You can find an explanation how this '{ rm file && awk > file ; } < file' construct works.
Cheers
mirni

Thanks really!