2019-09-24 09:33:21 +00:00
'use strict' ;
'require form' ;
'require rpc' ;
2019-10-02 17:53:17 +00:00
'require fs' ;
2019-11-03 20:54:40 +00:00
'require ui' ;
2019-09-24 09:33:21 +00:00
2019-10-02 17:53:17 +00:00
var callSystemValidateFirmwareImage = rpc . declare ( {
2019-09-25 14:51:37 +00:00
object : 'system' ,
method : 'validate_firmware_image' ,
params : [ 'path' ] ,
expect : { '' : { valid : false , forcable : true } }
} ) ;
2019-09-24 09:33:21 +00:00
function findStorageSize ( procmtd , procpart ) {
var kernsize = 0 , rootsize = 0 , wholesize = 0 ;
procmtd . split ( /\n/ ) . forEach ( function ( ln ) {
2019-09-25 14:23:02 +00:00
var match = ln . match ( /^mtd\d+: ([0-9a-f]+) [0-9a-f]+ "(.+)"$/ ) ,
size = match ? parseInt ( match [ 1 ] , 16 ) : 0 ;
2019-09-24 09:33:21 +00:00
switch ( match ? match [ 2 ] : '' ) {
case 'linux' :
case 'firmware' :
2019-09-25 14:23:02 +00:00
if ( size > wholesize )
wholesize = size ;
2019-09-24 09:33:21 +00:00
break ;
case 'kernel' :
case 'kernel0' :
2019-09-25 14:23:02 +00:00
kernsize = size ;
2019-09-24 09:33:21 +00:00
break ;
case 'rootfs' :
case 'rootfs0' :
case 'ubi' :
case 'ubi0' :
2019-09-25 14:23:02 +00:00
rootsize = size ;
2019-09-24 09:33:21 +00:00
break ;
}
} ) ;
if ( wholesize > 0 )
return wholesize ;
else if ( kernsize > 0 && rootsize > kernsize )
return kernsize + rootsize ;
procpart . split ( /\n/ ) . forEach ( function ( ln ) {
var match = ln . match ( /^\s*\d+\s+\d+\s+(\d+)\s+(\S+)$/ ) ;
if ( match ) {
var size = parseInt ( match [ 1 ] , 10 ) ;
if ( ! match [ 2 ] . match ( /\d/ ) && size > 2048 && wholesize == 0 )
wholesize = size * 1024 ;
}
} ) ;
return wholesize ;
}
var mapdata = { actions : { } , config : { } } ;
return L . view . extend ( {
load : function ( ) {
var tasks = [
2019-10-02 17:53:17 +00:00
L . resolveDefault ( fs . stat ( '/lib/upgrade/platform.sh' ) , { } ) ,
fs . trimmed ( '/proc/sys/kernel/hostname' ) ,
fs . trimmed ( '/proc/mtd' ) ,
2019-09-25 01:02:59 +00:00
fs . trimmed ( '/proc/partitions' ) ,
fs . trimmed ( '/proc/mounts' )
2019-09-24 09:33:21 +00:00
] ;
return Promise . all ( tasks ) ;
} ,
handleBackup : function ( ev ) {
var form = E ( 'form' , {
method : 'post' ,
action : '/cgi-bin/cgi-backup' ,
enctype : 'application/x-www-form-urlencoded'
} , E ( 'input' , { type : 'hidden' , name : 'sessionid' , value : rpc . getSessionID ( ) } ) ) ;
ev . currentTarget . parentNode . appendChild ( form ) ;
form . submit ( ) ;
form . parentNode . removeChild ( form ) ;
} ,
2019-09-25 17:37:27 +00:00
handleFirstboot : function ( ev ) {
2019-09-24 09:33:21 +00:00
if ( ! confirm ( _ ( 'Do you really want to erase all settings?' ) ) )
return ;
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Erasing...' ) , [
2019-11-01 11:42:48 +00:00
E ( 'p' , { 'class' : 'spinning' } , _ ( 'The system is erasing the configuration partition now and will reboot itself when finished.' ) )
] ) ;
2019-09-24 09:33:21 +00:00
2019-11-01 11:42:48 +00:00
/* Currently the sysupgrade rpc call will not return, hence no promise handling */
fs . exec ( '/sbin/firstboot' , [ '-r' , '-y' ] ) ;
2019-09-24 09:33:21 +00:00
2019-11-03 20:54:40 +00:00
ui . awaitReconnect ( '192.168.1.1' , 'openwrt.lan' ) ;
2019-09-24 09:33:21 +00:00
} ,
handleRestore : function ( ev ) {
2019-11-03 20:54:40 +00:00
return ui . uploadFile ( '/tmp/backup.tar.gz' , ev . target )
2019-09-24 09:33:21 +00:00
. then ( L . bind ( function ( btn , res ) {
btn . firstChild . data = _ ( 'Checking archive…' ) ;
2019-10-02 17:53:17 +00:00
return fs . exec ( '/bin/tar' , [ '-tzf' , '/tmp/backup.tar.gz' ] ) ;
2019-09-24 09:33:21 +00:00
} , this , ev . target ) )
. then ( L . bind ( function ( btn , res ) {
if ( res . code != 0 ) {
2019-11-03 20:54:40 +00:00
ui . addNotification ( null , E ( 'p' , _ ( 'The uploaded backup archive is not readable' ) ) ) ;
2019-10-02 17:53:17 +00:00
return fs . remove ( '/tmp/backup.tar.gz' ) ;
2019-09-24 09:33:21 +00:00
}
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Apply backup?' ) , [
2019-09-24 09:33:21 +00:00
E ( 'p' , _ ( 'The uploaded backup archive appears to be valid and contains the files listed below. Press "Continue" to restore the backup and reboot, or "Cancel" to abort the operation.' ) ) ,
E ( 'pre' , { } , [ res . stdout ] ) ,
E ( 'div' , { 'class' : 'right' } , [
E ( 'button' , {
'class' : 'btn' ,
2019-11-03 20:54:40 +00:00
'click' : ui . createHandlerFn ( this , function ( ev ) {
return fs . remove ( '/tmp/backup.tar.gz' ) . finally ( ui . hideModal ) ;
2019-09-24 09:33:21 +00:00
} )
} , [ _ ( 'Cancel' ) ] ) , ' ' ,
E ( 'button' , {
'class' : 'btn cbi-button-action important' ,
2019-11-03 20:54:40 +00:00
'click' : ui . createHandlerFn ( this , 'handleRestoreConfirm' , btn )
2019-09-24 09:33:21 +00:00
} , [ _ ( 'Continue' ) ] )
] )
] ) ;
} , this , ev . target ) )
2019-11-03 20:54:40 +00:00
. catch ( function ( e ) { ui . addNotification ( null , E ( 'p' , e . message ) ) } )
2019-09-24 09:33:21 +00:00
. finally ( L . bind ( function ( btn , input ) {
btn . firstChild . data = _ ( 'Upload archive...' ) ;
} , this , ev . target ) ) ;
} ,
handleRestoreConfirm : function ( btn , ev ) {
2019-10-02 17:53:17 +00:00
return fs . exec ( '/sbin/sysupgrade' , [ '--restore-backup' , '/tmp/backup.tar.gz' ] )
2019-09-24 09:33:21 +00:00
. then ( L . bind ( function ( btn , res ) {
if ( res . code != 0 ) {
2019-11-03 20:54:40 +00:00
ui . addNotification ( null , [
2019-09-24 09:33:21 +00:00
E ( 'p' , _ ( 'The restore command failed with code %d' ) . format ( res . code ) ) ,
res . stderr ? E ( 'pre' , { } , [ res . stderr ] ) : ''
] ) ;
L . raise ( 'Error' , 'Unpack failed' ) ;
}
btn . firstChild . data = _ ( 'Rebooting…' ) ;
2019-10-02 17:53:17 +00:00
return fs . exec ( '/sbin/reboot' ) ;
2019-09-24 09:33:21 +00:00
} , this , ev . target ) )
. then ( L . bind ( function ( res ) {
if ( res . code != 0 ) {
2019-11-03 20:54:40 +00:00
ui . addNotification ( null , E ( 'p' , _ ( 'The reboot command failed with code %d' ) . format ( res . code ) ) ) ;
2019-09-24 09:33:21 +00:00
L . raise ( 'Error' , 'Reboot failed' ) ;
}
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Rebooting…' ) , [
2019-09-24 09:33:21 +00:00
E ( 'p' , { 'class' : 'spinning' } , _ ( 'The system is rebooting now. If the restored configuration changed the current LAN IP address, you might need to reconnect manually.' ) )
] ) ;
2019-11-03 20:54:40 +00:00
ui . awaitReconnect ( window . location . host , '192.168.1.1' , 'openwrt.lan' ) ;
2019-09-24 09:33:21 +00:00
} , this ) )
2019-11-03 20:54:40 +00:00
. catch ( function ( e ) { ui . addNotification ( null , E ( 'p' , e . message ) ) } )
2019-10-02 17:53:17 +00:00
. finally ( function ( ) { btn . firstChild . data = _ ( 'Upload archive...' ) } ) ;
2019-09-24 09:33:21 +00:00
} ,
handleBlock : function ( hostname , ev ) {
var mtdblock = L . dom . parent ( ev . target , '.cbi-section' ) . querySelector ( '[data-name="mtdselect"] select' ) . value ;
var form = E ( 'form' , {
'method' : 'post' ,
'action' : '/cgi-bin/cgi-download' ,
'enctype' : 'application/x-www-form-urlencoded'
} , [
E ( 'input' , { 'type' : 'hidden' , 'name' : 'sessionid' , 'value' : rpc . getSessionID ( ) } ) ,
E ( 'input' , { 'type' : 'hidden' , 'name' : 'path' , 'value' : '/dev/mtdblock%d' . format ( mtdblock ) } ) ,
E ( 'input' , { 'type' : 'hidden' , 'name' : 'filename' , 'value' : '%s.mtd%d.bin' . format ( hostname , mtdblock ) } )
] ) ;
ev . currentTarget . parentNode . appendChild ( form ) ;
form . submit ( ) ;
form . parentNode . removeChild ( form ) ;
} ,
handleSysupgrade : function ( storage _size , ev ) {
2019-11-03 20:54:40 +00:00
return ui . uploadFile ( '/tmp/firmware.bin' , ev . target . firstChild )
2019-09-24 09:33:21 +00:00
. then ( L . bind ( function ( btn , reply ) {
btn . firstChild . data = _ ( 'Checking image…' ) ;
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Checking image…' ) , [
2019-09-24 09:33:21 +00:00
E ( 'span' , { 'class' : 'spinning' } , _ ( 'Verifying the uploaded image file.' ) )
] ) ;
2019-09-25 14:51:37 +00:00
return callSystemValidateFirmwareImage ( '/tmp/firmware.bin' )
. then ( function ( res ) { return [ reply , res ] ; } ) ;
} , this , ev . target ) )
. then ( L . bind ( function ( btn , reply ) {
2019-10-02 17:53:17 +00:00
return fs . exec ( '/sbin/sysupgrade' , [ '--test' , '/tmp/firmware.bin' ] )
2019-09-25 14:51:37 +00:00
. then ( function ( res ) { reply . push ( res ) ; return reply ; } ) ;
2019-09-24 09:33:21 +00:00
} , this , ev . target ) )
. then ( L . bind ( function ( btn , res ) {
2019-09-25 15:55:43 +00:00
var keep = E ( 'input' , { type : 'checkbox' } ) ,
2019-09-24 09:33:21 +00:00
force = E ( 'input' , { type : 'checkbox' } ) ,
2019-09-25 14:51:37 +00:00
is _valid = res [ 1 ] . valid ,
2019-09-25 14:51:38 +00:00
is _forceable = res [ 1 ] . forceable ,
2019-09-25 15:55:43 +00:00
allow _backup = res [ 1 ] . allow _backup ,
2019-09-24 09:33:21 +00:00
is _too _big = ( storage _size > 0 && res [ 0 ] . size > storage _size ) ,
body = [ ] ;
body . push ( E ( 'p' , _ ( 'The flash image was uploaded. Below is the checksum and file size listed, compare them with the original file to ensure data integrity. <br /> Click "Proceed" below to start the flash procedure.' ) ) ) ;
body . push ( E ( 'ul' , { } , [
res [ 0 ] . size ? E ( 'li' , { } , '%s: %1024.2mB' . format ( _ ( 'Size' ) , res [ 0 ] . size ) ) : '' ,
res [ 0 ] . checksum ? E ( 'li' , { } , '%s: %s' . format ( _ ( 'MD5' ) , res [ 0 ] . checksum ) ) : '' ,
2019-09-25 15:55:43 +00:00
res [ 0 ] . sha256sum ? E ( 'li' , { } , '%s: %s' . format ( _ ( 'SHA256' ) , res [ 0 ] . sha256sum ) ) : ''
2019-09-24 09:33:21 +00:00
] ) ) ;
2019-10-02 17:53:17 +00:00
body . push ( E ( 'p' , { } , E ( 'label' , { 'class' : 'btn' } , [
keep , ' ' , _ ( 'Keep settings and retain the current configuration' )
] ) ) ) ;
2019-09-25 14:51:37 +00:00
if ( ! is _valid || is _too _big )
2019-09-24 09:33:21 +00:00
body . push ( E ( 'hr' ) ) ;
if ( is _too _big )
body . push ( E ( 'p' , { 'class' : 'alert-message' } , [
_ ( 'It appears that you are trying to flash an image that does not fit into the flash memory, please verify the image file!' )
] ) ) ;
2019-09-25 14:51:37 +00:00
if ( ! is _valid )
2019-09-24 09:33:21 +00:00
body . push ( E ( 'p' , { 'class' : 'alert-message' } , [
2019-09-25 14:51:37 +00:00
res [ 2 ] . stderr ? res [ 2 ] . stderr : '' ,
res [ 2 ] . stderr ? E ( 'br' ) : '' ,
res [ 2 ] . stderr ? E ( 'br' ) : '' ,
2019-09-24 09:33:21 +00:00
_ ( 'The uploaded image file does not contain a supported format. Make sure that you choose the generic image format for your platform.' )
] ) ) ;
2019-09-25 15:55:43 +00:00
if ( ! allow _backup )
body . push ( E ( 'p' , { 'class' : 'alert-message' } , [
_ ( 'The uploaded firmware does not allow keeping current configuration.' )
] ) ) ;
2019-10-02 17:53:17 +00:00
2019-09-25 15:55:43 +00:00
if ( allow _backup )
keep . checked = true ;
else
keep . disabled = true ;
2019-10-02 17:53:17 +00:00
2019-09-25 15:55:43 +00:00
2019-09-25 14:51:38 +00:00
if ( ( ! is _valid || is _too _big ) && is _forceable )
2019-09-24 09:33:21 +00:00
body . push ( E ( 'p' , { } , E ( 'label' , { 'class' : 'btn alert-message danger' } , [
force , ' ' , _ ( 'Force upgrade' ) ,
E ( 'br' ) , E ( 'br' ) ,
_ ( 'Select \'Force upgrade\' to flash the image even if the image format check fails. Use only if you are sure that the firmware is correct and meant for your device!' )
] ) ) ) ;
var cntbtn = E ( 'button' , {
'class' : 'btn cbi-button-action important' ,
2019-11-03 20:54:40 +00:00
'click' : ui . createHandlerFn ( this , 'handleSysupgradeConfirm' , btn , keep , force ) ,
2019-09-25 14:51:37 +00:00
'disabled' : ( ! is _valid || is _too _big ) ? true : null
2019-09-24 09:33:21 +00:00
} , [ _ ( 'Continue' ) ] ) ;
body . push ( E ( 'div' , { 'class' : 'right' } , [
E ( 'button' , {
'class' : 'btn' ,
2019-11-03 20:54:40 +00:00
'click' : ui . createHandlerFn ( this , function ( ev ) {
return fs . remove ( '/tmp/firmware.bin' ) . finally ( ui . hideModal ) ;
2019-09-24 09:33:21 +00:00
} )
} , [ _ ( 'Cancel' ) ] ) , ' ' , cntbtn
] ) ) ;
force . addEventListener ( 'change' , function ( ev ) {
cntbtn . disabled = ! ev . target . checked ;
} ) ;
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Flash image?' ) , body ) ;
2019-09-24 09:33:21 +00:00
} , this , ev . target ) )
2019-11-03 20:54:40 +00:00
. catch ( function ( e ) { ui . addNotification ( null , E ( 'p' , e . message ) ) } )
2019-09-24 09:33:21 +00:00
. finally ( L . bind ( function ( btn ) {
btn . firstChild . data = _ ( 'Flash image...' ) ;
} , this , ev . target ) ) ;
} ,
handleSysupgradeConfirm : function ( btn , keep , force , ev ) {
btn . firstChild . data = _ ( 'Flashing…' ) ;
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Flashing…' ) , [
2019-09-24 09:33:21 +00:00
E ( 'p' , { 'class' : 'spinning' } , _ ( 'The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings.' ) )
] ) ;
var opts = [ ] ;
2019-10-07 17:55:31 +00:00
if ( ! keep . checked )
2019-09-24 09:33:21 +00:00
opts . push ( '-n' ) ;
2019-10-07 17:55:31 +00:00
if ( force . checked )
2019-09-24 09:33:21 +00:00
opts . push ( '--force' ) ;
opts . push ( '/tmp/firmware.bin' ) ;
/* Currently the sysupgrade rpc call will not return, hence no promise handling */
2019-10-02 17:53:17 +00:00
fs . exec ( '/sbin/sysupgrade' , opts ) ;
2019-09-24 09:33:21 +00:00
2019-11-01 11:45:00 +00:00
if ( keep . checked )
2019-11-03 20:54:40 +00:00
ui . awaitReconnect ( window . location . host ) ;
2019-11-01 11:45:00 +00:00
else
2019-11-03 20:54:40 +00:00
ui . awaitReconnect ( '192.168.1.1' , 'openwrt.lan' ) ;
2019-09-24 09:33:21 +00:00
} ,
handleBackupList : function ( ev ) {
2019-10-02 17:53:17 +00:00
return fs . exec ( '/sbin/sysupgrade' , [ '--list-backup' ] ) . then ( function ( res ) {
2019-09-24 09:33:21 +00:00
if ( res . code != 0 ) {
2019-11-03 20:54:40 +00:00
ui . addNotification ( null , [
2019-09-24 09:33:21 +00:00
E ( 'p' , _ ( 'The sysupgrade command failed with code %d' ) . format ( res . code ) ) ,
res . stderr ? E ( 'pre' , { } , [ res . stderr ] ) : ''
] ) ;
L . raise ( 'Error' , 'Sysupgrade failed' ) ;
}
2019-11-03 20:54:40 +00:00
ui . showModal ( _ ( 'Backup file list' ) , [
2019-09-24 09:33:21 +00:00
E ( 'p' , _ ( 'Below is the determined list of files to backup. It consists of changed configuration files marked by opkg, essential base files and the user defined backup patterns.' ) ) ,
E ( 'ul' , { } , ( res . stdout || '' ) . trim ( ) . split ( /\n/ ) . map ( function ( ln ) { return E ( 'li' , { } , ln ) } ) ) ,
E ( 'div' , { 'class' : 'right' } , [
E ( 'button' , {
'class' : 'btn' ,
2019-11-03 20:54:40 +00:00
'click' : ui . hideModal
2019-09-24 09:33:21 +00:00
} , [ _ ( 'Dismiss' ) ] )
] )
] , 'cbi-modal' ) ;
} ) ;
} ,
handleBackupSave : function ( m , ev ) {
return m . save ( function ( ) {
2019-10-02 17:53:17 +00:00
return fs . write ( '/etc/sysupgrade.conf' , mapdata . config . editlist . trim ( ) . replace ( /\r\n/g , '\n' ) + '\n' ) ;
2019-09-24 09:33:21 +00:00
} ) . then ( function ( ) {
2019-11-03 20:54:40 +00:00
ui . addNotification ( null , E ( 'p' , _ ( 'Contents have been saved.' ) ) , 'info' ) ;
2019-09-24 09:33:21 +00:00
} ) . catch ( function ( e ) {
2019-11-03 20:54:40 +00:00
ui . addNotification ( null , E ( 'p' , _ ( 'Unable to save contents: %s' ) . format ( e ) ) ) ;
2019-09-24 09:33:21 +00:00
} ) ;
} ,
render : function ( rpc _replies ) {
var has _sysupgrade = ( rpc _replies [ 0 ] . type == 'file' ) ,
hostname = rpc _replies [ 1 ] ,
procmtd = rpc _replies [ 2 ] ,
procpart = rpc _replies [ 3 ] ,
2019-09-25 01:02:59 +00:00
procmounts = rpc _replies [ 4 ] ,
has _rootfs _data = ( procmtd . match ( /"rootfs_data"/ ) != null ) || ( procmounts . match ( "overlayfs:\/overlay \/ " ) != null ) ,
2019-09-24 09:33:21 +00:00
storage _size = findStorageSize ( procmtd , procpart ) ,
m , s , o , ss ;
m = new form . JSONMap ( mapdata , _ ( 'Flash operations' ) ) ;
m . tabbed = true ;
s = m . section ( form . NamedSection , 'actions' , _ ( 'Actions' ) ) ;
o = s . option ( form . SectionValue , 'actions' , form . NamedSection , 'actions' , 'actions' , _ ( 'Backup' ) , _ ( 'Click "Generate archive" to download a tar archive of the current configuration files.' ) ) ;
ss = o . subsection ;
o = ss . option ( form . Button , 'dl_backup' , _ ( 'Download backup' ) ) ;
o . inputstyle = 'action important' ;
o . inputtitle = _ ( 'Generate archive' ) ;
o . onclick = this . handleBackup ;
o = s . option ( form . SectionValue , 'actions' , form . NamedSection , 'actions' , 'actions' , _ ( 'Restore' ) , _ ( 'To restore configuration files, you can upload a previously generated backup archive here. To reset the firmware to its initial state, click "Perform reset" (only possible with squashfs images).' ) ) ;
ss = o . subsection ;
if ( has _rootfs _data ) {
o = ss . option ( form . Button , 'reset' , _ ( 'Reset to defaults' ) ) ;
o . inputstyle = 'negative important' ;
o . inputtitle = _ ( 'Perform reset' ) ;
2019-09-25 17:37:27 +00:00
o . onclick = this . handleFirstboot ;
2019-09-24 09:33:21 +00:00
}
o = ss . option ( form . Button , 'restore' , _ ( 'Restore backup' ) , _ ( 'Custom files (certificates, scripts) may remain on the system. To prevent this, perform a factory-reset first.' ) ) ;
o . inputstyle = 'action important' ;
o . inputtitle = _ ( 'Upload archive...' ) ;
o . onclick = L . bind ( this . handleRestore , this ) ;
2019-09-25 17:42:06 +00:00
if ( procmtd . length ) {
o = s . option ( form . SectionValue , 'actions' , form . NamedSection , 'actions' , 'actions' , _ ( 'Save mtdblock contents' ) , _ ( 'Click "Save mtdblock" to download specified mtdblock file. (NOTE: THIS FEATURE IS FOR PROFESSIONALS! )' ) ) ;
ss = o . subsection ;
o = ss . option ( form . ListValue , 'mtdselect' , _ ( 'Choose mtdblock' ) ) ;
procmtd . split ( /\n/ ) . forEach ( function ( ln ) {
var match = ln . match ( /^mtd(\d+): .+ "(.+?)"$/ ) ;
if ( match )
o . value ( match [ 1 ] , match [ 2 ] ) ;
} ) ;
2019-09-24 09:33:21 +00:00
2019-09-25 17:42:06 +00:00
o = ss . option ( form . Button , 'mtddownload' , _ ( 'Download mtdblock' ) ) ;
o . inputstyle = 'action important' ;
o . inputtitle = _ ( 'Save mtdblock' ) ;
o . onclick = L . bind ( this . handleBlock , this , hostname ) ;
}
2019-09-24 09:33:21 +00:00
o = s . option ( form . SectionValue , 'actions' , form . NamedSection , 'actions' , 'actions' , _ ( 'Flash new firmware image' ) ,
has _sysupgrade
2019-09-25 15:55:43 +00:00
? _ ( 'Upload a sysupgrade-compatible image here to replace the running firmware.' )
2019-09-24 09:33:21 +00:00
: _ ( 'Sorry, there is no sysupgrade support present; a new firmware image must be flashed manually. Please refer to the wiki for device specific install instructions.' ) ) ;
ss = o . subsection ;
if ( has _sysupgrade ) {
o = ss . option ( form . Button , 'sysupgrade' , _ ( 'Image' ) ) ;
o . inputstyle = 'action important' ;
o . inputtitle = _ ( 'Flash image...' ) ;
o . onclick = L . bind ( this . handleSysupgrade , this , storage _size ) ;
}
s = m . section ( form . NamedSection , 'config' , 'config' , _ ( 'Configuration' ) , _ ( 'This is a list of shell glob patterns for matching files and directories to include during sysupgrade. Modified files in /etc/config/ and certain other configurations are automatically preserved.' ) ) ;
s . render = L . bind ( function ( view /*, ... */ ) {
return form . NamedSection . prototype . render . apply ( this , this . varargs ( arguments , 1 ) )
. then ( L . bind ( function ( node ) {
node . appendChild ( E ( 'div' , { 'class' : 'cbi-page-actions' } , [
E ( 'button' , {
'class' : 'cbi-button cbi-button-save' ,
2019-11-03 20:54:40 +00:00
'click' : ui . createHandlerFn ( view , 'handleBackupSave' , this . map )
2019-09-24 09:33:21 +00:00
} , [ _ ( 'Save' ) ] )
] ) ) ;
return node ;
} , this ) ) ;
} , s , this ) ;
o = s . option ( form . Button , 'showlist' , _ ( 'Show current backup file list' ) ) ;
o . inputstyle = 'action' ;
o . inputtitle = _ ( 'Open list...' ) ;
o . onclick = L . bind ( this . handleBackupList , this ) ;
o = s . option ( form . TextValue , 'editlist' ) ;
o . forcewrite = true ;
o . rows = 30 ;
o . load = function ( section _id ) {
2019-10-21 13:30:22 +00:00
return L . resolveDefault ( fs . read ( '/etc/sysupgrade.conf' ) , '' ) ;
2019-09-24 09:33:21 +00:00
} ;
return m . render ( ) ;
} ,
handleSaveApply : null ,
handleSave : null ,
handleReset : null
} ) ;