<?php /* FILE NAME : update_software.php DESCRIPTION: update software on nand flash REVISION: 1.00 AUTHOR: Oleg Dzhimiev <oleg@elphel.com> LICENSE: AGPL, see http://www.gnu.org/licenses/agpl.txt Copyright (C) 2016 Elphel, Inc. */ # hardcoded $UPDATE_DIR = "/var/volatile/html/update"; $NAND_PATH = "/tmp/rootfs.ro"; $FLASH_LOG = "/var/volatile/html/flash.log"; $FLASH_LOG_LINK = "var/flash.log"; $UBI_MNT = "/tmp/ubi0"; $BKP_NAME = "elphel393_backup.tar.gz"; $BKP_DIR = "/etc/elphel393"; # update files # file, expertise level, nand partition, size - see http://wiki.elphel.com/index.php?title=NAND_flash_boot_rootfs # partitions are also listed in the device tree # WARNING: DO NOT CHANGE $UPDATE_LIST = array( array(0,"boot.bin", "/dev/mtd0","0 2"), array(0,"u-boot-dtb.img","/dev/mtd1","0 8"), array(0,"devicetree.dtb","/dev/mtd2","0 8"), array(0,"uImage", "/dev/mtd3","0 128"), array(1,"rootfs.tar.gz", "",""), array(0,"rootfs.ubi", "/dev/mtd4","0 2048","-s 2048 -O 2048"), array(1,"rootfs.ubifs", "/dev/mtd4","/dev/ubi_ctrl -m 4","ubiupdatevol /dev/ubi0_0"), ); //respond_xml($updatedir); function lookup_name($name){ global $UPDATE_LIST; foreach($UPDATE_LIST as $e){ if ($name==$e[1]) return $e; } return false; } function verify($v){ global $UPDATE_DIR; global $NAND_PATH; global $UPDATE_LIST; $safe_list = array(); if (is_dir($UPDATE_DIR)){ foreach(scandir($UPDATE_DIR) as $e){ $tmp = lookup_name($e); if ($tmp!=false){ if ($tmp[0]==0){ array_push($safe_list,$tmp); } } } } if (count($safe_list)==0){ $tmp = ""; foreach($UPDATE_LIST as $e){ if($e[0]==0){ switch($e[1]){ case "boot.bin": case "u-boot-dtb.img": case "devicetree.dtb": $comment = "(rarely updated)"; break; case "uImage": case "rootfs.ubi": $comment = "(frequently updated)"; break; default: $comment = ""; } $tmp .= "<li><b>${e[1]}</b> <span style='font-size:0.9em;'>${comment}</span></li>"; } } backup_note(); $msg = <<<TXT <b style='color:red;'>ERROR</b>: Files not found. Accepted files are: <ul> $tmp </ul> TXT; die($msg); }else{ $tmp = ""; foreach($safe_list as $e){ $tmp .= "<li>{$e[1]}</li>"; } if ($v) printf("Files to be flashed:<ul>$tmp</ul>"); } //$safe_list is ready if (is_dir($NAND_PATH)){ backup_note(); die("<b style='color:red'>ERROR</b>: Please boot from mmc (<a href='http://wiki.elphel.com/index.php?title=Tmp_manual#Boot'>instructions</a>)"); }else{ if ($v) { backup_note(); printf("<span style='color:green'>Ready for flashing.</span>"); } } return $safe_list; } function backup_note(){ $tmp = strrpos($_SERVER['SCRIPT_NAME'],"/"); if ($tmp==0) $base = $_SERVER['SCRIPT_NAME']; else $base = substr($_SERVER['SCRIPT_NAME'],0,$tmp+1); print("<b>NOTE</b>: If flashing rootfs, please download a backup copy of <a href='$base?cmd=backup'>/etc/elphel393</a><br/>"); } function nandflash($list){ global $UPDATE_DIR; global $FLASH_LOG; global $FLASH_LOG_LINK; foreach($list as $e){ if ($e[0]==0){ exec("flash_unlock ${e[2]} >> $FLASH_LOG"); exec("flash_erase ${e[2]} ${e[3]} >> $FLASH_LOG"); if ($e[1]!="rootfs.ubi") exec("nandwrite -n ${e[2]} -p $UPDATE_DIR/${e[1]} >> $FLASH_LOG"); else exec("ubiformat ${e[2]} -f $UPDATE_DIR/${e[1]} ${e[4]} >> $FLASH_LOG"); } } print("Done. See/Download <a href='$FLASH_LOG_LINK'>flash.log</a>. Then power cycle."); } function backup(){ global $NAND_PATH; global $UBI_MNT; global $BKP_NAME; global $BKP_DIR; if (!is_dir($NAND_PATH)){ exec("flash_unlock /dev/mtd4"); exec("ubiattach /dev/ubi_ctrl -m 4"); if (!is_dir($UBI_MNT)) mkdir($UBI_MNT); exec("mount -t ubifs -o ro /dev/ubi0_0 $UBI_MNT"); exec("tar -czvf var/$BKP_NAME -C ${UBI_MNT}${BKP_DIR} ."); exec("umount $UBI_MNT"); if (is_dir($UBI_MNT)) rmdir($UBI_MNT); exec("ubidetach /dev/ubi_ctrl -m 4"); }else{ //booted from nand exec("tar -czvf var/$BKP_NAME -C ${BKP_DIR} ."); } } function send_backup(){ global $BKP_NAME; header("Content-Type: application/octet-stream"); header('Content-Disposition: attachment; filename='.$BKP_NAME); print(file_get_contents("var/$BKP_NAME")); } function restore_backup(){ global $NAND_PATH; global $UBI_MNT; global $BKP_NAME; global $BKP_DIR; if (!is_dir($NAND_PATH)){ exec("flash_unlock /dev/mtd4"); exec("ubiattach /dev/ubi_ctrl -m 4"); if (!is_dir($UBI_MNT)) mkdir($UBI_MNT); exec("mount -t ubifs -o ro /dev/ubi0_0 $UBI_MNT"); exec("tar -C ${UBI_MNT}${BKP_DIR} -xzpf var/$BKP_NAME"); exec("sync"); exec("umount $UBI_MNT"); if (is_dir($UBI_MNT)) rmdir($UBI_MNT); exec("ubidetach /dev/ubi_ctrl -m 4"); } } function remove(){ global $UPDATE_DIR; exec("rm -rf $UPDATE_DIR/*; sync"); backup_note(); print("<b>NOTE</b>: All files have been removed from <b>$UPDATE_DIR</b>."); } $cmd = "donothing"; if (isset($_GET['cmd'])) $cmd = $_GET['cmd']; else if (isset($argv[1])) $cmd = $argv[1]; switch($cmd){ case "flash": $flash_list = verify(false); backup(); nandflash($flash_list); restore_backup(); break; case "backup": backup(); send_backup(); break; case "remove": remove(); break; default: verify(true); } ?>