1 /* $OpenBSD: raidctl.c,v 1.23 2004/07/17 02:14:33 deraadt Exp $ */
2 /* $NetBSD: raidctl.c,v 1.27 2001/07/10 01:30:52 lukem Exp $ */
3
4 /*-
5 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Greg Oster
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * This program is a re-write of the original rf_ctrl program
42 * distributed by CMU with RAIDframe 1.1.
43 *
44 * This program is the userland interface to the RAIDframe kernel
45 * driver in Net/OpenBSD.
46 */
47
48 #include <sys/param.h>
49 #include <sys/ioctl.h>
50 #include <sys/stat.h>
51 #include <sys/sysctl.h>
52 #ifdef NETBSD
53 #include <sys/disklabel.h>
54 #endif
55
56 #include <ctype.h>
57 #include <err.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <paths.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <util.h>
66
67 #include "rf_raidframe.h"
68
69 extern char *__progname;
70
71 typedef struct {
72 int fd;
73 int id;
74 } fdidpair;
75
76 int main(int, char *[]);
77 void do_ioctl(int, u_long, void *, const char *);
78 static void rf_configure(fdidpair *, char*, int);
79 static const char *device_status(RF_DiskStatus_t);
80 static void rf_get_device_status(fdidpair *, int);
81 static void rf_output_configuration(fdidpair *, int);
82 static void get_component_number(fdidpair *, char *, int *, int *);
83 static void rf_fail_disk(fdidpair *, char *, int);
84 static void usage(void);
85 static void get_component_label(fdidpair *, char *);
86 static void set_component_label(fdidpair *, char *);
87 static void init_component_labels(fdidpair *, int);
88 static void set_autoconfig(fdidpair *, char *);
89 static void add_hot_spare(fdidpair *, char *);
90 static void remove_hot_spare(fdidpair *, char *);
91 static void rebuild_in_place(fdidpair *, char *);
92 static void check_status(fdidpair *,int,int);
93 static void check_parity(fdidpair *,int,int);
94 static void do_meter(fdidpair *, int, u_long);
95 static void get_bar(char *, double, int);
96 static void get_time_string(char *, int);
97 static int open_device(fdidpair **, char *);
98 static int get_all_devices(char ***, const char *);
99
100 int verbose;
101 int do_all;
102
103 int
main(int argc,char * argv[])104 main(int argc, char *argv[])
105 {
106 int ch;
107 int num_options;
108 unsigned int action;
109 char config_filename[PATH_MAX];
110 char name[PATH_MAX];
111 char component[PATH_MAX];
112 char autoconf[10];
113 int do_output;
114 int do_recon;
115 int do_rewrite;
116 int serial_number;
117 int i, nfd;
118 fdidpair *fds;
119 int force;
120 u_long meter;
121 const char *actionstr;
122
123 num_options = 0;
124 action = 0;
125 meter = 0;
126 do_output = 0;
127 do_recon = 0;
128 do_rewrite = 0;
129 do_all = 0;
130 serial_number = 0;
131 force = 0;
132 actionstr = NULL;
133
134 while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:r:R:sSpPuv"))
135 != -1)
136 switch(ch) {
137 case 'a':
138 action = RAIDFRAME_ADD_HOT_SPARE;
139 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
140 errx(1, "-a arg too long");
141 num_options++;
142 break;
143 case 'A':
144 action = RAIDFRAME_SET_AUTOCONFIG;
145 if (strlcpy(autoconf, optarg, sizeof(autoconf)) >= sizeof(autoconf))
146 errx(1, "-A arg too long");
147 num_options++;
148 break;
149 case 'B':
150 action = RAIDFRAME_COPYBACK;
151 num_options++;
152 break;
153 case 'c':
154 action = RAIDFRAME_CONFIGURE;
155 if (strlcpy(config_filename, optarg, sizeof config_filename) >=
156 sizeof(config_filename))
157 errx(1, "-c arg too long");
158 force = 0;
159 num_options++;
160 break;
161 case 'C':
162 if (strlcpy(config_filename, optarg, sizeof config_filename) >=
163 sizeof(config_filename))
164 errx(1, "-C arg too long");
165 action = RAIDFRAME_CONFIGURE;
166 force = 1;
167 num_options++;
168 break;
169 case 'f':
170 action = RAIDFRAME_FAIL_DISK;
171 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
172 errx(1, "-f arg too long");
173 do_recon = 0;
174 num_options++;
175 break;
176 case 'F':
177 action = RAIDFRAME_FAIL_DISK;
178 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
179 errx(1, "-F arg too long");
180 do_recon = 1;
181 num_options++;
182 break;
183 case 'g':
184 action = RAIDFRAME_GET_COMPONENT_LABEL;
185 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
186 errx(1, "-g arg too long");
187 num_options++;
188 break;
189 case 'G':
190 action = RAIDFRAME_GET_INFO;
191 do_output = 1;
192 num_options++;
193 break;
194 case 'i':
195 action = RAIDFRAME_REWRITEPARITY;
196 num_options++;
197 break;
198 case 'I':
199 action = RAIDFRAME_INIT_LABELS;
200 serial_number = atoi(optarg);
201 num_options++;
202 break;
203 case 'l':
204 action = RAIDFRAME_SET_COMPONENT_LABEL;
205 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
206 errx(1, "-l arg too long");
207 num_options++;
208 break;
209 case 'r':
210 action = RAIDFRAME_REMOVE_HOT_SPARE;
211 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
212 errx(1, "-r arg too long");
213 num_options++;
214 break;
215 case 'R':
216 if (strlcpy(component, optarg, sizeof component) >= sizeof(component))
217 errx(1, "-R arg too long");
218 action = RAIDFRAME_REBUILD_IN_PLACE;
219 num_options++;
220 break;
221 case 's':
222 action = RAIDFRAME_GET_INFO;
223 num_options++;
224 break;
225 case 'S':
226 action = RAIDFRAME_CHECK_RECON_STATUS_EXT;
227 num_options++;
228 break;
229 case 'p':
230 action = RAIDFRAME_CHECK_PARITY;
231 num_options++;
232 break;
233 case 'P':
234 action = RAIDFRAME_CHECK_PARITY;
235 do_rewrite = 1;
236 num_options++;
237 break;
238 case 'u':
239 action = RAIDFRAME_SHUTDOWN;
240 num_options++;
241 break;
242 case 'v':
243 verbose = 1;
244 break;
245 default:
246 usage();
247 }
248 argc -= optind;
249 argv += optind;
250
251 if ((num_options > 1) || (argc == 0))
252 usage();
253
254 if (strlcpy(name, argv[0], sizeof name) >= sizeof(name))
255 errx(1, "device name too long");
256
257 if ((nfd = open_device(&fds, name)) < 1) {
258 /* No configured raid device */
259 free(fds);
260 return (0);
261 }
262
263 if (do_all) {
264 switch(action) {
265 case RAIDFRAME_ADD_HOT_SPARE:
266 case RAIDFRAME_REMOVE_HOT_SPARE:
267 case RAIDFRAME_CONFIGURE:
268 case RAIDFRAME_SET_AUTOCONFIG:
269 case RAIDFRAME_FAIL_DISK:
270 case RAIDFRAME_SET_COMPONENT_LABEL:
271 case RAIDFRAME_GET_COMPONENT_LABEL:
272 case RAIDFRAME_INIT_LABELS:
273 case RAIDFRAME_REBUILD_IN_PLACE:
274 errx(1,
275 "This action doesn't work with the 'all' device");
276 break;
277 default:
278 break;
279 }
280 }
281
282 switch(action) {
283 case RAIDFRAME_ADD_HOT_SPARE:
284 add_hot_spare(fds, component);
285 break;
286 case RAIDFRAME_REMOVE_HOT_SPARE:
287 remove_hot_spare(fds, component);
288 break;
289 case RAIDFRAME_CONFIGURE:
290 rf_configure(fds, config_filename, force);
291 break;
292 case RAIDFRAME_SET_AUTOCONFIG:
293 set_autoconfig(fds, autoconf);
294 break;
295 case RAIDFRAME_COPYBACK:
296 i = nfd;
297 while (i--) {
298 do_ioctl(fds[i].fd, RAIDFRAME_COPYBACK, NULL,
299 "RAIDFRAME_COPYBACK");
300 }
301 actionstr = "Copyback";
302 meter = RAIDFRAME_CHECK_COPYBACK_STATUS_EXT;
303 break;
304 case RAIDFRAME_FAIL_DISK:
305 rf_fail_disk(fds, component, do_recon);
306 break;
307 case RAIDFRAME_SET_COMPONENT_LABEL:
308 set_component_label(fds, component);
309 break;
310 case RAIDFRAME_GET_COMPONENT_LABEL:
311 get_component_label(fds, component);
312 break;
313 case RAIDFRAME_INIT_LABELS:
314 init_component_labels(fds, serial_number);
315 break;
316 case RAIDFRAME_REWRITEPARITY:
317 i = nfd;
318 while (i--) {
319 do_ioctl(fds[i].fd, RAIDFRAME_REWRITEPARITY, NULL,
320 "RAIDFRAME_REWRITEPARITY");
321 }
322 actionstr = "Parity Re-Write";
323 meter = RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT;
324 break;
325 case RAIDFRAME_CHECK_RECON_STATUS_EXT:
326 check_status(fds, nfd, 1);
327 break;
328 case RAIDFRAME_GET_INFO:
329 if (do_output)
330 rf_output_configuration(fds, nfd);
331 else
332 rf_get_device_status(fds, nfd);
333 break;
334 case RAIDFRAME_REBUILD_IN_PLACE:
335 rebuild_in_place(fds, component);
336 break;
337 case RAIDFRAME_CHECK_PARITY:
338 check_parity(fds, nfd, do_rewrite);
339 break;
340 case RAIDFRAME_SHUTDOWN:
341 i = nfd;
342 while (i--) {
343 do_ioctl(fds[i].fd, RAIDFRAME_SHUTDOWN, NULL,
344 "RAIDFRAME_SHUTDOWN");
345 }
346 break;
347 default:
348 break;
349 }
350
351 if (verbose && meter) {
352 sleep(3); /* XXX give the action a chance to start */
353 printf("%s status:\n", actionstr);
354 do_meter(fds, nfd, meter);
355 }
356
357 i = nfd;
358 while (i--)
359 close(fds[i].fd);
360
361 free(fds);
362 return (0);
363 }
364
365 void
do_ioctl(int fd,unsigned long command,void * arg,const char * ioctl_name)366 do_ioctl(int fd, unsigned long command, void *arg, const char *ioctl_name)
367 {
368 if (ioctl(fd, command, arg) < 0)
369 errx(1, "ioctl (%s) failed", ioctl_name);
370 }
371
372
373 static void
rf_configure(fdidpair * fds,char * config_file,int force)374 rf_configure(fdidpair *fds, char *config_file, int force)
375 {
376 void *generic;
377 RF_Config_t cfg;
378
379 if (rf_MakeConfig(config_file, &cfg) != 0)
380 errx(1, "unable to create RAIDframe configuration structure");
381
382 cfg.force = force;
383
384 /*
385 * Note the extra level of redirection needed here, since
386 * what we really want to pass in is a pointer to the pointer to
387 * the configuration structure.
388 */
389
390 generic = (void *) &cfg;
391 do_ioctl(fds->fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE");
392 }
393
394 static const char *
device_status(RF_DiskStatus_t status)395 device_status(RF_DiskStatus_t status)
396 {
397
398 switch (status) {
399 case rf_ds_optimal:
400 return ("optimal");
401 case rf_ds_failed:
402 return ("failed");
403 case rf_ds_reconstructing:
404 return ("reconstructing");
405 case rf_ds_dist_spared:
406 return ("dist_spared");
407 case rf_ds_spared:
408 return ("spared");
409 case rf_ds_spare:
410 return ("spare");
411 case rf_ds_used_spare:
412 return ("used_spare");
413 default:
414 return ("UNKNOWN");
415 }
416 /* NOTREACHED */
417 }
418
419 static void
rf_get_device_status(fdidpair * fds,int nfd)420 rf_get_device_status(fdidpair *fds, int nfd)
421 {
422 RF_DeviceConfig_t device_config;
423 void *cfg_ptr;
424 int is_clean;
425 int i,j;
426
427 cfg_ptr = &device_config;
428
429 i = nfd;
430 while (i--) {
431 do_ioctl(fds[i].fd, RAIDFRAME_GET_INFO, &cfg_ptr,
432 "RAIDFRAME_GET_INFO");
433
434 printf("raid%d Components:\n", fds[i].id);
435 for (j = 0; j < device_config.ndevs; j++) {
436 printf("%20s: %s\n", device_config.devs[j].devname,
437 device_status(device_config.devs[j].status));
438 }
439 if (device_config.nspares > 0) {
440 printf("Spares:\n");
441 for (j = 0; j < device_config.nspares; j++) {
442 printf("%20s: %s\n",
443 device_config.spares[j].devname,
444 device_status(device_config.spares[j].status));
445 }
446 } else {
447 printf("No spares.\n");
448 }
449 if (verbose) {
450 for(j=0; j < device_config.ndevs; j++) {
451 if (device_config.devs[j].status ==
452 rf_ds_optimal) {
453 get_component_label(&fds[i],
454 device_config.devs[j].devname);
455 } else {
456 printf("%s status is: %s. "
457 "Skipping label.\n",
458 device_config.devs[j].devname,
459 device_status(device_config.devs[j].status));
460 }
461 }
462
463 if (device_config.nspares > 0) {
464 for(j=0; j < device_config.nspares; j++) {
465 if ((device_config.spares[j].status ==
466 rf_ds_optimal) ||
467 (device_config.spares[j].status ==
468 rf_ds_used_spare)) {
469 get_component_label(&fds[i],
470 device_config.spares[j].devname);
471 } else {
472 printf("%s status is: %s. "
473 "Skipping label.\n",
474 device_config.spares[j].devname,
475 device_status(device_config.spares[j].status));
476 }
477 }
478 }
479 }
480
481 do_ioctl(fds[i].fd, RAIDFRAME_CHECK_PARITY, &is_clean,
482 "RAIDFRAME_CHECK_PARITY");
483 if (is_clean) {
484 printf("Parity status: clean\n");
485 } else {
486 printf("Parity status: DIRTY\n");
487 }
488 check_status(&fds[i], 1, 0);
489 }
490 }
491
492 static void
rf_output_configuration(fdidpair * fds,int nfd)493 rf_output_configuration(fdidpair *fds, int nfd)
494 {
495 RF_DeviceConfig_t device_config;
496 void *cfg_ptr;
497 int i,j;
498 RF_ComponentLabel_t component_label;
499 void *label_ptr;
500 int component_num;
501 int num_cols;
502 char name[PATH_MAX];
503
504 cfg_ptr = &device_config;
505
506 i = nfd;
507 while (i--) {
508 snprintf(name, PATH_MAX, "/dev/raid%dc", fds[i].id);
509
510 printf("# raidctl config file for %s\n", name);
511 printf("\n");
512 do_ioctl(fds[i].fd, RAIDFRAME_GET_INFO, &cfg_ptr,
513 "RAIDFRAME_GET_INFO");
514
515 printf("START array\n");
516 printf("# numRow numCol numSpare\n");
517 printf("%d %d %d\n", device_config.rows, device_config.cols,
518 device_config.nspares);
519 printf("\n");
520
521 printf("START disks\n");
522 for(j = 0; j < device_config.ndevs; j++)
523 printf("%s\n", device_config.devs[j].devname);
524 printf("\n");
525
526 if (device_config.nspares > 0) {
527 printf("START spare\n");
528 for(j = 0; j < device_config.nspares; j++)
529 printf("%s\n", device_config.spares[j].devname);
530 printf("\n");
531 }
532
533 for(j = 0; j < device_config.ndevs; j++) {
534 if (device_config.devs[j].status == rf_ds_optimal)
535 break;
536 }
537 if (j == device_config.ndevs) {
538 printf("# WARNING: no optimal components; using %s\n",
539 device_config.devs[0].devname);
540 j = 0;
541 }
542 get_component_number(&fds[i], device_config.devs[j].devname,
543 &component_num, &num_cols);
544 memset(&component_label, 0, sizeof(RF_ComponentLabel_t));
545 component_label.row = component_num / num_cols;
546 component_label.column = component_num % num_cols;
547 label_ptr = &component_label;
548 do_ioctl(fds[i].fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr,
549 "RAIDFRAME_GET_COMPONENT_LABEL");
550
551 printf("START layout\n");
552 printf(
553 "# sectPerSU SUsPerParityUnit SUsPerReconUnit "
554 "RAID_level_%c\n",
555 (char) component_label.parityConfig);
556 printf("%d %d %d %c\n",
557 component_label.sectPerSU, component_label.SUsPerPU,
558 component_label.SUsPerRU,
559 (char) component_label.parityConfig);
560 printf("\n");
561
562 printf("START queue\n");
563 printf("fifo %d\n", device_config.maxqdepth);
564 }
565 }
566
567 static void
get_component_number(fdidpair * fds,char * component_name,int * component_number,int * num_columns)568 get_component_number(fdidpair *fds, char *component_name, int *component_number,
569 int *num_columns)
570 {
571 RF_DeviceConfig_t device_config;
572 void *cfg_ptr;
573 int i;
574 int found;
575
576 *component_number = -1;
577
578 /* Assuming a full path spec... */
579 cfg_ptr = &device_config;
580 do_ioctl(fds->fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
581
582 *num_columns = device_config.cols;
583
584 found = 0;
585 for (i = 0; i < device_config.ndevs; i++) {
586 if (strncmp(component_name, device_config.devs[i].devname,
587 PATH_MAX) == 0) {
588 found = 1;
589 *component_number = i;
590 }
591 }
592 if (!found) { /* maybe it's a spare? */
593 for (i = 0; i < device_config.nspares; i++) {
594 if (strncmp(component_name,
595 device_config.spares[i].devname,
596 PATH_MAX) == 0) {
597 found = 1;
598 *component_number = i + device_config.ndevs;
599 /* the way spares are done should
600 really change... */
601 *num_columns = device_config.cols +
602 device_config.nspares;
603 }
604 }
605 }
606
607 if (!found)
608 errx(1, "%s is not a component of this device", component_name);
609 }
610
611 static void
rf_fail_disk(fdidpair * fds,char * component_to_fail,int do_recon)612 rf_fail_disk(fdidpair *fds, char *component_to_fail, int do_recon)
613 {
614 struct rf_recon_req recon_request;
615 int component_num;
616 int num_cols;
617
618 get_component_number(fds, component_to_fail, &component_num, &num_cols);
619
620 recon_request.row = component_num / num_cols;
621 recon_request.col = component_num % num_cols;
622 if (do_recon) {
623 recon_request.flags = RF_FDFLAGS_RECON;
624 } else {
625 recon_request.flags = RF_FDFLAGS_NONE;
626 }
627 do_ioctl(fds->fd, RAIDFRAME_FAIL_DISK, &recon_request,
628 "RAIDFRAME_FAIL_DISK");
629 if (do_recon && verbose) {
630 printf("Reconstruction status:\n");
631 sleep(3); /* XXX give reconstruction a chance to start */
632 do_meter(fds, 1, RAIDFRAME_CHECK_RECON_STATUS_EXT);
633 }
634 }
635
636 static void
get_component_label(fdidpair * fds,char * component)637 get_component_label(fdidpair *fds, char *component)
638 {
639 RF_ComponentLabel_t component_label;
640 void *label_ptr;
641 int component_num;
642 int num_cols;
643
644 get_component_number(fds, component, &component_num, &num_cols);
645
646 memset(&component_label, 0, sizeof(RF_ComponentLabel_t));
647 component_label.row = component_num / num_cols;
648 component_label.column = component_num % num_cols;
649
650 label_ptr = &component_label;
651 do_ioctl(fds->fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr,
652 "RAIDFRAME_GET_COMPONENT_LABEL");
653
654 printf("Component label for %s:\n", component);
655
656 printf(" Row: %d, Column: %d, Num Rows: %d, Num Columns: %d\n",
657 component_label.row, component_label.column,
658 component_label.num_rows, component_label.num_columns);
659 printf(" Version: %d, Serial Number: %d, Mod Counter: %d\n",
660 component_label.version, component_label.serial_number,
661 component_label.mod_counter);
662 printf(" Clean: %s, Status: %d\n",
663 component_label.clean ? "Yes" : "No",
664 component_label.status);
665 printf(" sectPerSU: %d, SUsPerPU: %d, SUsPerRU: %d\n",
666 component_label.sectPerSU, component_label.SUsPerPU,
667 component_label.SUsPerRU);
668 printf(" Queue size: %d, blocksize: %d, numBlocks: %d\n",
669 component_label.maxOutstanding, component_label.blockSize,
670 component_label.numBlocks);
671 printf(" RAID Level: %c\n", (char) component_label.parityConfig);
672 printf(" Autoconfig: %s\n",
673 component_label.autoconfigure ? "Yes" : "No");
674 printf(" Root partition: %s\n",
675 component_label.root_partition ? "Yes" : "No");
676 printf(" Last configured as: raid%d\n", component_label.last_unit);
677 }
678
679 static void
set_component_label(fdidpair * fds,char * component)680 set_component_label(fdidpair *fds, char *component)
681 {
682 RF_ComponentLabel_t component_label;
683 int component_num;
684 int num_cols;
685
686 get_component_number(fds, component, &component_num, &num_cols);
687
688 /* XXX This is currently here for testing, and future expandability */
689
690 component_label.version = 1;
691 component_label.serial_number = 123456;
692 component_label.mod_counter = 0;
693 component_label.row = component_num / num_cols;
694 component_label.column = component_num % num_cols;
695 component_label.num_rows = 0;
696 component_label.num_columns = 5;
697 component_label.clean = 0;
698 component_label.status = 1;
699
700 do_ioctl(fds->fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label,
701 "RAIDFRAME_SET_COMPONENT_LABEL");
702 }
703
704
705 static void
init_component_labels(fdidpair * fds,int serial_number)706 init_component_labels(fdidpair *fds, int serial_number)
707 {
708 RF_ComponentLabel_t component_label;
709
710 component_label.version = 0;
711 component_label.serial_number = serial_number;
712 component_label.mod_counter = 0;
713 component_label.row = 0;
714 component_label.column = 0;
715 component_label.num_rows = 0;
716 component_label.num_columns = 0;
717 component_label.clean = 0;
718 component_label.status = 0;
719
720 do_ioctl(fds->fd, RAIDFRAME_INIT_LABELS, &component_label,
721 "RAIDFRAME_SET_COMPONENT_LABEL");
722 }
723
724 static void
set_autoconfig(fdidpair * fds,char * autoconf)725 set_autoconfig(fdidpair *fds, char *autoconf)
726 {
727 int auto_config;
728 int root_config;
729
730 auto_config = 0;
731 root_config = 0;
732
733 if (strncasecmp(autoconf, "root", 4) == 0) {
734 root_config = 1;
735 }
736
737 if ((strncasecmp(autoconf, "yes", 3) == 0) ||
738 root_config == 1) {
739 auto_config = 1;
740 }
741
742 do_ioctl(fds->fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config,
743 "RAIDFRAME_SET_AUTOCONFIG");
744
745 do_ioctl(fds->fd, RAIDFRAME_SET_ROOT, &root_config,
746 "RAIDFRAME_SET_ROOT");
747
748 printf("raid%d: Autoconfigure: %s\n", fds->id,
749 auto_config ? "Yes" : "No");
750
751 if (root_config == 1) {
752 printf("raid%d: Root: %s\n", fds->id,
753 auto_config ? "Yes" : "No");
754 }
755 }
756
757 static void
add_hot_spare(fdidpair * fds,char * component)758 add_hot_spare(fdidpair *fds, char *component)
759 {
760 RF_SingleComponent_t hot_spare;
761
762 hot_spare.row = 0;
763 hot_spare.column = 0;
764 strlcpy(hot_spare.component_name, component,
765 sizeof(hot_spare.component_name));
766
767 do_ioctl(fds->fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare,
768 "RAIDFRAME_ADD_HOT_SPARE");
769 }
770
771 static void
remove_hot_spare(fdidpair * fds,char * component)772 remove_hot_spare(fdidpair *fds, char *component)
773 {
774 RF_SingleComponent_t hot_spare;
775 int component_num;
776 int num_cols;
777
778 get_component_number(fds, component, &component_num, &num_cols);
779
780 hot_spare.row = component_num / num_cols;
781 hot_spare.column = component_num % num_cols;
782
783 strlcpy(hot_spare.component_name, component,
784 sizeof(hot_spare.component_name));
785
786 do_ioctl(fds->fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare,
787 "RAIDFRAME_REMOVE_HOT_SPARE");
788 }
789
790 static void
rebuild_in_place(fdidpair * fds,char * component)791 rebuild_in_place(fdidpair *fds, char *component)
792 {
793 RF_SingleComponent_t comp;
794 int component_num;
795 int num_cols;
796
797 get_component_number(fds, component, &component_num, &num_cols);
798
799 comp.row = 0;
800 comp.column = component_num;
801 strlcpy(comp.component_name, component, sizeof(comp.component_name));
802
803 do_ioctl(fds->fd, RAIDFRAME_REBUILD_IN_PLACE, &comp,
804 "RAIDFRAME_REBUILD_IN_PLACE");
805
806 if (verbose) {
807 printf("Reconstruction status:\n");
808 sleep(3); /* XXX give reconstruction a chance to start */
809 do_meter(fds, 1, RAIDFRAME_CHECK_RECON_STATUS_EXT);
810 }
811
812 }
813
814 static void
check_parity(fdidpair * fds,int nfd,int do_rewrite)815 check_parity(fdidpair *fds, int nfd, int do_rewrite)
816 {
817 int i, is_clean, all_dirty, was_dirty;
818 int percent_done;
819 char dev_name[PATH_MAX];
820
821 all_dirty = 0;
822 i = nfd;
823 while (i--) {
824 is_clean = 0;
825 percent_done = 0;
826 snprintf(dev_name, PATH_MAX, "raid%d", fds[i].id);
827
828 do_ioctl(fds[i].fd, RAIDFRAME_CHECK_PARITY, &is_clean,
829 "RAIDFRAME_CHECK_PARITY");
830 if (is_clean) {
831 printf("%s: Parity status: clean\n", dev_name);
832 } else {
833 all_dirty |= 1 << fds[i].id;
834 printf("%s: Parity status: DIRTY\n", dev_name);
835 if (do_rewrite) {
836 printf("%s: Initiating re-write of parity\n",
837 dev_name);
838 do_ioctl(fds[i].fd, RAIDFRAME_REWRITEPARITY,
839 NULL, "RAIDFRAME_REWRITEPARITY");
840 } else {
841 /* parity is wrong, and is not being fixed. */
842 exit(1);
843 }
844 }
845 }
846
847 if (do_all)
848 strncpy(dev_name, "all raid", PATH_MAX);
849
850 was_dirty = all_dirty;
851 while (all_dirty) {
852 sleep(3); /* wait a bit... */
853 if (verbose) {
854 printf("Parity Re-write status:\n");
855 do_meter(fds, nfd,
856 RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
857 all_dirty = 0;
858 } else {
859 i = nfd;
860 while (i--) {
861 do_ioctl(fds[i].fd,
862 RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
863 &percent_done,
864 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"
865 );
866 if (percent_done == 100) {
867 all_dirty &= ~(1 << fds[i].id);
868 }
869 }
870 }
871 }
872 if (verbose && was_dirty)
873 printf("%s: Parity Re-write complete\n", dev_name);
874 }
875
876
877 static void
check_status(fdidpair * fds,int nfd,int meter)878 check_status(fdidpair *fds, int nfd, int meter)
879 {
880 int i;
881 int recon_percent_done = 0;
882 int parity_percent_done = 0;
883 int copyback_percent_done = 0;
884 int do_recon = 0;
885 int do_parity = 0;
886 int do_copyback = 0;
887 u_long check = 0;
888
889 i = nfd;
890 while (i--) {
891 if (meter) {
892 printf("raid%d Status:\n", fds[i].id);
893 }
894 do_ioctl(fds[i].fd, RAIDFRAME_CHECK_RECON_STATUS,
895 &recon_percent_done,
896 "RAIDFRAME_CHECK_RECON_STATUS");
897 printf("Reconstruction is %d%% complete.\n",
898 recon_percent_done);
899 if (recon_percent_done < 100) {
900 do_recon |= 1 << fds[i].id;
901 }
902 do_ioctl(fds[i].fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
903 &parity_percent_done,
904 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
905 printf("Parity Re-write is %d%% complete.\n",
906 parity_percent_done);
907 if (parity_percent_done < 100) {
908 do_parity |= 1 << fds[i].id;
909 }
910 do_ioctl(fds[i].fd, RAIDFRAME_CHECK_COPYBACK_STATUS,
911 ©back_percent_done,
912 "RAIDFRAME_CHECK_COPYBACK_STATUS");
913 printf("Copyback is %d%% complete.\n",
914 copyback_percent_done);
915 if (copyback_percent_done < 100) {
916 do_copyback |= 1 << fds[i].id;
917 }
918 }
919
920 if (meter && verbose) {
921 /* These 3 should be mutually exclusive at this point */
922 if (do_recon) {
923 printf("Reconstruction status:\n");
924 check = RAIDFRAME_CHECK_RECON_STATUS_EXT;
925 } else if (do_parity) {
926 printf("Parity Re-write status:\n");
927 check = RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT;
928 } else if (do_copyback) {
929 printf("Copyback status:\n");
930 check = RAIDFRAME_CHECK_COPYBACK_STATUS_EXT;
931 }
932 do_meter(fds, nfd, check);
933 }
934 }
935
936 const char *tbits = "|/-\\";
937
938 static void
do_meter(fdidpair * fds,int nfd,u_long option)939 do_meter(fdidpair *fds, int nfd, u_long option)
940 {
941 int percent_done;
942 int start_value;
943 RF_ProgressInfo_t *progressInfo;
944 void *pInfoPtr;
945 struct timeval start_time;
946 struct timeval current_time;
947 double elapsed;
948 int elapsed_sec;
949 int elapsed_usec;
950 int progress_total, progress_completed;
951 int simple_eta, last_eta;
952 double rate;
953 int amount;
954 int tbit_value;
955 char buffer[1024];
956 char bar_buffer[1024];
957 char eta_buffer[1024];
958 int not_done;
959 int i;
960
961 not_done = 0;
962 percent_done = 0;
963 tbit_value = 0;
964 start_value = 0;
965 last_eta = 0;
966 progress_total = progress_completed = 0;
967 progressInfo = malloc(nfd * sizeof(RF_ProgressInfo_t));
968 memset(&progressInfo[0], 0, nfd * sizeof(RF_ProgressInfo_t));
969
970 if (gettimeofday(&start_time, NULL))
971 err(1, "gettimeofday");
972
973 current_time = start_time;
974
975 i = nfd;
976 while (i--) {
977 pInfoPtr = &progressInfo[i];
978 do_ioctl(fds[i].fd, option, &pInfoPtr, "");
979 start_value += progressInfo[i].completed;
980 progress_total += progressInfo[i].total;
981
982 if (progressInfo[i].completed < progressInfo[i].total) {
983 not_done |= 1 << i;
984 }
985 }
986
987 while (not_done) {
988 progress_completed = 0;
989 percent_done = 0;
990 amount = 0;
991
992 i = nfd;
993 while (i--) {
994 pInfoPtr = &progressInfo[i];
995 do_ioctl(fds[i].fd, option, &pInfoPtr, "");
996 progress_completed += progressInfo[i].completed;
997
998 if (progressInfo[i].completed >=
999 progressInfo[i].total) {
1000 not_done &= ~(1 << i);
1001 }
1002 }
1003 percent_done = (progress_completed * 100) / progress_total;
1004 amount = progress_completed - start_value;
1005
1006 get_bar(bar_buffer, percent_done, 40);
1007
1008 elapsed_sec = current_time.tv_sec -
1009 start_time.tv_sec;
1010 elapsed_usec = current_time.tv_usec -
1011 start_time.tv_usec;
1012 if (elapsed_usec < 0) {
1013 elapsed_usec += 1000000;
1014 elapsed_sec--;
1015 }
1016
1017 elapsed = (double) elapsed_sec +
1018 (double) elapsed_usec / 1000000.0;
1019
1020 if (amount <= 0) { /* we don't do negatives (yet?) */
1021 amount = 0;
1022 }
1023
1024 if (elapsed == 0)
1025 rate = 0.0;
1026 else
1027 rate = amount / elapsed;
1028
1029 if (rate > 0.0) {
1030 simple_eta = (int)
1031 (((double)progress_total -
1032 (double) progress_completed)
1033 / rate);
1034 } else {
1035 simple_eta = -1;
1036 }
1037
1038 if (simple_eta <= 0) {
1039 simple_eta = last_eta;
1040 } else {
1041 last_eta = simple_eta;
1042 }
1043
1044 get_time_string(eta_buffer, simple_eta);
1045
1046 snprintf(buffer, 1024,
1047 "\r\t%3d%% |%s| ETA: %s %c",
1048 percent_done, bar_buffer,
1049 eta_buffer, tbits[tbit_value]);
1050
1051 write(fileno(stdout), buffer, strlen(buffer));
1052 fflush(stdout);
1053
1054 if (++tbit_value > 3)
1055 tbit_value = 0;
1056
1057 if (not_done)
1058 sleep(2);
1059
1060 if (gettimeofday(¤t_time, NULL))
1061 err(1, "gettimeofday");
1062 }
1063 printf("\n");
1064 }
1065
1066 /* 40 '*''s per line, then 40 ' ''s line. */
1067 /* If you've got a screen wider than 160 characters, "tough" */
1068
1069 #define STAR_MIDPOINT 4*40
1070 const char stars[] = "****************************************"
1071 "****************************************"
1072 "****************************************"
1073 "****************************************"
1074 " "
1075 " "
1076 " "
1077 " ";
1078
1079 static void
get_bar(char * string,double percent,int max_strlen)1080 get_bar(char *string, double percent, int max_strlen)
1081 {
1082 int offset;
1083
1084 if (max_strlen > STAR_MIDPOINT) {
1085 max_strlen = STAR_MIDPOINT;
1086 }
1087 offset = STAR_MIDPOINT -
1088 (int)((percent * max_strlen) / 100);
1089 if (offset < 0)
1090 offset = 0;
1091 snprintf(string, max_strlen, "%s", &stars[offset]);
1092 }
1093
1094 static void
get_time_string(char * string,int simple_time)1095 get_time_string(char *string, int simple_time)
1096 {
1097 int minutes, seconds, hours;
1098 char hours_buffer[5];
1099 char minutes_buffer[5];
1100 char seconds_buffer[5];
1101
1102 if (simple_time >= 0) {
1103
1104 minutes = (int) simple_time / 60;
1105 seconds = ((int)simple_time - 60 * minutes);
1106 hours = minutes / 60;
1107 minutes = minutes - 60 * hours;
1108
1109 if (hours > 0) {
1110 snprintf(hours_buffer, sizeof(hours_buffer),
1111 "%02d:", hours);
1112 } else {
1113 snprintf(hours_buffer, sizeof(hours_buffer), " ");
1114 }
1115
1116 snprintf(minutes_buffer, sizeof(minutes_buffer),
1117 "%02d:", minutes);
1118 snprintf(seconds_buffer, sizeof(seconds_buffer),
1119 "%02d", seconds);
1120 snprintf(string, 1024, "%s%s%s",
1121 hours_buffer, minutes_buffer, seconds_buffer);
1122 } else {
1123 snprintf(string, 1024, " --:--");
1124 }
1125
1126 }
1127
1128 static int
open_device(fdidpair ** devfd,char * name)1129 open_device(fdidpair **devfd, char *name)
1130 {
1131 int nfd, i;
1132 struct stat st;
1133 char **devname;
1134
1135 if (strcmp(name, "all") == 0) {
1136 do_all = 1;
1137 nfd = get_all_devices(&devname, "raid");
1138 } else {
1139 nfd = 1;
1140 devname = malloc(sizeof(void*));
1141 devname[0] = malloc(PATH_MAX);
1142
1143 if ((name[0] == '/') || (name[0] == '.')) {
1144 /* they've (apparently) given a full path... */
1145 strlcpy(devname[0], name, PATH_MAX);
1146 } else {
1147 if (isdigit(name[strlen(name) - 1])) {
1148 snprintf(devname[0], PATH_MAX, "%s%s%c",
1149 _PATH_DEV, name, 'a' + getrawpartition());
1150 } else {
1151 snprintf(devname[0], PATH_MAX, "%s%s",
1152 _PATH_DEV, name);
1153 }
1154 }
1155 }
1156
1157 if ((*devfd = malloc(nfd * sizeof(fdidpair))) == NULL)
1158 errx(1, "malloc() error");
1159
1160 i = nfd;
1161 while (i--) {
1162 if (stat(devname[i], &st) != 0)
1163 errx(errno, "stat failure on: %s", devname[i]);
1164 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
1165 errx(EINVAL, "invalid device: %s", devname[i]);
1166
1167 if (((*devfd)[i].fd = open(devname[i], O_RDWR, 0640)) < 0)
1168 errx(1, "unable to open device file: %s", devname[i]);
1169 (*devfd)[i].id = RF_DEV2RAIDID(st.st_rdev);
1170
1171 free(devname[i]);
1172 }
1173
1174 if (devname != NULL)
1175 free(devname);
1176
1177 return (nfd);
1178 }
1179
1180 static int
get_all_devices(char *** diskarray,const char * genericname)1181 get_all_devices(char ***diskarray, const char *genericname)
1182 {
1183 int i, numdevs, mib[2];
1184 size_t len;
1185 char *disks, *fp, *p;
1186
1187 numdevs = 0;
1188
1189 mib[0] = CTL_HW;
1190 mib[1] = HW_DISKNAMES;
1191 sysctl(mib, 2, NULL, &len, NULL, 0);
1192 if ((disks = malloc(len + 1)) == NULL)
1193 errx(1, "malloc() error");
1194 sysctl(mib, 2, disks, &len, NULL, 0);
1195 disks[len] = '\0';
1196
1197 fp = disks;
1198 while ((fp = strstr((const char*)fp, genericname)) != NULL) {
1199 numdevs++;
1200 fp++;
1201 }
1202
1203 *diskarray = (char**) malloc(numdevs * sizeof(void*));
1204 i = 0;
1205 fp = disks;
1206 while ((p = strsep(&fp, ",")) != NULL) {
1207 if (strstr((const char*)p, genericname) != NULL) {
1208 int len = strlen(p) + 7;
1209
1210 (*diskarray)[i] = (char*) malloc(len);
1211 snprintf((*diskarray)[i++], len, "/dev/%s%c", p,
1212 'a' + getrawpartition());
1213 }
1214 }
1215
1216 free(disks);
1217
1218 return (numdevs);
1219 }
1220
1221 static void
usage(void)1222 usage(void)
1223 {
1224 fprintf(stderr,
1225 "usage: raidctl [-v] [-afFgrR component] [-BGipPsSu] [-cC config_file]\n");
1226 fprintf(stderr,
1227 " [-A [yes | no | root]] [-I serial_number] dev\n");
1228 exit(1);
1229 /* NOTREACHED */
1230 }
1231