source: mainline/uspace/app/hrctl/hrctl.c@ 095a989

Last change on this file since 095a989 was 095a989, checked in by Miroslav Cimerman <mc@…>, 11 months ago

hr: add status printing

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 2024 Miroslav Cimerman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup hrctl
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <errno.h>
37#include <getopt.h>
38#include <hr.h>
39#include <sif.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <str.h>
43#include <str_error.h>
44
45#define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif"
46
47static void usage(void);
48static errno_t fill_config_devs(int, char **, int, hr_config_t *);
49static errno_t load_config(const char *, hr_config_t *);
50
51static const char usage_str[] =
52 "Usage: hrctl [OPTION]... -n <dev_no> <devices>...\n"
53 "\n"
54 "Options:\n"
55 " -h, --help display this help and exit\n"
56 " -C, --config-file=path create an array from file,\n"
57 " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n"
58 " -s, --status display status of active arrays\n"
59 " -a, --assemble=NAME assemble an existing array\n"
60 " -c, --create=NAME create new array\n"
61 " -n non-zero number of devices\n"
62 " -l, --level=LEVEL set the RAID level,\n"
63 " valid values: 0, 1, 5, linear\n"
64 " -0 striping\n"
65 " -1 mirroring\n"
66 " -5 distributed parity\n"
67 " -L linear concatenation\n"
68 "\n"
69 "Example usage:\n"
70 " hrctl --create /hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
71 " - creates new mirroring RAID device named /hr0 consisting\n"
72 " of 2 drives\n"
73 " hrctl --assemble /hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
74 " - assembles RAID device named /hr0 consisting of 2 drives,\n"
75 " that were previously in an array\n";
76
77static struct option const long_options[] = {
78 { "help", no_argument, 0, 'h' },
79 { "status", no_argument, 0, 's' },
80 { "assemble", required_argument, 0, 'a' },
81 { "create", required_argument, 0, 'c' },
82 { "level", required_argument, 0, 'l' },
83 { "config-file", required_argument, 0, 'C' },
84 { 0, 0, 0, 0 }
85};
86
87static void usage(void)
88{
89 printf("%s", usage_str);
90}
91
92static errno_t fill_config_devs(int argc, char **argv, int optind,
93 hr_config_t *cfg)
94{
95 errno_t rc;
96 size_t i;
97
98 for (i = 0; i < cfg->dev_no; i++) {
99 rc = loc_service_get_id(argv[optind++], &cfg->devs[i], 0);
100 if (rc != EOK) {
101 printf("hrctl: error resolving device \"%s\"\n", argv[i]);
102 return EINVAL;
103 }
104 }
105
106 return EOK;
107}
108
109static errno_t load_config(const char *path, hr_config_t *cfg)
110{
111 errno_t rc;
112 size_t i;
113 sif_doc_t *doc = NULL;
114 sif_node_t *narrays;
115 sif_node_t *rnode;
116 sif_node_t *narray;
117 sif_node_t *nextent;
118 const char *ntype;
119 const char *devname;
120 const char *level_str;
121 const char *dev_no_str;
122 const char *extent_devname;
123
124 rc = sif_load(path, &doc);
125 if (rc != EOK)
126 goto error;
127
128 rnode = sif_get_root(doc);
129
130 narrays = sif_node_first_child(rnode);
131 ntype = sif_node_get_type(narrays);
132 if (str_cmp(ntype, "arrays") != 0) {
133 rc = EIO;
134 goto error;
135 }
136
137 narray = sif_node_first_child(narrays);
138 ntype = sif_node_get_type(narray);
139 if (str_cmp(ntype, "array") != 0) {
140 rc = EIO;
141 goto error;
142 }
143
144 devname = sif_node_get_attr(narray, "devname");
145 if (devname == NULL) {
146 rc = EIO;
147 goto error;
148 }
149 str_cpy(cfg->devname, 32, devname);
150
151 level_str = sif_node_get_attr(narray, "level");
152 if (level_str == NULL) {
153 rc = EIO;
154 goto error;
155 }
156 cfg->level = strtol(level_str, NULL, 10);
157
158 dev_no_str = sif_node_get_attr(narray, "n");
159 if (dev_no_str == NULL) {
160 rc = EIO;
161 goto error;
162 }
163 cfg->dev_no = strtol(dev_no_str, NULL, 10);
164
165 nextent = sif_node_first_child(narray);
166 for (i = 0; i < cfg->dev_no; i++) {
167 if (nextent == NULL) {
168 rc = EINVAL;
169 goto error;
170 }
171
172 ntype = sif_node_get_type(nextent);
173 if (str_cmp(ntype, "extent") != 0) {
174 rc = EIO;
175 goto error;
176 }
177
178 extent_devname = sif_node_get_attr(nextent, "devname");
179 if (extent_devname == NULL) {
180 rc = EIO;
181 goto error;
182 }
183
184 rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
185 if (rc != EOK) {
186 printf("hrctl: error resolving device \"%s\"\n",
187 extent_devname);
188 return EINVAL;
189 }
190
191 nextent = sif_node_next_child(nextent);
192 }
193
194error:
195 if (doc != NULL)
196 sif_delete(doc);
197 return rc;
198}
199
200int main(int argc, char **argv)
201{
202 errno_t rc;
203 int retval, c;
204 bool create, assemble;
205 hr_t *hr;
206 hr_config_t *cfg;
207
208 cfg = calloc(1, sizeof(hr_config_t));
209 if (cfg == NULL)
210 return 1;
211
212 retval = 0;
213 cfg->level = hr_l_empty;
214 cfg->dev_no = 0;
215 create = assemble = false;
216
217 if (argc < 2) {
218 goto bad;
219 }
220
221 c = 0;
222 optreset = 1;
223 optind = 0;
224
225 while (c != -1) {
226 c = getopt_long(argc, argv, "hsC:c:a:l:015Ln:",
227 long_options, NULL);
228 switch (c) {
229 case 'h':
230 usage();
231 return 0;
232 case 's':
233 rc = hr_print_status();
234 if (rc != EOK)
235 return 1;
236 return 0;
237 case 'a':
238 if (str_size(optarg) > 31) {
239 printf("hrctl: device name longer than 31 bytes\n");
240 return 1;
241 }
242 str_cpy(cfg->devname, 32, optarg);
243 assemble = true;
244 break;
245 case 'C':
246 /* only support 1 array inside config for now XXX */
247 rc = load_config(optarg, cfg);
248 if (rc != EOK) {
249 printf("hrctl: failed to load config\n");
250 return 1;
251 }
252 create = true;
253 goto skip;
254 case 'c':
255 if (str_size(optarg) > 31) {
256 printf("hrctl: device name longer than 31 bytes\n");
257 return 1;
258 }
259 str_cpy(cfg->devname, 32, optarg);
260 create = true;
261 break;
262 case 'l':
263 if (cfg->level != hr_l_empty)
264 goto bad;
265 if (str_cmp(optarg, "linear") == 0)
266 cfg->level = hr_l_linear;
267 else
268 cfg->level = strtol(optarg, NULL, 10);
269 break;
270 case '0':
271 if (cfg->level != hr_l_empty)
272 goto bad;
273 cfg->level = hr_l_0;
274 break;
275 case '1':
276 if (cfg->level != hr_l_empty)
277 goto bad;
278 cfg->level = hr_l_1;
279 break;
280 case '5':
281 if (cfg->level != hr_l_empty)
282 goto bad;
283 cfg->level = hr_l_5;
284 break;
285 case 'L':
286 if (cfg->level != hr_l_empty)
287 goto bad;
288 cfg->level = hr_l_linear;
289 break;
290 case 'n':
291 cfg->dev_no = strtol(optarg, NULL, 10);
292 if ((int) cfg->dev_no + optind != argc)
293 goto bad;
294 if (cfg->dev_no > HR_MAXDEVS) {
295 printf("hrctl: too many devices\n");
296 return 1;
297 }
298 rc = fill_config_devs(argc, argv, optind, cfg);
299 if (rc != EOK)
300 return 1;
301 break;
302 }
303 }
304
305skip:
306 if ((create && assemble) ||
307 (!create && !assemble) ||
308 (create && cfg->level == hr_l_empty) ||
309 (assemble && cfg->level != hr_l_empty) ||
310 (cfg->dev_no == 0)) {
311 goto bad;
312 }
313
314 rc = hr_sess_init(&hr);
315 if (rc != EOK) {
316 printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc));
317 retval = 1;
318 goto end;
319 }
320
321 if (create) {
322 rc = hr_create(hr, cfg);
323 printf("hrctl: hr_create() rc: %s\n", str_error(rc));
324 } else if (assemble) {
325 printf("hrctl: assemble not implemented yet\n");
326 }
327
328end:
329 free(cfg);
330 hr_sess_destroy(hr);
331 return retval;
332bad:
333 free(cfg);
334 printf("hrctl: bad usage, try hrctl --help\n");
335 return 1;
336}
337
338/** @}
339 */
Note: See TracBrowser for help on using the repository browser.