1
0
Fork 0
forked from mirror/openwrt
openwrt/package/utils/provision/files/usr/sbin/provision
Felix Fietkau 5d40123818 provision: add script for managing device provisioning data
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>
2025-03-17 13:17:52 +01:00

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();
}