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

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

hrctl: inform about stopping a service that does not exit

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