Merge pull request #297 from mdmillerii/runtime-update

Update flash update to be useable at runtime.
diff --git a/meta-phosphor/classes/obmc-phosphor-image_types_uboot.bbclass b/meta-phosphor/classes/obmc-phosphor-image_types_uboot.bbclass
index c44139e..23903d8 100644
--- a/meta-phosphor/classes/obmc-phosphor-image_types_uboot.bbclass
+++ b/meta-phosphor/classes/obmc-phosphor-image_types_uboot.bbclass
@@ -52,6 +52,8 @@
        uinitrd="${initrd}.u-boot"
        rootfs="${IMAGE_LINK_NAME}.${IMAGE_BASETYPE}"
        rwfs="rwfs.${OVERLAY_BASETYPE}"
+       rofsimg=rofs.${IMAGE_BASETYPE}.cpio
+       netimg=initramfs-netboot.cpio
 
        if [ ! -f $ddir/$kernel ]; then
               bbfatal "Kernel file ${ddir}/${kernel} does not exist"
@@ -77,11 +79,11 @@
        dst="${ddir}/${FLASH_IMAGE_NAME}"
        rm -rf $dst
        mk_nor_image ${dst} ${FLASH_SIZE}
-       dd if=${ddir}/${uboot} of=${dst} bs=1k seek=${FLASH_UBOOT_OFFSET}
-       dd if=${ddir}/${kernel} of=${dst} bs=1k seek=${FLASH_KERNEL_OFFSET}
-       dd if=${ddir}/${uinitrd} of=${dst} bs=1k seek=${FLASH_INITRD_OFFSET}
-       dd if=${ddir}/${rootfs} of=${dst} bs=1k seek=${FLASH_ROFS_OFFSET}
-       dd if=${ddir}/${rwfs} of=${dst} bs=1k seek=${FLASH_RWFS_OFFSET}
+       dd if=${ddir}/${uboot} of=${dst} bs=1k conv=notrunc seek=${FLASH_UBOOT_OFFSET}
+       dd if=${ddir}/${kernel} of=${dst} bs=1k conv=notrunc seek=${FLASH_KERNEL_OFFSET}
+       dd if=${ddir}/${uinitrd} of=${dst} bs=1k conv=notrunc seek=${FLASH_INITRD_OFFSET}
+       dd if=${ddir}/${rootfs} of=${dst} bs=1k conv=notrunc seek=${FLASH_ROFS_OFFSET}
+       dd if=${ddir}/${rwfs} of=${dst} bs=1k conv=notrunc seek=${FLASH_RWFS_OFFSET}
        dstlink="${ddir}/${FLASH_IMAGE_LINK}"
        rm -rf $dstlink
        ln -sf ${FLASH_IMAGE_NAME} $dstlink
@@ -95,5 +97,13 @@
 
        tar -h -cvf ${ddir}/${MACHINE}-${DATETIME}.all.tar -C ${ddir} image-bmc
        tar -h -cvf ${ddir}/${MACHINE}-${DATETIME}.tar -C ${ddir} image-u-boot image-kernel image-initramfs image-rofs image-rwfs
+
+       # Package the root image (rofs layer) with the initramfs for net booting.
+       # Uses the symlink above to get the desired name in the cpio
+       ( cd $ddir && echo image-rofs | cpio -oHnewc -L > ${rofsimg} )
+       # Prepend the rofs cpio -- being uncompressed it must be 4-byte aligned
+       cat ${ddir}/${rofsimg} ${ddir}/${initrd} > ${ddir}/${netimg}
+       oe_mkimage  "${netimg}" "${INITRD_CTYPE}"
+
 }
 do_generate_flash[vardepsexclude] = "DATETIME"
diff --git a/meta-phosphor/classes/obmc-phosphor-initfs.bbclass b/meta-phosphor/classes/obmc-phosphor-initfs.bbclass
deleted file mode 100644
index de7923e..0000000
--- a/meta-phosphor/classes/obmc-phosphor-initfs.bbclass
+++ /dev/null
@@ -1,4 +0,0 @@
-# Common code for recipes that implement Phosphor OpenBMC filesystem
-
-RPROVIDES_${PN} += "obmc-phosphor-initfs"
-PROVIDES += "obmc-phosphor-initfs"
diff --git a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-init.sh b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-init.sh
index c37b3d5..70af93d 100644
--- a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-init.sh
+++ b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-init.sh
@@ -184,6 +184,7 @@
 fsck=$fsckbase$rwfst
 fsckopts=-a
 optfile=/run/initramfs/init-options
+optbase=/run/initramfs/init-options-base
 urlfile=/run/initramfs/init-download-url
 update=/run/initramfs/update
 
@@ -192,9 +193,16 @@
 	cp /${optfile##*/} $optfile
 fi
 
+if test -e /${optbase##*/}
+then
+	cp /${optbase##*/} $optbase
+else
+	touch $optbase
+fi
+
 if test ! -f $optfile
 then
-	cat /proc/cmdline > $optfile
+	cat /proc/cmdline $optbase > $optfile
 	get_fw_env_var openbmcinit >> $optfile
 	get_fw_env_var openbmconce >> $optfile
 fi
diff --git a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-shutdown.sh b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-shutdown.sh
index 8d5d0c9..8d5c672 100644
--- a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-shutdown.sh
+++ b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-shutdown.sh
@@ -44,6 +44,14 @@
 	if test -x $update
 	then
 		$update --clean-saved-files
+		remaining=$(ls $image*)
+		if test -n "$remaining"
+		then
+			echo 1>&2 "Flash update failed to flash these images:"
+			echo 1>&2 "$remaining"
+		else
+			echo "Flash update completed."
+		fi
 	else
 		echo 1>&2 "Flash update requested but $update program missing!"
 	fi
diff --git a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-update.sh b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-update.sh
index aa8fd89..f0c41a7 100755
--- a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-update.sh
+++ b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/obmc-update.sh
@@ -2,8 +2,9 @@
 
 echo update: "$@"
 
-export PS1=update-sh#\ 
-# exec /bin/sh
+echoerr() {
+	echo 1>&2 "ERROR: $@"
+}
 
 cd /
 if ! test -r /proc/mounts || ! test -f /proc/mounts
@@ -21,12 +22,43 @@
 	mkdir -p /dev
 	mount -t devtmpfs dev dev
 fi
-while grep mtd /proc/mounts
-do
-	echo 1>&2 "Error: A mtd device is mounted."
-	sulogin
-	# exec /bin/sh
-done
+
+# mtd number N with mtd name Name can be mounted via mtdN, or mtd:Name
+# (with a mtd aware fs) or by /dev/mtdblockN (with a mtd or block fs).
+mtdismounted() {
+	m=${1##mtd}
+	if grep -s "mtdblock$m " /proc/mounts || grep -s "mtd$m " /proc/mounts
+	then
+		return 0
+	fi
+	n=$(cat /sys/class/mtd/mtd$m/name)
+	if test -n "$n" && grep -s "mtd:$n " /proc/mounts
+	then
+		return 0
+	fi
+	return 1
+}
+
+# Detect child partitions when the whole flash is to be updated.
+# Ignore mtdNro and mtdblockN names in the class subsystem directory.
+childmtds() {
+	for m in /sys/class/mtd/$1/mtd*
+	do
+		m=${m##*/}
+		if test "${m%ro}" = "${m#mtdblock}"
+		then
+			echo $m
+		fi
+	done
+}
+
+toobig() {
+	if test $(stat -L -c "%s" "$1") -gt $(cat /sys/class/mtd/"$2"/size)
+	then
+		return 0
+	fi
+	return 1
+}
 
 findmtd() {
 	m=$(grep -xl "$1" /sys/class/mtd/*/name)
@@ -60,17 +92,39 @@
 save=/run/save/${upper##*/}
 
 mounted=
+doflash=y
 doclean=
 dosave=y
 dorestore=y
 toram=
+checksize=y
+checkmount=y
 
 whitelist=/run/initramfs/whitelist
 image=/run/initramfs/image-
+imglist=
 
 while test "$1" != "${1#-}"
 do
 	case "$1" in
+	--help)
+		cat <<HERE
+Usage: $0 [options] -- Write images in /run/initramfs to flash (/dev/mtd*)
+    --help                    Show this message
+    --no-flash                Don't attempt to write images to flash
+    --ignore-size             Don't compare image size to mtd device size
+    --ignore-mount            Don't check if destination is mounted
+    --save-files              Copy whitelisted files to save directory in RAM
+    --no-save-files           Don't copy whitelisted files to save directory
+    --copy-files              Copy files from save directory to rwfs mountpoint
+    --restore-files           Restore files from save directory to rwfs layer
+    --no-restore-files        Don't restore saved files from ram to rwfs layer
+    --clean-saved-files       Delete saved whitelisted files from RAM
+    --no-clean-saved-files    Retain saved whitelisted files in RAM
+HERE
+
+	    exit 0 ;;
+
 	--no-clean-saved-files)
 		doclean=
 		shift ;;
@@ -89,11 +143,21 @@
 	--restore-files)
 		dorestore=y
 		shift ;;
+	--no-flash)
+		doflash=
+		shift ;;
+	--ignore-size)
+		checksize=
+		shift ;;
+	--ignore-mount)
+		checkmount=
+		doflash=
+		shift ;;
 	--copy-files)
 		toram=y
 		shift ;;
 	*)
-		echo 2>&1 "Unknown option $1"
+		echoerr "Unknown option $1.  Try $0 --help."
 		exit 1 ;;
 	esac
 done
@@ -109,13 +173,24 @@
 
 	while read f
 	do
-		if ! test -e $upper/$f
+		# Entries shall start with /, no trailing /.. or embedded /../
+		if test "/${f#/}" != "$f" -o "${f%/..}" != "${f#*/../}"
+		then
+			echo 1>&2 "WARNING: Skipping bad whitelist entry $f."
+			continue
+		fi
+		if ! test -e "$upper/$f"
 		then
 			continue
 		fi
 		d="$save/$f"
+		while test "${d%/}" != "${d%/.}"
+		do
+			d="${d%/.}"
+			d="${d%/}"
+		done
 		mkdir -p "${d%/*}"
-		cp -rp $upper/$f "${d%/*}/"
+		cp -rp "$upper/$f" "${d%/*}/"
 	done < $whitelist
 
 	if test -n "$mounted"
@@ -124,30 +199,54 @@
 	fi
 fi
 
-for f in $image*
+imglist=$(echo $image*)
+if test "$imglist" = "$image*" -a ! -e "$imglist"
+then
+	# shell didn't expand the wildcard, so no files exist
+	echo "No images found to update."
+	imglist=
+fi
+
+for f in $imglist
 do
 	m=$(findmtd ${f#$image})
 	if test -z "$m"
 	then
-		echo 1>&2  "Unable to find mtd partiton for ${f##*/}."
-		exec /bin/sh
+		echoerr "Unable to find mtd partiton for ${f##*/}."
+		exit 1
 	fi
-done
-
-for f in $image*
-do
-	if test ! -s $f
+	if test -n "$checksize" && toobig "$f" "$m"
 	then
-		echo "Skipping empty update of ${f#$image}."
-		rm $f
-		continue
+		echoerr "Image ${f##*/} too big for $m."
+		exit 1
 	fi
-	m=$(findmtd ${f#$image})
-	echo "Updating ${f#$image}..."
-	flashcp -v $f /dev/$m && rm $f
+	for s in $m $(childmtds $m)
+	do
+		if test -n "$checkmount" && mtdismounted $s
+		then
+			echoerr "Device $s is mounted, ${f##*/} is busy."
+			exit 1
+		fi
+	done
 done
 
-if test "x$toram" = xy
+if test -n "$doflash"
+then
+	for f in $imglist
+	do
+		if test ! -s $f
+		then
+			echo "Skipping empty update of ${f#$image}."
+			rm $f
+			continue
+		fi
+		m=$(findmtd ${f#$image})
+		echo "Updating ${f#$image}..."
+		flashcp -v $f /dev/$m && rm $f
+	done
+fi
+
+if test -d $save -a "x$toram" = xy
 then
 	mkdir -p $upper
 	cp -rp $save/. $upper/
@@ -173,11 +272,3 @@
 fi
 
 exit
-
-# NOT REACHED without edit
-# NOT REACHED without edit
-
-echo "Flash completed.  Inspect, cleanup and reboot -f to continue."
-
-export PS1=update-sh#\ 
-exec /bin/sh
diff --git a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/whitelist b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/whitelist
index 603cec7..c35a552 100644
--- a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/whitelist
+++ b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/files/whitelist
@@ -6,4 +6,4 @@
 /etc/group
 /etc/shadow
 /etc/gshadow
-/var/lib/obmc/events/
+/var/lib/obmc/events
diff --git a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/obmc-phosphor-init.bb b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/obmc-phosphor-initfs.bb
similarity index 96%
rename from meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/obmc-phosphor-init.bb
rename to meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/obmc-phosphor-initfs.bb
index 3fa88c9..f81e21d 100644
--- a/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/obmc-phosphor-init.bb
+++ b/meta-phosphor/common/recipes-phosphor/obmc-phosphor-initfs/obmc-phosphor-initfs.bb
@@ -3,7 +3,6 @@
 PR = "r1"
 
 inherit obmc-phosphor-license
-inherit obmc-phosphor-initfs
 
 S = "${WORKDIR}"
 SRC_URI += "file://obmc-init.sh"