<?php
include_once "lang.php";
include_once "device_config_file.php";
function randStr($length=16)
{
return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, $length);
}
function hashPassword($password, $salt)
{
return sha1($password . $salt)
}
function arrayMapToString($array, $connector)
{
$result = array();
foreach($array as $k => $v) {
$result[] = "$k='$v'";
}
return implode($connector, $result);
}
function arrayGet($array, $key, $default=null) {
return isset($array[$key]) ? $array[$key] : $default;
}
function startsWith($haystack, $needle) {
return $needle === "" || strpos($haystack, $needle) === 0;
}
function endsWith($haystack, $needle) {
return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
function parentPath($level) {
$curPath = __FILE__;
$parts = explode(DIRECTORY_SEPARATOR, $curPath);
for($i=0; $i<$level; ++$i)
array_pop($parts);
return realpath(implode(DIRECTORY_SEPARATOR, $parts));
}
function cptBaseDir() {
return parentPath(2);
}
function sync() {
// shell_exec("sync");
// shell_exec("echo 3 > /proc/sys/vm/drop_caches");
// return;
$output = array();
$return_val = 0;
exec("sync", $output, $return_val);
error_log("sync output : " . implode("\n", $output) . " return: " . $return_val);
unset($output);
$return_val = 0;
exec("echo 3 > /proc/sys/vm/drop_caches", $output, $return_val);
error_log("drop caches output : " . implode("\n", $output) . " return: " . $return_val);
}
function build_file_path() {
return join(DIRECTORY_SEPARATOR, func_get_args());
}
function get_absolute_path($path) {
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' == $part) continue;
if ('..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
$result = implode(DIRECTORY_SEPARATOR, $absolutes);
if (startsWith($path, DIRECTORY_SEPARATOR))
return DIRECTORY_SEPARATOR . $result;
else
return $result;
}
function webrootPath() {
$confFile = new DeviceConfigFile;
if (!$confFile->load())
return NULL;
$path = $confFile->value("Webroot Path", NULL);
if (is_null($path)) {
if (file_exists("/var/www"))
$path = "/var/www";
else if (file_exists("/www"))
$path = "/www";
}
return rtrim($path, "/");
}
function sdcardMountPath($confFile=NULL) {
if (is_null($confFile)) {
$confFile = new DeviceConfigFile;
if (!$confFile->load())
return NULL;
}
$sdcardPath = $confFile->value("SDcard Path", NULL);
return $sdcardPath;
}
function sdcardBackupPath() {
if (in_array(platformName(), array("FG", "FG+", "FG-")))
return backupBasePath();
$sdcardPath = sdcardMountPath();
//TODO: how to integrate with configs in cpt_site_config file ?
// maybe we should get rid of the cpt_site_config.php file ?
$sdBackupBasePath = build_file_path($sdcardPath, 'cpt-backups');
return $sdBackupBasePath;
}
function sdcardFtpPath() {
if (in_array(platformName(), array("FG", "FG+", "FG-")))
return build_file_path('', 'public', 'sdcard');
return build_file_path('', 'mountable_sdcard');
}
function sdcardBackupFtpPath() {
return build_file_path(sdcardFtpPath(), 'cpt-backups');
}
function backupBasePath() {
$rootPath = $_SERVER['DOCUMENT_ROOT'];
if (file_exists(build_file_path($rootPath, 'cpt_site_config.php')))
{
include_once(build_file_path($rootPath, 'cpt_site_config.php'))
return CptSiteConfig::$backupBasePath;
}
else
return build_file_path($rootPath, 'sdcard', 'cpt-backups');
}
function sedonaPath() {
$confFile = new DeviceConfigFile;
if ($confFile->load()) {
$path = $confFile->value("SVM Path", NULL);
if (!is_null($path))
return $path;
}
$rootPath = $_SERVER['DOCUMENT_ROOT'];
if (file_exists(build_file_path($rootPath, 'cpt_site_config.php')))
{
include_once(build_file_path($rootPath, 'cpt_site_config.php'))
return CptSiteConfig::$sedonaPath;
}
else
{
$sedonaPath = build_file_path('', 'mnt', 'sedona');
if (!file_exists($sedonaPath))
$sedonaPath = build_file_path('', 'mnt');
return $sedonaPath;
}
}
function imgPath() {
return build_file_path(cptBaseDir(), "img");
}
function dashboardPath() {
return build_file_path(cptBaseDir(), "dashboard");
}
function isDashboardExisted() {
return file_exists(dashboardPath());
}
function pluginsPath() {
return build_file_path(cptBaseDir(), "plugins");
}
function collectPlugins() {
$plugins = array();
$pluginsPath = pluginsPath();
if (file_exists($pluginsPath) && is_dir($pluginsPath)) {
$pathIterIter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pluginsPath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST);
$pathIterIter->setMaxDepth(0);
foreach($pathIterIter as $path) {
if (!$path->isDir())
continue;
$indexFile = NULL;
$label = NULL;
$enabled = true;
$isSupported = true;
$openNewPage = true;
$pluginManifestFile = build_file_path($path->getPathName(), "manifest.json");
if (file_exists($pluginManifestFile)) {
$manifest = json_decode(file_get_contents($pluginManifestFile), true);
if (is_array($manifest)) {
$indexFile = isset($manifest['indexFile']) ? $manifest['indexFile'] : NULL;
$utilityFile = isset($manifest['utilityFile']) ? $manifest['utilityFile'] : NULL;
$label = isset($manifest['label']) ? $manifest['label'] : NULL;
$enabled = isset($manifest['enabled']) ? $manifest['enabled'] : true;
$show = isset($manifest['show']) ? $manifest['show'] : true;
$openNewPage = isset($manifest['openNewPage']) ? $manifest['openNewPage'] : true;
if (isset($manifest['supportedPlatforms'])) {
$platformName = platformName();
$isSupported = in_array($platformName, $manifest['supportedPlatforms']);
}
}
}
if (!$enabled || !$isSupported)
continue;
if (empty($indexFile)) {
if (file_exists(build_file_path($path->getPathName(), "index.php")))
$indexFile = "index.php";
else if (file_exists(build_file_path($path->getPathName(), "index.html")))
$indexFile = "index.html";
else if (file_exists(build_file_path($path->getPathName(), "index.htm")))
$indexFile = "index.htm";
else
continue;
}
$baseName = $path->getBaseName();
$indexFilePath = "plugins/" . $baseName . '/' . $indexFile;
if (!empty($utilityFile))
$utilityFile = "plugins/" . $baseName . '/' . $utilityFile;
$plugins[] = array("name" => empty($label) ? $baseName : $label,
"openNewPage" => $openNewPage,
"show" => $show,
"indexFile" => $indexFilePath,
"utilityFile" => $utilityFile);
}
}
return $plugins;
}
function rmIfExists($dirPath) {
if (!is_dir($dirPath))
return;
// execCmd('rm -rf ' . $dirPath);
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirPath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) {
$path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname())
}
rmdir($dirPath);
}
function escapeJsonChars($val) {
return addcslashes($val, "\\\"\n\r");
}
function collectBackups($path, $type, $returnJson) {
$backups = array();
if (!file_exists($path))
return $backups;
$type = strtolower($type);
if ($handle = openDir($path)) {
while (false !== ($entry = readdir($handle))) {
if ($entry == "." || $entry == "..")
continue;
$fullPath = build_file_path($path, $entry);
$withNetworkConf = withNetworkConfBackup($fullPath);
$backupEntry = array("name" => $entry, "type" => $type,
"withNetworkConf" => $withNetworkConf,
"ts" => filemtime($fullPath));
if ($returnJson)
$backups[] = map2json($backupEntry);
else
$backups[] = $backupEntry;
}
closedir($handle);
}
return $backups;
}
function doListBackups($returnJson=true) {
$basePath = backupBasePath();
$backups = array();
//for old platforms
if (in_array(platformName(), array("FG+", "FG", "FG-")))
$backups = collectBackups($basePath, "sdcard", $returnJson);
else { // for newer platform check backups in flash and sdcard
$backups = collectBackups($basePath, "flash", $returnJson);
$sdBackupPath = sdcardBackupPath();
if (!is_null($sdBackupPath) && does_sdcard_exist())
$backups = array_merge($backups, collectBackups($sdBackupPath, 'sdcard', $returnJson));
}
return $backups;
}
function checkBackupError($backupDir)
{
rmIfExists($backupDir);
$freeSpace = disk_free_space($backupDir);
$minBackupSize = 4*1024*1024; //MB
if ($freeSpace < $minBackupSize)
return sprintf(L("failed to backup '%s', please make sure there is enough disk space."), 'graphics');
else
return sprintf(L("failed to backup '%s'."), 'graphics');
}
function doBackup($name, $cptBasePath=NULL, $backupHistoryDB=false, $type="sdcard", $dataOnly=false, $backupNetworkConf=false) {
if (in_array(platformName(), array("FG", "FG+", "FG-")) && !does_sdcard_exist())
return L("can not make backup when there is no sdcard.");
$type = strtolower($type);
if ($type == "flash" && in_array(platformName(), array("FG+", "FG", "FG-")))
return L("can not backup to flash.");
$backupPath = backupBasePath();
if ($type == "sdcard") {
$sdBackupPath = sdcardBackupPath();
if (!is_null($sdBackupPath))
$backupPath = $sdBackupPath;
}
$backupDir = build_file_path($backupPath, $name);
if (file_exists($backupDir))
return L("backup folder already exists, please choose a new folder.");
// make sure all things have been saved
sync();
if (!mkdir($backupDir, 0777, true))
return sprintf(L("failed to create backup folder '%s'."), $name);
//write backup manifest data
$manifest = array();
$manifest['version'] = '1.0';
$manifest['createdAt'] = date_create("now", new DateTimeZone("UTC"))->format("Y-m-d H:i:s");
$manifest['dataOnly'] = $dataOnly;
$manifest['networkConf'] = $backupNetworkConf;
file_put_contents(build_file_path($backupDir, 'manifest.json'), map2json($manifest));
//backup sedona files(app.sab & kits.scode)
$sedonaPath = sedonaPath();
if (!copy(build_file_path($sedonaPath, 'app.sab'),
build_file_path($backupDir, 'app.sab')))
{
rmIfExists($backupDir);
return sprintf(L("failed to backup '%s'."), 'app.sab');
}
if (!copy(build_file_path($sedonaPath, 'kits.scode'),
build_file_path($backupDir, 'kits.scode')))
{
rmIfExists($backupDir);
return sprintf(L("failed to backup '%s'."), 'kits.scode');
}
if (!copy(build_file_path($sedonaPath, 'cpt_session.xml'),
build_file_path($backupDir, 'cpt_session.xml')))
error_log("can not backup cpt_session.xml.");
//backup app files
if (empty($cptBasePath))
$cptBasePath = cptBaseDir();
$graphicDir = rtrim($cptBasePath, DIRECTORY_SEPARATOR);
if (is_dir($graphicDir))
{
if ($dataOnly)
{
$dataFiles = array();
$dataFiles[] = build_file_path($graphicDir, "app", "cpt-web.db");
$dataFiles[] = build_file_path($graphicDir, "app", "grdata");
$dataFiles[] = build_file_path($graphicDir, "app", "graphics", "assets", "imported");
$dataFiles[] = build_file_path($graphicDir, "dashboard", "uploads");
$dataFiles[] = build_file_path($graphicDir, "user_data");
foreach($dataFiles as $dataFile)
{
if (!file_exists($dataFile))
continue;
$dstPath = build_file_path($backupDir, 'cpt',
substr($dataFile, strlen($graphicDir)+1));
if (!recurseCopy($dataFile, $dstPath))
{
error_log("failed to backup " . $dataFile . " to " . $dstPath);
return checkBackupError($backupDir);
}
}
}
else
{
if (!recurseCopy($graphicDir, build_file_path($backupDir, 'cpt')))
return checkBackupError($backupDir);
}
runPluginBackupCallbacks($backupDir, $graphicDir);
if (!backupFirmwareCustomData($backupDir))
return L("failed to backup firmware data");
if ($backupHistoryDB)
{
$parentPath = dirname($graphicDir);
$historyDBPath = build_file_path($parentPath, "easyio.db");
if (file_exists($historyDBPath))
{
if (!copy($historyDBPath, build_file_path($backupDir, 'easyio.db')))
return sprintf(L("failed to backup '%s'."), 'easyio.db');
}
else
error_log("can not find history db file at " . $historyDBPath);
// return sprintf(L("can not find history db file '%s'."), 'easyio.db');
}
}
if ($backupNetworkConf)
{
$networkConfs = array('/etc/config/wireless', '/etc/config/network', '/etc/config/dhcp', '/etc/config/samba', '/mnt/fw.config', '/etc/wpa_supplicant/wpa_supplicant_wired.conf');
foreach($networkConfs as $conf) {
if (file_exists($conf)) {
$dstPath = get_absolute_path(build_file_path($backupDir, 'root', $conf));
if (!recurseCopy($conf, $dstPath))
return sprintf(L("failed to backup network config file: '%s'."), $conf);
} else {
error_log("can not find config file: " . $conf);
}
}
}
error_log("backup " . $name . " done");
sync();
}
function isDataOnlyBackup($backupDir) {
if (!function_exists("json_decode"))
return false;
$filePath = build_file_path($backupDir, 'manifest.json');
if (file_exists($filePath)) {
$manifest = json_decode(file_get_contents($filePath), true);
if (!is_null($manifest) && isset($manifest['dataOnly']))
return $manifest['dataOnly'];
}
return !file_exists(build_file_path($backupDir, 'cpt', 'js'));
}
function withNetworkConfBackup($backupDir) {
if (!function_exists("json_decode"))
return false;
$filePath = build_file_path($backupDir, 'manifest.json');
if (file_exists($filePath)) {
$manifest = json_decode(file_get_contents($filePath), true);
if (!is_null($manifest) && isset($manifest['networkConf']))
return $manifest['networkConf'];
}
return false;
}
function doRestore($name, $cptBasePath=NULL, $withHistoryDB=true, $type="sdcard", $withNetworkConf=false) {
if (in_array(platformName(), array("FG", "FG+", "FG-")) && !does_sdcard_exist())
return L("can not restore backup when there is no sdcard.");
$type = strtolower($type);
if ($type == "sdcard") {
if (!does_sdcard_exist())
return L("no sdcard available");
$sdBackupPath = sdcardBackupPath();
if (!file_exists($sdBackupPath)) {
error_log("can not find sdcard mount path: " . $sdBackupPath);
return L("can not find sdcard path");
}
$backupPath = $sdBackupPath;
} else
$backupPath = backupBasePath();
$backupDir = build_file_path($backupPath, $name);
if (!file_exists($backupDir))
return sprintf(L("backup folder(%s) does not exist."), $backupDir);
// make sure all things have been saved
sync();
$sedonaAppRestored = false;
$sedonaPath = sedonaPath();
$appPathInBackup = build_file_path($backupDir, 'app.sab');
$kitsPathInBackup = build_file_path($backupDir, 'kits.scode');
if (file_exists($appPathInBackup) && file_exists($kitsPathInBackup))
{
if (!copy($appPathInBackup,
build_file_path($sedonaPath, 'app.sab.writing')))
return sprintf(L("failed to restore '%s'."), 'app.sab');
if (!copy($kitsPathInBackup,
build_file_path($sedonaPath, 'kits.scode.writing')))
return sprintf(L("failed to restore '%s'."), 'kits.scode');
error_log("copied app.sab and kits.scode");
if (!rename(build_file_path($sedonaPath, 'app.sab.writing'),
build_file_path($sedonaPath, 'app.sab.stage'))
|| !rename(build_file_path($sedonaPath, 'kits.scode.writing'),
build_file_path($sedonaPath, 'kits.scode.stage')))
return sprintf(L("failed to rename '%s' to '%s'."), 'writing', 'stage');
$sedonaAppRestored = true;
}
else
error_log("can not find sedona app in backup folder, skip it");
$cpt_session_file = build_file_path($backupDir, 'cpt_session.xml');
if (file_exists($cpt_session_file))
copy($cpt_session_file,
build_file_path($sedonaPath, 'cpt_session.xml'));
if (empty($cptBasePath))
$cptBasePath = cptBaseDir();
$graphicDir = rtrim($cptBasePath, DIRECTORY_SEPARATOR);
$parts = explode(DIRECTORY_SEPARATOR, $graphicDir);
array_pop($parts);
$cptParentDir = implode(DIRECTORY_SEPARATOR, $parts);
$dstPath = null;
$dataOnly = isDataOnlyBackup($backupDir);
if ($dataOnly)
{
$dstPath = build_file_path($cptParentDir, 'cpt');
if (!file_exists($dstPath))
return L("failed to restore backup: 'cpt' folder missing.");
}
else
{
$dstPath = build_file_path($cptParentDir, 'cpt-writing');
rmIfExists($dstPath);
}
$cptFolderInBackup = build_file_path($backupDir, 'cpt');
if (is_dir($cptFolderInBackup))
{
if (!recurseCopy($cptFolderInBackup, $dstPath))
return L("failed to restore graphics, please make sure there is enough free disk space.");
error_log("cpt folder copied ");
if (!$dataOnly)
{
rmIfExists(build_file_path($cptParentDir, 'cpt-old'));
if (is_dir($graphicDir) && !rename($graphicDir, build_file_path($cptParentDir, 'cpt-old')))
return sprintf(L("failed to rename %s to %s."), 'cpt', 'cpt-old');
if (!rename($dstPath, $graphicDir))
return sprintf(L("failed to rename %s to %s."), 'cpt.writing', 'cpt');
}
}
else
error_log("can not find 'cpt' folder in this backup, skip it");
runPluginRestoreCallbacks($graphicDir);
if (!restoreFirmwareCustomData($backupDir))
return L("failed to restore firmware data");
if ($withHistoryDB)
{
$historyDBPath = build_file_path($backupDir, 'easyio.db');
if (file_exists($historyDBPath))
{
$origHistoryDBPath = build_file_path($cptParentDir, 'easyio.db');
if (file_exists($origHistoryDBPath))
if (!rename($origHistoryDBPath, build_file_path($cptParentDir, 'easyio.db.old')))
return L("failed to rename old history db.");
if (!copy($historyDBPath, $origHistoryDBPath))
return sprintf(L("failed to restore '%s'."), 'easyio.db');
}
}
if ($withNetworkConf)
{
//call external handler app to do customized restore process
$postRestoreHandler = "/mnt/sedona/post_restore_handler";
if (file_exists($postRestoreHandler)) {
$backupConfigRootDir = build_file_path($backupDir, 'root');
$output = rtrim(`( $postRestoreHandler $backupConfigRootDir 2>&1 && echo OK ) || echo ERROR`);
if (!endsWith($output, 'OK'))
error_log("failed to execute post restore handler");
} else {
error_log("can not find post restore handler at: " . $postRestoreHandler);
}
// //merge fw.config file first
// $fw_config = "/mnt/fw.config";
// $new_fw_config = get_absolute_path(build_file_path($backupDir, 'root', $fw_config));
// if (file_exists($fw_config) && file_exists($new_fw_config))
// mergeFWConfig($fw_config, $new_fw_config);
//
// $networkConfs = array('/etc/config/wireless', '/etc/config/network', '/etc/config/dhcp', '/etc/config/samba');
// foreach($networkConfs as $conf)
// {
// $confPath = get_absolute_path(build_file_path($backupDir, 'root', $conf));
// if (file_exists($confPath) && startsWith($confPath, $backupDir))
// if (!recurseCopy($confPath, $conf))
// return sprintf(L("failed to restore config file: '%s'."), $conf);
// }
}
error_log("restored to " . $name);
sync();
if ($withNetworkConf)
doReboot(true);
else if ($sedonaAppRestored)
restartSvm();
}
function loadFWConfig($config_path) {
$lines = explode("\n", file_get_contents($config_path));
$config = array();
foreach($lines as $line) {
if (strlen($line) == 0)
continue;
$parts = explode(":", $line, 2);
if (count($parts) != 2)
continue;
$config[$parts[0]] = $parts[1];
}
return $config;
}
function mergeFWConfig($fw_config_old, $fw_config_new) {
$old_config = loadFWConfig($fw_config_old);
$new_config = loadFWConfig($fw_config_new);
//we need to keep ReleaseDate, SvmVersion, McuVersion old configs, so we
//ignore these in new config
unset($new_config['ReleaseDate']);
unset($new_config['SvmVersion']);
unset($new_config['McuVersion']);
$result = array();
$merged_config = array_merge($old_config, $new_config);
foreach($merged_config as $key => $value) {
array_push($result, $key . ":" . $value);
}
file_put_contents($fw_config_old, implode("\n", $result));
}
function doCompressBackup($name, $type) {
$type = strtolower($type);
if ($type == "sdcard") {
if (!does_sdcard_exist())
return L("no sdcard available");
$sdBackupPath = sdcardBackupPath();
if (!file_exists($sdBackupPath)) {
error_log("can not find sdcard mount path: " . $sdBackupPath);
return L("can not find sdcard path");
}
$backupPath = $sdBackupPath;
} else
$backupPath = backupBasePath();
$backupDir = build_file_path($backupPath, $name);
if (!file_exists($backupDir))
return; // just return when backup folder is missing
//tar -C /www/public/sdcard/cpt-backups -czvf /tmp/foo.tgz 20170914_backup
$platName = platformName();
$tarFilePath = "/tmp/{$platName}-{$name}.tgz";
//tar: tar -cf - t2 | gzip -c > test.tgz
$cmd = "tar -C {$backupPath} -cf - " . escapeshellarg($name) . " | gzip -c > " . escapeshellarg($tarFilePath);
if(!execShellCmd($cmd)) {
error_log("failed to build backup tgz");
return;
}
return $tarFilePath;
}
function isUpgradeFix($backupDir) {
if (!function_exists("json_decode"))
return false;
$filePath = build_file_path($backupDir, 'manifest.json');
if (file_exists($filePath)) {
$manifest = json_decode(file_get_contents($filePath), true);
if (!is_null($manifest) && isset($manifest['dataOnly']) && isset($manifest['upgradeFix']))
return $manifest['dataOnly'] && $manifest['upgradeFix'];
}
return false;
}
function doHandleUploadBackup($tempName, $tarBallName, $size, $type, $restoreNow, $withNetworkConf, &$response) {
$type = strtolower($type);
if ($type == "sdcard") {
if (!does_sdcard_exist())
return L("no sdcard available");
$sdBackupPath = sdcardBackupPath();
if (!file_exists($sdBackupPath)) {
error_log("can not find sdcard mount path: " . $sdBackupPath);
return L("can not find sdcard path");
}
$backupPath = $sdBackupPath;
} else
$backupPath = backupBasePath();
if (!file_exists($backupPath)) {
if (!mkdir($backupPath, 0777, true)) {
error_log("can not create backup folder: " . $backupPath);
return L("can not create backup folder");
}
}
$freeSpace = disk_free_space($backupPath);
$compressRatio = 5;
$size = (int)$size;
if ($freeSpace <= $size*$compressRatio) {
error_log("not enough disk free space({$freeSpace} bytes left)");
return L("not enough disk free space({$freeSpace} bytes left)");
}
$ext = pathinfo($tarBallName, PATHINFO_EXTENSION);
$name = basename($tarBallName, ".$ext");
if (!is_uploaded_file($tempName)) {
error_log("uploaded file {$name} verfication failed.");
return L("uploaded file {$name} verfication failed.");
}
$cmd = null;
if ($ext == "tgz")
$cmd = "gunzip -c {$tempName} | tar -C {$backupPath} -xf -";
elseif ($ext == "zip")
$cmd = "unzip -o -d {$backupPath} {$tempName}";
else {
error_log("invalid backup tarball format: $ext");
return L("invalid backup tarball format: $ext");
}
if (!execShellCmd($cmd)) {
error_log("failed to uncompress backup tarball");
return L("failed to uncompress backup tarball");
}
//check if this is a upgrade tarball, if yes, apply it now and clean it up
$output = null;
if ($ext == "tgz")
$output = shell_exec("gunzip -c {$tempName} | tar -tf -");
elseif ($ext == "zip")
$output = shell_exec("unzip -l {$tempName} | awk 'NR == 4 {print $NF}'");
if (!empty($output) && sizeof($output) > 0) {
$output = explode("\n", $output);
$backupName = rtrim($output[0], DIRECTORY_SEPARATOR);
$backupDir = build_file_path($backupPath, $backupName);
$isUpgrade = isUpgradeFix($backupDir);
if ($isUpgrade) {
error_log("Found upgrade backup {$backupName}, apply this ugprade ...");
$error = doRestore($backupName, NULL, false, $type, $withNetworkConf);
error_log("Delete upgrade backup folder {$backupName}");
rmIfExists($backupDir);
if (!empty($error)) {
error_log("Failed to apply upgrade: {$error}");
return L("failed to apply upgrade: {$error}");
}
else {
if (isset($response)) {
$response['msg'] = L("Success to apply upgrade {$backupName}.");
$response['reloadRequired'] = true;
}
error_log("Success to apply upgrade {$backupName}.");
}
} else if ($restoreNow) {
$error = doRestore($backupName, NULL, true, $type, $withNetworkConf);
if (!empty($error)) {
error_log("Failed to restore backup: {$error}");
return L("failed to restore backup: {$error}");
}
else {
if (isset($response)) {
$response['msg'] = L("Success to restore to backup {$backupName}.");
$response['reloadRequired'] = true;
}
error_log("Success to restore to backup {$backupName}.");
}
}
}
return '';
}
function doDeleteBackup($name, $type) {
$type = strtolower($type);
if ($type == "sdcard") {
if (!does_sdcard_exist())
return L("no sdcard available");
$sdBackupPath = sdcardBackupPath();
if (!file_exists($sdBackupPath)) {
error_log("can not find sdcard mount path: " . $sdBackupPath);
return L("can not find sdcard path");
}
$backupPath = $sdBackupPath;
} else
$backupPath = backupBasePath();
$backupDir = build_file_path($backupPath, $name);
if (!file_exists($backupDir))
return; // just return when backup folder is missing
// return "backup folder(" . $backupDir . ") does not exist.";
//security check
if (!startsWith(realpath($backupDir), $backupPath))
return L("invalid backup folder.");
rmIfExists($backupDir);
error_log("backup " . $name . " is deleted");
sync();
}
function doRenameBackup($old_name, $new_name, $type) {
$type = strtolower($type);
if ($type == "sdcard") {
if (!does_sdcard_exist())
return L("no sdcard available");
$sdBackupPath = sdcardBackupPath();
if (!file_exists($sdBackupPath)) {
error_log("can not find sdcard mount path: " . $sdBackupPath);
return L("can not find sdcard path");
}
$backupPath = $sdBackupPath;
}
else
$backupPath = backupBasePath();
$oldBackupDir = build_file_path($backupPath, $old_name);
if (!file_exists($oldBackupDir))
return L("invalid backup folder.");
$newBackupDir = build_file_path($backupPath, $new_name);
if (file_exists($newBackupDir))
return sprintf(L("rename failed. '%s' already exists."), $new_name);
//security check
if (!startsWith(realpath($oldBackupDir), $backupPath)
|| !startsWith($newBackupDir, $backupPath))
return L("invalid backup folder.");
if (!rename($oldBackupDir, $newBackupDir))
return sprintf(L("can not rename backup from '%s' to '%s'"), $old_name, $new_name);
error_log("backup '$old_name' is renamed to '$new_name'");
sync();
}
function doReboot($async=false) {
sync();
if ($async)
//FW doesn't support sleep less than 1 second
shell_exec('(sleep 1 && reboot >/dev/null 2>&1 ) &');
else
execCmd('reboot');
}
function recurseCopy($src, $dst) {
if (is_file($src)) {
$dst_dir = dirname($dst);
if (!file_exists($dst_dir))
mkdir($dst_dir, 0777, true);
return copy($src, $dst);
}
if (!file_exists($dst))
mkdir($dst, 0777, true);
$dir = opendir($src);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir(build_file_path($src, $file)) ) {
if (!recurseCopy(build_file_path($src, $file), build_file_path($dst, $file))) {
closedir($dir);
return false;
}
}
else {
if (!copy(build_file_path($src, $file), build_file_path($dst, $file))) {
closedir($dir);
return false;
}
}
}
}
closedir($dir);
return true;
}
function execCmd($cmd) {
exec(escapeshellcmd($cmd))
}
function execShellCmd($cmd) {
//the input cmd is not escaped yet, it's the caller's responsibility to escape it
$output = shell_exec("( $cmd ) && echo 'SUCCESS'");
return !(is_null($output) || preg_match("/SUCCESS\s*$/", $output) != 1);
}
function cleanupGhostScripts() {
$docRootPath = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR);
$ghostScriptsPath = build_file_path($docRootPath, 'ghost_scripts');
rmIfExists($ghostScriptsPath);
}
function restartSvm() {
$pfName = platformName();
if ($pfName == "FW") {
include_once "UDPClient.class.php";
//restart svm by sedona action
$client = new UDPClient("127.0.0.1", "1001");
$client->setDebug(false);
$client->invokeAction("/app/objects/.restart", "void", "");
}
else {
//reboot command was added since FG+(from cheah)
//for FG and FG-, use the old way, otherwise use reboot command
if ($pfName == "FG" || $pfName == "FG-")
execCmd("killall FGBase svm.exe");
else
doReboot(true);
//execCmd("/sbin/reboot");
}
}
// echo arrayMapToString(array('a' => 1, 'b' =>2, 'c' => 100), ",");
function firmwareUpgradePath() {
$name = platformName();
if ($name == "FS")
return build_file_path('', 'media', 'boot', 'fs');
else if ($name == "FW")
return build_file_path('', 'tmp');
else {
$rootPath = $_SERVER['DOCUMENT_ROOT'];
if (file_exists(build_file_path($rootPath, 'cpt_site_config.php')))
{
include_once(build_file_path($rootPath, 'cpt_site_config.php'))
return CptSiteConfig::$firmwareUpgradePath;
}
else
{
if ($name == "FG+" || $name == "FG")
return build_file_path('', 'sdcard', 'fg320');
else
{
error_log("firmware upgrade is not supported on this platform: " . $name);
return null;
}
}
}
}
function firmwareFileName() {
// FS32: fs_rom.xz
// FG32: fg320.tar.gz
// FG32+: fg320plus.md5, rootfs.yaffs2, u-boot.bin, zImage (not supported)
$name = platformName();
if ($name == "FS")
return "fs_rom.xz";
else if ($name == "FG")
return "fg320.tar.gz";
else if ($name == "FW")
return "fw140.tar.gz";
else
return "";
}
function does_sdcard_exist() {
$sdcardPath = sdcardMountPath();
if (is_null($sdcardPath)) {
$filePath = realpath("/sdcard/No SD Card");
if (file_exists($filePath))
return false;
else
return true;
} else {
return (file_exists($sdcardPath) && !file_exists(rtrim($sdcardPath, '/') . "/No SD Card"));
}
}
function isPlatformNewerThan($dt_str) {
if (is_string($dt_str))
$dt = date_create_from_format("Y-m-d H:i:s", $dt_str);
else {
if ($dt_str instanceof DateTime)
$dt = $dt_str;
else
throw new Exception("invalid datetime parameter");
}
$plat_dt = platformReleaseDate();
return $plat_dt >= $dt;
}
function platformReleaseDate() {
$plat_dt = NULL;
$confFile = new DeviceConfigFile;
if ($confFile->load()) {
$plat_dt = $confFile->value("ReleaseDate", NULL);
if (!is_null($plat_dt))
$plat_dt = date_create_from_format("Y-m-d H:i:s", $plat_dt);
}
return $plat_dt;
}
function platformName() {
//first check /mnt/sedona/easyio.conf file
$confFile = new DeviceConfigFile;
if ($confFile->load()) {
$name = $confFile->value("Model", NULL);
if (!is_null($name))
return strtoupper($name);
}
// if can not find easyio.conf, use legacy hacky way
if (file_exists("/mnt/fw.config"))
return "FW";
$matches = array();
$fg_linux_ver = '2.6.29.2';
$fs_linux_ver = '3.4';
$versionStr = file_get_contents("/proc/version");
if (!preg_match('/linux version ([0-9.]+)/i', $versionStr, $matches))
return "InvalidPlatform";
else {
if (count($matches) < 2 || !isset($matches[1]))
return "InvalidPlatform";
else {
$result = strcmp($matches[1], $fg_linux_ver);
if ($result > 0) {
$result2 = strcmp($matches[1], $fs_linux_ver);
if ($result2 >= 0)
return "FS";
else
return "FG+"; # platform released after FG
}
else if ($result == 0)
return "FG"; # FG platform
else
return "FG-"; # platform released before FG
}
}
}
function file_force_contents($filename, $data, $flags = 0){
if(!is_dir(dirname($filename)))
mkdir(dirname($filename).DIRECTORY_SEPARATOR, 0777, true);
return file_put_contents($filename, $data, $flags);
}
function setupIndex($docRootPath, $cptBasePath, $graphicRoot=true) {
if (empty($docRootPath))
$docRootPath = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR);
if (empty($cptBasePath))
$cptBasePath = cptBaseDir();
$indexPath = join(DIRECTORY_SEPARATOR, array($docRootPath, 'index.html'));
$indexLegacyPath = join(DIRECTORY_SEPARATOR, array($docRootPath, 'index_legacy.html'));
if ($graphicRoot) {
$graphicIndexPath = join(DIRECTORY_SEPARATOR, array($cptBasePath, 'index.html'));
if (!file_exists($indexLegacyPath) && file_exists($indexPath))
copy($indexPath, $indexLegacyPath);
copy($graphicIndexPath, $indexPath);
}
else {
if (file_exists($indexLegacyPath))
copy($indexLegacyPath, $indexPath);
}
}
function isAssoc($array) {
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
function list2json($listData) {
$json = array();
foreach($listData as $item) {
if (is_string($item))
$item = addcslashes($item,"\\\"\n\r");
else if (is_array($item)) {
if (isAssoc($item))
$item = map2json($item);
else
$item = list2json($item);
$json[] = $item;
continue;
}
$json[] = '"' . $item . '"';
}
return '[' . implode(',', $json) . ']';
}
function map2json($mapData) {
if (function_exists("json_encode"))
return json_encode($mapData);
$json = array();
foreach($mapData as $k => $v) {
if (is_string($k))
$k = addcslashes($k,"\\\"\n\r");
if (is_string($v))
$v = addcslashes($v,"\\\"\n\r");
else if (is_bool($v)) {
$v = $v ? 'true' : 'false';
$json[] = "\"$k\": $v";
continue;
}
else if (is_array($v)) {
if (isAssoc($v))
$v = map2json($v);
else
$v = list2json($v);
$json[] = "\"$k\": $v";
continue;
}
$json[] = "\"$k\": \"$v\"";
}
return '{' . implode(',', $json) . '}';
}
function cptToolsPath() {
$rootPath = $_SERVER['DOCUMENT_ROOT'];
return build_file_path($rootPath, 'sdcard', 'CPT-Tools.zip');
}
function updatePhpAdminAuth($salt, $checksum) {
$root_path = parentPath(3);
$file_path = build_file_path($root_path, 'phpliteadmin.config.php');
$cpt_auth_content = <<<EOS
<?php
\$cpt_password_salt = "$salt";
\$cpt_password_checksum = "$checksum";
?>
EOS;
file_force_contents($file_path, $cpt_auth_content);
}
function readfile_chunked($filename, $retbytes=true) {
$chunksize = 1*(32*1024); // how many bytes per chunk
$buffer = '';
$cnt =0;
$handle = fopen($filename, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
function getDeviceData() {
$data = array();
//populate device config data
$confFile = new DeviceConfigFile;
if ($confFile->load()) {
foreach($confFile->keys() as $key) {
$value = $confFile->value($key, NULL);
if (is_null($value))
continue;
$key = '_' . str_replace(" ", "_", trim(strtolower($key)));
$data[$key] = $value;
}
}
//add calculated device data
$data["platform_name"] = platformName();
$data["sdcard_exists"] = does_sdcard_exist();
if ($data["sdcard_exists"]) {
$sdcardPath = sdcardMountPath();
if (is_null($sdcardPath)) // then is the case of FG or FG+
$sdcardPath = "/sdcard"; //sdcard is mounted at /sdcard for FG or FG+
$data["sdcard_free_space"] = disk_free_space($sdcardPath);
$data["sdcard_backup_ftp_path"] = sdcardBackupFtpPath();
$data["sdcard_ftp_path"] = sdcardFtpPath();
}
$data["flash_free_space"] = disk_free_space("/");
return $data;
}
function getPlatformConfig() {
$config = array();
//first, read easyio.config file into $config hash
$conf_file_path = "/mnt/sedona/easyio.config";
if (!file_exists($conf_file_path)) {
error_log("can not find " . $conf_file_path);
return $config;
}
$contents = file_get_contents($conf_file_path);
foreach(explode(PHP_EOL, $contents) as $line) {
if (empty($line))
continue;
$parts = explode(":", $line, 2);
if (count($parts) != 2) {
error_log("invalid config line: " . $line);
continue;
}
$config[$parts[0]] = $parts[1];
}
if (empty($config))
error_log("can not read content from config file: " . $conf_file_path);
return $config;
}
function savePlatformConfig($config) {
$lines = array();
foreach($config as $key => $value)
$lines[] = $key . ':' . $value;
$conf_file_path = "/mnt/sedona/easyio.config";
file_put_contents($conf_file_path, implode(PHP_EOL, $lines));
}
$netmaskList = array(
"0.0.0.0", "128.0.0.0", "192.0.0.0", "224.0.0.0",
"240.0.0.0", "248.0.0.0", "252.0.0.0", "254.0.0.0",
"255.0.0.0", "255.128.0.0", "255.192.0.0", "255.224.0.0",
"255.240.0.0", "255.248.0.0", "255.252.0.0", "255.254.0.0",
"255.255.0.0", "255.255.128.0", "255.255.192.0", "255.255.224.0",
"255.255.240.0", "255.255.248.0", "255.255.252.0", "255.255.254.0",
"255.255.255.0", "255.255.255.128", "255.255.255.192", "255.255.255.224",
"255.255.255.240", "255.255.255.248", "255.255.255.252", "255.255.255.254",
);
function cdir2MaskIP($cdir) {
global $netmaskList;
$index = intval($cdir);
if ($index >= 0 && $index < count($netmaskList))
return $netmaskList[$index];
else
return null;
}
function maskIP2CDIR($netmask) {
global $netmaskList;
return array_search($netmask, $netmaskList);
}
function render_template($path, array $args){
ob_start();
include($path);
$var=ob_get_contents();
ob_end_clean();
return $var;
}
function runPluginBackupCallbacks($backupDir, $graphicDir) {
error_log("run plugin backup callback");
$pluginsBackupDir = build_file_path($backupDir, "cpt", "plugins");
if (!file_exists($pluginsBackupDir))
mkdir($pluginsBackupDir, 0777);
$plugins = collectPlugins();
foreach($plugins as $plugin) {
if (!is_array($plugin) || !isset($plugin['utilityFile']))
continue;
$utilityFilePath = build_file_path($graphicDir, $plugin['utilityFile']);
if (!file_exists($utilityFilePath))
continue;
$utilityInstance = include $utilityFilePath;
if (is_null($utilityInstance))
continue;
if (method_exists($utilityInstance, "backup"))
$utilityInstance->backup($pluginsBackupDir);
}
}
function runPluginRestoreCallbacks($graphicDir) {
error_log("run plugin restore callback");
$plugins = collectPlugins();
foreach($plugins as $plugin) {
if (!is_array($plugin) || !isset($plugin['utilityFile']))
continue;
$utilityFilePath = build_file_path($graphicDir, $plugin['utilityFile']);
if (!file_exists($utilityFilePath))
continue;
$utilityInstance = include $utilityFilePath;
if (is_null($utilityInstance))
continue;
if (method_exists($utilityInstance, "restore"))
$utilityInstance->restore();
}
}
function backupFirmwareCustomData($backupDir) {
$fwCustomDataDir = "/mnt/data";
if (file_exists($fwCustomDataDir))
{
$tarFilePath = build_file_path($backupDir, "firmware_data.tar");
$output = shell_exec("tar -C /mnt/data -cf $tarFilePath . && echo 'SUCCESS'");
if (is_null($output) || preg_match("/SUCCESS\s*$/", $output) != 1) {
error_log("failed to backup " . $fwCustomDataDir . " to " . $tarFilePath);
return false;
}
}
return true;
}
function restoreFirmwareCustomData($backupDir) {
$fwCustomDataBackupTarFile = build_file_path($backupDir, "firmware_data.tar");
if (file_exists($fwCustomDataBackupTarFile))
{
$fwCustomDataDir = "/mnt/data";
if (!file_exists($fwCustomDataDir))
mkdir($fwCustomDataDir, 0644, TRUE);
$output = shell_exec("tar -C /mnt/data -xf $fwCustomDataBackupTarFile && echo 'SUCCESS'");
if (is_null($output) || preg_match("/SUCCESS\s*$/", $output) != 1) {
error_log("failed to restore " . $fwCustomDataBackupTarFile . " to " . $fwCustomDataDir);
return false;
}
}
return true;
}
function clientIP() {
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
return $ip;
}
?>