luci-mod-system: remplement fstab settings as client side view

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2019-09-21 18:36:31 +02:00
parent 54cab2f26b
commit 71e265a7f0
6 changed files with 436 additions and 491 deletions

View file

@ -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": [ "*" ]

View file

@ -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 (<em>%s</em>)'.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 (<em>%s</em>)'.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 (<em>%s</em>)'.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 <em>block mount</em> 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 (<abbr title="for example">e.g.</abbr> <code>/dev/sda1</code>)'));
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 = '' +
'<p>%s</p>'.format(_('Make sure to clone the root filesystem using something like the commands below:')) +
'<pre>' +
'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' +
'</pre>'
;
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 <abbr title="Random Access Memory">RAM</abbr>. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the <abbr title="Random Access Memory">RAM</abbr>.'));
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 (<abbr title="for example">e.g.</abbr> <code>/dev/sda1</code>)'));
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();
}
});

View file

@ -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/*")

View file

@ -1,272 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- 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 (<em>%s</em>)" %{ 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 (<em>%s</em>)" %{ 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 (<em>%s</em>)" %{ 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 <abbr title=\"Random Access Memory\">RAM</abbr>. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the <abbr title=\"Random Access Memory\">RAM</abbr>."))
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

View file

@ -1,158 +0,0 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- 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 (<abbr title=\"for example\">e.g.</abbr> <code>/dev/sda1</code>)"))
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 = [[
<p>%s</p><pre>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</pre>
]] %{
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 (<abbr title=\"for example\">e.g.</abbr> <samp><abbr title=\"Third Extended Filesystem\">ext3</abbr></samp>)"))
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

View file

@ -1,54 +0,0 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- 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 (<abbr title=\"for example\">e.g.</abbr> <code>/dev/sda1</code>)"))
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