From 71e265a7f038f172eada95576496ef240a9c83e7 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 21 Sep 2019 18:36:31 +0200 Subject: [PATCH] luci-mod-system: remplement fstab settings as client side view Signed-off-by: Jo-Philipp Wich --- .../root/usr/share/rpcd/acl.d/luci-base.json | 11 +- .../resources/view/system/mounts.js | 428 ++++++++++++++++++ .../luasrc/controller/admin/system.lua | 4 +- .../luasrc/model/cbi/admin_system/fstab.lua | 272 ----------- .../model/cbi/admin_system/fstab/mount.lua | 158 ------- .../model/cbi/admin_system/fstab/swap.lua | 54 --- 6 files changed, 436 insertions(+), 491 deletions(-) create mode 100644 modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js delete mode 100644 modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua delete mode 100644 modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua delete mode 100644 modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua diff --git a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json index 32cb10596b..af06d840d0 100644 --- a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json +++ b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json @@ -25,13 +25,15 @@ "/*": [ "list" ], "/etc/crontabs/root": [ "read" ], "/etc/dropbear/authorized_keys": [ "read" ], + "/etc/filesystems": [ "read" ], "/etc/rc.local": [ "read" ], + "/proc/filesystems": [ "read" ], "/proc/sys/kernel/hostname": [ "read" ] }, "ubus": { "file": [ "list", "read", "stat" ], "iwinfo": [ "assoclist", "freqlist", "txpowerlist", "countrylist" ], - "luci": [ "getBoardJSON", "getDUIDHints", "getHostHints", "getIfaddrs", "getInitList", "getLocaltime", "getTimezones", "getDHCPLeases", "getLEDs", "getNetworkDevices", "getUSBDevices", "getWirelessDevices", "getSwconfigFeatures", "getSwconfigPortState" ], + "luci": [ "getBoardJSON", "getDUIDHints", "getHostHints", "getIfaddrs", "getInitList", "getLocaltime", "getTimezones", "getDHCPLeases", "getLEDs", "getNetworkDevices", "getUSBDevices", "getWirelessDevices", "getSwconfigFeatures", "getSwconfigPortState", "getBlockDevices", "getMountPoints" ], "network.device": [ "status" ], "network.interface": [ "dump" ], "network": [ "get_proto_handlers" ], @@ -45,12 +47,13 @@ "/etc/crontabs/root": [ "write" ], "/etc/dropbear/authorized_keys": [ "write" ], "/etc/luci-uploads/*": [ "write" ], - "/etc/rc.local": [ "write" ] + "/etc/rc.local": [ "write" ], + "/sbin/block": [ "exec" ] }, "ubus": { - "file": [ "write", "remove" ], + "file": [ "write", "remove", "exec" ], "iwinfo": [ "scan" ], - "luci": [ "setInitAction", "setLocaltime", "setPassword" ], + "luci": [ "setInitAction", "setLocaltime", "setPassword", "setBlockDetect", "setUmount" ], "uci": [ "add", "apply", "confirm", "delete", "order", "set", "rename" ] }, "uci": [ "*" ] diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js new file mode 100644 index 0000000000..b9028b20e7 --- /dev/null +++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js @@ -0,0 +1,428 @@ +'use strict'; +'require uci'; +'require rpc'; +'require form'; + +var callBlockDevices, callMountPoints, callBlockDetect, callUmount, + callFileRead, callFileStat, callFileExec; + +callBlockDevices = rpc.declare({ + object: 'luci', + method: 'getBlockDevices', + expect: { '': {} } +}); + +callMountPoints = rpc.declare({ + object: 'luci', + method: 'getMountPoints', + expect: { result: [] } +}); + +callBlockDetect = rpc.declare({ + object: 'luci', + method: 'setBlockDetect', + expect: { result: false } +}); + +callUmount = rpc.declare({ + object: 'luci', + method: 'setUmount', + params: [ 'path' ], + expect: { result: false } +}); + +callFileRead = rpc.declare({ + object: 'file', + method: 'read', + params: [ 'path' ], + expect: { data: '' }, + filter: function(s) { + return (s || '').split(/\n/).filter(function(ln) { + return ln.match(/\S/) && !ln.match(/^nodev\t/); + }).map(function(ln) { + return ln.trim(); + }); + } +}); + +callFileStat = rpc.declare({ + object: 'file', + method: 'stat', + params: [ 'path' ], + expect: { '': {} }, + filter: function(st) { + return (L.isObject(st) && st.path != null); + } +}); + +callFileExec = rpc.declare({ + object: 'file', + method: 'exec', + params: [ 'command', 'params' ], + expect: { code: 255 } +}); + +function device_textvalue(devices, section_id) { + var v = (uci.get('fstab', section_id, 'uuid') || '').toLowerCase(), + e = Object.keys(devices).filter(function(dev) { return (devices[dev].uuid || '-').toLowerCase() == v })[0]; + + if (v) { + this.section.devices[section_id] = devices[e]; + + if (e && devices[e].size) + return E('span', 'UUID: %h (%s, %1024.2mB)'.format(v, devices[e].dev, devices[e].size)); + else if (e) + return E('span', 'UUID: %h (%s)'.format(v, devices[e].dev)); + else + return E('span', 'UUID: %h (%s)'.format(v, _('not present'))); + } + + v = uci.get('fstab', section_id, 'label'); + e = Object.keys(devices).filter(function(dev) { return devices[dev].label == v })[0]; + + if (v) { + this.section.devices[section_id] = this.section.devices[section_id] || devices[e]; + + if (e && devices[e].size) + return E('span', 'Label: %h (%s, %1024.2mB)'.format(v, devices[e].dev, devices[e].size)); + else if (e) + return E('span', 'Label: %h (%s)'.format(v, devices[e].dev)); + else + return E('span', 'Label: %h (%s)'.format(v, _('not present'))); + } + + v = uci.get('fstab', section_id, 'device'); + e = Object.keys(devices).filter(function(dev) { return devices[dev].dev == v })[0]; + + if (v) { + this.section.devices[section_id] = this.section.devices[section_id] || devices[e]; + + if (e && devices[e].size) + return E('span', '%h (%1024.2mB)'.format(v, devices[e].size)); + else if (e) + return E('span', '%h'.format(v)); + else + return E('span', '%h (%s)'.format(v, _('not present'))); + } +} + +return L.view.extend({ + handleDetect: function(m, ev) { + return callBlockDetect() + .then(L.bind(uci.unload, uci, 'fstab')) + .then(L.bind(m.render, m)); + }, + + handleMountAll: function(m, ev) { + return callFileExec('/sbin/block', ['mount']) + .then(function(rc) { + if (rc != 0) + L.ui.addNotification(null, E('p', _('The block mount command failed with code %d').format(rc))); + }) + .then(L.bind(uci.unload, uci, 'fstab')) + .then(L.bind(m.render, m)); + }, + + handleUmount: function(m, path, ev) { + return callUmount(path) + .then(L.bind(uci.unload, uci, 'fstab')) + .then(L.bind(m.render, m)); + }, + + load: function() { + return Promise.all([ + callBlockDevices(), + callFileRead('/proc/filesystems'), + callFileRead('/etc/filesystems'), + callFileStat('/usr/sbin/e2fsck'), + callFileStat('/usr/sbin/fsck.f2fs'), + callFileStat('/usr/sbin/dosfsck'), + callFileStat('/usr/bin/btrfsck') + ]); + }, + + render: function(results) { + var devices = results[0], + procfs = results[1], + etcfs = results[2], + triggers = {}, + trigger, m, s, o; + + var filesystems = procfs.concat(etcfs.filter(function(fs) { + return procfs.indexOf(fs) < 0; + })).sort(); + + var fsck = { + ext2: results[3], + ext3: results[3], + ext4: results[3], + f2fs: results[4], + vfat: results[5], + btrfs: results[6] + }; + + m = new form.Map('fstab', _('Mount Points')); + + s = m.section(form.TypedSection, 'global', _('Global Settings')); + s.addremove = false; + s.anonymous = true; + + o = s.option(form.Button, '_detect', _('Generate Config'), _('Find all currently attached filesystems and swap and replace configuration with defaults based on what was detected')); + o.onclick = this.handleDetect.bind(this, m); + o.inputstyle = 'reload'; + + o = s.option(form.Button, '_mountall', _('Mount attached devices'), _('Attempt to enable configured mount points for attached devices')); + o.onclick = this.handleMountAll.bind(this, m); + o.inputstyle = 'reload'; + + o = s.option(form.Flag, 'anon_swap', _('Anonymous Swap'), _('Mount swap not specifically configured')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(form.Flag, 'anon_mount', _('Anonymous Mount'), _('Mount filesystems not specifically configured')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(form.Flag, 'auto_swap', _('Automount Swap'), _('Automatically mount swap on hotplug')); + o.default = o.enabled; + o.rmempty = false; + + o = s.option(form.Flag, 'auto_mount', _('Automount Filesystem'), _('Automatically mount filesystems on hotplug')); + o.default = o.enabled; + o.rmempty = false; + + o = s.option(form.Flag, 'check_fs', _('Check filesystems before mount'), _('Automatically check filesystem for errors before mounting')); + o.default = o.disabled; + o.rmempty = false; + + + // Mount status table + o = s.option(form.DummyValue, '_mtab'); + + o.load = function(section_id) { + return callMountPoints().then(L.bind(function(mounts) { + this.mounts = mounts; + }, this)); + }; + + o.render = L.bind(function(view, section_id) { + var table = E('div', { 'class': 'table' }, [ + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th' }, _('Filesystem')), + E('div', { 'class': 'th' }, _('Mount Point')), + E('div', { 'class': 'th center' }, _('Available')), + E('div', { 'class': 'th center' }, _('Used')), + E('div', { 'class': 'th' }, _('Unmount')) + ]) + ]); + + var rows = []; + + for (var i = 0; i < this.mounts.length; i++) { + var used = this.mounts[i].size - this.mounts[i].free, + umount = true; + + if (/^\/(overlay|rom|tmp(?:\/.+)?|dev(?:\/.+)?|)$/.test(this.mounts[i].mount)) + umount = false; + + rows.push([ + this.mounts[i].device, + this.mounts[i].mount, + '%1024.2mB / %1024.2mB'.format(this.mounts[i].avail, this.mounts[i].size), + '%.2f%% (%1024.2mB)'.format(100 / this.mounts[i].size * used, used), + umount ? E('button', { + 'class': 'btn cbi-button-remove', + 'click': L.ui.createHandlerFn(view, 'handleUmount', m, this.mounts[i].mount) + }, [ _('Unmount') ]) : '-' + ]); + } + + cbi_update_table(table, rows, E('em', _('Unable to obtain mount information'))); + + return E([], [ E('h3', _('Mounted file systems')), table ]); + }, o, this); + + + // Mounts + s = m.section(form.GridSection, 'mount', _('Mount Points'), _('Mount Points define at which point a memory device will be attached to the filesystem')); + s.modaltitle = _('Mount Points - Mount Entry'); + s.anonymous = true; + s.addremove = true; + s.sortable = true; + s.devices = {}; + + s.renderHeaderRows = function(/* ... */) { + var trEls = form.GridSection.prototype.renderHeaderRows.apply(this, arguments); + return trEls.childNodes[0]; + } + + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + + o = s.taboption('general', form.Flag, 'enabled', _('Enabled')); + o.rmempty = false; + o.editable = true; + + o = s.taboption('general', form.DummyValue, '_device', _('Device')); + o.rawhtml = true; + o.modalonly = false; + o.write = function() {}; + o.remove = function() {}; + o.textvalue = device_textvalue.bind(o, devices); + + o = s.taboption('general', form.Value, 'uuid', _('UUID'), _('If specified, mount the device by its UUID instead of a fixed device node')); + o.modalonly = true; + o.value('', _('-- match by uuid --')); + + var devs = Object.keys(devices).sort(); + for (var i = 0; i < devs.length; i++) { + var dev = devices[devs[i]]; + if (dev.uuid && dev.size) + o.value(dev.uuid, '%s (%s, %1024.2mB)'.format(dev.uuid, dev.dev, dev.size)); + else if (dev.uuid) + o.value(dev.uuid, '%s (%s)'.format(dev.uuid, dev.dev)); + } + + o = s.taboption('general', form.Value, 'label', _('Label'), _('If specified, mount the device by the partition label instead of a fixed device node')); + o.modalonly = true; + o.depends('uuid', ''); + o.value('', _('-- match by label --')); + + for (var i = 0; i < devs.length; i++) { + var dev = devices[devs[i]]; + if (dev.label && dev.size) + o.value(dev.label, '%s (%s, %1024.2mB)'.format(dev.label, dev.dev, dev.size)); + else if (dev.label) + o.value(dev.label, '%s (%s)'.format(dev.label, dev.dev)); + } + + o = s.taboption('general', form.Value, 'device', _('Device'), _('The device file of the memory or partition (e.g. /dev/sda1)')); + o.modalonly = true; + o.depends({ uuid: '', label: '' }); + + for (var i = 0; i < devs.length; i++) { + var dev = devices[devs[i]]; + if (dev.size) + o.value(dev.dev, '%s (%1024.2mB)'.format(dev.dev, dev.size)); + else + o.value(dev.dev); + } + + o = s.taboption('general', form.Value, 'target', _('Mount point'), _('Specifies the directory the device is attached to')); + o.value('/', _('Use as root filesystem (/)')); + o.value('/overlay', _('Use as external overlay (/overlay)')); + o.rmempty = false; + + o = s.taboption('general', form.DummyValue, '__notice', _('Root preparation')); + o.depends('target', '/'); + o.modalonly = true; + o.rawhtml = true; + o.default = '' + + '

%s

'.format(_('Make sure to clone the root filesystem using something like the commands below:')) + + '
' +
+				'mkdir -p /tmp/introot\n' +
+				'mkdir -p /tmp/extroot\n' +
+				'mount --bind / /tmp/introot\n' +
+				'mount /dev/sda1 /tmp/extroot\n' +
+				'tar -C /tmp/introot -cvf - . | tar -C /tmp/extroot -xf -\n' +
+				'umount /tmp/introot\n' +
+				'umount /tmp/extroot\n' +
+			'
' + ; + + o = s.taboption('advanced', form.ListValue, 'fstype', _('Filesystem')); + + o.textvalue = function(section_id) { + var dev = this.section.devices[section_id], + text = this.cfgvalue(section_id) || 'auto'; + + if (dev && dev.type && dev.type != text) + text += ' (%s)'.format(dev.type); + + return text; + }; + + o.value('', 'auto'); + + for (var i = 0; i < filesystems.length; i++) + o.value(filesystems[i]); + + o = s.taboption('advanced', form.Value, 'options', _('Mount options'), _('See "mount" manpage for details')); + o.textvalue = function(section_id) { return this.cfgvalue(section_id) || 'defaults' }; + o.placeholder = 'defaults'; + + s.taboption('advanced', form.Flag, 'enabled_fsck', _('Run filesystem check'), _('Run a filesystem check before mounting the device')); + + + // Swaps + s = m.section(form.GridSection, 'swap', _('SWAP'), _('If your physical memory is insufficient unused data can be temporarily swapped to a swap-device resulting in a higher amount of usable RAM. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the RAM.')); + s.modaltitle = _('Mount Points - Swap Entry'); + s.anonymous = true; + s.addremove = true; + s.sortable = true; + s.devices = {}; + + s.renderHeaderRows = function(/* ... */) { + var trEls = form.GridSection.prototype.renderHeaderRows.apply(this, arguments); + trEls.childNodes[0].childNodes[1].style.width = '90%'; + return trEls.childNodes[0]; + } + + o = s.option(form.Flag, 'enabled', _('Enabled')); + o.rmempty = false; + o.editable = true; + + o = s.option(form.DummyValue, '_device', _('Device')); + o.modalonly = false; + o.textvalue = device_textvalue.bind(o, devices); + + o = s.option(form.Value, 'uuid', _('UUID'), _('If specified, mount the device by its UUID instead of a fixed device node')); + o.modalonly = true; + o.value('', _('-- match by uuid --')); + + var devs = Object.keys(devices).sort(); + for (var i = 0; i < devs.length; i++) { + var dev = devices[devs[i]]; + if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/)) + continue; + + if (dev.uuid && dev.size) + o.value(dev.uuid, '%s (%s, %1024.2mB)'.format(dev.uuid, dev.dev, dev.size)); + else if (dev.uuid) + o.value(dev.uuid, '%s (%s)'.format(dev.uuid, dev.dev)); + } + + o = s.option(form.Value, 'label', _('Label'), _('If specified, mount the device by the partition label instead of a fixed device node')); + o.modalonly = true; + o.depends('uuid', ''); + o.value('', _('-- match by label --')); + + for (var i = 0; i < devs.length; i++) { + var dev = devices[devs[i]]; + if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/)) + continue; + + if (dev.label && dev.size) + o.value(dev.label, '%s (%s, %1024.2mB)'.format(dev.label, dev.dev, dev.size)); + else if (dev.label) + o.value(dev.label, '%s (%s)'.format(dev.label, dev.dev)); + } + + o = s.option(form.Value, 'device', _('Device'), _('The device file of the memory or partition (e.g. /dev/sda1)')); + o.modalonly = true; + o.depends({ uuid: '', label: '' }); + + for (var i = 0; i < devs.length; i++) { + var dev = devices[devs[i]]; + if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/)) + continue; + + if (dev.size) + o.value(dev.dev, '%s (%1024.2mB)'.format(dev.dev, dev.size)); + else + o.value(dev.dev); + } + + return m.render(); + } +}); diff --git a/modules/luci-mod-system/luasrc/controller/admin/system.lua b/modules/luci-mod-system/luasrc/controller/admin/system.lua index 0ce08d10bd..eaf1105dd6 100644 --- a/modules/luci-mod-system/luasrc/controller/admin/system.lua +++ b/modules/luci-mod-system/luasrc/controller/admin/system.lua @@ -23,9 +23,7 @@ function index() entry({"admin", "system", "crontab"}, view("system/crontab"), _("Scheduled Tasks"), 46) if fs.access("/sbin/block") and fs.access("/etc/config/fstab") then - entry({"admin", "system", "fstab"}, cbi("admin_system/fstab"), _("Mount Points"), 50) - entry({"admin", "system", "fstab", "mount"}, cbi("admin_system/fstab/mount"), nil).leaf = true - entry({"admin", "system", "fstab", "swap"}, cbi("admin_system/fstab/swap"), nil).leaf = true + entry({"admin", "system", "mounts"}, view("system/mounts"), _("Mount Points"), 50) end local nodes, number = fs.glob("/sys/class/leds/*") diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua deleted file mode 100644 index 4a31146a03..0000000000 --- a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua +++ /dev/null @@ -1,272 +0,0 @@ --- Copyright 2008 Steven Barth --- Licensed to the public under the Apache License 2.0. - -require("luci.tools.webadmin") - -local fs = require "nixio.fs" -local util = require "nixio.util" -local tp = require "luci.template.parser" - -local block = io.popen("block info", "r") -local ln, dev, devices = nil, nil, {} - -repeat - ln = block:read("*l") - dev = ln and ln:match("^/dev/(.-):") - - if dev then - local e, s, key, val = { } - - for key, val in ln:gmatch([[(%w+)="(.-)"]]) do - e[key:lower()] = val - devices[val] = e - end - - s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev))) - - e.dev = "/dev/%s" % dev - e.size = s and math.floor(s / 2048) - - devices[e.dev] = e - end -until not ln - -block:close() - -m = Map("fstab", translate("Mount Points")) -s = m:section(TypedSection, "global", translate("Global Settings")) -s.addremove = false -s.anonymous = true - -detect = s:option(Button, "block_detect", translate("Generate Config"), translate("Find all currently attached filesystems and swap and replace configuration with defaults based on what was detected")) -detect.inputstyle = "reload" - -detect.write = function(self, section) - luci.sys.call("block detect >/etc/config/fstab") - luci.http.redirect(luci.dispatcher.build_url("admin/system", "fstab")) -end - -o = s:option(Flag, "anon_swap", translate("Anonymous Swap"), translate("Mount swap not specifically configured")) -o.default = o.disabled -o.rmempty = false - -o = s:option(Flag, "anon_mount", translate("Anonymous Mount"), translate("Mount filesystems not specifically configured")) -o.default = o.disabled -o.rmempty = false - -o = s:option(Flag, "auto_swap", translate("Automount Swap"), translate("Automatically mount swap on hotplug")) -o.default = o.enabled -o.rmempty = false - -o = s:option(Flag, "auto_mount", translate("Automount Filesystem"), translate("Automatically mount filesystems on hotplug")) -o.default = o.enabled -o.rmempty = false - -o = s:option(Flag, "check_fs", translate("Check filesystems before mount"), translate("Automatically check filesystem for errors before mounting")) -o.default = o.disabled -o.rmempty = false - -local mounts = luci.sys.mounts() -local non_system_mounts = {} -for rawmount, val in pairs(mounts) do - if (string.find(val.mountpoint, "/tmp/.jail") == nil) then - repeat - val.umount = false - if (val.mountpoint == "/") then - break - elseif (val.mountpoint == "/overlay") then - break - elseif (val.mountpoint == "/rom") then - break - elseif (val.mountpoint == "/tmp") then - break - elseif (val.mountpoint == "/tmp/shm") then - break - elseif (val.mountpoint == "/tmp/upgrade") then - break - elseif (val.mountpoint == "/dev") then - break - end - val.umount = true - until true - non_system_mounts[rawmount] = val - end -end - -v = m:section(Table, non_system_mounts, translate("Mounted file systems")) - -fs = v:option(DummyValue, "fs", translate("Filesystem")) - -mp = v:option(DummyValue, "mountpoint", translate("Mount Point")) - -avail = v:option(DummyValue, "avail", translate("Available")) -function avail.cfgvalue(self, section) - return luci.tools.webadmin.byte_format( - ( tonumber(mounts[section].available) or 0 ) * 1024 - ) .. " / " .. luci.tools.webadmin.byte_format( - ( tonumber(mounts[section].blocks) or 0 ) * 1024 - ) -end - -used = v:option(DummyValue, "used", translate("Used")) -function used.cfgvalue(self, section) - return ( mounts[section].percent or "0%" ) .. " (" .. - luci.tools.webadmin.byte_format( - ( tonumber(mounts[section].used) or 0 ) * 1024 - ) .. ")" -end - -unmount = v:option(Button, "unmount", translate("Unmount")) -function unmount.cfgvalue(self, section) - return non_system_mounts[section].umount -end - -unmount.render = function(self, section, scope) - self.title = translate("Unmount") - self.inputstyle = "remove" - Button.render(self, section, scope) -end - -unmount.write = function(self, section) - if non_system_mounts[section].umount then - luci.sys.call("/bin/umount '%s'" % luci.util.shellstartsqescape(non_system_mounts[section].mountpoint)) - return luci.http.redirect(luci.dispatcher.build_url("admin/system", "fstab")) - end -end - -mount = m:section(TypedSection, "mount", translate("Mount Points"), translate("Mount Points define at which point a memory device will be attached to the filesystem")) -mount.anonymous = true -mount.addremove = true -mount.template = "cbi/tblsection" -mount.extedit = luci.dispatcher.build_url("admin/system/fstab/mount/%s") - -mount.create = function(...) - local sid = TypedSection.create(...) - if sid then - luci.http.redirect(mount.extedit % sid) - return - end -end - - -mount:option(Flag, "enabled", translate("Enabled")).rmempty = false - -dev = mount:option(DummyValue, "device", translate("Device")) -dev.rawhtml = true -dev.cfgvalue = function(self, section) - local v, e - - v = m.uci:get("fstab", section, "uuid") - e = v and devices[v:lower()] - if v and e and e.size then - return "UUID: %s (%s, %d MB)" %{ tp.pcdata(v), e.dev, e.size } - elseif v and e then - return "UUID: %s (%s)" %{ tp.pcdata(v), e.dev } - elseif v then - return "UUID: %s (%s)" %{ tp.pcdata(v), translate("not present") } - end - - v = m.uci:get("fstab", section, "label") - e = v and devices[v] - if v and e and e.size then - return "Label: %s (%s, %d MB)" %{ tp.pcdata(v), e.dev, e.size } - elseif v and e then - return "Label: %s (%s)" %{ tp.pcdata(v), e.dev } - elseif v then - return "Label: %s (%s)" %{ tp.pcdata(v), translate("not present") } - end - - v = Value.cfgvalue(self, section) or "?" - e = v and devices[v] - if v and e and e.size then - return "%s (%d MB)" %{ tp.pcdata(v), e.size } - elseif v and e then - return tp.pcdata(v) - elseif v then - return "%s (%s)" %{ tp.pcdata(v), translate("not present") } - end -end - -mp = mount:option(DummyValue, "target", translate("Mount Point")) -mp.cfgvalue = function(self, section) - if m.uci:get("fstab", section, "is_rootfs") == "1" then - return "/overlay" - else - return Value.cfgvalue(self, section) or "?" - end -end - -fs = mount:option(DummyValue, "fstype", translate("Filesystem")) -fs.cfgvalue = function(self, section) - local v, e - - v = m.uci:get("fstab", section, "uuid") - v = v and v:lower() or m.uci:get("fstab", section, "label") - v = v or m.uci:get("fstab", section, "device") - - e = v and devices[v] - - return e and e.type or m.uci:get("fstab", section, "fstype") or "?" -end - -op = mount:option(DummyValue, "options", translate("Options")) -op.cfgvalue = function(self, section) - return Value.cfgvalue(self, section) or "defaults" -end - -rf = mount:option(DummyValue, "is_rootfs", translate("Root")) -rf.cfgvalue = function(self, section) - local target = m.uci:get("fstab", section, "target") - if target == "/" then - return translate("yes") - elseif target == "/overlay" then - return translate("overlay") - else - return translate("no") - end -end - -ck = mount:option(DummyValue, "enabled_fsck", translate("Check")) -ck.cfgvalue = function(self, section) - return Value.cfgvalue(self, section) == "1" - and translate("yes") or translate("no") -end - - -swap = m:section(TypedSection, "swap", translate("SWAP"), translate("If your physical memory is insufficient unused data can be temporarily swapped to a swap-device resulting in a higher amount of usable RAM. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the RAM.")) -swap.anonymous = true -swap.addremove = true -swap.template = "cbi/tblsection" -swap.extedit = luci.dispatcher.build_url("admin/system/fstab/swap/%s") - -swap.create = function(...) - local sid = TypedSection.create(...) - if sid then - luci.http.redirect(swap.extedit % sid) - return - end -end - - -swap:option(Flag, "enabled", translate("Enabled")).rmempty = false - -dev = swap:option(DummyValue, "device", translate("Device")) -dev.cfgvalue = function(self, section) - local v - - v = m.uci:get("fstab", section, "uuid") - if v then return "UUID: %s" % v end - - v = m.uci:get("fstab", section, "label") - if v then return "Label: %s" % v end - - v = Value.cfgvalue(self, section) or "?" - e = v and devices[v] - if v and e and e.size then - return "%s (%s MB)" % {v, e.size} - else - return v - end -end - -return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua deleted file mode 100644 index f21a2775e1..0000000000 --- a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua +++ /dev/null @@ -1,158 +0,0 @@ --- Copyright 2010 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local fs = require "nixio.fs" -local util = require "nixio.util" - -local has_fscheck = fs.access("/usr/sbin/e2fsck") - -local block = io.popen("block info", "r") -local ln, dev, devices = nil, nil, {} - -repeat - ln = block:read("*l") - dev = ln and ln:match("^/dev/(.-):") - - if dev then - local e, s, key, val = { } - - for key, val in ln:gmatch([[(%w+)="(.-)"]]) do - e[key:lower()] = val - end - - s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev))) - - e.dev = "/dev/%s" % dev - e.size = s and math.floor(s / 2048) - - devices[#devices+1] = e - end -until not ln - -block:close() - - -m = Map("fstab", translate("Mount Points - Mount Entry")) -m.redirect = luci.dispatcher.build_url("admin/system/fstab") - -if not arg[1] or m.uci:get("fstab", arg[1]) ~= "mount" then - luci.http.redirect(m.redirect) - return -end - - - -mount = m:section(NamedSection, arg[1], "mount", translate("Mount Entry")) -mount.anonymous = true -mount.addremove = false - -mount:tab("general", translate("General Settings")) -mount:tab("advanced", translate("Advanced Settings")) - - -mount:taboption("general", Flag, "enabled", translate("Enable this mount")).rmempty = false - - -o = mount:taboption("general", Value, "uuid", translate("UUID"), - translate("If specified, mount the device by its UUID instead of a fixed device node")) - -o:value("", translate("-- match by uuid --")) - -for i, d in ipairs(devices) do - if d.uuid and d.size then - o:value(d.uuid, "%s (%s, %d MB)" %{ d.uuid, d.dev, d.size }) - elseif d.uuid then - o:value(d.uuid, "%s (%s)" %{ d.uuid, d.dev }) - end -end - - -o = mount:taboption("general", Value, "label", translate("Label"), - translate("If specified, mount the device by the partition label instead of a fixed device node")) - -o:value("", translate("-- match by label --")) - -o:depends("uuid", "") - -for i, d in ipairs(devices) do - if d.label and d.size then - o:value(d.label, "%s (%s, %d MB)" %{ d.label, d.dev, d.size }) - elseif d.label then - o:value(d.label, "%s (%s)" %{ d.label, d.dev }) - end -end - - -o = mount:taboption("general", Value, "device", translate("Device"), - translate("The device file of the memory or partition (e.g. /dev/sda1)")) - -o:value("", translate("-- match by device --")) - -o:depends({ uuid = "", label = "" }) - -for i, d in ipairs(devices) do - if d.size then - o:value(d.dev, "%s (%d MB)" %{ d.dev, d.size }) - else - o:value(d.dev) - end -end - - -o = mount:taboption("general", Value, "target", translate("Mount point"), - translate("Specifies the directory the device is attached to")) - -o:value("/", translate("Use as root filesystem (/)")) -o:value("/overlay", translate("Use as external overlay (/overlay)")) - - -o = mount:taboption("general", DummyValue, "__notice", translate("Root preparation")) -o:depends("target", "/") -o.rawhtml = true -o.default = [[ -

%s

mkdir -p /tmp/introot
-mkdir -p /tmp/extroot
-mount --bind / /tmp/introot
-mount /dev/sda1 /tmp/extroot
-tar -C /tmp/introot -cvf - . | tar -C /tmp/extroot -xf -
-umount /tmp/introot
-umount /tmp/extroot
-]] %{ - translate("Make sure to clone the root filesystem using something like the commands below:"), - -} - - -o = mount:taboption("advanced", Value, "fstype", translate("Filesystem"), - translate("The filesystem that was used to format the memory (e.g. ext3)")) - -o:value("", "auto") - -local fs -for fs in io.lines("/proc/filesystems") do - fs = fs:match("%S+") - if fs ~= "nodev" then - o:value(fs) - end -end - -local ok, lines = pcall(io.lines, "/etc/filesystem") -if ok then - local fs - for fs in lines do - o:value(fs) - end -end - -o = mount:taboption("advanced", Value, "options", translate("Mount options"), - translate("See \"mount\" manpage for details")) - -o.placeholder = "defaults" - - -if has_fscheck then - o = mount:taboption("advanced", Flag, "enabled_fsck", translate("Run filesystem check"), - translate("Run a filesystem check before mounting the device")) -end - -return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua deleted file mode 100644 index 82468d5fcc..0000000000 --- a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua +++ /dev/null @@ -1,54 +0,0 @@ --- Copyright 2010 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local fs = require "nixio.fs" -local util = require "nixio.util" - -local devices = {} -util.consume((fs.glob("/dev/sd*")), devices) -util.consume((fs.glob("/dev/hd*")), devices) -util.consume((fs.glob("/dev/scd*")), devices) -util.consume((fs.glob("/dev/mmc*")), devices) - -local size = {} -for i, dev in ipairs(devices) do - local s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev:sub(6)))) - size[dev] = s and math.floor(s / 2048) -end - - -m = Map("fstab", translate("Mount Points - Swap Entry")) -m.redirect = luci.dispatcher.build_url("admin/system/fstab") - -if not arg[1] or m.uci:get("fstab", arg[1]) ~= "swap" then - luci.http.redirect(m.redirect) - return -end - - -mount = m:section(NamedSection, arg[1], "swap", translate("Swap Entry")) -mount.anonymous = true -mount.addremove = false - -mount:tab("general", translate("General Settings")) -mount:tab("advanced", translate("Advanced Settings")) - - -mount:taboption("general", Flag, "enabled", translate("Enable this swap")).rmempty = false - - -o = mount:taboption("general", Value, "device", translate("Device"), - translate("The device file of the memory or partition (e.g. /dev/sda1)")) - -for i, d in ipairs(devices) do - o:value(d, size[d] and "%s (%s MB)" % {d, size[d]}) -end - -o = mount:taboption("advanced", Value, "uuid", translate("UUID"), - translate("If specified, mount the device by its UUID instead of a fixed device node")) - -o = mount:taboption("advanced", Value, "label", translate("Label"), - translate("If specified, mount the device by the partition label instead of a fixed device node")) - - -return m -- 2.30.2