source: mainline/uspace/app/hrctl/hrctl.c@ 64eba57

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

hrctl: fix memory leaks

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