uvol: unbreak build and adapt to updated ucode

* Fix build which was broken by a wrong path in the Makefile.

Adapt to ucode commit 4618807 ("main: rework CLI frontend"):
 * ucode now no longer needs the {% %} around each code file, remove
   that and safe one level of indentation.
 * ARGV now no longer includes ucode executable and script itself

Fixes: 6350c7bc6 ("uvol: replace with re-write in ucode")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2022-03-31 21:41:17 +01:00
parent 8324c1fe06
commit 22d202e3a5
No known key found for this signature in database
GPG key ID: 5A8F39C31C3217CA
6 changed files with 932 additions and 943 deletions

View file

@ -67,7 +67,7 @@ define Package/autopart/install
endef endef
define Package/uvol/install define Package/uvol/install
$(INSTALL_DIR) $(1)/etc/init.d $(1)/usr/uvol/backends $(1)/usr/sbin $(1)/etc/uci-defaults $(INSTALL_DIR) $(1)/etc/init.d $(1)/usr/lib/uvol/backends $(1)/usr/sbin $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/uvol.init $(1)/etc/init.d/uvol $(INSTALL_BIN) ./files/uvol.init $(1)/etc/init.d/uvol
$(INSTALL_DATA) ./files/blockdev_common.uc $(1)/usr/lib/uvol/ $(INSTALL_DATA) ./files/blockdev_common.uc $(1)/usr/lib/uvol/
$(INSTALL_DATA) ./files/uci.uc $(1)/usr/lib/uvol/ $(INSTALL_DATA) ./files/uci.uc $(1)/usr/lib/uvol/

View file

@ -1,64 +1,64 @@
{%
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// Helper functions used to identify the boot device // Helper functions used to identify the boot device
// adapted from /lib/functions.sh
let cmdline_get_var = function(var) {
let cmdline = fs.open("/proc/cmdline", "r");
let allargs = cmdline.read("all");
cmdline.close();
let ret = null;
for (let arg in split(allargs, /[ \t\n]/)) {
let el = split(arg, "=");
if (shift(el) == var)
return join("=", el);
}
return ret;
};
// adapted from /lib/upgrade/common.sh // adapted from /lib/functions.sh
let get_blockdevs = function() { let cmdline_get_var = function(var) {
let devs = []; let cmdline = fs.open("/proc/cmdline", "r");
for (let dev in fs.glob('/dev/*')) let allargs = cmdline.read("all");
if (fs.stat(dev).type == "block") cmdline.close();
push(devs, split(dev, '/')[-1]); let ret = null;
for (let arg in split(allargs, /[ \t\n]/)) {
let el = split(arg, "=");
if (shift(el) == var)
return join("=", el);
}
return ret;
};
return devs; // adapted from /lib/upgrade/common.sh
}; let get_blockdevs = function() {
let devs = [];
for (let dev in fs.glob('/dev/*'))
if (fs.stat(dev).type == "block")
push(devs, split(dev, '/')[-1]);
// adapted from /lib/upgrade/common.sh return devs;
let get_uevent_major_minor = function(file) { };
let uevf = fs.open(file, "r");
if (!uevf)
return null;
let r = {}; // adapted from /lib/upgrade/common.sh
let evl; let get_uevent_major_minor = function(file) {
while ((evl = uevf.read("line"))) { let uevf = fs.open(file, "r");
let ev = split(evl, '='); if (!uevf)
if (ev[0] == "MAJOR") return null;
r.major = +ev[1];
if (ev[0] == "MINOR")
r.minor = +ev[1];
}
uevf.close();
return r;
};
// adapted from /lib/upgrade/common.sh let r = {};
let get_bootdev = function(void) { let evl;
let rootpart = cmdline_get_var("root"); while ((evl = uevf.read("line"))) {
let uevent = null; let ev = split(evl, '=');
if (ev[0] == "MAJOR")
r.major = +ev[1];
if (ev[0] == "MINOR")
r.minor = +ev[1];
}
uevf.close();
return r;
};
if (wildcard(rootpart, "PARTUUID=[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]-[a-f0-9][a-f0-9]")) { // adapted from /lib/upgrade/common.sh
let uuidarg = split(substr(rootpart, 9), '-')[0]; let get_bootdev = function(void) {
for (let bd in get_blockdevs()) { let rootpart = cmdline_get_var("root");
let bdf = fs.open(sprintf("/dev/%s", bd), "r"); let uevent = null;
bdf.seek(440);
let bduuid = bdf.read(4); if (wildcard(rootpart, "PARTUUID=[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]-[a-f0-9][a-f0-9]")) {
bdf.close(); let uuidarg = split(substr(rootpart, 9), '-')[0];
if (uuidarg == sprintf("%x%x%x%x", ord(bduuid, 3), ord(bduuid, 2), ord(bduuid, 1), ord(bduuid, 0))) { for (let bd in get_blockdevs()) {
uevent = sprintf("/sys/class/block/%s/uevent", bd); let bdf = fs.open(sprintf("/dev/%s", bd), "r");
break; bdf.seek(440);
let bduuid = bdf.read(4);
bdf.close();
if (uuidarg == sprintf("%x%x%x%x", ord(bduuid, 3), ord(bduuid, 2), ord(bduuid, 1), ord(bduuid, 0))) {
uevent = sprintf("/sys/class/block/%s/uevent", bd);
break;
} }
} }
} else if (wildcard(rootpart, "PARTUUID=????????-????-????-????-??????????0?/PARTNROFF=*") || } else if (wildcard(rootpart, "PARTUUID=????????-????-????-????-??????????0?/PARTNROFF=*") ||
@ -72,52 +72,52 @@
if (!bduuid) if (!bduuid)
continue; continue;
let uuid = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", let uuid = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
ord(bduuid, 3), ord(bduuid, 2), ord(bduuid, 1), ord(bduuid, 0), ord(bduuid, 3), ord(bduuid, 2), ord(bduuid, 1), ord(bduuid, 0),
ord(bduuid, 5), ord(bduuid, 4), ord(bduuid, 5), ord(bduuid, 4),
ord(bduuid, 7), ord(bduuid, 6), ord(bduuid, 7), ord(bduuid, 6),
ord(bduuid, 8), ord(bduuid, 9), ord(bduuid, 8), ord(bduuid, 9),
ord(bduuid, 10), ord(bduuid, 11), ord(bduuid, 12), ord(bduuid, 13), ord(bduuid, 14), ord(bduuid, 15)); ord(bduuid, 10), ord(bduuid, 11), ord(bduuid, 12), ord(bduuid, 13), ord(bduuid, 14), ord(bduuid, 15));
if (uuidarg == uuid) {
uevent = sprintf("/sys/class/block/%s/uevent", bd);
break;
}
}
} else if (wildcard(rootpart, "0x[a-f0-9][a-f0-9][a-f0-9]") ||
wildcard(rootpart, "0x[a-f0-9][a-f0-9][a-f0-9][a-f0-9]") ||
wildcard(rootpart, "[a-f0-9][a-f0-9][a-f0-9]") ||
wildcard(rootpart, "[a-f0-9][a-f0-9][a-f0-9][a-f0-9]")) {
let devid = rootpart;
if (substr(devid, 0, 2) == "0x")
devid = substr(devid, 2);
devid = hex(devid); if (uuidarg == uuid) {
for (let bd in get_blockdevs()) { uevent = sprintf("/sys/class/block/%s/uevent", bd);
let r = get_uevent_major_minor(sprintf("/sys/class/block/%s/uevent", bd));
if (r && (r.major == devid / 256) && (r.minor == devid % 256)) {
uevent = sprintf("/sys/class/block/%s/../uevent", bd);
break;
}
}
} else if (wildcard(rootpart, "/dev/*")) {
uevent = sprintf("/sys/class/block/%s/../uevent", split(rootpart, '/')[-1]);
}
return get_uevent_major_minor(uevent);
};
// adapted from /lib/upgrade/common.sh
let get_partition = function(dev, num) {
for (let bd in get_blockdevs()) {
let r = get_uevent_major_minor(sprintf("/sys/class/block/%s/uevent", bd));
if (r.major == dev.major && r.minor == dev.minor + num) {
return bd;
break; break;
} }
} }
return null; } else if (wildcard(rootpart, "0x[a-f0-9][a-f0-9][a-f0-9]") ||
}; wildcard(rootpart, "0x[a-f0-9][a-f0-9][a-f0-9][a-f0-9]") ||
wildcard(rootpart, "[a-f0-9][a-f0-9][a-f0-9]") ||
wildcard(rootpart, "[a-f0-9][a-f0-9][a-f0-9][a-f0-9]")) {
let devid = rootpart;
if (substr(devid, 0, 2) == "0x")
devid = substr(devid, 2);
blockdev_common = {}; devid = hex(devid);
blockdev_common.get_partition = get_partition; for (let bd in get_blockdevs()) {
blockdev_common.get_bootdev = get_bootdev; let r = get_uevent_major_minor(sprintf("/sys/class/block/%s/uevent", bd));
%} if (r && (r.major == devid / 256) && (r.minor == devid % 256)) {
uevent = sprintf("/sys/class/block/%s/../uevent", bd);
break;
}
}
} else if (wildcard(rootpart, "/dev/*")) {
uevent = sprintf("/sys/class/block/%s/../uevent", split(rootpart, '/')[-1]);
}
return get_uevent_major_minor(uevent);
};
// adapted from /lib/upgrade/common.sh
let get_partition = function(dev, num) {
for (let bd in get_blockdevs()) {
let r = get_uevent_major_minor(sprintf("/sys/class/block/%s/uevent", bd));
if (r.major == dev.major && r.minor == dev.minor + num) {
return bd;
break;
}
}
return null;
};
blockdev_common = {};
blockdev_common.get_partition = get_partition;
blockdev_common.get_bootdev = get_bootdev;

View file

@ -1,4 +1,3 @@
{%
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// LVM2 backend for uvol // LVM2 backend for uvol
// (c) 2022 Daniel Golle <daniel@makrotopia.org> // (c) 2022 Daniel Golle <daniel@makrotopia.org>
@ -10,458 +9,457 @@
// By setting the UCI option 'vg_name' in the 'uvol' section in /etc/config/fstab // By setting the UCI option 'vg_name' in the 'uvol' section in /etc/config/fstab
// you may set an arbitrary LVM2 volume group to back uvol instad. // you may set an arbitrary LVM2 volume group to back uvol instad.
let lvm_exec = "/sbin/lvm"; let lvm_exec = "/sbin/lvm";
function lvm(cmd, ...args) { function lvm(cmd, ...args) {
let lvm_json_cmds = [ "lvs", "pvs", "vgs" ]; let lvm_json_cmds = [ "lvs", "pvs", "vgs" ];
try { try {
let json_param = ""; let json_param = "";
if (cmd in lvm_json_cmds) if (cmd in lvm_json_cmds)
json_param = "--reportformat json --units b "; json_param = "--reportformat json --units b ";
let stdout = fs.popen(sprintf("LVM_SUPPRESS_FD_WARNINGS=1 %s %s %s%s", lvm_exec, cmd, json_param, join(" ", args))); let stdout = fs.popen(sprintf("LVM_SUPPRESS_FD_WARNINGS=1 %s %s %s%s", lvm_exec, cmd, json_param, join(" ", args)));
let tmp; let tmp;
if (stdout) { if (stdout) {
tmp = stdout.read("all"); tmp = stdout.read("all");
let ret = {}; let ret = {};
ret.retval = stdout.close(); ret.retval = stdout.close();
if (json_param) { if (json_param) {
let data = json(tmp); let data = json(tmp);
if (data.report) if (data.report)
ret.report = data.report[0]; ret.report = data.report[0];
} else {
ret.stdout = trim(tmp);
}
return ret;
} else { } else {
printf("lvm cli command failed: %s\n", fs.error()); ret.stdout = trim(tmp);
} }
} catch(e) { return ret;
printf("Failed to parse lvm cli output: %s\n%s\n", e, e.stacktrace[0].context);
}
return null;
}
function pvs() {
let fstab = cursor.get_all('fstab');
for (let k, section in fstab) {
if (section['.type'] != 'uvol' || !section.vg_name)
continue;
return section.vg_name;
}
include("/usr/lib/uvol/blockdev_common.uc");
let rootdev = blockdev_common.get_partition(blockdev_common.get_bootdev(), 0);
let tmp = lvm("pvs", "-o", "vg_name", "-S", sprintf("\"pv_name=~^/dev/%s.*\$\"", rootdev));
if (tmp.report.pv)
return tmp.report.pv[0].vg_name;
else
return null;
}
function vgs(vg_name) {
let tmp = lvm("vgs", "-o", "vg_extent_size,vg_extent_count,vg_free_count", "-S", sprintf("\"vg_name=%s\"", vg_name));
let ret = null;
if (tmp && tmp.report.vg) {
ret = tmp.report.vg;
for (let r in ret) {
r.vg_extent_size = +(rtrim(r.vg_extent_size, "B"));
r.vg_extent_count = +r.vg_extent_count;
r.vg_free_count = +r.vg_free_count;
}
}
if (ret)
return ret[0];
else
return null;
}
function lvs(vg_name, vol_name, extra_exp) {
let ret = [];
if (!vol_name)
vol_name = ".*";
let lvexpr = sprintf("\"lvname=~^[rw][owp]_%s\$ && vg_name=%s%s%s\"",
vol_name, vg_name, extra_exp?" && ":"", extra_exp?extra_exp:"");
let tmp = lvm("lvs", "-o", "lv_active,lv_name,lv_full_name,lv_size,lv_path,lv_dm_path", "-S", lvexpr);
if (tmp && tmp.report.lv) {
ret = tmp.report.lv;
for (let r in ret) {
r.lv_size = +(rtrim(r.lv_size, "B"));
r.lv_active = (r.lv_active == "active");
}
}
return ret;
}
function getdev(lv) {
if (!lv)
return null;
for (let dms in fs.glob("/sys/devices/virtual/block/dm-*")) {
let f = fs.open(sprintf("%s/dm/name", dms), "r");
if (!f)
continue;
let dm_name = trim(f.read("all"));
f.close();
if ( split(lv.lv_dm_path, '/')[-1] == dm_name )
return split(dms, '/')[-1]
}
return null;
}
function lvm_init(ctx) {
cursor = ctx.cursor;
fs = ctx.fs;
if (!fs.access(lvm_exec, "x"))
return false;
vg_name = pvs();
if (!vg_name)
return false;
vg = vgs(vg_name);
uvol_uci_add = ctx.uci_add;
uvol_uci_commit = ctx.uci_commit;
uvol_uci_remove = ctx.uci_remove;
uvol_uci_init = ctx.uci_init;
return true;
}
function lvm_free() {
if (!vg || !vg.vg_free_count || !vg.vg_extent_size)
return 2;
return sprintf("%d", vg.vg_free_count * vg.vg_extent_size);
}
function lvm_total() {
if (!vg || !vg.vg_extent_count || !vg.vg_extent_size)
return 2;
return sprintf("%d", vg.vg_extent_count * vg.vg_extent_size);
}
function lvm_align() {
if (!vg || !vg.vg_extent_size)
return 2;
return sprintf("%d", vg.vg_extent_size);
}
function lvm_list(vol_name) {
let vols = [];
if (!vg_name)
return vols;
let res = lvs(vg_name, vol_name);
for (let lv in res) {
let vol = {};
if (substr(lv.lv_name, 3, 1) == ".")
continue;
vol.name = substr(lv.lv_name, 3);
vol.mode = substr(lv.lv_name, 0, 2);
if (!lv.lv_active) {
if (vol.mode == "ro")
vol.mode = "rd";
if (vol.mode == "rw")
vol.mode = "wd";
}
vol.size = lv.lv_size;
push(vols, vol);
}
return vols;
}
function lvm_size(vol_name) {
if (!vol_name || !vg_name)
return 2;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
return sprintf("%d", res[0].lv_size);
}
function lvm_status(vol_name) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
let mode = substr(res[0].lv_name, 0, 2);
if ((mode != "ro" && mode != "rw") || !res[0].lv_active)
return 1;
return 0;
}
function lvm_device(vol_name) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
let mode = substr(res[0].lv_name, 0, 2);
if ((mode != "ro" && mode != "rw") || !res[0].lv_active)
return 22;
return getdev(res[0]);
}
function lvm_updown(vol_name, up) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
let lv = res[0];
if (!lv.lv_path)
return 2;
if (up && (wildcard(lv.lv_path, "/dev/*/wo_*") ||
wildcard(lv.lv_path, "/dev/*/wp_*")))
return 22;
if (up)
uvol_uci_commit(vol_name);
if (lv.lv_active == up)
return 0;
if (!up) {
let devname = getdev(lv);
if (devname)
system(sprintf("umount /dev/%s", devname));
}
let lvchange_r = lvm("lvchange", up?"-k":"-a", "n", lv.lv_full_name);
if (up && lvchange_r.retval != 0)
return lvchange_r.retval;
lvchange_r = lvm("lvchange", up?"-a":"-k", "y", lv.lv_full_name);
if (lvchange_r.retval != 0)
return lvchange_r.retval;
return 0
}
function lvm_up(vol_name) {
return lvm_updown(vol_name, true);
}
function lvm_down(vol_name) {
return lvm_updown(vol_name, false);
}
function lvm_create(vol_name, vol_size, vol_mode) {
if (!vol_name || !vg_name)
return 22;
vol_size = +vol_size;
if (vol_size <= 0)
return 22;
let res = lvs(vg_name, vol_name);
if (res[0])
return 17;
let size_ext = vol_size / vg.vg_extent_size;
if (vol_size % vg.vg_extent_size)
++size_ext;
let lvmode, mode;
if (vol_mode == "ro" || vol_mode == "wo") {
lvmode = "r";
mode = "wo";
} else if (vol_mode == "rw") {
lvmode = "rw";
mode = "wp";
} else { } else {
return 22; printf("lvm cli command failed: %s\n", fs.error());
} }
} catch(e) {
printf("Failed to parse lvm cli output: %s\n%s\n", e, e.stacktrace[0].context);
}
return null;
}
let ret = lvm("lvcreate", "-p", lvmode, "-a", "n", "-y", "-W", "n", "-Z", "n", "-n", sprintf("%s_%s", mode, vol_name), "-l", size_ext, vg_name); function pvs() {
if (ret.retval != 0 || lvmode == "r") let fstab = cursor.get_all('fstab');
for (let k, section in fstab) {
if (section['.type'] != 'uvol' || !section.vg_name)
continue;
return section.vg_name;
}
include("/usr/lib/uvol/blockdev_common.uc");
let rootdev = blockdev_common.get_partition(blockdev_common.get_bootdev(), 0);
let tmp = lvm("pvs", "-o", "vg_name", "-S", sprintf("\"pv_name=~^/dev/%s.*\$\"", rootdev));
if (tmp.report.pv)
return tmp.report.pv[0].vg_name;
else
return null;
}
function vgs(vg_name) {
let tmp = lvm("vgs", "-o", "vg_extent_size,vg_extent_count,vg_free_count", "-S", sprintf("\"vg_name=%s\"", vg_name));
let ret = null;
if (tmp && tmp.report.vg) {
ret = tmp.report.vg;
for (let r in ret) {
r.vg_extent_size = +(rtrim(r.vg_extent_size, "B"));
r.vg_extent_count = +r.vg_extent_count;
r.vg_free_count = +r.vg_free_count;
}
}
if (ret)
return ret[0];
else
return null;
}
function lvs(vg_name, vol_name, extra_exp) {
let ret = [];
if (!vol_name)
vol_name = ".*";
let lvexpr = sprintf("\"lvname=~^[rw][owp]_%s\$ && vg_name=%s%s%s\"",
vol_name, vg_name, extra_exp?" && ":"", extra_exp?extra_exp:"");
let tmp = lvm("lvs", "-o", "lv_active,lv_name,lv_full_name,lv_size,lv_path,lv_dm_path", "-S", lvexpr);
if (tmp && tmp.report.lv) {
ret = tmp.report.lv;
for (let r in ret) {
r.lv_size = +(rtrim(r.lv_size, "B"));
r.lv_active = (r.lv_active == "active");
}
}
return ret;
}
function getdev(lv) {
if (!lv)
return null;
for (let dms in fs.glob("/sys/devices/virtual/block/dm-*")) {
let f = fs.open(sprintf("%s/dm/name", dms), "r");
if (!f)
continue;
let dm_name = trim(f.read("all"));
f.close();
if ( split(lv.lv_dm_path, '/')[-1] == dm_name )
return split(dms, '/')[-1]
}
return null;
}
function lvm_init(ctx) {
cursor = ctx.cursor;
fs = ctx.fs;
if (!fs.access(lvm_exec, "x"))
return false;
vg_name = pvs();
if (!vg_name)
return false;
vg = vgs(vg_name);
uvol_uci_add = ctx.uci_add;
uvol_uci_commit = ctx.uci_commit;
uvol_uci_remove = ctx.uci_remove;
uvol_uci_init = ctx.uci_init;
return true;
}
function lvm_free() {
if (!vg || !vg.vg_free_count || !vg.vg_extent_size)
return 2;
return sprintf("%d", vg.vg_free_count * vg.vg_extent_size);
}
function lvm_total() {
if (!vg || !vg.vg_extent_count || !vg.vg_extent_size)
return 2;
return sprintf("%d", vg.vg_extent_count * vg.vg_extent_size);
}
function lvm_align() {
if (!vg || !vg.vg_extent_size)
return 2;
return sprintf("%d", vg.vg_extent_size);
}
function lvm_list(vol_name) {
let vols = [];
if (!vg_name)
return vols;
let res = lvs(vg_name, vol_name);
for (let lv in res) {
let vol = {};
if (substr(lv.lv_name, 3, 1) == ".")
continue;
vol.name = substr(lv.lv_name, 3);
vol.mode = substr(lv.lv_name, 0, 2);
if (!lv.lv_active) {
if (vol.mode == "ro")
vol.mode = "rd";
if (vol.mode == "rw")
vol.mode = "wd";
}
vol.size = lv.lv_size;
push(vols, vol);
}
return vols;
}
function lvm_size(vol_name) {
if (!vol_name || !vg_name)
return 2;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
return sprintf("%d", res[0].lv_size);
}
function lvm_status(vol_name) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
let mode = substr(res[0].lv_name, 0, 2);
if ((mode != "ro" && mode != "rw") || !res[0].lv_active)
return 1;
return 0;
}
function lvm_device(vol_name) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
let mode = substr(res[0].lv_name, 0, 2);
if ((mode != "ro" && mode != "rw") || !res[0].lv_active)
return 22;
return getdev(res[0]);
}
function lvm_updown(vol_name, up) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
let lv = res[0];
if (!lv.lv_path)
return 2;
if (up && (wildcard(lv.lv_path, "/dev/*/wo_*") ||
wildcard(lv.lv_path, "/dev/*/wp_*")))
return 22;
if (up)
uvol_uci_commit(vol_name);
if (lv.lv_active == up)
return 0;
if (!up) {
let devname = getdev(lv);
if (devname)
system(sprintf("umount /dev/%s", devname));
}
let lvchange_r = lvm("lvchange", up?"-k":"-a", "n", lv.lv_full_name);
if (up && lvchange_r.retval != 0)
return lvchange_r.retval;
lvchange_r = lvm("lvchange", up?"-a":"-k", "y", lv.lv_full_name);
if (lvchange_r.retval != 0)
return lvchange_r.retval;
return 0
}
function lvm_up(vol_name) {
return lvm_updown(vol_name, true);
}
function lvm_down(vol_name) {
return lvm_updown(vol_name, false);
}
function lvm_create(vol_name, vol_size, vol_mode) {
if (!vol_name || !vg_name)
return 22;
vol_size = +vol_size;
if (vol_size <= 0)
return 22;
let res = lvs(vg_name, vol_name);
if (res[0])
return 17;
let size_ext = vol_size / vg.vg_extent_size;
if (vol_size % vg.vg_extent_size)
++size_ext;
let lvmode, mode;
if (vol_mode == "ro" || vol_mode == "wo") {
lvmode = "r";
mode = "wo";
} else if (vol_mode == "rw") {
lvmode = "rw";
mode = "wp";
} else {
return 22;
}
let ret = lvm("lvcreate", "-p", lvmode, "-a", "n", "-y", "-W", "n", "-Z", "n", "-n", sprintf("%s_%s", mode, vol_name), "-l", size_ext, vg_name);
if (ret.retval != 0 || lvmode == "r")
return ret.retval;
let lv = lvs(vg_name, vol_name);
if (!lv[0] || !lv[0].lv_full_name)
return 22;
lv = lv[0];
let ret = lvm("lvchange", "-a", "y", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval;
let use_f2fs = (lv.lv_size > (100 * 1024 * 1024));
if (use_f2fs) {
let mkfs_ret = system(sprintf("/usr/sbin/mkfs.f2fs -f -l \"%s\" \"%s\"", vol_name, lv.lv_path));
if (mkfs_ret != 0 && mkfs_ret != 134) {
lvchange_r = lvm("lvchange", "-a", "n", lv.lv_full_name);
if (lvchange_r.retval != 0)
return lvchange_r.retval;
return mkfs_ret;
}
} else {
let mkfs_ret = system(sprintf("/usr/sbin/mke2fs -F -L \"%s\" \"%s\"", vol_name, lv.lv_path));
if (mkfs_ret != 0) {
lvchange_r = lvm("lvchange", "-a", "n", lv.lv_full_name);
if (lvchange_r.retval != 0)
return lvchange_r.retval;
return mkfs_ret;
}
}
uvol_uci_add(vol_name, sprintf("/dev/%s", getdev(lv)), "rw");
ret = lvm("lvchange", "-a", "n", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval;
ret = lvm("lvrename", vg_name, sprintf("wp_%s", vol_name), sprintf("rw_%s", vol_name));
if (ret.retval != 0)
return ret.retval;
return 0;
}
function lvm_remove(vol_name) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
if (res[0].lv_active)
return 16;
let ret = lvm("lvremove", "-y", res[0].lv_full_name);
if (ret.retval != 0)
return ret.retval;
uvol_uci_remove(vol_name);
uvol_uci_commit(vol_name);
return 0;
}
function lvm_dd(in_fd, out_fd, vol_size) {
let rem = vol_size;
let buf;
while ((buf = in_fd.read(vg.vg_extent_size)) && (rem > 0)) {
rem -= length(buf);
if (rem < 0) {
buf = substr(buf, 0, rem);
}
out_fd.write(buf);
}
return rem;
}
function lvm_write(vol_name, vol_size) {
if (!vol_name || !vg_name)
return 22;
let lv = lvs(vg_name, vol_name);
if (!lv[0] || !lv[0].lv_full_name)
return 2;
lv = lv[0];
vol_size = +vol_size;
if (vol_size > lv.lv_size)
return 27;
if (wildcard(lv.lv_path, "/dev/*/wo_*")) {
let ret = lvm("lvchange", "-p", "rw", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval; return ret.retval;
let lv = lvs(vg_name, vol_name);
if (!lv[0] || !lv[0].lv_full_name)
return 22;
lv = lv[0];
let ret = lvm("lvchange", "-a", "y", lv.lv_full_name); let ret = lvm("lvchange", "-a", "y", lv.lv_full_name);
if (ret.retval != 0) if (ret.retval != 0)
return ret.retval; return ret.retval;
let use_f2fs = (lv.lv_size > (100 * 1024 * 1024)); let volfile = fs.open(lv.lv_path, "w");
if (use_f2fs) { let ret = lvm_dd(fs.stdin, volfile, vol_size);
let mkfs_ret = system(sprintf("/usr/sbin/mkfs.f2fs -f -l \"%s\" \"%s\"", vol_name, lv.lv_path)); volfile.close();
if (mkfs_ret != 0 && mkfs_ret != 134) { if (ret < 0) {
lvchange_r = lvm("lvchange", "-a", "n", lv.lv_full_name); printf("more %d bytes data than given size!\n", -ret);
if (lvchange_r.retval != 0)
return lvchange_r.retval;
return mkfs_ret;
}
} else {
let mkfs_ret = system(sprintf("/usr/sbin/mke2fs -F -L \"%s\" \"%s\"", vol_name, lv.lv_path));
if (mkfs_ret != 0) {
lvchange_r = lvm("lvchange", "-a", "n", lv.lv_full_name);
if (lvchange_r.retval != 0)
return lvchange_r.retval;
return mkfs_ret;
}
} }
uvol_uci_add(vol_name, sprintf("/dev/%s", getdev(lv)), "rw");
ret = lvm("lvchange", "-a", "n", lv.lv_full_name); if (ret > 0) {
printf("reading finished %d bytes before given size!\n", ret);
}
uvol_uci_add(vol_name, sprintf("/dev/%s", getdev(lv)), "ro");
let ret = lvm("lvchange", "-a", "n", lv.lv_full_name);
if (ret.retval != 0) if (ret.retval != 0)
return ret.retval; return ret.retval;
ret = lvm("lvrename", vg_name, sprintf("wp_%s", vol_name), sprintf("rw_%s", vol_name)); let ret = lvm("lvchange", "-p", "r", lv.lv_full_name);
if (ret.retval != 0) if (ret.retval != 0)
return ret.retval; return ret.retval;
return 0; let ret = lvm("lvrename", vg_name, sprintf("wo_%s", vol_name), sprintf("ro_%s", vol_name));
}
function lvm_remove(vol_name) {
if (!vol_name || !vg_name)
return 22;
let res = lvs(vg_name, vol_name);
if (!res[0])
return 2;
if (res[0].lv_active)
return 16;
let ret = lvm("lvremove", "-y", res[0].lv_full_name);
if (ret.retval != 0) if (ret.retval != 0)
return ret.retval; return ret.retval;
uvol_uci_remove(vol_name); } else {
uvol_uci_commit(vol_name); return 22;
return 0;
} }
return 0;
}
function lvm_dd(in_fd, out_fd, vol_size) { function lvm_detect() {
let rem = vol_size; let temp_up = [];
let buf; let inactive_lv = lvs(vg_name, null, "lv_skip_activation!=0");
while ((buf = in_fd.read(vg.vg_extent_size)) && (rem > 0)) { for (let lv in inactive_lv) {
rem -= length(buf); lvm("lvchange", "-k", "n", lv.lv_full_name);
if (rem < 0) { lvm("lvchange", "-a", "y", lv.lv_full_name);
buf = substr(buf, 0, rem); push(temp_up, lv.lv_full_name);
}
out_fd.write(buf);
}
return rem;
} }
sleep(1000);
function lvm_write(vol_name, vol_size) { uvol_uci_init();
if (!vol_name || !vg_name) for (let lv in lvs(vg_name)) {
return 22; let vol_name = substr(lv.lv_name, 3);
let vol_mode = substr(lv.lv_name, 0, 2);
let lv = lvs(vg_name, vol_name); uvol_uci_add(vol_name, sprintf("/dev/%s", getdev(lv)), vol_mode);
if (!lv[0] || !lv[0].lv_full_name)
return 2;
lv = lv[0];
vol_size = +vol_size;
if (vol_size > lv.lv_size)
return 27;
if (wildcard(lv.lv_path, "/dev/*/wo_*")) {
let ret = lvm("lvchange", "-p", "rw", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval;
let ret = lvm("lvchange", "-a", "y", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval;
let volfile = fs.open(lv.lv_path, "w");
let ret = lvm_dd(fs.stdin, volfile, vol_size);
volfile.close();
if (ret < 0) {
printf("more %d bytes data than given size!\n", -ret);
}
if (ret > 0) {
printf("reading finished %d bytes before given size!\n", ret);
}
uvol_uci_add(vol_name, sprintf("/dev/%s", getdev(lv)), "ro");
let ret = lvm("lvchange", "-a", "n", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval;
let ret = lvm("lvchange", "-p", "r", lv.lv_full_name);
if (ret.retval != 0)
return ret.retval;
let ret = lvm("lvrename", vg_name, sprintf("wo_%s", vol_name), sprintf("ro_%s", vol_name));
if (ret.retval != 0)
return ret.retval;
} else {
return 22;
}
return 0;
} }
uvol_uci_commit();
function lvm_detect() { for (let lv_full_name in temp_up) {
let temp_up = []; lvm("lvchange", "-a", "n", lv_full_name);
let inactive_lv = lvs(vg_name, null, "lv_skip_activation!=0"); lvm("lvchange", "-k", "y", lv_full_name);
for (let lv in inactive_lv) {
lvm("lvchange", "-k", "n", lv.lv_full_name);
lvm("lvchange", "-a", "y", lv.lv_full_name);
push(temp_up, lv.lv_full_name);
}
sleep(1000);
uvol_uci_init();
for (let lv in lvs(vg_name)) {
let vol_name = substr(lv.lv_name, 3);
let vol_mode = substr(lv.lv_name, 0, 2);
uvol_uci_add(vol_name, sprintf("/dev/%s", getdev(lv)), vol_mode);
}
uvol_uci_commit();
for (let lv_full_name in temp_up) {
lvm("lvchange", "-a", "n", lv_full_name);
lvm("lvchange", "-k", "y", lv_full_name);
}
return 0;
} }
return 0;
}
function lvm_boot() { function lvm_boot() {
return 0; return 0;
} }
backend.backend = "LVM"; backend.backend = "LVM";
backend.priority = 50; backend.priority = 50;
backend.init = lvm_init; backend.init = lvm_init;
backend.boot = lvm_boot; backend.boot = lvm_boot;
backend.detect = lvm_detect; backend.detect = lvm_detect;
backend.free = lvm_free; backend.free = lvm_free;
backend.align = lvm_align; backend.align = lvm_align;
backend.total = lvm_total; backend.total = lvm_total;
backend.list = lvm_list; backend.list = lvm_list;
backend.size = lvm_size; backend.size = lvm_size;
backend.status = lvm_status; backend.status = lvm_status;
backend.device = lvm_device; backend.device = lvm_device;
backend.up = lvm_up; backend.up = lvm_up;
backend.down = lvm_down; backend.down = lvm_down;
backend.create = lvm_create; backend.create = lvm_create;
backend.remove = lvm_remove; backend.remove = lvm_remove;
backend.write = lvm_write; backend.write = lvm_write;
%}

View file

@ -1,378 +1,376 @@
{%
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// UBI backend for uvol // UBI backend for uvol
// (c) 2022 Daniel Golle <daniel@makrotopia.org> // (c) 2022 Daniel Golle <daniel@makrotopia.org>
// //
// This plugin uses UBI on NAND flash as a storage backend for uvol. // This plugin uses UBI on NAND flash as a storage backend for uvol.
function read_file(file) { function read_file(file) {
let fp = fs.open(file); let fp = fs.open(file);
if (!fp) if (!fp)
return null;
let var = rtrim(fp.read("all"));
fp.close();
return var;
}
function mkdtemp() {
math = require("math");
let r1 = math.rand();
let r2 = math.rand();
let randbytes = chr((r1 >> 24) & 0xff, (r1 >> 16) & 0xff, (r1 >> 8) & 0xff, r1 & 0xff,
(r2 >> 24) & 0xff, (r2 >> 16) & 0xff, (r2 >> 8) & 0xff, r2 & 0xff);
let randstr = replace(b64enc(randbytes), /[\/-_.=]/g, "");
let dirname = sprintf("/tmp/uvol-%s", randstr);
fs.mkdir(dirname, 0700);
return dirname;
}
function ubi_get_dev(vol_name) {
let wcstring = sprintf("uvol-[rw][owpd]-%s", vol_name);
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (wildcard(vol_ubiname, wcstring))
return fs.basename(vol_dir);
}
return null; return null;
}
function vol_get_mode(vol_dev, mode) { let var = rtrim(fp.read("all"));
let vol_name = read_file(sprintf("/sys/devices/virtual/ubi/%s/%s/name", ubidev, vol_dev)); fp.close();
return substr(vol_name, 5, 2); return var;
} }
function mkubifs(vol_dev) { function mkdtemp() {
let temp_mp = mkdtemp(); math = require("math");
system(sprintf("mount -t ubifs /dev/%s %s", vol_dev, temp_mp)); let r1 = math.rand();
system(sprintf("umount %s", temp_mp)); let r2 = math.rand();
fs.rmdir(temp_mp); let randbytes = chr((r1 >> 24) & 0xff, (r1 >> 16) & 0xff, (r1 >> 8) & 0xff, r1 & 0xff,
(r2 >> 24) & 0xff, (r2 >> 16) & 0xff, (r2 >> 8) & 0xff, r2 & 0xff);
let randstr = replace(b64enc(randbytes), /[\/-_.=]/g, "");
let dirname = sprintf("/tmp/uvol-%s", randstr);
fs.mkdir(dirname, 0700);
return dirname;
}
function ubi_get_dev(vol_name) {
let wcstring = sprintf("uvol-[rw][owpd]-%s", vol_name);
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (wildcard(vol_ubiname, wcstring))
return fs.basename(vol_dir);
}
return null;
}
function vol_get_mode(vol_dev, mode) {
let vol_name = read_file(sprintf("/sys/devices/virtual/ubi/%s/%s/name", ubidev, vol_dev));
return substr(vol_name, 5, 2);
}
function mkubifs(vol_dev) {
let temp_mp = mkdtemp();
system(sprintf("mount -t ubifs /dev/%s %s", vol_dev, temp_mp));
system(sprintf("umount %s", temp_mp));
fs.rmdir(temp_mp);
return 0;
}
function block_hotplug(action, devname) {
return system(sprintf("ACTION=%s DEVNAME=%s /sbin/block hotplug", action, devname));
}
function ubi_init(ctx) {
cursor = ctx.cursor;
fs = ctx.fs;
let ubiver = read_file("/sys/class/ubi/version");
if (ubiver != 1)
return false;
let ubidevpath = null;
for (ubidevpath in fs.glob("/sys/devices/virtual/ubi/*"))
break;
if (!ubidevpath)
return false;
ubidev = fs.basename(ubidevpath);
ebsize = read_file(sprintf("%s/eraseblock_size", ubidevpath));
uvol_uci_add = ctx.uci_add;
uvol_uci_commit = ctx.uci_commit;
uvol_uci_remove = ctx.uci_remove;
uvol_uci_init = ctx.uci_init;
return true;
}
function ubi_free() {
let availeb = read_file(sprintf("/sys/devices/virtual/ubi/%s/avail_eraseblocks", ubidev));
return sprintf("%d", availeb * ebsize);
}
function ubi_align() {
return sprintf("%d", ebsize);
}
function ubi_total() {
let totaleb = read_file(sprintf("/sys/devices/virtual/ubi/%s/total_eraseblocks", ubidev));
return sprintf("%d", totaleb * ebsize);
}
function ubi_status(vol_name) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "wo") return 22;
if (vol_mode == "wp") return 16;
if (vol_mode == "wd") return 1;
if (vol_mode == "ro" &&
!fs.access(sprintf("/dev/ubiblock%s", substr(vol_dev, 3)), "r")) return 1;
return 0;
}
function ubi_size(vol_name) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let vol_size = read_file(sprintf("/sys/devices/virtual/ubi/%s/%s/data_bytes", ubidev, vol_dev));
return sprintf("%d", vol_size);
}
function ubi_device(vol_name) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "ro")
return sprintf("/dev/ubiblock%s", substr(vol_dev, 3));
else if (vol_mode == "rw")
return sprintf("/dev/%s", vol_dev);
return null;
}
function ubi_create(vol_name, vol_size, vol_mode) {
let vol_dev = ubi_get_dev(vol_name);
if (vol_dev)
return 17;
let mode;
if (vol_mode == "ro" || vol_mode == "wo")
mode = "wo";
else if (vol_mode == "rw")
mode = "wp";
else
return 22;
let vol_size = +vol_size;
if (vol_size <= 0)
return 22;
let ret = system(sprintf("ubimkvol /dev/%s -N \"uvol-%s-%s\" -s %d", ubidev, mode, vol_name, vol_size));
if (ret != 0)
return ret;
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let ret = system(sprintf("ubiupdatevol -t /dev/%s", vol_dev));
if (ret != 0)
return ret;
if (mode != "wp")
return 0; return 0;
}
function block_hotplug(action, devname) { let ret = mkubifs(vol_dev);
return system(sprintf("ACTION=%s DEVNAME=%s /sbin/block hotplug", action, devname)); if (ret != 0)
} return ret;
function ubi_init(ctx) { uvol_uci_add(vol_name, sprintf("/dev/%s", vol_dev), "rw");
cursor = ctx.cursor;
fs = ctx.fs;
let ubiver = read_file("/sys/class/ubi/version"); let ret = system(sprintf("ubirename /dev/%s \"uvol-wp-%s\" \"uvol-wd-%s\"", ubidev, vol_name, vol_name));
if (ubiver != 1) if (ret != 0)
return false; return ret;
let ubidevpath = null; return 0;
for (ubidevpath in fs.glob("/sys/devices/virtual/ubi/*")) }
break;
if (!ubidevpath) function ubi_remove(vol_name) {
return false; let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
ubidev = fs.basename(ubidevpath); let vol_mode = vol_get_mode(vol_dev);
ebsize = read_file(sprintf("%s/eraseblock_size", ubidevpath)); if (vol_mode == "rw" || vol_mode == "ro")
return 16;
uvol_uci_add = ctx.uci_add; let volnum = split(vol_dev, "_")[1];
uvol_uci_commit = ctx.uci_commit;
uvol_uci_remove = ctx.uci_remove;
uvol_uci_init = ctx.uci_init;
return true; let ret = system(sprintf("ubirmvol /dev/%s -n %d", ubidev, volnum));
} if (ret != 0)
return ret;
function ubi_free() { uvol_uci_remove(vol_name);
let availeb = read_file(sprintf("/sys/devices/virtual/ubi/%s/avail_eraseblocks", ubidev)); uvol_uci_commit(vol_name);
return sprintf("%d", availeb * ebsize);
}
function ubi_align() { return 0;
return sprintf("%d", ebsize); }
}
function ubi_total() { function ubi_up(vol_name) {
let totaleb = read_file(sprintf("/sys/devices/virtual/ubi/%s/total_eraseblocks", ubidev)); let vol_dev = ubi_get_dev(vol_name);
return sprintf("%d", totaleb * ebsize); if (!vol_dev)
} return 2;
function ubi_status(vol_name) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "wo") return 22;
if (vol_mode == "wp") return 16;
if (vol_mode == "wd") return 1;
if (vol_mode == "ro" &&
!fs.access(sprintf("/dev/ubiblock%s", substr(vol_dev, 3)), "r")) return 1;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "rw" || vol_mode == "ro")
return 0; return 0;
} else if (vol_mode == "wo")
return 22;
else if (vol_mode == "wp")
return 16;
function ubi_size(vol_name) { uvol_uci_commit(vol_name);
let vol_dev = ubi_get_dev(vol_name); if (vol_mode == "rd") {
if (!vol_dev) let ret = system(sprintf("ubirename /dev/%s \"uvol-rd-%s\" \"uvol-ro-%s\"", ubidev, vol_name, vol_name));
return 2;
let vol_size = read_file(sprintf("/sys/devices/virtual/ubi/%s/%s/data_bytes", ubidev, vol_dev));
return sprintf("%d", vol_size);
}
function ubi_device(vol_name) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "ro")
return sprintf("/dev/ubiblock%s", substr(vol_dev, 3));
else if (vol_mode == "rw")
return sprintf("/dev/%s", vol_dev);
return null;
}
function ubi_create(vol_name, vol_size, vol_mode) {
let vol_dev = ubi_get_dev(vol_name);
if (vol_dev)
return 17;
let mode;
if (vol_mode == "ro" || vol_mode == "wo")
mode = "wo";
else if (vol_mode == "rw")
mode = "wp";
else
return 22;
let vol_size = +vol_size;
if (vol_size <= 0)
return 22;
let ret = system(sprintf("ubimkvol /dev/%s -N \"uvol-%s-%s\" -s %d", ubidev, mode, vol_name, vol_size));
if (ret != 0) if (ret != 0)
return ret; return ret;
let vol_dev = ubi_get_dev(vol_name); return system(sprintf("ubiblock --create /dev/%s", vol_dev));
if (!vol_dev) } else if (vol_mode == "wd") {
return 2; let ret = system(sprintf("ubirename /dev/%s \"uvol-wd-%s\" \"uvol-rw-%s\"", ubidev, vol_name, vol_name));
let ret = system(sprintf("ubiupdatevol -t /dev/%s", vol_dev));
if (ret != 0) if (ret != 0)
return ret; return ret;
if (mode != "wp") return block_hotplug("add", vol_dev);
return 0; }
return 0;
}
let ret = mkubifs(vol_dev); function ubi_down(vol_name) {
if (ret != 0) let vol_dev = ubi_get_dev(vol_name);
return ret; if (!vol_dev)
return 2;
uvol_uci_add(vol_name, sprintf("/dev/%s", vol_dev), "rw");
let ret = system(sprintf("ubirename /dev/%s \"uvol-wp-%s\" \"uvol-wd-%s\"", ubidev, vol_name, vol_name));
if (ret != 0)
return ret;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "rd" || vol_mode == "wd")
return 0; return 0;
else if (vol_mode == "wo")
return 22;
else if (vol_mode == "wp")
return 16;
else if (vol_mode == "ro") {
system(sprintf("umount /dev/ubiblock%s 2>&1 >/dev/null", substr(vol_dev, 3)));
system(sprintf("ubiblock --remove /dev/%s", vol_dev));
let ret = system(sprintf("ubirename /dev/%s \"uvol-ro-%s\" \"uvol-rd-%s\"", ubidev, vol_name, vol_name));
return ret;
} else if (vol_mode == "rw") {
system(sprintf("umount /dev/%s 2>&1 >/dev/null", vol_dev));
let ret = system(sprintf("ubirename /dev/%s \"uvol-rw-%s\" \"uvol-wd-%s\"", ubidev, vol_name, vol_name));
block_hotplug("remove", vol_dev);
return ret;
} }
return 0;
}
function ubi_remove(vol_name) { function ubi_list(search_name) {
let vol_dev = ubi_get_dev(vol_name); let volumes = [];
if (!vol_dev) for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
return 2; let vol = {};
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-[rw][wod]-*"))
continue;
let vol_mode = vol_get_mode(vol_dev); let vol_mode = substr(vol_ubiname, 5, 2);
if (vol_mode == "rw" || vol_mode == "ro") let vol_name = substr(vol_ubiname, 8);
return 16; let vol_size = read_file(sprintf("%s/data_bytes", vol_dir));
if (substr(vol_name, 0, 1) == ".")
continue;
let volnum = split(vol_dev, "_")[1]; vol.name = vol_name;
vol.mode = vol_mode;
let ret = system(sprintf("ubirmvol /dev/%s -n %d", ubidev, volnum)); vol.size = vol_size;
if (ret != 0) push(volumes, vol);
return ret;
uvol_uci_remove(vol_name);
uvol_uci_commit(vol_name);
return 0;
} }
return volumes;
}
function ubi_up(vol_name) { function ubi_detect() {
let vol_dev = ubi_get_dev(vol_name); let tmpdev = [];
if (!vol_dev) for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
return 2; let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
let vol_mode = vol_get_mode(vol_dev); if (!wildcard(vol_ubiname, "uvol-r[od]-*"))
if (vol_mode == "rw" || vol_mode == "ro") continue;
return 0;
else if (vol_mode == "wo")
return 22;
else if (vol_mode == "wp")
return 16;
uvol_uci_commit(vol_name); let vol_name = substr(vol_ubiname, 8);
if (vol_mode == "rd") { let vol_mode = substr(vol_ubiname, 5, 2);
let ret = system(sprintf("ubirename /dev/%s \"uvol-rd-%s\" \"uvol-ro-%s\"", ubidev, vol_name, vol_name)); let vol_dev = fs.basename(vol_dir);
if (ret != 0)
return ret;
return system(sprintf("ubiblock --create /dev/%s", vol_dev)); ret = system(sprintf("ubiblock --create /dev/%s", vol_dev));
} else if (vol_mode == "wd") {
let ret = system(sprintf("ubirename /dev/%s \"uvol-wd-%s\" \"uvol-rw-%s\"", ubidev, vol_name, vol_name));
if (ret != 0)
return ret;
return block_hotplug("add", vol_dev);
}
return 0;
}
function ubi_down(vol_name) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode == "rd" || vol_mode == "wd")
return 0;
else if (vol_mode == "wo")
return 22;
else if (vol_mode == "wp")
return 16;
else if (vol_mode == "ro") {
system(sprintf("umount /dev/ubiblock%s 2>&1 >/dev/null", substr(vol_dev, 3)));
system(sprintf("ubiblock --remove /dev/%s", vol_dev));
let ret = system(sprintf("ubirename /dev/%s \"uvol-ro-%s\" \"uvol-rd-%s\"", ubidev, vol_name, vol_name));
return ret;
} else if (vol_mode == "rw") {
system(sprintf("umount /dev/%s 2>&1 >/dev/null", vol_dev));
let ret = system(sprintf("ubirename /dev/%s \"uvol-rw-%s\" \"uvol-wd-%s\"", ubidev, vol_name, vol_name));
block_hotplug("remove", vol_dev);
return ret;
}
return 0;
}
function ubi_list(search_name) {
let volumes = [];
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol = {};
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-[rw][wod]-*"))
continue;
let vol_mode = substr(vol_ubiname, 5, 2);
let vol_name = substr(vol_ubiname, 8);
let vol_size = read_file(sprintf("%s/data_bytes", vol_dir));
if (substr(vol_name, 0, 1) == ".")
continue;
vol.name = vol_name;
vol.mode = vol_mode;
vol.size = vol_size;
push(volumes, vol);
}
return volumes;
}
function ubi_detect() {
let tmpdev = [];
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-r[od]-*"))
continue;
let vol_name = substr(vol_ubiname, 8);
let vol_mode = substr(vol_ubiname, 5, 2);
let vol_dev = fs.basename(vol_dir);
ret = system(sprintf("ubiblock --create /dev/%s", vol_dev));
if (ret)
continue;
if (vol_mode == "rd")
push(tmpdev, vol_dev);
}
uvol_uci_init();
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-[rw][wod]-*"))
continue;
let vol_dev = fs.basename(vol_dir);
let vol_name = substr(vol_ubiname, 8);
let vol_mode = substr(vol_ubiname, 5, 2);
if (vol_mode == "ro" || vol_mode == "rd")
uvol_uci_add(vol_name, sprintf("/dev/ubiblock%s", substr(vol_dev, 3)), "ro");
else if (vol_mode == "rw" || vol_mode == "wd")
uvol_uci_add(vol_name, sprintf("/dev/%s", vol_dev), "rw");
}
uvol_uci_commit();
for (vol_dev in tmpdev)
system(sprintf("ubiblock --remove /dev/%s", vol_dev));
return 0;
}
function ubi_boot() {
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_dev = fs.basename(vol_dir);
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-ro-*"))
continue;
system(sprintf("ubiblock --create /dev/%s", vol_dev));
}
}
function ubi_write(vol_name, write_size) {
let vol_dev = ubi_get_dev(vol_name);
if (!vol_dev)
return 2;
write_size = +write_size;
if (write_size <= 0)
return 22;
let vol_mode = vol_get_mode(vol_dev);
if (vol_mode != "wo")
return 22;
let ret = system(sprintf("ubiupdatevol -s %s /dev/%s -", write_size, vol_dev));
if (ret) if (ret)
return ret; continue;
if (vol_mode == "rd")
push(tmpdev, vol_dev);
}
uvol_uci_init();
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-[rw][wod]-*"))
continue;
let vol_dev = fs.basename(vol_dir);
let vol_name = substr(vol_ubiname, 8);
let vol_mode = substr(vol_ubiname, 5, 2);
if (vol_mode == "ro" || vol_mode == "rd")
uvol_uci_add(vol_name, sprintf("/dev/ubiblock%s", substr(vol_dev, 3)), "ro");
else if (vol_mode == "rw" || vol_mode == "wd")
uvol_uci_add(vol_name, sprintf("/dev/%s", vol_dev), "rw");
}
uvol_uci_commit();
for (vol_dev in tmpdev)
system(sprintf("ubiblock --remove /dev/%s", vol_dev));
return 0;
}
function ubi_boot() {
for (vol_dir in fs.glob(sprintf("/sys/devices/virtual/ubi/%s/%s_*", ubidev, ubidev))) {
let vol_dev = fs.basename(vol_dir);
let vol_ubiname = read_file(sprintf("%s/name", vol_dir));
if (!wildcard(vol_ubiname, "uvol-ro-*"))
continue;
system(sprintf("ubiblock --create /dev/%s", vol_dev)); system(sprintf("ubiblock --create /dev/%s", vol_dev));
uvol_uci_add(vol_name, sprintf("/dev/ubiblock%s", substr(vol_dev, 3)), "ro");
system(sprintf("ubiblock --remove /dev/%s", vol_dev));
system(sprintf("ubirename /dev/%s \"uvol-wo-%s\" \"uvol-rd-%s\"", ubidev, vol_name, vol_name));
return 0;
} }
}
backend.backend = "UBI"; function ubi_write(vol_name, write_size) {
backend.priority = 20; let vol_dev = ubi_get_dev(vol_name);
backend.init = ubi_init; if (!vol_dev)
backend.boot = ubi_boot; return 2;
backend.detect = ubi_detect;
backend.free = ubi_free; write_size = +write_size;
backend.align = ubi_align; if (write_size <= 0)
backend.total = ubi_total; return 22;
backend.list = ubi_list;
backend.size = ubi_size; let vol_mode = vol_get_mode(vol_dev);
backend.status = ubi_status; if (vol_mode != "wo")
backend.device = ubi_device; return 22;
backend.up = ubi_up;
backend.down = ubi_down; let ret = system(sprintf("ubiupdatevol -s %s /dev/%s -", write_size, vol_dev));
backend.create = ubi_create; if (ret)
backend.remove = ubi_remove; return ret;
backend.write = ubi_write;
%} system(sprintf("ubiblock --create /dev/%s", vol_dev));
uvol_uci_add(vol_name, sprintf("/dev/ubiblock%s", substr(vol_dev, 3)), "ro");
system(sprintf("ubiblock --remove /dev/%s", vol_dev));
system(sprintf("ubirename /dev/%s \"uvol-wo-%s\" \"uvol-rd-%s\"", ubidev, vol_name, vol_name));
return 0;
}
backend.backend = "UBI";
backend.priority = 20;
backend.init = ubi_init;
backend.boot = ubi_boot;
backend.detect = ubi_detect;
backend.free = ubi_free;
backend.align = ubi_align;
backend.total = ubi_total;
backend.list = ubi_list;
backend.size = ubi_size;
backend.status = ubi_status;
backend.device = ubi_device;
backend.up = ubi_up;
backend.down = ubi_down;
backend.create = ubi_create;
backend.remove = ubi_remove;
backend.write = ubi_write;

View file

@ -1,4 +1,3 @@
{%
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// UCI tools for uvol // UCI tools for uvol
// (c) 2022 Daniel Golle <daniel@makrotopia.org> // (c) 2022 Daniel Golle <daniel@makrotopia.org>
@ -136,4 +135,3 @@ uvol_uci = {
return 0; return 0;
} }
}; };
%}

View file

@ -1,13 +1,9 @@
#!/usr/bin/ucode #!/usr/bin/ucode
{%
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// uvol - storage volume manager for OpenWrt // uvol - storage volume manager for OpenWrt
// (c) 2022 Daniel Golle <daniel@makrotopia.org> // (c) 2022 Daniel Golle <daniel@makrotopia.org>
function help() { let help_output = "uvol storage volume manager
%}
uvol storage volume manager
syntax: uvol command ... syntax: uvol command ...
commands: commands:
@ -29,102 +25,101 @@ commands:
1 - volume is not ready for use 1 - volume is not ready for use
2 - volume doesn'y exist 2 - volume doesn'y exist
write volname size write to volume from stdin, size in bytes write volname size write to volume from stdin, size in bytes
{% "
function help() {
printf("%s", help_output);
);
let fs = require("fs");
let uci = require("uci");
let cursor = uci ? uci.cursor() : null;
let ctx = {};
ctx.cursor = cursor;
ctx.fs = fs;
include("/usr/lib/uvol/uci.uc");
ctx.uci_add = uvol_uci.uvol_uci_add;
ctx.uci_remove = uvol_uci.uvol_uci_remove;
ctx.uci_commit = uvol_uci.uvol_uci_commit;
ctx.uci_init = uvol_uci.uvol_uci_init;
let backend = null;
let tried_backends = [];
for (plugin in fs.glob("/usr/lib/uvol/backends/*.uc")) {
let current_backend = {};
include(plugin, { backend: current_backend });
push(tried_backends, current_backend.backend);
if (type(backend) == "object" &&
type(backend.priority) == "int" &&
type(current_backend.priority) == "int" &&
backend.priority > current_backend.priority)
continue;
if (type(current_backend.init) == "function" &&
current_backend.init(ctx)) {
backend = current_backend;
break;
} }
}
let fs = require("fs"); if (!backend) {
let uci = require("uci"); printf("No backend available. (tried: %s)\n", join(" ", tried_backends));
let cursor = uci ? uci.cursor() : null; printf("To setup devices with block storage install 'autopart'.\n");
exit(2);
}
let ctx = {}; let cmd = shift(ARGV);
ctx.cursor = cursor;
ctx.fs = fs;
include("/usr/lib/uvol/uci.uc");
ctx.uci_add = uvol_uci.uvol_uci_add;
ctx.uci_remove = uvol_uci.uvol_uci_remove;
ctx.uci_commit = uvol_uci.uvol_uci_commit;
ctx.uci_init = uvol_uci.uvol_uci_init;
let backend = null; if (!cmd || cmd == "-h" || cmd == "help") {
let tried_backends = []; help();
for (plugin in fs.glob("/usr/lib/uvol/backends/*.uc")) { return cmd?0:22;
let current_backend = {}; }
include(plugin, { backend: current_backend });
push(tried_backends, current_backend.backend);
if (type(backend) == "object" &&
type(backend.priority) == "int" &&
type(current_backend.priority) == "int" &&
backend.priority > current_backend.priority)
continue;
if (type(current_backend.init) == "function" && if (!(cmd in keys(backend))) {
current_backend.init(ctx)) { printf("command %s not found\n", cmd);
backend = current_backend; return 22;
break; }
}
}
if (!backend) {
printf("No backend available. (tried: %s)\n", join(" ", tried_backends));
printf("To setup devices with block storage install 'autopart'.\n");
exit(2);
}
let json_output = false;
if (ARGV[0] == "-j") {
json_output = true;
shift(ARGV); shift(ARGV);
shift(ARGV); }
let cmd = shift(ARGV);
if (!cmd || cmd == "-h" || cmd == "help") { let legacy_output = function(var) {
help(); let out = "";
return cmd?0:22; if (type(var) == "array") {
} for (let line in var) {
if (!(cmd in keys(backend))) {
printf("command %s not found\n", cmd);
return 22;
}
let json_output = false;
if (ARGV[0] == "-j") {
json_output = true;
shift(ARGV);
}
let legacy_output = function(var) {
let out = "";
if (type(var) == "array") {
for (let line in var) {
out += join(" ", values(line));
out += "\n";
}
} else if (type(var) == "object") {
out += join(" ", values(line)); out += join(" ", values(line));
out += "\n"; out += "\n";
} }
return out; } else if (type(var) == "object") {
}; out += join(" ", values(line));
out += "\n";
}
return out;
};
if (type(backend[cmd]) == "string") { if (type(backend[cmd]) == "string") {
printf("%s\n", backend[cmd]); printf("%s\n", backend[cmd]);
} else if (type(backend[cmd]) == "function") { } else if (type(backend[cmd]) == "function") {
let ret = backend[cmd](...ARGV); let ret = backend[cmd](...ARGV);
if (type(ret) == "int") if (type(ret) == "int")
exit(ret); exit(ret);
if (type(ret) == "string") { if (type(ret) == "string") {
printf("%s\n", ret); printf("%s\n", ret);
} else {
if (json_output)
printf("%.J\n", ret);
else
printf("%s", legacy_output(ret));
}
} else { } else {
if (json_output) if (json_output)
printf("%.J\n", backend[cmd]); printf("%.J\n", ret);
else else
printf("%s\n", legacy_output(backend[cmd])); printf("%s", legacy_output(ret));
} }
} else {
if (json_output)
printf("%.J\n", backend[cmd]);
else
printf("%s\n", legacy_output(backend[cmd]));
}
return 0; exit(0);
%}