*
* @par License:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
# 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
# e[3]s for flash_erase are now calculated from sysfs and depend on the device tree
# WARNING: TRY NOT TO 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(0,"rootfs.ubi", "/dev/mtd4","0 2560","-s 512 -O 512"),
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;
$rootfs_uploaded = false;
$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 .= "
${e[1]} ${comment}";
}
}
backup_note();
$msg = <<ERROR: Files not found. Accepted files are:
TXT;
die($msg);
}else{
$tmp = "";
foreach($safe_list as $e){
if ($e[1]=="rootfs.ubi"){
$rootfs_uploaded = true;
}
$tmp .= "{$e[1]}";
}
if ($v) printf("Files to be flashed:");
}
//$safe_list is ready
if (is_dir($NAND_PATH)&&$rootfs_uploaded){
backup_note();
rootfs_warning_note();
}
if ($v) {
backup_note();
printf("Ready for flashing.");
}
return $safe_list;
}
function rootfs_warning_note(){
printf("Warning: To update rootfs, please boot from mmc (instructions). Will skip rootfs.ubi");
}
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("NOTE: If flashing rootfs, please download a backup copy of /etc/elphel393
");
}
// $defaults are not used yet. No need
function get_flash_erase_args($dev, $defaults){
$mtd_device = explode("/",$dev)[2];
$mtd_sysfs_path = "/sys/class/mtd/$mtd_device";
$mtd_size = intval(file_get_contents("$mtd_sysfs_path/size"));
$mtd_erasesize = intval(file_get_contents("$mtd_sysfs_path/erasesize"));
$mtd_size_blocks = intval($mtd_size/$mtd_erasesize);
$mtd_erase_start = 0;
$res = "$mtd_erase_start $mtd_size_blocks";
return $res;
}
function nandflash($list){
global $UPDATE_DIR;
global $FLASH_LOG;
global $FLASH_LOG_LINK;
global $NAND_PATH;
$rootfs_note = "";
foreach($list as $e){
if ($e[0]==0){
if ($e[1]!="rootfs.ubi"){
exec("flash_unlock ${e[2]} >> $FLASH_LOG");
$flash_erase_args = get_flash_erase_args($e[2],$e[3]);
exec("flash_erase ${e[2]} $flash_erase_args >> $FLASH_LOG");
// -n - write without ecc
//exec("nandwrite -n ${e[2]} -p $UPDATE_DIR/${e[1]} >> $FLASH_LOG");
exec("nandwrite ${e[2]} -p $UPDATE_DIR/${e[1]} >> $FLASH_LOG");
}else{
if (!is_dir($NAND_PATH)) {
exec("flash_unlock ${e[2]} >> $FLASH_LOG");
$flash_erase_args = get_flash_erase_args($e[2],$e[3]);
exec("flash_erase ${e[2]} $flash_erase_args >> $FLASH_LOG");
exec("ubiformat ${e[2]} -f $UPDATE_DIR/${e[1]} ${e[4]} >> $FLASH_LOG");
}else{
rootfs_warning_note();
}
}
}
}
print("Success. See/Download flash.log. 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");
if (is_dir("${UBI_MNT}${BKP_DIR}")){
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 copy_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 /dev/ubi0_0 $UBI_MNT");
/*
if (!is_dir("$UBI_MNT${BKP_DIR}_bkp")) mkdir("$UBI_MNT${BKP_DIR}_bkp");
exec("tar -C ${UBI_MNT}${BKP_DIR}_bkp -xzpf var/$BKP_NAME");
*/
if (is_file("var/$BKP_NAME")){
if (is_dir("$UBI_MNT${BKP_DIR}_defaults")) rmdir("$UBI_MNT${BKP_DIR}_defaults");
rename("$UBI_MNT${BKP_DIR}","$UBI_MNT${BKP_DIR}_defaults");
//restore old configs
exec("mkdir -p ${UBI_MNT}${BKP_DIR}");
exec("tar -C ${UBI_MNT}${BKP_DIR} -xzpf var/$BKP_NAME");
//take package versions from defaults
exec("cp ${UBI_MNT}${BKP_DIR}_defaults/packages/* ${UBI_MNT}${BKP_DIR}/packages/");
}else{
exec("cp -r $UBI_MNT${BKP_DIR} $UBI_MNT${BKP_DIR}_defaults");
}
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("NOTE: All files have been removed from $UPDATE_DIR.");
}
$cmd = "donothing";
if (isset($_GET['cmd']))
$cmd = $_GET['cmd'];
else if (isset($argv[1]))
$cmd = $argv[1];
// default Content-Type is text/html - LibreJS (if turned on) can add extra tags: response
header("Content-Type: text/plain");
switch($cmd){
case "flash":
$flash_list = verify(false);
backup();
nandflash($flash_list);
if (isset($_GET['restore'])) copy_backup();
break;
case "backup":
backup();
send_backup();
break;
case "restore":
copy_backup();
break;
case "remove":
remove();
break;
default:
verify(true);
}
?>