diff --git a/xCAT-server/lib/xcat/plugins/statelite.pm b/xCAT-server/lib/xcat/plugins/statelite.pm index 9105299d5..616b80d2a 100644 --- a/xCAT-server/lib/xcat/plugins/statelite.pm +++ b/xCAT-server/lib/xcat/plugins/statelite.pm @@ -219,26 +219,36 @@ sub process_request { return; } + # validate the options for all litefile entries + # if there is any scenario not supported, the command exits foreach my $entry (keys %hashNew) { my @tmp = split (/\s+/, $entry); + my $f = $tmp[1]; if ($hashNew{$entry}) { - if ( $tmp[0] =~ m/ro/ or $tmp[0] =~ m/con/) { - $callback->({error=>[qq{the parent directory should not be with "ro" or "con" as its option}], errorcode=>[1]}); + if ( $tmp[0] =~ m/ro$/ or $tmp[0] =~ m/con$/) { + $callback->({error=>[qq{the directory "$f" should not be with "ro" or "con" as its option}], errorcode=>[1]}); return; } foreach my $child ( @{$hashNew{$entry}} ) { my @tmpc = split (/\s+/, $child); - my $f = $tmp[1]; my $fc = $tmpc[1]; - if ( ($tmp[0] =~ m/link/) and ( $tmpc[0] !~ m/link/) ) { - $callback->({error=>[qq{Based on the option of $f, $fc can only use "link"-headed options}], errorcode=> [ 1]}); - return; + if ($tmp[0] =~ m/link/) { + if ($tmpc[0] eq "link,ro") { + $callback->({error=>[qq{Based on the option of $f, $fc should not use "link,ro" as its option}], errorcode=> [1]}); + return; + } + if ($tmpc[0] !~ m/link/) { + $callback->({error=>[qq{Based on the option of $f, $fc can only use "link"-based options}], errorcode=> [1]}); + return; + } + } else { + if ($tmpc[0] =~ m/link/) { + $callback->({error=>[qq{Based on the option of $f, $fc should not use "link"-based options}], errorcode=>[1]}); + return; + } } - if ( ($tmp[0] !~ m/link/) and ($tmpc[0] =~ m/link/) ) { - $callback->({error=>[qq{$fc shouldnot use "link"-headed options }], errorcode=> [ 1]}); - return; - } - if ( ($tmp[0] eq qq{persistent}) and ($tmpc[0] ne qq{persistent}) ) { + if ( ($tmp[0] =~ m{persistent}) and ($tmpc[0] !~ m{persistent}) ) { + # TODO: if the parent is "persistent", the child can be ro/persistent/rw/con $callback->({error=>["$fc should have persistent option like $f "], errorcode=> [ 1]}); return; } @@ -287,10 +297,12 @@ sub process_request { } } + # there's one parent directory, whose option is different from the old one unless ($entry[1] eq $oldentry[0]) { recoverFiles($rootimg_dir, \@oldentry, $callback); + # if its children items exist, we need to copy the backup files from .statebackup to the rootfs, if ($hashSaved{$line}) { - $verbose && $callback->({info=>["$f has sub items in the litefile table."]}); + $verbose && $callback->({info=>["$f has child file/directory in the litefile table."]}); my $childrenRef = $hashSaved{$line}; foreach my $child (@{$childrenRef}) { # recover them from .statebackup to $rootimg_dir @@ -305,6 +317,13 @@ sub process_request { xCAT::Utils->runcmd("rm -rf $destf", 0, 1); } + # maybe the dir of $destf doesn't exist, so we will create one + my $dirDestf = dirname $destf; + unless ( -d $dirDestf ) { + $verbose && $callback->({info=>["mkdir -p $dirDestf"]}); + xCAT::Utils->runcmd("mkdir -p $dirDestf", 0, 1); + } + if ( -e $srcf ) { $verbose && $callback->({info=>["recovering from $srcf to $destf"]}); xCAT::Utils->runcmd("cp -r -a $srcf $destf", 0, 1); @@ -316,7 +335,7 @@ sub process_request { # recover the children if ($hashSaved{$line}) { - $verbose && $callback->({info=>["$f has sub items in the litefile table."]}); + $verbose && $callback->({info=>["$f has child file/directory in the litefile table."]}); my $childrenRef = $hashSaved{$line}; foreach my $child (@{$childrenRef}) { my @tmpc = split (/\s+/, $child); @@ -412,26 +431,28 @@ In order to handle such a scenario, one hash is generated to show the hirarachy For example, one array with entry names is used as the input: my @entries = ( - "imagename bind,persistent /var/", - "imagename bind /var/tmp/", - "imagename tmpfs,rw /root/", - "imagename tmpfs,rw /root/.bashrc", - "imagename tmpfs,rw /root/test/", - "imagename bind /etc/resolv.conf", - "imagename bind /var/run/" + "imagename persistent /var/", + "imagename tempfs /var/tmp/", + "imagename link /root/", + "imagename link /root/.bashrc", + "imagename link /root/test/", + "imagename link /root/second/third", + "imagename tempfs /etc/resolv.conf", + "imagename tempfs /var/run/" ); Then, one hash will generated as: %hashentries = { - 'bind,persistent /var/' => [ - 'bind /var/tmp/', - 'bind /var/run/' - ], - 'bind /etc/resolv.conf' => undef, - 'tmpfs,rw /root/' => [ - 'tmpfs,rw /root/.bashrc', - 'tmpfs,rw /root/test/' - ] - }; + 'persistent /var/' => [ + 'tempfs /var/tmp/', + 'tempfs /var/run/' + ], + 'tempfs /etc/resolv.conf' => undef, + 'link /root/' => [ + 'link /root/.bashrc', + 'link /root/test/', + 'link /root/second/third" + ] +}; Arguments: one array with entrynames, @@ -451,24 +472,27 @@ sub parseLiteFiles { foreach (@entries) { my $entry = $_; my @str = split /\s+/, $entry; - shift @str; + shift @str; # remove the imgname in @entries $entry = join "\t", @str; my $file = $str[1]; chop $file if ($file =~ m{/$}); unless (exists $dhref->{"$entry"}) { - my $parent = dirname($file); - # to see whether $parent exists in @entries or not - unless ($parent =~ m/\/$/) { - $parent .= "/"; + my $parent = dirname $file; + my @res; + my $found = 0; + while($parent ne "/") { + # to see whether $parent exists in @entries or not + $parent .= "/" unless ($parent =~ m/\/$/); + @res = grep {$_ =~ m/\Q$parent\E$/} @entries; + $found = scalar @res; + last if ($found eq 1); + $parent = dirname $parent; } - #my $found = grep $_ =~ m/\Q$parent\E$/, @entries; - my @res = grep {$_ =~ m/\Q$parent\E$/} @entries; - my $found = scalar @res; if($found eq 1) { # $parent is found in @entries # handle $res[0]; my @tmpresentry=split /\s+/, $res[0]; - shift @tmpresentry; + shift @tmpresentry; # remove the imgname in @tmpresentry $res[0] = join "\t", @tmpresentry; chop $parent; my @keys = keys %{$dhref}; @@ -497,7 +521,7 @@ sub recoverFiles { #$callback->({info => ["! updating $f ..."]}); - if ($oldentry->[0] eq "tmpfs,rw" or $oldentry->[0] eq "ro" ) { + if ($oldentry->[0] =~ m{^link}) { my $target = $rootimg_dir . $f; if (-l $target) { #not one directory my $location = readlink $target; @@ -546,9 +570,9 @@ sub liteItem { my @entry = split (/\s+/, $item); - my $f = $entry[1]; + my $f = $entry[1]; # file name - my $rif = $rootimg_dir . $f; + my $rif = $rootimg_dir . $f; # the file's location in rootimg_dir my $d = dirname($f); if ($entry[0] =~ m/link/) { @@ -636,7 +660,7 @@ sub liteItem { } else { # since its parent directory has been linked to .default and .statelite/tmpfs/, - # what we only to do is to check it exists in .default directory + # what we need to do is only to check whether it exists in .default directory if($f =~ m{/$}) { # one directory unless ( -d "$rootimg_dir/.default$f" ) { if (-e "$rootimg_dir/.default$f") { @@ -648,6 +672,7 @@ sub liteItem { }else { # only one file my $fdir = dirname($f); unless ( -d "$rootimg_dir/.default$fdir") { + $verbose && $callback->({info=>["mkdir -p $rootimg_dir/.default$fdir"]}); xCAT::Utils->runcmd("mkdir -p $rootimg_dir/.default$fdir", 0, 1); } unless( -e "$rootimg_dir/.default$f") { diff --git a/xCAT-server/share/xcat/netboot/add-on/statelite/rc.statelite b/xCAT-server/share/xcat/netboot/add-on/statelite/rc.statelite index 520df5f3f..a7bd7e8bf 100755 --- a/xCAT-server/share/xcat/netboot/add-on/statelite/rc.statelite +++ b/xCAT-server/share/xcat/netboot/add-on/statelite/rc.statelite @@ -179,7 +179,6 @@ ResolveLinks () { done num=${#ELIST[@]} - # put all the child entry to the end of the ELIST array for ((i=0;i<$num;i++)); do set -- ${ELIST[$i]} type=$1 @@ -187,21 +186,34 @@ ResolveLinks () { parent="`dirname $path`/" efound=0 - for ((j=0;j<$num;j++)); do - set -- ${ELIST[$j]} - jtype=$1 - jpath=$2 - if [ "$parent" = "$jpath" ]; then - efound=1 - fi + while [ "$parent" != "//" ]; do + for ((j=0;j<$num;j++)); do + set -- ${ELIST[$j]} + jtype=$1 + jpath=$2 + if [ "$parent" = "$jpath" ]; then + efound=1 + break 2 + fi + done + parent="`dirname $parent`/" done if [ "$efound" = "1" ]; then # put it into CLIST CLIST[$[ ${#CLIST[@]} ]]=${ELIST[$i]} else - # put it into PLIST - PLIST[$[ ${#PLIST[@]} ]]=${ELIST[$i]} + pfound=0 + pnum=${#PLIST[@]} + for ((k=0;k<$pnum;k++)); do + if [ "${PLIST[$k]}" = "${path}" ]; then + pfound=1 + fi + done + if [ "$pfound" = "0" ]; then + # put it into PLIST + PLIST[$[ ${#PLIST[@]} ]]=${ELIST[$i]} + fi fi done @@ -227,7 +239,7 @@ ProcessType () { #TYPE=$3 # type of file #isChild=$4 # child = 1, parent = 0 - PPATH=`dirname ${2}` + PPATH=`/usr/bin/dirname ${2}` # every type has to have a base dir in tmpfs if [ ! -d ${TMPFS}${PPATH} ] && [ ! -L ${TMPFS}${PPATH} ]; then @@ -238,24 +250,27 @@ ProcessType () { case "${3}" in link) # the previous name is tmpfs,rw if [ -d ${TMPFS}${2} ]; then - cp -r -a ${1}* ${TMPFS}${2} + /bin/cp -r -a ${1}* ${TMPFS}${2} echo "cp -r -a ${1}* ${TMPFS}${2}" >>$LOG else - cp -r -a ${1} ${TMPFS}${2} + /bin/cp -r -a ${1} ${TMPFS}${2} echo "cp -r -a ${1} ${TMPFS}${2}" >>$LOG fi - # the link will already be in place on the image, so nothing else to do! + # the link has already be in place on the image, so nothing else to do! ;; link,ro) - # need to make sure directory exists: + # need to make sure its parent directory exists: if [ ! -d ${TMPFS}${PPATH} ]; then - mkdir -p ${TMPFS}${PPATH} >>$LOG 2>&1 + /bin/mkdir -p ${TMPFS}${PPATH} >>$LOG 2>&1 fi - TARGET=`echo ${TMPFS}${2} | sed -e 's/\/$//'` - LINK=`echo ${1} | sed -e "s/^\/sysroot//"` - - echo "ln -sf ${LINK} ${TARGET}" >>$LOG 2>&1 - ln -sf ${LINK} ${TARGET} >>$LOG 2>&1 + + if [ "${4}" = "0" ]; then + TARGET=`echo ${TMPFS}${2} | /bin/sed -e 's/\/$//'` + LINK=`echo ${1} | /bin/sed -e "s/^\/sysroot//"` + + echo "ln -sf ${LINK} ${TARGET}" >>$LOG 2>&1 + /bin/ln -sf ${LINK} ${TARGET} >>$LOG 2>&1 + fi ;; link,persistent) # everything from root image points to tmpfs @@ -264,151 +279,148 @@ ProcessType () { # make tree in persistent and tmpfs # need to check whether the option of its parent direcotry is persistent or not - TMPDIR=`dirname ${2}` - if [ ! -e ${PERSISTENT}${TMPDIR} ]; then - mkdir -p ${PERSISTENT}${TMPDIR} >>$LOG 2>&1 - echo "mkdir -p ${PERSISTENT}${TMPDIR}" >>$LOG 2>&1 + PATH=${2} + MOUNT=${1} + # if target is a directory, then remove it first, + # otherwise, the link will be created under this dir instead of replacing it. + # whack of trailing / for persistent directories: + + PATH=`echo ${PATH} | /bin/sed -e 's/\/$//'` + + TARGET=${TMPFS}${PATH} + if [ -d ${TARGET} ]; then + echo "rm -Rf ${TARGET}" >>$LOG 2>&1 + /bin/rm -Rf ${TARGET} 2>&1 >>$LOG + fi + + if [ ! -d ${PERSISTENT}${PPATH} ]; then + /bin/mkdir -p ${PERSISTENT}${PPATH} 2>&1 >>$LOG + echo "mkdir -p ${PERSISTENT}${PPATH}" >>$LOG + fi + + # if the file/directory doesn't exist, copy it over to persistent + if [ ! -e ${PERSISTENT}${PATH} ]; then + echo "cp -r -a ${MOUNT} ${PERSISTENT}${PATH}" >>$LOG 2>&1 + /bin/cp -r -a ${MOUNT} ${PERSISTENT}${PATH} fi if [ "$isChild" = "1" ]; then num=${#PLIST[@]} + echo "${PPATH}: " for ((i=0;i<$num; i++)); do set -- ${PLIST[$i]} itype=$1 ipath=$2 if [ "$PPATH" = "$ipath" ]; then - if [[ ! "$itype" =~ "persistent*" ]]; then - if [ ! -e ${PERSISTENT}${2} ]; then - echo "cp -r -a ${1} ${PERSISTENT}${2}" >>$LOG 2>&1 - cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG - fi + echo "${itype}" + if [ "$itype" = "link,persistent" ]; then # mount it to ${TARGET} - echo "mount --bind ${PERSISTENT}${2} ${TARGET}" >>$LOG 2>&1 - mount --bind ${PERSISTENT}${2} ${TARGET} + echo "mount --bind ${PERSISTENT}${PATH} ${TARGET}" >>$LOG 2>&1 + /bin/mount --bind ${PERSISTENT}${PATH} ${TARGET} fi fi done else - if [[ ! -d ${PERSISTENT}${PPATH} && ! -d `readlink -m ${PERSISTENT}${PPERS}` ]]; then - # unless the entry is one directory or one link to the directory - rm -rf ${PERSISTENT}${PPERS} >>$LOG 2>&1 - mkdir -p ${PERSISTENT}${PPERS} >>$LOG 2>&1 - echo "mkdir -p ${PERSISTENT}${PPERS}" >>$LOG 2>&1 - fi - # if the file doesn't exist, then copy it over to persistent - if [ ! -e ${PERSISTENT}${2} ]; then - # if its not there, then take it from something else - echo "cp -r -a ${1} ${PERSISTENT}${2}" >>$LOG 2>&1 - cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG 2>&1 - fi - # if target is a directory, then remove it first, - # otherwise, the link will be created under this dir instead of replacing it. - # whack of trailing / for persistent directories: - TARGET=`echo ${TMPFS}${2} | sed -e 's/\/$//'` - if [ -d ${TARGET} ]; then - echo "rm -Rf ${TARGET}" >>$LOG 2>&1 - rm -Rf ${TARGET} 2>&1 >>$LOG - fi # finally make the tmpfs link point to the persistent file # you have to get rid of the /sysroot in the beginning # so that when the chroot happens the link is valid. - LINK=`echo ${PERSISTENT}${2} | sed -e 's/^\/sysroot//'` + LINK=`echo ${PERSISTENT}${PATH} | /bin/sed -e 's/^\/sysroot//'` echo "ln -sf ${LINK} ${TARGET}" >>$LOG - ln -sf ${LINK} ${TARGET} >>$LOG 2>&1 + /bin/ln -sf ${LINK} ${TARGET} >>$LOG 2>&1 fi ;; link,con) echo "cat ${1} >>${TMPFS}${2}" >>$LOG 2>&1 - cat ${1} >>${TMPFS}${2} 2>&1 + /bin/cat ${1} >>${TMPFS}${2} 2>&1 ;; con) # there's one more option to indicate the con is at the end if [ "${5}" = "1" ]; then # mount the file with "--bind" option echo "mount --bind ${TMPFS}${2} /sysroot${2}" >>$LOG - mount --bind ${TMPFS}${2} /sysroot${2} >> $LOG 2>&1 + /bin/mount --bind ${TMPFS}${2} /sysroot${2} >> $LOG 2>&1 else echo "cat ${1} >>${TMPFS}${2}" >>$LOG 2>&1 - cat ${1} >>${TMPFS}${2} 2>&1 + /bin/cat ${1} >>${TMPFS}${2} 2>&1 fi ;; tempfs) # the default option, same as "tempfs" and "NULL" - ORIG=`echo ${2} | sed -e 's/\/$//'` + ORIG=`echo ${2} | /bin/sed -e 's/\/$//'` TARGET=`echo ${1}` if [ -d ${TMPFS}${2} ]; then - cp -r -a ${1}* ${TMPFS}${2} + /bin/cp -r -a ${1}* ${TMPFS}${2} echo "cp -r -a ${1}* ${TMPFS}${2}" >>$LOG else - cp -r -a ${1} ${TMPFS}${2} + /bin/cp -r -a ${1} ${TMPFS}${2} echo "cp -r -a ${1} ${TMPFS}${2}" >>$LOG fi if [ "$isChild" = "0" ]; then echo "mount --bind ${TMPFS}${2} /sysroot${ORIG}" >>$LOG - mount --bind ${TMPFS}${2} /sysroot${ORIG}>>$LOG 2>&1 + /bin/mount --bind ${TMPFS}${2} /sysroot${ORIG}>>$LOG 2>&1 fi ;; rw) # the default option, same as "tempfs" and "NULL" - ORIG=`echo ${2} | sed -e 's/\/$//'` + ORIG=`echo ${2} | /bin/sed -e 's/\/$//'` TARGET=`echo ${1}` if [ -d ${TMPFS}${2} ]; then - cp -r -a ${1}* ${TMPFS}${2} + /bin/cp -r -a ${1}* ${TMPFS}${2} echo "cp -r -a ${1}* ${TMPFS}${2}" >>$LOG else - cp -r -a ${1} ${TMPFS}${2} + /bin/cp -r -a ${1} ${TMPFS}${2} echo "cp -r -a ${1} ${TMPFS}${2}" >>$LOG fi if [ "$isChild" = "0" ]; then echo "mount --bind ${TMPFS}${2} /sysroot${ORIG}" >>$LOG - mount --bind ${TMPFS}${2} /sysroot${ORIG}>>$LOG 2>&1 + /bin/mount --bind ${TMPFS}${2} /sysroot${ORIG}>>$LOG 2>&1 fi ;; persistent) if [ ! -d ${PERSISTENT}${PPATH} ]; then - mkdir -p ${PERSISTENT}${PPATH} + /bin/mkdir -p ${PERSISTENT}${PPATH} echo "mkdir -p ${PERSISTENT}${PPATH}" >>$LOG fi # if the file doesn't exist, then copy it over to persistent if [ ! -e ${PERSISTENT}${2} ]; then echo "cp -r -a ${1} ${PERSISTENT}${2}" >>$LOG - cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG + /bin/cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG fi - ORIG=`echo ${2} | sed -e 's/\/$//'` + ORIG=`echo ${2} | /bin/sed -e 's/\/$//'` TARGET=`echo ${PERSISTENT}${2}` echo "mount --bind ${TARGET} /sysroot/${ORIG}" >>$LOG - mount --bind ${TARGET} /sysroot/${ORIG}>>$LOG 2>&1 + /bin/mount --bind ${TARGET} /sysroot/${ORIG}>>$LOG 2>&1 ;; ro) # need to make sure directory exists: if [ ! -d ${TMPFS}${PPATH} ]; then - mkdir -p ${TMPFS}${PPATH} >>$LOG 2>&1 + /bin/mkdir -p ${TMPFS}${PPATH} >>$LOG 2>&1 fi # before mount, need to check whether it exists or not STRPATH="${TMPFS}${2}" STRLEN=${#STRPATH} - CHAREND=`echo ${STRPATH} | cut -c${STRLEN}` + CHAREND=`echo ${STRPATH} | /bin/cut -c${STRLEN}` if [ "${CHAREND}" = "/" ]; then # it is one directory if [ ! -d ${STRPATH} ]; then - rm -rf ${STRPATH} - mkdir ${STRPATH} + /bin/rm -rf ${STRPATH} + /bin/mkdir ${STRPATH} fi else if [ ! -f ${STRPATH} ]; then - rm -rf ${STRPATH} - touch ${STRPATH} + /bin/rm -rf ${STRPATH} + /bin/touch ${STRPATH} fi fi echo "mout --bind -o ro ${1} ${MNTDIR}${2}" >>$LOG 2>&1 - mount --bind -o ro ${1} ${MNTDIR}${2} >>$LOG 2>&1 + /bin/mount --bind -o ro ${1} ${MNTDIR}${2} >>$LOG 2>&1 ;; *) ;; @@ -424,15 +436,15 @@ FindFile () { type=$2 isChild=$3 FOUND=0 - for DIR in `cat ${SYNCTREE}` ;do + for DIR in `/bin/cat ${SYNCTREE}` ;do DIR=${DIR/:/} if [ -e ${TREEMOUNT}/${DIR}${path} ]; then FOUND=1 # we found it! - if [ -d ${TREEMOUNT}/${DIR}${path} ] && [ "0" -eq `ls -A ${TREEMOUNT}/${DIR}${path} |wc -l` ]; then + if [ -d ${TREEMOUNT}/${DIR}${path} ] && [ "0" -eq `/bin/ls -A ${TREEMOUNT}/${DIR}${path} |/usr/bin/wc -l` ]; then FOUND=0 else ProcessType ${TREEMOUNT}/${DIR}${path} ${path} ${type} ${isChild} - if [[ "${2}" -eq "link,con" ]] || [[ "${2}" -eq "con" ]]; then + if [ "${2}" = "link,con" ] || [ "${2}" = "con" ]; then continue else break @@ -473,7 +485,7 @@ MountTrees ResolveLinks # make sure mtab points to the right place: -ln -sf /proc/mounts ${TMPFS}/etc/mtab +/bin/ln -sf /proc/mounts ${TMPFS}/etc/mtab # catch all hack for debugging: #cp -r -a ${DEFAULT}/* /.snapshot/tmpfs/