openwrt-packages/utils/uvol/files/blockdev_common.uc

168 lines
4.7 KiB
Ucode

// SPDX-License-Identifier: GPL-2.0-or-later
// 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
let get_blockdevs = function() {
let devs = [];
for (let dev in fs.glob('/dev/*'))
if (fs.stat(dev).type == "block")
push(devs, split(dev, '/')[-1]);
return devs;
};
// adapted from /lib/upgrade/common.sh
let get_uevent_major_minor = function(file) {
let uevf = fs.open(file, "r");
if (!uevf)
return null;
let r = {};
let evl;
while ((evl = uevf.read("line"))) {
let ev = split(evl, '=');
if (ev[0] == "MAJOR")
r.major = +ev[1];
if (ev[0] == "MINOR")
r.minor = +ev[1];
}
uevf.close();
return r;
};
// adapted from /lib/upgrade/common.sh
let fitblk_get_bootdev = function(void) {
let rootdisk_handle = fs.open("/sys/firmware/devicetree/base/chosen/rootdisk", "r");
if (!rootdisk_handle)
return null;
// read rootdisk handle
let rootdisk = rootdisk_handle.read("all");
rootdisk_handle.close();
// find all block device handle sysfs files
let handles = fs.glob('/sys/class/block/*/of_node/phandle');
let mtd_handles = fs.glob('/sys/class/block/*/device/of_node/phandle');
// concat array of both globs
for (let mtddev in mtd_handles)
push(handles, mtddev);
for (let dev in handles) {
let bdev_handle = fs.open(dev, "r");
if (!bdev_handle)
continue;
let bdev = bdev_handle.read("all");
bdev_handle.close();
if ( bdev != rootdisk )
continue;
let path = split(dev, '/');
let pe = length(path) - 3;
if (path[pe] == "device")
--pe;
return path[pe];
}
return null;
};
// adapted from /lib/upgrade/common.sh
let get_bootdev = function(void) {
let rootpart = cmdline_get_var("root");
let uevent = null;
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]")) {
let uuidarg = split(substr(rootpart, 9), '-')[0];
for (let bd in get_blockdevs()) {
let bdf = fs.open(sprintf("/dev/%s", bd), "r");
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=*") ||
wildcard(rootpart, "PARTUUID=????????-????-????-????-??????????02")) {
let uuidarg = substr(split(substr(rootpart, 9), '/')[0], 0, -2) + "00";
for (let bd in get_blockdevs()) {
let bdf = fs.open(sprintf("/dev/%s", bd), "r");
bdf.seek(568);
let bduuid = bdf.read(16);
bdf.close();
if (!bduuid)
continue;
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, 5), ord(bduuid, 4),
ord(bduuid, 7), ord(bduuid, 6),
ord(bduuid, 8), ord(bduuid, 9),
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);
for (let bd in get_blockdevs()) {
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 (rootpart == "/dev/fit0") {
uevent = sprintf("/sys/class/block/%s/../uevent", fitblk_get_bootdev());
} 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) {
if (!dev)
return null;
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;