forked from mirror/openwrt
This is useful for keeping specific data on a device across factory reset. It uses a separate partition (only UBI supported at the moment) to store the data. The primary use case is storing sensitive data like cryptographic keys for maintaining a device as part of a network. Signed-off-by: Felix Fietkau <nbd@nbd.name>
107 lines
2 KiB
Text
Executable file
107 lines
2 KiB
Text
Executable file
#!/usr/bin/env ucode
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2025 Felix Fietkau <nbd@nbd.name>
|
|
*/
|
|
'use strict';
|
|
import { basename } from "fs";
|
|
import * as provision from "provision";
|
|
|
|
const usage_message = `Usage: ${basename(sourcepath())} <command> [<args>]
|
|
|
|
Commands:
|
|
- get [<path>]: Get string value at <path> (or all if no path given)
|
|
- set <path> <value> Set string value at <path> to <value>
|
|
- get_json [<path>]: Get JSON data at <path> (or all if no path given)
|
|
- set_json <path> <value> Set JSON value at <path> to <value>
|
|
- delete <path> Delete value at <path>
|
|
- reset Clear provision data
|
|
- create Create provisioning partition
|
|
- destroy Destroy provisioning partition
|
|
|
|
`;
|
|
|
|
|
|
function usage()
|
|
{
|
|
warn(usage_message);
|
|
exit(1);
|
|
}
|
|
|
|
if (!length(ARGV))
|
|
usage();
|
|
|
|
const create_error_msg = `Provisioning partition could not be created.
|
|
This is only supported on devices with UBI for now.
|
|
If there was not enough space, please reflash using the sysugrade -P parameter
|
|
`;
|
|
|
|
let ctx;
|
|
if (ARGV[0] == "create") {
|
|
ctx = provision.create();
|
|
if (!ctx) {
|
|
warn(create_error_msg);
|
|
exit(1);
|
|
}
|
|
ctx.reset();
|
|
ctx.commit();
|
|
exit(0);
|
|
} else {
|
|
ctx = provision.open();
|
|
if (!ctx) {
|
|
warn(`Provisioning partition not found. Try ${basename(sourcepath())} enable\n`);
|
|
exit(1);
|
|
}
|
|
}
|
|
ctx.init();
|
|
|
|
let cmd = shift(ARGV);
|
|
switch (cmd) {
|
|
case "get":
|
|
let val = ctx.get(ARGV[0]);
|
|
val ??= "";
|
|
print(val + "\n");
|
|
break;
|
|
case "get_json":
|
|
printf("%.J\n", ctx.get(ARGV[0]));
|
|
break;
|
|
case "set_json":
|
|
if (length(ARGV) != 2)
|
|
usage();
|
|
ARGV[1] = json(ARGV[1]);
|
|
if (ARGV[1] == null) {
|
|
warn('Invalid JSON argument\n');
|
|
exit(1);
|
|
}
|
|
// fallthrough
|
|
case "set":
|
|
if (length(ARGV) != 2)
|
|
usage();
|
|
|
|
if (!ctx.set(ARGV[0], ARGV[1])) {
|
|
warn('Set failed\n');
|
|
exit(1);
|
|
}
|
|
|
|
ctx.commit();
|
|
break;
|
|
case "delete":
|
|
if (length(ARGV) != 1)
|
|
usage();
|
|
|
|
if (!ctx.set(ARGV[0])) {
|
|
warn('Delete failed\n');
|
|
exit(1);
|
|
}
|
|
ctx.commit();
|
|
break;
|
|
case "reset":
|
|
ctx.reset();
|
|
ctx.commit();
|
|
break;
|
|
case "destroy":
|
|
ctx.destroy();
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|