aboutsummaryrefslogtreecommitdiff
path: root/utils/uvol/files/uvol
blob: a4f023ffd78133c85a81d09a452f33c05fceb348 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/ucode -R
// SPDX-License-Identifier: GPL-2.0-or-later
// uvol - storage volume manager for OpenWrt
//  (c) 2022 Daniel Golle <daniel@makrotopia.org>

let help_output = "uvol storage volume manager
syntax: uvol command ...

commands:
  boot				get active volumes ready (called on boot)
  free				show number of bytes available
  total				show total number of bytes
  align				show sector size in bytes
  list [volname]		list volumes
  create volname size type	create new volume
    size: in bytes
    type: 'ro' or 'rw'
  remove volname		delete volume
  device volname		show block device for mounting
  size volname			show size of volume
  up volname			get volume ready for mounting
  down volname			take volume down after unmounting
  status volname		return status of volume
    return code: 0 - volume is ready for use
                 1 - volume is not ready for use
                 2 - volume doesn'y exist
  write volname size		write to volume from stdin, size in bytes
";

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

if (!backend) {
	printf("No backend available. (tried: %s)\n", join(" ", tried_backends));
	printf("To setup devices with block storage install 'autopart'.\n");
	exit(2);
}

// The below code is needed as older versions of ucode pass the complete cmdline via ARGV
// Once we can rely in more recent ucode the while loop can be replaced by simply
// let cmd = shift(ARGV);
let skip = null;
let cmd = null;
let skip_argv = ["/usr/bin/ucode", "-R", "/usr/sbin/uvol"];
while (skip = shift(ARGV)) {
	if (skip != shift(skip_argv)) {
		cmd = skip;
		break;
	}
}

if (!cmd || cmd == "-h" || cmd == "help") {
	printf("%s", help_output);
	return cmd?0:22;
}

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 += "\n";
	}
	return out;
};

if (type(backend[cmd]) == "string") {
	printf("%s\n", backend[cmd]);
} else if (type(backend[cmd]) == "function") {
	let ret = backend[cmd](...ARGV);
	if (type(ret) == "int")
		exit(ret);

	if (type(ret) == "string") {
		printf("%s\n", ret);
	} else {
		if (json_output)
			printf("%.J\n", ret);
		else
			printf("%s", legacy_output(ret));
	}
} else {
	if (json_output)
		printf("%.J\n", backend[cmd]);
	else
		printf("%s\n", legacy_output(backend[cmd]));
}

exit(0);