source: mainline/uspace/app/hrctl/hrctl.c@ 2b8901be

Last change on this file since 2b8901be was 2b8901be, checked in by Miroslav Cimerman <mc@…>, 10 months ago

hrctl: add RAID 4 to usage message

  • Property mode set to 100644
File size: 9.2 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, --create-file=path create an array from file,\n"
57 " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n"
58 " -A, --assemble-file=path create an array from file\n"
59 " -s, --status display status of active arrays\n"
60 " -T, --stop stop an active array\n"
61 " -c, --create=NAME create new array\n"
62 " -a, --assemble=NAME assemble an existing array\n"
63 " -n non-zero number of devices\n"
64 " -l, --level=LEVEL set the RAID level,\n"
65 " valid values: 0, 1, 4, 5, linear\n"
66 " -0 striping\n"
67 " -1 mirroring\n"
68 " -4 parity on one extent\n"
69 " -5 distributed parity\n"
70 " -L linear concatenation\n"
71 "\n"
72 "Example usage:\n"
73 " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
74 " - creates new mirroring RAID device named /hr0 consisting\n"
75 " of 2 drives\n"
76 " hrctl --assemble hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
77 " - assembles RAID device named /hr0 consisting of 2 drives,\n"
78 " that were previously in an array\n"
79 "Limitations:\n"
80 " - device name must be less than 32 characters in size\n";
81
82static struct option const long_options[] = {
83 { "help", no_argument, 0, 'h' },
84 { "status", no_argument, 0, 's' },
85 { "assemble", required_argument, 0, 'a' },
86 { "create", required_argument, 0, 'c' },
87 { "level", required_argument, 0, 'l' },
88 { "create-file", required_argument, 0, 'C' },
89 { "assemble-file", required_argument, 0, 'A' },
90 { "stop", required_argument, 0, 'T' },
91 { 0, 0, 0, 0 }
92};
93
94static void usage(void)
95{
96 printf("%s", usage_str);
97}
98
99static errno_t fill_config_devs(int argc, char **argv, int optind,
100 hr_config_t *cfg)
101{
102 errno_t rc;
103 size_t i;
104
105 for (i = 0; i < cfg->dev_no; i++) {
106 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
107 if (rc != EOK) {
108 printf("hrctl: error resolving device \"%s\"\n", argv[optind]);
109 return EINVAL;
110 }
111
112 optind++;
113 }
114
115 return EOK;
116}
117
118static errno_t load_config(const char *path, hr_config_t *cfg)
119{
120 errno_t rc;
121 size_t i;
122 sif_doc_t *doc = NULL;
123 sif_node_t *narrays;
124 sif_node_t *rnode;
125 sif_node_t *narray;
126 sif_node_t *nextent;
127 const char *ntype;
128 const char *devname;
129 const char *level_str;
130 const char *dev_no_str;
131 const char *extent_devname;
132
133 rc = sif_load(path, &doc);
134 if (rc != EOK)
135 goto error;
136
137 rnode = sif_get_root(doc);
138
139 narrays = sif_node_first_child(rnode);
140 ntype = sif_node_get_type(narrays);
141 if (str_cmp(ntype, "arrays") != 0) {
142 rc = EIO;
143 goto error;
144 }
145
146 narray = sif_node_first_child(narrays);
147 ntype = sif_node_get_type(narray);
148 if (str_cmp(ntype, "array") != 0) {
149 rc = EIO;
150 goto error;
151 }
152
153 devname = sif_node_get_attr(narray, "devname");
154 if (devname == NULL) {
155 rc = EIO;
156 goto error;
157 }
158 str_cpy(cfg->devname, sizeof(cfg->devname), devname);
159
160 level_str = sif_node_get_attr(narray, "level");
161 if (level_str == NULL)
162 cfg->level = hr_l_empty;
163 else if (str_cmp(level_str, "linear") == 0)
164 cfg->level = hr_l_linear;
165 else
166 cfg->level = strtol(level_str, NULL, 10);
167
168 dev_no_str = sif_node_get_attr(narray, "n");
169 if (dev_no_str == NULL) {
170 rc = EIO;
171 goto error;
172 }
173 cfg->dev_no = strtol(dev_no_str, NULL, 10);
174
175 nextent = sif_node_first_child(narray);
176 for (i = 0; i < cfg->dev_no; i++) {
177 if (nextent == NULL) {
178 rc = EINVAL;
179 goto error;
180 }
181
182 ntype = sif_node_get_type(nextent);
183 if (str_cmp(ntype, "extent") != 0) {
184 rc = EIO;
185 goto error;
186 }
187
188 extent_devname = sif_node_get_attr(nextent, "devname");
189 if (extent_devname == NULL) {
190 rc = EIO;
191 goto error;
192 }
193
194 rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
195 if (rc != EOK) {
196 printf("hrctl: error resolving device \"%s\"\n",
197 extent_devname);
198 return EINVAL;
199 }
200
201 nextent = sif_node_next_child(nextent);
202 }
203
204error:
205 if (doc != NULL)
206 sif_delete(doc);
207 return rc;
208}
209
210int main(int argc, char **argv)
211{
212 errno_t rc;
213 int retval, c;
214 bool create, assemble;
215 hr_t *hr;
216 hr_config_t *cfg;
217
218 cfg = calloc(1, sizeof(hr_config_t));
219 if (cfg == NULL)
220 return 1;
221
222 retval = 0;
223 cfg->level = hr_l_empty;
224 cfg->dev_no = 0;
225 create = assemble = false;
226
227 if (argc < 2) {
228 goto bad;
229 }
230
231 c = 0;
232 optreset = 1;
233 optind = 0;
234
235 while (c != -1) {
236 c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:T:",
237 long_options, NULL);
238 switch (c) {
239 case 'h':
240 usage();
241 return 0;
242 case 's':
243 rc = hr_print_status();
244 if (rc != EOK)
245 return 1;
246 return 0;
247 case 'C':
248 /* only support 1 array inside config for now XXX */
249 rc = load_config(optarg, cfg);
250 if (rc != EOK) {
251 printf("hrctl: failed to load config\n");
252 return 1;
253 }
254 create = true;
255 goto skip;
256 case 'c':
257 if (str_size(optarg) > sizeof(cfg->devname) - 1) {
258 printf("hrctl: device name too long\n");
259 return 1;
260 }
261 str_cpy(cfg->devname, sizeof(cfg->devname), optarg);
262 create = true;
263 break;
264 case 'A':
265 rc = load_config(optarg, cfg);
266 if (rc != EOK) {
267 printf("hrctl: failed to load config\n");
268 return 1;
269 }
270 assemble = true;
271 goto skip;
272 case 'a':
273 if (str_size(optarg) > sizeof(cfg->devname) - 1) {
274 printf("hrctl: device name too long\n");
275 return 1;
276 }
277 str_cpy(cfg->devname, sizeof(cfg->devname), optarg);
278 assemble = true;
279 break;
280 case 'T':
281 rc = hr_stop(optarg);
282 free(cfg);
283 if (rc != EOK) {
284 if (rc == ENOENT)
285 printf("hrctl: service named \"%s\" does not exist\n",
286 optarg);
287 return 1;
288 }
289 return 0;
290 case 'l':
291 if (cfg->level != hr_l_empty)
292 goto bad;
293 if (str_cmp(optarg, "linear") == 0)
294 cfg->level = hr_l_linear;
295 else
296 cfg->level = strtol(optarg, NULL, 10);
297 break;
298 case '0':
299 if (cfg->level != hr_l_empty)
300 goto bad;
301 cfg->level = hr_l_0;
302 break;
303 case '1':
304 if (cfg->level != hr_l_empty)
305 goto bad;
306 cfg->level = hr_l_1;
307 break;
308 case '4':
309 if (cfg->level != hr_l_empty)
310 goto bad;
311 cfg->level = hr_l_4;
312 break;
313 case '5':
314 if (cfg->level != hr_l_empty)
315 goto bad;
316 cfg->level = hr_l_5;
317 break;
318 case 'L':
319 if (cfg->level != hr_l_empty)
320 goto bad;
321 cfg->level = hr_l_linear;
322 break;
323 case 'n':
324 cfg->dev_no = strtol(optarg, NULL, 10);
325 if ((int) cfg->dev_no + optind != argc)
326 goto bad;
327 rc = fill_config_devs(argc, argv, optind, cfg);
328 if (rc != EOK)
329 return 1;
330 break;
331 }
332 }
333
334skip:
335 if ((create && assemble) || (!create && !assemble))
336 goto bad;
337
338 if (create && cfg->level == hr_l_empty) {
339 printf("hrctl: invalid level, exiting\n");
340 return 1;
341 }
342
343 if (cfg->dev_no > HR_MAXDEVS) {
344 printf("hrctl: too many devices, exiting\n");
345 return 1;
346 }
347
348 if (cfg->dev_no == 0) {
349 printf("hrctl: invalid number of devices, exiting\n");
350 return 1;
351 }
352
353 rc = hr_sess_init(&hr);
354 if (rc != EOK) {
355 printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc));
356 retval = 1;
357 goto end;
358 }
359
360 if (create) {
361 rc = hr_create(hr, cfg);
362 printf("hrctl: hr_create() rc: %s\n", str_error(rc));
363 } else if (assemble) {
364 rc = hr_assemble(hr, cfg);
365 printf("hrctl: hr_assemble() rc: %s\n", str_error(rc));
366 }
367
368end:
369 free(cfg);
370 hr_sess_destroy(hr);
371 return retval;
372bad:
373 free(cfg);
374 printf("hrctl: bad usage, try hrctl --help\n");
375 return 1;
376}
377
378/** @}
379 */
Note: See TracBrowser for help on using the repository browser.