source: mainline/uspace/app/hrctl/hrctl.c@ bf0a791

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

hr: cstyle

  • Property mode set to 100644
File size: 10.7 KB
RevLine 
[94d84a0]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>
[e192339]39#include <sif.h>
[94d84a0]40#include <stdlib.h>
41#include <stdio.h>
42#include <str.h>
43#include <str_error.h>
44
[e192339]45#define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif"
46
[94d84a0]47static void usage(void);
[e192339]48static errno_t fill_config_devs(int, char **, int, hr_config_t *);
49static errno_t load_config(const char *, hr_config_t *);
[94d84a0]50
51static const char usage_str[] =
52 "Usage: hrctl [OPTION]... -n <dev_no> <devices>...\n"
53 "\n"
54 "Options:\n"
[b0f1366]55 " -h, --help display this help and exit\n"
[6d55e39]56 " -C, --create-file=PATH create an array from file,\n"
[b0f1366]57 " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n"
[6d55e39]58 " -A, --assemble-file=PATH create an array from file\n"
[b0f1366]59 " -s, --status display status of active arrays\n"
[8f7e1b1]60 " -D, --destroy destroy/disassemble an active array\n"
[cf28ffd3]61 " -F, --fail-extent fail an extent, use with -T and set it before\n"
[b0f1366]62 " -c, --create=NAME create new array\n"
63 " -a, --assemble=NAME assemble an existing array\n"
64 " -n non-zero number of devices\n"
65 " -l, --level=LEVEL set the RAID level,\n"
[6d55e39]66 " valid values: 0, 1, 4, 5\n"
[b0f1366]67 " -0 striping\n"
68 " -1 mirroring\n"
[2b8901be]69 " -4 parity on one extent\n"
[b0f1366]70 " -5 distributed parity\n"
[5b320ac]71 " -H, --hotspare=DEV add hotspare extent\n"
[94d84a0]72 "\n"
[972b011]73 "When specifying name for creation or assembly, the device name\n"
74 "is automatically prepended with \"devices/\" prefix.\n"
75 "\n"
[94d84a0]76 "Example usage:\n"
[ee83e9c]77 " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
[94d84a0]78 " - creates new mirroring RAID device named /hr0 consisting\n"
79 " of 2 drives\n"
[ee83e9c]80 " hrctl --assemble hr0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n"
[94d84a0]81 " - assembles RAID device named /hr0 consisting of 2 drives,\n"
[ee83e9c]82 " that were previously in an array\n"
[5b320ac]83 " hrctl devices/hr0 --hotspare=devices/disk10\n"
84 " - adds \"devices/disk10\" as hotspare extent\n"
[ee83e9c]85 "Limitations:\n"
86 " - device name must be less than 32 characters in size\n";
[94d84a0]87
88static struct option const long_options[] = {
89 { "help", no_argument, 0, 'h' },
90 { "status", no_argument, 0, 's' },
91 { "assemble", required_argument, 0, 'a' },
92 { "create", required_argument, 0, 'c' },
93 { "level", required_argument, 0, 'l' },
[b0f1366]94 { "create-file", required_argument, 0, 'C' },
95 { "assemble-file", required_argument, 0, 'A' },
[8f7e1b1]96 { "destroy", required_argument, 0, 'D' },
[cf28ffd3]97 { "fail-extent", required_argument, 0, 'F' },
[5b320ac]98 { "hotspare", required_argument, 0, 'H' },
[94d84a0]99 { 0, 0, 0, 0 }
100};
101
102static void usage(void)
103{
104 printf("%s", usage_str);
105}
106
[68e357e]107static errno_t fill_config_devs(int argc, char **argv, int optind,
108 hr_config_t *cfg)
[94d84a0]109{
110 errno_t rc;
[68e357e]111 size_t i;
[94d84a0]112
[68e357e]113 for (i = 0; i < cfg->dev_no; i++) {
[ee83e9c]114 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
[e47a032]115 if (rc == ENOENT) {
116 printf("hrctl: no device \"%s\", marking as missing\n",
117 argv[optind]);
118 cfg->devs[i] = 0;
119 } else if (rc != EOK) {
120 printf("hrctl: error resolving device \"%s\", aborting\n",
121 argv[optind]);
[94d84a0]122 return EINVAL;
123 }
[ee83e9c]124
125 optind++;
[94d84a0]126 }
127
128 return EOK;
129}
130
[e192339]131static errno_t load_config(const char *path, hr_config_t *cfg)
132{
133 errno_t rc;
134 size_t i;
135 sif_doc_t *doc = NULL;
136 sif_node_t *narrays;
137 sif_node_t *rnode;
138 sif_node_t *narray;
139 sif_node_t *nextent;
140 const char *ntype;
141 const char *devname;
142 const char *level_str;
143 const char *dev_no_str;
144 const char *extent_devname;
145
146 rc = sif_load(path, &doc);
147 if (rc != EOK)
148 goto error;
149
150 rnode = sif_get_root(doc);
151
152 narrays = sif_node_first_child(rnode);
153 ntype = sif_node_get_type(narrays);
154 if (str_cmp(ntype, "arrays") != 0) {
155 rc = EIO;
156 goto error;
157 }
158
159 narray = sif_node_first_child(narrays);
160 ntype = sif_node_get_type(narray);
161 if (str_cmp(ntype, "array") != 0) {
162 rc = EIO;
163 goto error;
164 }
165
166 devname = sif_node_get_attr(narray, "devname");
167 if (devname == NULL) {
168 rc = EIO;
169 goto error;
170 }
[ee83e9c]171 str_cpy(cfg->devname, sizeof(cfg->devname), devname);
[e192339]172
173 level_str = sif_node_get_attr(narray, "level");
[b0f1366]174 if (level_str == NULL)
[50bed55d]175 cfg->level = HR_LVL_UNKNOWN;
[b0f1366]176 else
177 cfg->level = strtol(level_str, NULL, 10);
[e192339]178
179 dev_no_str = sif_node_get_attr(narray, "n");
180 if (dev_no_str == NULL) {
181 rc = EIO;
182 goto error;
183 }
184 cfg->dev_no = strtol(dev_no_str, NULL, 10);
185
186 nextent = sif_node_first_child(narray);
187 for (i = 0; i < cfg->dev_no; i++) {
188 if (nextent == NULL) {
189 rc = EINVAL;
190 goto error;
191 }
192
193 ntype = sif_node_get_type(nextent);
194 if (str_cmp(ntype, "extent") != 0) {
195 rc = EIO;
196 goto error;
197 }
198
199 extent_devname = sif_node_get_attr(nextent, "devname");
200 if (extent_devname == NULL) {
201 rc = EIO;
202 goto error;
203 }
204
205 rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
[e47a032]206 if (rc == ENOENT) {
207 printf("hrctl: no device \"%s\", marking as missing\n",
208 extent_devname);
209 cfg->devs[i] = 0;
210 rc = EOK;
211 } else if (rc != EOK) {
212 printf("hrctl: error resolving device \"%s\", aborting\n",
[e192339]213 extent_devname);
214 return EINVAL;
215 }
216
217 nextent = sif_node_next_child(nextent);
218 }
219
220error:
221 if (doc != NULL)
222 sif_delete(doc);
223 return rc;
224}
225
[94d84a0]226int main(int argc, char **argv)
227{
228 errno_t rc;
[68e357e]229 int retval, c;
[94d84a0]230 bool create, assemble;
[cf28ffd3]231 long fail_extent = -1;
[94d84a0]232 hr_t *hr;
[68e357e]233 hr_config_t *cfg;
234
235 cfg = calloc(1, sizeof(hr_config_t));
236 if (cfg == NULL)
237 return 1;
[94d84a0]238
239 retval = 0;
[50bed55d]240 cfg->level = HR_LVL_UNKNOWN;
[68e357e]241 cfg->dev_no = 0;
[94d84a0]242 create = assemble = false;
243
244 if (argc < 2) {
245 goto bad;
246 }
247
248 c = 0;
249 optreset = 1;
250 optind = 0;
251
252 while (c != -1) {
[5b320ac]253 c = getopt_long(argc, argv, "hsC:c:A:a:l:0145Ln:D:F:H:",
[94d84a0]254 long_options, NULL);
255 switch (c) {
256 case 'h':
257 usage();
[64eba57]258 free(cfg);
[94d84a0]259 return 0;
260 case 's':
[64eba57]261 free(cfg);
[095a989]262 rc = hr_print_status();
263 if (rc != EOK)
264 return 1;
265 return 0;
[b0f1366]266 case 'C':
267 /* only support 1 array inside config for now XXX */
268 rc = load_config(optarg, cfg);
269 if (rc != EOK) {
270 printf("hrctl: failed to load config\n");
[64eba57]271 free(cfg);
[b0f1366]272 return 1;
273 }
274 create = true;
275 goto skip;
276 case 'c':
[ee83e9c]277 if (str_size(optarg) > sizeof(cfg->devname) - 1) {
278 printf("hrctl: device name too long\n");
[64eba57]279 free(cfg);
[68e357e]280 return 1;
281 }
[ee83e9c]282 str_cpy(cfg->devname, sizeof(cfg->devname), optarg);
[b0f1366]283 create = true;
[94d84a0]284 break;
[b0f1366]285 case 'A':
[e192339]286 rc = load_config(optarg, cfg);
287 if (rc != EOK) {
288 printf("hrctl: failed to load config\n");
[64eba57]289 free(cfg);
[e192339]290 return 1;
291 }
[b0f1366]292 assemble = true;
[e192339]293 goto skip;
[b0f1366]294 case 'a':
[ee83e9c]295 if (str_size(optarg) > sizeof(cfg->devname) - 1) {
296 printf("hrctl: device name too long\n");
[64eba57]297 free(cfg);
[68e357e]298 return 1;
299 }
[ee83e9c]300 str_cpy(cfg->devname, sizeof(cfg->devname), optarg);
[b0f1366]301 assemble = true;
[94d84a0]302 break;
[8f7e1b1]303 case 'D':
[cf28ffd3]304 rc = hr_stop(optarg, fail_extent);
[a19d7fc4]305 free(cfg);
[34abe6c5]306 if (rc != EOK) {
307 if (rc == ENOENT)
308 printf("hrctl: service named \"%s\" does not exist\n",
309 optarg);
[a19d7fc4]310 return 1;
[34abe6c5]311 }
[a19d7fc4]312 return 0;
[cf28ffd3]313 case 'F':
314 fail_extent = strtol(optarg, NULL, 10);
315 break;
[94d84a0]316 case 'l':
[50bed55d]317 if (cfg->level != HR_LVL_UNKNOWN)
[94d84a0]318 goto bad;
[6d55e39]319 cfg->level = strtol(optarg, NULL, 10);
[94d84a0]320 break;
321 case '0':
[50bed55d]322 if (cfg->level != HR_LVL_UNKNOWN)
[94d84a0]323 goto bad;
[50bed55d]324 cfg->level = HR_LVL_0;
[94d84a0]325 break;
326 case '1':
[50bed55d]327 if (cfg->level != HR_LVL_UNKNOWN)
[94d84a0]328 goto bad;
[50bed55d]329 cfg->level = HR_LVL_1;
[94d84a0]330 break;
[4a2a6b8b]331 case '4':
[50bed55d]332 if (cfg->level != HR_LVL_UNKNOWN)
[4a2a6b8b]333 goto bad;
[50bed55d]334 cfg->level = HR_LVL_4;
[4a2a6b8b]335 break;
[94d84a0]336 case '5':
[50bed55d]337 if (cfg->level != HR_LVL_UNKNOWN)
[94d84a0]338 goto bad;
[50bed55d]339 cfg->level = HR_LVL_5;
[94d84a0]340 break;
341 case 'n':
[68e357e]342 cfg->dev_no = strtol(optarg, NULL, 10);
[bf0a791]343 if ((int)cfg->dev_no + optind != argc)
[94d84a0]344 goto bad;
[68e357e]345 rc = fill_config_devs(argc, argv, optind, cfg);
[64eba57]346 if (rc != EOK) {
347 free(cfg);
[94d84a0]348 return 1;
[64eba57]349 }
[94d84a0]350 break;
[5b320ac]351 case 'H':
352 if (optind != 3 && argc != 4)
353 goto bad;
354
355 service_id_t hotspare;
356 service_id_t vol_svc_id;
357
358 rc = loc_service_get_id(argv[1], &vol_svc_id, 0);
359 if (rc != EOK) {
360 printf("hrctl: error resolving volume \"%s\", "
361 "aborting extent addition\n", argv[1]);
362 goto bad;
363 }
364
365 rc = loc_service_get_id(optarg, &hotspare, 0);
366 if (rc != EOK) {
367 printf("hrctl: error resolving device \"%s\", "
368 "aborting extent addition\n", optarg);
369 goto bad;
370 }
371
372 rc = hr_add_hotspare(vol_svc_id, hotspare);
373 if (rc != EOK)
374 printf("hrctl: hr_add_hotspare() rc: %s\n",
375 str_error(rc));
376
377 free(cfg);
378 if (rc != EOK)
379 return 1;
380 else
381 return 0;
[94d84a0]382 }
383 }
384
[e192339]385skip:
[b0f1366]386 if ((create && assemble) || (!create && !assemble))
[94d84a0]387 goto bad;
[b0f1366]388
[50bed55d]389 if (create && cfg->level == HR_LVL_UNKNOWN) {
[b0f1366]390 printf("hrctl: invalid level, exiting\n");
[64eba57]391 goto bad;
[b0f1366]392 }
393
[dfa2313]394 if (cfg->dev_no > HR_MAX_EXTENTS) {
[b0f1366]395 printf("hrctl: too many devices, exiting\n");
[64eba57]396 goto bad;
[b0f1366]397 }
398
399 if (cfg->dev_no == 0) {
400 printf("hrctl: invalid number of devices, exiting\n");
[64eba57]401 goto bad;
[94d84a0]402 }
403
404 rc = hr_sess_init(&hr);
405 if (rc != EOK) {
406 printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc));
407 retval = 1;
408 goto end;
409 }
410
411 if (create) {
[c997374]412 rc = hr_create(hr, cfg, false);
[94d84a0]413 printf("hrctl: hr_create() rc: %s\n", str_error(rc));
414 } else if (assemble) {
[c997374]415 rc = hr_create(hr, cfg, true);
[b0f1366]416 printf("hrctl: hr_assemble() rc: %s\n", str_error(rc));
[94d84a0]417 }
418
419end:
[68e357e]420 free(cfg);
[94d84a0]421 hr_sess_destroy(hr);
422 return retval;
423bad:
[68e357e]424 free(cfg);
[94d84a0]425 printf("hrctl: bad usage, try hrctl --help\n");
426 return 1;
427}
428
429/** @}
430 */
Note: See TracBrowser for help on using the repository browser.