source: MondoRescue/branches/3.2/mondo/src/mondorestore/mondo-rstr-newt.c@ 3510

Last change on this file since 3510 was 3289, checked in by Bruno Cornec, 10 years ago
  • change function number_of_disks_as_string into one returning a dynamically allocates tring
  • Property svn:keywords set to Id
File size: 83.8 KB
Line 
1/***************************************************************************
2 * $Id: mondo-rstr-newt.c 3289 2014-05-06 08:24:14Z bruno $
3 * Functions for handling GUI interfaces in the restore.
4 */
5
6#ifdef __FreeBSD__
7#define OSSWAP(linux,fbsd) fbsd
8#else
9#define OSSWAP(linux,fbsd) linux
10#endif
11
12#include "mondo-rstr-newt.h"
13#include "mr_mem.h"
14#include "mr_str.h"
15
16//static char cvsid[] = "$Id: mondo-rstr-newt.c 3289 2014-05-06 08:24:14Z bruno $";
17
18extern bool popup_with_buttons(char *p, char *button1, char *button2);
19extern char err_log_lines[NOOF_ERR_LINES][MAX_STR_LEN];
20
21/**
22 * @defgroup restoreGuiDisklist Disklist GUI
23 * Functions for manipulating the disklist GUI.
24 * @ingroup restoreGuiGroup
25 */
26/**
27 * @defgroup restoreGuiMountlist Mountlist GUI
28 * Functions for manipulating the mountlist/raidlist GUI.
29 * @ingroup restoreGuiGroup
30 */
31/**
32 * @defgroup restoreGuiVarslist RAID Variables GUI
33 * Functions for manipulating the RAID variables GUI.
34 * @ingroup restoreGuiGroup
35 */
36
37/**
38 * @addtogroup restoreGuiGroup
39 * @{
40 */
41/**
42 * Add an entry in @p disklist from the list in @p unallocated_raid_partitions.
43 * @param disklist The disklist to add an entry to.
44 * @param raid_device Unused; make sure it's non-NULL non-"".
45 * @param unallocated_raid_partitions The list of unallocated RAID partitions
46 * that the user may choose from.
47 * @bug raid_device is unused.
48 * @ingroup restoreGuiDisklist
49 */
50void
51add_disklist_entry(struct list_of_disks *disklist, char *raid_device,
52 struct mountlist_itself *unallocated_raid_partitions)
53{
54 /** buffers ***********************************************************/
55 char *tmp = NULL;
56
57 /** newt **************************************************************/
58 newtComponent myForm;
59 newtComponent bOK;
60 newtComponent bCancel;
61 newtComponent b_res;
62 newtComponent partitionsListbox;
63 newtComponent headerMsg;
64
65 /** prototypes *********************************************************/
66 void *keylist[ARBITRARY_MAXIMUM];
67 void *curr_choice;
68
69 /** int ****************************************************************/
70 int i = 0;
71 int index = 0;
72 int currline = 0;
73 int items = 0;
74
75 assert(disklist != NULL);
76 assert_string_is_neither_NULL_nor_zerolength(raid_device);
77 assert(unallocated_raid_partitions != NULL);
78
79 newtPushHelpLine
80 (" Add one of the following unallocated RAID partitions to this RAID device.");
81 mr_asprintf(tmp, "%-26s %s", "Device", "Size");
82 headerMsg = newtLabel(1, 1, tmp);
83 partitionsListbox =
84 newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
85 redraw_unallocpartnslist(unallocated_raid_partitions, keylist,
86 partitionsListbox);
87 i = 7;
88 bOK = newtCompactButton(i, 9, " OK ");
89 bCancel = newtCompactButton(i += 9, 9, "Cancel");
90 newtOpenWindow(22, 6, 36, 10, "Unallocated RAID partitions");
91 myForm = newtForm(NULL, NULL, 0);
92 newtFormAddComponents(myForm, headerMsg, partitionsListbox, bOK,
93 bCancel, NULL);
94 b_res = newtRunForm(myForm);
95 if (b_res != bCancel) {
96 curr_choice = newtListboxGetCurrent(partitionsListbox);
97 for (currline = 0;
98 currline < unallocated_raid_partitions->entries
99 && keylist[currline] != curr_choice; currline++);
100 if (currline == unallocated_raid_partitions->entries
101 && unallocated_raid_partitions->entries > 0) {
102 log_it("I don't know what this button does");
103 } else {
104 index = find_next_free_index_in_disklist(disklist);
105
106 items = disklist->entries;
107 strcpy(disklist->el[items].device, unallocated_raid_partitions->el[currline].device);
108 disklist->el[items].index = index;
109 disklist->entries = ++items;
110
111 }
112 }
113 newtFormDestroy(myForm);
114 mr_free(tmp);
115 newtPopWindow();
116 newtPopHelpLine();
117}
118
119
120
121
122/**
123 * Add an entry to @p mountlist.
124 * @param mountlist The mountlist to add an entry to.
125 * @param raidlist The raidlist that accompanies @p mountlist.
126 * @param listbox The listbox component in the mountlist editor.
127 * @param currline The line selected in @p listbox.
128 * @param keylist The list of keys for @p listbox.
129 * @ingroup restoreGuiMountlist
130 */
131void
132add_mountlist_entry(struct mountlist_itself *mountlist,
133 struct raidlist_itself *raidlist,
134 newtComponent listbox, int currline, void *keylist[])
135{
136
137 /** int **************************************************************/
138 int i = 0;
139
140 /** newt *************************************************************/
141 newtComponent myForm;
142 newtComponent bOK;
143 newtComponent bCancel;
144 newtComponent b_res;
145 newtComponent mountpointComp;
146 newtComponent label0;
147 newtComponent label1;
148 newtComponent label2;
149 newtComponent label3;
150 newtComponent sizeComp;
151 newtComponent deviceComp;
152 newtComponent formatComp;
153
154 /** buffers **********************************************************/
155 char *drive_to_add = NULL;
156 char *mountpoint_str = NULL;
157 char *size_str = NULL;
158 char *device_str = NULL;
159 char *format_str = NULL;
160
161 /** pointers *********************************************************/
162 char *mountpoint_here;
163 char *size_here;
164 char *device_here;
165 char *format_here;
166
167 assert(mountlist != NULL);
168 assert(raidlist != NULL);
169 assert(listbox != NULL);
170 assert(keylist != NULL);
171
172 mr_asprintf(device_str, "/dev/");
173 mr_asprintf(mountpoint_str, "/");
174 mr_asprintf(size_str, "");
175#ifdef __FreeBSD__
176 mr_asprintf(format_str, "ufs");
177#else
178 mr_asprintf(format_str, "ext3");
179#endif
180 newtOpenWindow(20, 5, 48, 10, "Add entry");
181 label0 = newtLabel(2, 1, "Device: ");
182 label1 = newtLabel(2, 2, "Mountpoint:");
183 label2 = newtLabel(2, 3, "Size (MB): ");
184 label3 = newtLabel(2, 4, "Format: ");
185 deviceComp = newtEntry(14, 1, device_str, 30, (void *) &device_here, 0);
186 mountpointComp = newtEntry(14, 2, mountpoint_str, 30, (void *) &mountpoint_here, 0);
187 formatComp = newtEntry(14, 4, format_str, 15, (void *) &format_here, 0);
188 sizeComp = newtEntry(14, 3, size_str, 10, (void *) &size_here, 0);
189 bOK = newtButton(5, 6, " OK ");
190 bCancel = newtButton(17, 6, "Cancel");
191 newtPushHelpLine
192 ("To add an entry to the mountlist, please fill in these fields and then hit 'OK'");
193 myForm = newtForm(NULL, NULL, 0);
194 newtFormAddComponents(myForm, deviceComp, mountpointComp, sizeComp,
195 formatComp, label0, label1, label2, label3, bOK,
196 bCancel, NULL);
197 for (b_res = NULL; b_res != bOK && b_res != bCancel;) {
198 b_res = newtRunForm(myForm);
199 mr_free(device_str);
200 mr_asprintf(device_str, "%s", device_here);
201
202 mr_free(mountpoint_str);
203 mr_asprintf(mountpoint_str, "%s", mountpoint_here);
204 mr_strip_spaces(mountpoint_str);
205
206 mr_free(format_str);
207 mr_asprintf(format_str, "%s", format_here);
208 mr_strip_spaces(format_str);
209
210 mr_free(size_str);
211 mr_asprintf(size_str, "%s", size_here);
212 mr_strip_spaces(size_str);
213
214 mr_strip_spaces(device_str);
215 if (b_res == bOK) {
216 if (device_str[strlen(device_str) - 1] == '/') {
217 popup_and_OK("You left the device nearly blank!");
218 b_res = NULL;
219 }
220 if (size_of_specific_device_in_mountlist(mountlist, device_str) >= 0) {
221 popup_and_OK("Can't add this - you've got one already!");
222 b_res = NULL;
223 }
224 }
225 }
226 newtFormDestroy(myForm);
227 newtPopHelpLine();
228 newtPopWindow();
229 if (b_res == bCancel) {
230 return;
231 }
232 mr_asprintf(drive_to_add, "%s", device_str);
233 for (i = strlen(drive_to_add); isdigit(drive_to_add[i - 1]); i--);
234 mr_free(drive_to_add);
235
236 currline = mountlist->entries;
237 strcpy(mountlist->el[currline].device, device_str);
238 strcpy(mountlist->el[currline].mountpoint, mountpoint_str);
239 mr_free(mountpoint_str);
240
241 strcpy(mountlist->el[currline].format, format_str);
242 mr_free(format_str);
243
244 mountlist->el[currline].size = atol(size_str) * 1024L;
245 mr_free(size_str);
246
247 mountlist->entries++;
248 if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) {
249 initiate_new_raidlist_entry(raidlist, mountlist, currline, device_str);
250 }
251 mr_free(device_str);
252
253 redraw_mountlist(mountlist, keylist, listbox);
254}
255
256
257#ifndef __FreeBSD__
258/**
259 * Add an entry to the additional RAID variables section of @p raidrec.
260 * @param raidrec The RAID device record containing the RAID variables list to add to.
261 * @ingroup restoreGuiVarslist
262 */
263void add_varslist_entry(struct raid_device_record *raidrec)
264{
265
266 /** buffers ***********************************************************/
267 char sz_out[MAX_STR_LEN];
268
269 /** int ****************************************************************/
270 int items = 0;
271 int i = 0;
272
273 assert(raidrec != NULL);
274
275 sz_out[0] = '\0';
276 if (popup_and_get_string
277 ("Add variable", "Enter the name of the variable to add", sz_out,
278 MAX_STR_LEN)) {
279 strip_spaces(sz_out);
280 items = raidrec->additional_vars.entries;
281 for (i = 0;
282 i < items
283 && strcmp(raidrec->additional_vars.el[i].label, sz_out); i++);
284 if (i < items) {
285 popup_and_OK
286 ("No need to add that variable. It is already listed here.");
287 } else {
288 strcpy(raidrec->additional_vars.el[items].label, sz_out);
289 edit_varslist_entry(raidrec, items);
290 raidrec->additional_vars.entries = ++items;
291 }
292 }
293}
294#endif
295
296/**
297 * Calculate the size of @p raid_device.
298 * @param mountlist The mountlist containing information about the user's partitions.
299 * @param raidlist The raidlist that goes with @p mountlist.
300 * @param raid_device The device to calculate the size of.
301 * @return The size of the RAID device in Kilobytes.
302 * @ingroup restoreUtilityGroup
303 */
304long
305calculate_raid_device_size(struct mountlist_itself *mountlist,
306 struct raidlist_itself *raidlist,
307 char *raid_device)
308{
309#ifdef __FreeBSD__
310 /** FreeBSD-specific version of calculate_raid_device_size() **/
311
312 /** structures ********************************************************/
313 struct vinum_volume *raidrec;
314
315 /** int ***************************************************************/
316 int i = 0, j = 0;
317 int noof_partitions = 0;
318
319 /** long **************************************************************/
320 long total_size = 0;
321 long plex_size = 0;
322 long smallest_partition = 999999999;
323 long smallest_plex = 999999999;
324 long sp = 0;
325
326 /** buffers ***********************************************************/
327 char tmp = NULL;
328 char *devname = NULL;
329
330 for (i = 0;
331 i < raidlist->entries
332 && strcmp(raidlist->el[i].volname, basename(raid_device)); i++);
333 if (i == raidlist->entries) {
334 log_it("Cannot calc size of raid device %s - cannot find it in raidlist", raid_device);
335 return (0); // Isn't this more sensible than 999999999? If the raid dev !exists,
336 // then it has no size, right?
337 }
338 raidrec = &raidlist->el[i];
339 total_size = 0;
340 if (raidrec->plexes == 0)
341 return 0;
342 for (j = 0; j < raidrec->plexes; j++) {
343 plex_size = 0;
344 int k = 0, l = 0;
345 for (k = 0; k < raidrec->plex[j].subdisks; ++k) {
346 mr_asprintf(devname, "%s", raidrec->plex[j].sd[k].which_device);
347 for (l = 0; l < raidlist->disks.entries; ++l) {
348 if (!strcmp(devname, raidlist->disks.el[l].name)) {
349 switch (raidrec->plex[j].raidlevel) {
350 case -1:
351 plex_size +=
352 size_of_specific_device_in_mountlist(mountlist,
353 raidlist->
354 disks.
355 el[l].
356 device);
357 break;
358 case 0:
359 case 5:
360 if (size_of_specific_device_in_mountlist(mountlist,
361 raidlist->
362 disks.
363 el[l].
364 device) <
365 smallest_partition) {
366 smallest_partition =
367 size_of_specific_device_in_mountlist
368 (mountlist, raidlist->disks.el[l].device);
369 }
370 break;
371 }
372 }
373 }
374 mr_free(devname);
375 }
376
377 if (!is_this_raid_personality_registered
378 (raidrec->plex[j].raidlevel)) {
379 log_it
380 ("%s has a really weird RAID level - couldn't calc size :(",
381 raid_device);
382 return (999999999);
383 }
384 if (raidrec->plex[j].raidlevel != -1) {
385 plex_size = smallest_partition * (raidrec->plex[j].subdisks -
386 (raidrec->plex[j].
387 raidlevel == 5 ? 1 : 0));
388 }
389 if (plex_size < smallest_plex)
390 smallest_plex = plex_size;
391
392 smallest_partition = 999999999;
393 }
394
395 log_it("I have calculated %s's real size to be %ld", raid_device, (long) smallest_plex);
396 return (smallest_plex);
397#else
398 /** Linux-specific version of calculate_raid_device_size() **/
399
400 /** structures ********************************************************/
401 struct raid_device_record *raidrec;
402
403 /** int ***************************************************************/
404 int i = 0;
405 int noof_partitions = 0;
406
407 /** long **************************************************************/
408 long total_size = 0;
409 long smallest_partition = 999999999;
410 long sp = 0;
411
412 assert(mountlist != NULL);
413 assert(raidlist != NULL);
414 assert_string_is_neither_NULL_nor_zerolength(raid_device);
415
416 for (i = 0;
417 i < raidlist->entries
418 && strcmp(raidlist->el[i].raid_device, raid_device); i++);
419 if (i == raidlist->entries) {
420 log_it("Cannot calc size of raid device %s - cannot find it in raidlist", raid_device);
421 return (999999999);
422 }
423 raidrec = &raidlist->el[i];
424 noof_partitions = raidrec->data_disks.entries;
425 if (raidrec->raid_level == -1 || raidrec->raid_level == 0) {
426 for (total_size = 0, i = 0; i < noof_partitions; i++) {
427 total_size +=
428 size_of_specific_device_in_mountlist(mountlist,
429 raidrec->data_disks.
430 el[i].device);
431 }
432 } else {
433 for (i = 0; i < noof_partitions; i++) {
434 sp = size_of_specific_device_in_mountlist(mountlist,
435 raidrec->data_disks.
436 el[i].device);
437 if (smallest_partition > sp) {
438 smallest_partition = sp;
439 }
440 }
441 total_size = smallest_partition * (noof_partitions - 1);
442 }
443 log_it("I have calculated %s's real size to be %ld", raid_device, (long) total_size);
444 return (total_size);
445#endif
446}
447
448
449
450/**
451 * Choose the RAID level for the RAID device record in @p raidrec.
452 * @param raidrec The RAID device record to set the RAID level of.
453 * @ingroup restoreGuiMountlist
454 */
455void
456choose_raid_level(struct OSSWAP (raid_device_record, vinum_plex) * raidrec)
457{
458
459#ifdef __FreeBSD__
460
461 /** int ***************************************************************/
462 int res = 0;
463 int out = 0;
464
465 /** buffers ***********************************************************/
466 char tmp[MAX_STR_LEN];
467 char *prompt = NULL;
468 char sz[MAX_STR_LEN];
469
470 mr_asprintf(prompt, "Please enter the RAID level you want. (concat, striped, raid5)");
471 if (raidrec->raidlevel == -1) {
472 strcpy(tmp, "concat");
473 } else if (raidrec->raidlevel == 0) {
474 strcpy(tmp, "striped");
475 } else {
476 sprintf(tmp, "raid%i", raidrec->raidlevel);
477 }
478 for (out = 999; out == 999;) {
479 res = popup_and_get_string("Specify RAID level", prompt, tmp, 10);
480 if (!res) {
481 mr_free(prompt);
482 return;
483 }
484 strip_spaces(tmp);
485 if (tmp[0] == '[' && tmp[strlen(tmp) - 1] == ']') {
486 strcpy(sz, tmp);
487 strncpy(tmp, sz + 1, strlen(sz) - 2);
488 tmp[strlen(sz) - 2] = '\0';
489 }
490 if (!strcmp(tmp, "concat")) {
491 out = -1;
492 } else if (!strcmp(tmp, "striped")) {
493 out = 0;
494 } else if (!strcmp(tmp, "raid5")) {
495 out = 5;
496 }
497 log_it(tmp);
498 if (is_this_raid_personality_registered(out)) {
499 log_it("Groovy. You've picked a RAID personality which is registered.");
500 } else {
501 if (ask_me_yes_or_no("You have chosen a RAID personality which is not registered with the kernel. Make another selection?"))
502 {
503 out = 999;
504 }
505 }
506 }
507 mr_free(prompt);
508
509 raidrec->raidlevel = out;
510#else
511 /** buffers ***********************************************************/
512 char tmp[MAX_STR_LEN];
513 char *personalities = NULL;
514 char *prompt = NULL;
515 char sz[MAX_STR_LEN];
516 int out = 0;
517 int res = 0;
518
519
520 assert(raidrec != NULL);
521 paranoid_system("grep Pers /proc/mdstat > /tmp/raid-personalities.txt 2> /dev/null");
522 mr_asprintf(personalities, "%s", last_line_of_file("/tmp/raid-personalities.txt"));
523 mr_asprintf(prompt, "Please enter the RAID level you want. %s", personalities);
524 mr_free(personalities);
525
526 if (raidrec->raid_level == -1) {
527 strcpy(tmp, "linear");
528 } else {
529 sprintf(tmp, "%d", raidrec->raid_level);
530 }
531 for (out = 999;
532 out != -1 && out != 0 && out != 1 && out != 4 && out != 5
533 && out != 10;) {
534 res = popup_and_get_string("Specify RAID level", prompt, tmp, 10);
535 if (!res) {
536 return;
537 }
538 strip_spaces(tmp);
539 if (tmp[0] == '[' && tmp[strlen(tmp) - 1] == ']') {
540 strcpy(sz, tmp);
541 strncpy(tmp, sz + 1, strlen(sz) - 2);
542 tmp[strlen(sz) - 2] = '\0';
543 }
544 if (!strcmp(tmp, "linear")) {
545 out = -1;
546 } else if (!strncmp(tmp, "raid", 4)) {
547 out = atoi(tmp + 4);
548 } else {
549 out = atoi(tmp);
550 }
551 log_it(tmp);
552 if (is_this_raid_personality_registered(out)) {
553 log_it("Groovy. You've picked a RAID personality which is registered.");
554 } else {
555 if (ask_me_yes_or_no("You have chosen a RAID personality which is not registered with the kernel. Make another selection?")) {
556 out = 999;
557 }
558 }
559 }
560 mr_free(prompt);
561
562 raidrec->raid_level = out;
563#endif
564}
565
566
567
568/**
569 * Delete the partitions in @p disklist from @p mountlist because they
570 * were part of a deleted RAID device.
571 * @param mountlist The mountlist containing information about the user's partitions.
572 * @param raidlist The raidlist that goes with @p mounntlist.
573 * @param disklist The list of disks to remove from @p mountlist.
574 * @ingroup restoreGuiDisklist
575 */
576void
577del_partns_listed_in_disklist(struct mountlist_itself *mountlist,
578 struct raidlist_itself *raidlist,
579 struct list_of_disks *disklist)
580{
581
582 /** int ***************************************************************/
583 int i = 0;
584 int pos = 0;
585
586 assert(mountlist != NULL);
587 assert(raidlist != NULL);
588 assert(disklist != NULL);
589
590 for (i = 0; i < disklist->entries; i++) {
591 for (pos = 0;
592 pos < mountlist->entries
593 && strcmp(mountlist->el[pos].device, disklist->el[i].device);
594 pos++);
595 if (pos < mountlist->entries) {
596 log_it("Deleting partition %s cos it was part of a now-defunct RAID", mountlist->el[pos].device);
597
598 memcpy((void *) &mountlist->el[pos],
599 (void *) &mountlist->el[mountlist->entries - 1],
600 sizeof(struct mountlist_line));
601 mountlist->entries--;
602 }
603 }
604}
605
606
607
608/**
609 * Delete entry number @p currline from @p disklist.
610 * @param disklist The disklist to remove the entry from.
611 * @param raid_device The RAID device containing the partition we're removing.
612 * Used only in the popup "are you sure?" box.
613 * @param currline The line number (starting from 0) of the item to delete.
614 * @ingroup restoreGuiDisklist
615 */
616void
617delete_disklist_entry(struct list_of_disks *disklist, char *raid_device,
618 int currline)
619{
620
621 /** int ***************************************************************/
622 int pos = 0;
623 int res = 0;
624
625 /** buffers ***********************************************************/
626 char *tmp = NULL;
627
628 assert(disklist != NULL);
629 assert_string_is_neither_NULL_nor_zerolength(raid_device);
630
631 mr_asprintf(tmp, "Delete %s from RAID device %s - are you sure?", disklist->el[currline].device, raid_device);
632 res = ask_me_yes_or_no(tmp);
633 mr_free(tmp);
634
635 if (!res) {
636 return;
637 }
638 for (pos = currline; pos < disklist->entries - 1; pos++) {
639 strcpy(disklist->el[pos].device, disklist->el[pos + 1].device);
640 }
641 disklist->entries--;
642}
643
644
645
646/**
647 * Delete entry number @p currline from @p mountlist.
648 * @param mountlist The mountlist to delete the entry from.
649 * @param raidlist The raidlist that goes with @p mountlist.
650 * @param listbox The Newt listbox component in the mountlist editor.
651 * @param currline The line number (starting from 0) of the item to delete.
652 * @param keylist The list of keys for @p listbox.
653 * @ingroup restoreGuiMountlist
654 */
655void
656delete_mountlist_entry(struct mountlist_itself *mountlist,
657 struct raidlist_itself *raidlist,
658 newtComponent listbox, int currline,
659 void *keylist[])
660{
661
662 /** int ***************************************************************/
663 int pos = 0;
664 int res = 0;
665
666 /** buffers ***********************************************************/
667 char *tmp = NULL;
668 char *device = NULL;
669
670
671 assert(mountlist != NULL);
672 assert(raidlist != NULL);
673 assert(listbox != NULL);
674 assert(keylist != NULL);
675
676 pos = which_raid_device_is_using_this_partition(raidlist, mountlist->el[currline].device);
677 if (pos >= 0) {
678 mr_asprintf(tmp, "Cannot delete %s: it is in use by RAID device %s", mountlist->el[currline].device, raidlist->el[pos].OSSWAP(raid_device, volname));
679 popup_and_OK(tmp);
680 mr_free(tmp);
681 return;
682 }
683 mr_asprintf(tmp, "Delete %s - are you sure?", mountlist->el[currline].device);
684 res = ask_me_yes_or_no(tmp);
685 mr_free(tmp);
686
687 if (!res) {
688 return;
689 }
690 if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) {
691 mr_asprintf(device, "%s", mountlist->el[currline].device);
692 delete_raidlist_entry(mountlist, raidlist, device);
693 for (currline = 0;
694 currline < mountlist->entries
695 && strcmp(mountlist->el[currline].device, device);
696 currline++);
697 mr_free(device);
698
699 if (currline == mountlist->entries) {
700 log_it("Dev is gone. I can't delete it. Ho-hum");
701 return;
702 }
703 }
704 memcpy((void *) &mountlist->el[currline],
705 (void *) &mountlist->el[mountlist->entries - 1],
706 sizeof(struct mountlist_line));
707 mountlist->entries--;
708 redraw_mountlist(mountlist, keylist, listbox);
709}
710
711
712/**
713 * Delete @p device from @p raidlist.
714 * @param mountlist The mountlist containing information about the user's partitions.
715 * @param raidlist The raidlist containing the RAID device to delete.
716 * @param device The device (e.g. /dev/md0) to delete.
717 * @ingroup restoreGuiMountlist
718 */
719void
720delete_raidlist_entry(struct mountlist_itself *mountlist,
721 struct raidlist_itself *raidlist, char *device)
722{
723
724 /** int ***************************************************************/
725 int i = 0;
726 int items = 0;
727
728 /** bool **************************************************************/
729 bool delete_partitions_too;
730
731 /** buffers ***********************************************************/
732 char *tmp = NULL;
733
734 assert(mountlist != NULL);
735 assert(raidlist != NULL);
736 assert_string_is_neither_NULL_nor_zerolength(device);
737
738 i = find_raid_device_in_raidlist(raidlist, device);
739 if (i < 0) {
740 return;
741 }
742 mr_asprintf(tmp, "Do you want me to delete %s's partitions, too?", device);
743 delete_partitions_too = ask_me_yes_or_no(tmp);
744 if (delete_partitions_too) {
745#ifdef __FreeBSD__
746 // static so it's zeroed
747 static struct list_of_disks d;
748 int x, y, z;
749
750 for (x = 0; x < raidlist->el[i].plexes; ++x) {
751 for (y = 0; y < raidlist->el[i].plex[x].subdisks; ++y) {
752 for (z = 0; z < raidlist->disks.entries; ++z) {
753 if (!strcmp(raidlist->el[i].plex[x].sd[y].which_device,
754 raidlist->disks.el[z].name)) {
755 strcpy(d.el[d.entries].name, raidlist->disks.el[z].name);
756 strcpy(d.el[d.entries++].device, raidlist->disks.el[z].device);
757 }
758 }
759 }
760 }
761
762 del_partns_listed_in_disklist(mountlist, raidlist, &d);
763#else
764 del_partns_listed_in_disklist(mountlist, raidlist,
765 &raidlist->el[i].data_disks);
766 del_partns_listed_in_disklist(mountlist, raidlist,
767 &raidlist->el[i].spare_disks);
768 del_partns_listed_in_disklist(mountlist, raidlist,
769 &raidlist->el[i].parity_disks);
770 del_partns_listed_in_disklist(mountlist, raidlist,
771 &raidlist->el[i].failed_disks);
772#endif
773 }
774 items = raidlist->entries;
775 if (items == 1) {
776 items = 0;
777 } else {
778 log_it(tmp);
779 memcpy((void *) &raidlist->el[i],
780 (void *) &raidlist->el[items - 1],
781 sizeof(struct OSSWAP (raid_device_record, vinum_volume)));
782 items--;
783 }
784 mr_free(tmp);
785 raidlist->entries = items;
786}
787
788
789#ifndef __FreeBSD__
790/**
791 * Delete entry number @p lino in the additional RAID variables section of @p raidrec.
792 * @param raidrec The RAID device record containing the RAID variable to delete.
793 * @param lino The line number (starting from 0) of the variable to delete.
794 * @ingroup restoreGuiVarslist
795 */
796void delete_varslist_entry(struct raid_device_record *raidrec, int lino)
797{
798
799 /** buffers ************************************************************/
800 char *tmp = NULL;
801 int res = 0;
802
803 /** structures *********************************************************/
804 struct additional_raid_variables *av;
805
806 assert(raidrec != NULL);
807
808 av = &raidrec->additional_vars;
809 mr_asprintf(tmp, "Delete %s - are you sure?", av->el[lino].label);
810 res = ask_me_yes_or_no(tmp);
811 mr_free(tmp);
812
813 if (res) {
814 if (!strcmp(av->el[lino].label, "persistent-superblock")
815 || !strcmp(av->el[lino].label, "chunk-size")) {
816 mr_asprintf(tmp, "%s must not be deleted. It would be bad.", av->el[lino].label);
817 popup_and_OK(tmp);
818 mr_free(tmp);
819 } else {
820 memcpy((void *) &av->el[lino], (void *) &av->el[av->entries--],
821 sizeof(struct raid_var_line));
822 }
823 }
824}
825#endif
826
827
828/**
829 * Redraw the filelist display.
830 * @param filelist The filelist structure to edit.
831 * @param keylist The list of keys for @p listbox.
832 * @param listbox The Newt listbox component containing some of the filelist entries.
833 * @return The number of lines currently being displayed.
834 * @ingroup restoreGuiGroup
835 */
836int
837redraw_filelist(struct s_node *filelist, void *keylist[ARBITRARY_MAXIMUM],
838 newtComponent listbox)
839{
840
841 /** int ***************************************************************/
842 static int lines_in_flist_window = 0;
843 static int depth = 0;
844
845 /** long **************************************************************/
846 long i = 0;
847
848 /** structures *******************************************************/
849 struct s_node *node;
850
851 /** buffers **********************************************************/
852 static char current_filename[MAX_STR_LEN];
853 char tmp[MAX_STR_LEN + 2];
854 char *tmp1 = NULL;
855
856 /** bool *************************************************************/
857 /* void*dummyptr; */
858 bool dummybool;
859 static bool warned_already;
860
861 assert(filelist != NULL);
862 assert(keylist != NULL);
863 assert(listbox != NULL);
864
865
866 if (depth == 0) {
867 lines_in_flist_window = 0;
868 warned_already = FALSE;
869 for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
870 g_strings_of_flist_window[i][0] = '\0';
871 g_is_path_selected[i] = FALSE;
872 }
873 }
874 for (node = filelist; node != NULL; node = node->right) {
875 current_filename[depth] = node->ch;
876 if (node->down) {
877 depth++;
878 i = redraw_filelist(node->down, keylist, listbox);
879 depth--;
880 }
881 if (node->ch == '\0' && node->expanded) {
882 if (lines_in_flist_window == ARBITRARY_MAXIMUM) {
883 if (!warned_already) {
884 warned_already = TRUE;
885 mr_asprintf(tmp1, "Too many lines. Displaying first %d entries only. Close a directory to see more.", ARBITRARY_MAXIMUM);
886 popup_and_OK(tmp1);
887 mr_free(tmp1);
888 }
889 } else {
890 strcpy(g_strings_of_flist_window[lines_in_flist_window], current_filename);
891 g_is_path_selected[lines_in_flist_window] = node->selected;
892 lines_in_flist_window++;
893 }
894 }
895 }
896 if (depth == 0) {
897 if (lines_in_flist_window > ARBITRARY_MAXIMUM) {
898 lines_in_flist_window = ARBITRARY_MAXIMUM;
899 }
900/* do an elementary sort */
901 for (i = 1; i < lines_in_flist_window; i++) {
902 if (strcmp
903 (g_strings_of_flist_window[i],
904 g_strings_of_flist_window[i - 1]) < 0) {
905 mr_asprintf(tmp1, "%s", g_strings_of_flist_window[i]);
906 strcpy(g_strings_of_flist_window[i], g_strings_of_flist_window[i - 1]);
907 strcpy(g_strings_of_flist_window[i - 1], tmp1);
908 mr_free(tmp1);
909
910 dummybool = g_is_path_selected[i];
911 g_is_path_selected[i] = g_is_path_selected[i - 1];
912 g_is_path_selected[i - 1] = dummybool;
913 i = 0;
914 }
915 }
916/* write list to screen */
917 newtListboxClear(listbox);
918 for (i = 0; i < lines_in_flist_window; i++) {
919 sprintf(tmp, "%c%c %-80s", (g_is_path_selected[i] ? '*' : ' '),
920 (g_is_path_expanded[i] ? '+' : '-'),
921 strip_path(g_strings_of_flist_window[i]));
922 tmp[70] = '\0';
923 keylist[i] = (void *) i;
924 newtListboxAppendEntry(listbox, tmp, keylist[i]);
925 }
926 return (lines_in_flist_window);
927 } else {
928 return (0);
929 }
930}
931
932
933/**
934 * Strip a path to the bare minimum (^ pointing to the directory above, plus filename).
935 * @param tmp The path to strip.
936 * @return The stripped path.
937 * @author Conor Daly
938 * @ingroup restoreUtilityGroup
939 */
940char *strip_path(char *tmp)
941{
942
943 int i = 0, j = 0, slashcount = 0;
944 int slashloc = 0, lastslashloc = 0;
945
946 while (tmp[i] != '\0') { /* Count the slashes in tmp
947 1 slash per dir */
948 if (tmp[i] == '/') {
949 slashcount++;
950 lastslashloc = slashloc;
951 slashloc = i;
952 if (tmp[i + 1] == '\0') { /* if this slash is last char, back off */
953 slashcount--;
954 slashloc = lastslashloc;
955 }
956 }
957 i++;
958 }
959 if (slashcount > 0)
960 slashcount--; /* Keep one slash 'cos Hugh does... */
961
962 for (i = 0; i < slashcount; i++) { /* Replace each dir with a space char */
963 tmpnopath[i] = ' ';
964 }
965
966 i = slashloc;
967 j = slashcount;
968 while (tmp[i] != '\0') { /* Now add what's left of tmp */
969 if ((tmpprevpath[j] == ' ' || tmpprevpath[j] == '^')
970 && tmp[i] == '/' && tmpnopath[j - 1] != '^' && j != 0) { /* Add a pointer upwards if this is not in the same dir as line above */
971 tmpnopath[j - 1] = '^';
972 } else {
973 tmpnopath[j++] = tmp[i++];
974 }
975 }
976 tmpnopath[j] = '\0';
977
978 strcpy(tmpprevpath, tmpnopath); /* Make a copy for next iteration */
979
980 return (tmpnopath);
981}
982
983
984/**
985 * Allow the user to edit the filelist and choose which files to restore.
986 * @param filelist The node structure containing the filelist.
987 * @return 0 if the user pressed OK, 1 if they pressed Cancel.
988 */
989int edit_filelist(struct s_node *filelist)
990{
991
992 /** newt **************************************************************/
993 newtComponent myForm;
994 newtComponent bLess = NULL;
995 newtComponent bMore = NULL;
996 newtComponent bToggle = NULL;
997 newtComponent bOK = NULL;
998 newtComponent bCancel = NULL;
999 newtComponent b_res = NULL;
1000 newtComponent filelistListbox = NULL;
1001 newtComponent bRegex = NULL;
1002
1003 /** int ***************************************************************/
1004 int finished = FALSE;
1005 int lines_in_flist_window = 0;
1006 int indexno = 0;
1007 int j = 0;
1008
1009 /** ???? **************************************************************/
1010 void *curr_choice;
1011 void *keylist[ARBITRARY_MAXIMUM];
1012
1013 /** bool **************************************************************/
1014 bool dummybool;
1015
1016/* struct s_node *node; */
1017
1018 assert(filelist != NULL);
1019
1020 log_to_screen("Editing filelist");
1021 newtPushHelpLine
1022 (" Please edit the filelist to your satisfaction, then click OK or Cancel.");
1023 j = 4;
1024 bLess = newtCompactButton(j, 17, " Less ");
1025 bMore = newtCompactButton(j += 12, 17, " More ");
1026 bToggle = newtCompactButton(j += 12, 17, "Toggle");
1027 bRegex = newtCompactButton(j += 12, 17, "RegEx");
1028 bCancel = newtCompactButton(j += 12, 17, "Cancel");
1029 bOK = newtCompactButton(j += 12, 17, " OK ");
1030 filelistListbox =
1031 newtListbox(2, 1, 15, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1032 toggle_all_root_dirs_on(filelist);
1033 lines_in_flist_window =
1034 redraw_filelist(filelist, keylist, filelistListbox);
1035 newtOpenWindow(1, 3, 77, 18, "Editing filelist");
1036 myForm = newtForm(NULL, NULL, 0);
1037 newtFormAddComponents(myForm, filelistListbox, bLess, bMore, bToggle,
1038 bRegex, bCancel, bOK, NULL);
1039 while (!finished) {
1040 b_res = newtRunForm(myForm);
1041 if (b_res == bOK) {
1042 finished =
1043 ask_me_yes_or_no
1044 ("Are you happy with your file selection?");
1045 } else if (b_res == bCancel) {
1046 finished = TRUE;
1047 } else if (b_res == bRegex) {
1048 popup_and_OK("I haven't implemented this yet...");
1049 } else {
1050 curr_choice = newtListboxGetCurrent(filelistListbox);
1051 for (indexno = 0;
1052 indexno < lines_in_flist_window
1053 && keylist[indexno] != curr_choice; indexno++);
1054 if (indexno == lines_in_flist_window) {
1055 log_it
1056 ("I don't know what this button does; assuming I am to toggle 1st entry");
1057 indexno = 0;
1058 }
1059 log_it("You selected '%s'", g_strings_of_flist_window[indexno]);
1060
1061 if (b_res == bMore) {
1062 g_is_path_expanded[indexno] = TRUE;
1063 toggle_path_expandability(filelist,
1064 g_strings_of_flist_window
1065 [indexno], TRUE);
1066 lines_in_flist_window =
1067 redraw_filelist(filelist, keylist, filelistListbox);
1068 newtListboxSetCurrentByKey(filelistListbox, curr_choice);
1069 } else if (b_res == bLess) {
1070 g_is_path_expanded[indexno] = FALSE;
1071 toggle_path_expandability(filelist,
1072 g_strings_of_flist_window
1073 [indexno], FALSE);
1074 lines_in_flist_window =
1075 redraw_filelist(filelist, keylist, filelistListbox);
1076 newtListboxSetCurrentByKey(filelistListbox, curr_choice);
1077 } else {
1078 if (!strcmp(g_strings_of_flist_window[indexno], "/")) {
1079 dummybool = !g_is_path_selected[indexno];
1080 for (j = 1; j < lines_in_flist_window; j++) {
1081 toggle_path_selection(filelist,
1082 g_strings_of_flist_window[j],
1083 dummybool);
1084 }
1085 } else {
1086 toggle_path_selection(filelist,
1087 g_strings_of_flist_window
1088 [indexno],
1089 !g_is_path_selected[indexno]);
1090 lines_in_flist_window =
1091 redraw_filelist(filelist, keylist,
1092 filelistListbox);
1093 }
1094 newtListboxSetCurrentByKey(filelistListbox, curr_choice);
1095 }
1096 for (indexno = 0;
1097 indexno < lines_in_flist_window
1098 && keylist[indexno] != curr_choice; indexno++);
1099 if (indexno == lines_in_flist_window) {
1100 log_it
1101 ("Layout of table has changed. Y pointer is reverting to zero.");
1102 indexno = 0;
1103 }
1104 }
1105 }
1106 newtFormDestroy(myForm);
1107 newtPopWindow();
1108 newtPopHelpLine();
1109 if (b_res == bOK) {
1110 return (0);
1111 } else {
1112/* popup_and_OK("You pushed 'cancel'. I shall now abort."); */
1113 return (1);
1114 }
1115}
1116
1117
1118/**
1119 * Edit an entry in @p mountlist.
1120 * @param mountlist The mountlist containing information about the user's partitions.
1121 * @param raidlist The raidlist to accompany @p mountlist.
1122 * @param listbox The Newt listbox component in the mountlist editor.
1123 * @param currline The selected line (starting from 0) in @p listbox.
1124 * @param keylist The list of keys for @p listbox.
1125 * @ingroup restoreGuiMountlist
1126 */
1127void
1128edit_mountlist_entry(struct mountlist_itself *mountlist,
1129 struct raidlist_itself *raidlist,
1130 newtComponent listbox, int currline, void *keylist[])
1131{
1132
1133 /** structures ********************************************************/
1134 static struct raidlist_itself bkp_raidlist;
1135
1136 /** newt **************************************************************/
1137 newtComponent myForm;
1138 newtComponent bOK;
1139 newtComponent bCancel;
1140 newtComponent b_res;
1141 newtComponent mountpointComp;
1142 newtComponent label0;
1143 newtComponent label1;
1144 newtComponent label2;
1145 newtComponent label3;
1146 newtComponent sizeComp;
1147 newtComponent deviceComp;
1148 newtComponent formatComp;
1149 newtComponent b_raid = NULL;
1150
1151 /** buffers ***********************************************************/
1152 char *device_str = NULL;
1153 char *mountpoint_str = NULL;
1154 char *size_str = NULL;
1155 char *format_str = NULL;
1156 char *tmp = NULL;
1157 char *device_used_to_be = NULL;
1158 char *mountpt_used_to_be = NULL;
1159
1160 /** pointers **********************************************************/
1161 char *device_here;
1162 char *mountpoint_here;
1163 char *size_here;
1164 char *format_here;
1165
1166 /** int ***************************************************************/
1167 int j = 0;
1168
1169 assert(mountlist != NULL);
1170 assert(raidlist != NULL);
1171 assert(listbox != NULL);
1172 assert(keylist != NULL);
1173
1174 memcpy((void *) &bkp_raidlist, (void *) raidlist,
1175 sizeof(struct raidlist_itself));
1176 mr_asprintf(device_str, "%s", mountlist->el[currline].device);
1177 mr_asprintf(device_used_to_be, "%s", mountlist->el[currline].device);
1178 mr_asprintf(mountpoint_str, "%s", mountlist->el[currline].mountpoint);
1179 mr_asprintf(mountpt_used_to_be, "%s", mountlist->el[currline].mountpoint);
1180 mr_asprintf(format_str, "%s", mountlist->el[currline].format);
1181 mr_asprintf(size_str, "%lld", mountlist->el[currline].size / 1024L);
1182 newtOpenWindow(20, 5, 48, 10, "Edit entry");
1183 label0 = newtLabel(2, 1, "Device:");
1184 label1 = newtLabel(2, 2, "Mountpoint:");
1185 label2 = newtLabel(2, 3, "Size (MB): ");
1186 label3 = newtLabel(2, 4, "Format: ");
1187 deviceComp = newtEntry(14, 1, device_str, 30, (void *) &device_here, 0);
1188 mountpointComp = newtEntry(14, 2, mountpoint_str, 30, (void *) &mountpoint_here, 0);
1189 formatComp = newtEntry(14, 4, format_str, 15, (void *) &format_here, 0);
1190 if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)
1191 || !strcmp(mountlist->el[currline].mountpoint, "image")) {
1192 sizeComp = newtLabel(14, 3, size_str);
1193 } else {
1194 sizeComp = newtEntry(14, 3, size_str, 10, (void *) &size_here, 0);
1195 }
1196 bOK = newtButton(2, 6, " OK ");
1197 bCancel = newtButton(14, 6, "Cancel");
1198 if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) {
1199 b_raid = newtButton(26, 6, "RAID..");
1200 }
1201 newtPushHelpLine
1202 (" Edit this partition's mountpoint, size and format; then click 'OK'.");
1203 myForm = newtForm(NULL, NULL, 0);
1204 newtFormAddComponents(myForm, deviceComp, mountpointComp, sizeComp,
1205 formatComp, label0, label1, label2, label3, bOK,
1206 bCancel, b_raid, NULL);
1207 for (b_res = NULL; b_res != bOK && b_res != bCancel;) {
1208 b_res = newtRunForm(myForm);
1209 mr_free(device_str);
1210 mr_asprintf(device_str, "%s", device_here);
1211 mr_strip_spaces(device_str);
1212
1213 mr_free(mountpoint_str);
1214 mr_asprintf(mountpoint_str, "%s", mountpoint_here);
1215 mr_strip_spaces(mountpoint_str);
1216
1217 mr_free(format_str);
1218 mr_asprintf(format_str, "%s", format_here);
1219 mr_strip_spaces(format_str);
1220
1221 if (b_res == bOK && strstr(device_str, RAID_DEVICE_STUB)
1222 && strstr(device_used_to_be, RAID_DEVICE_STUB)
1223 && strcmp(device_str, device_used_to_be)) {
1224 popup_and_OK("You can't change /dev/mdX to /dev/mdY.");
1225 b_res = NULL;
1226 continue;
1227 } else if (b_res == bOK && !strcmp(mountpoint_str, "image")
1228 && strcmp(mountpt_used_to_be, "image")) {
1229 popup_and_OK("You can't change a regular device to an image.");
1230 b_res = NULL;
1231 continue;
1232 }
1233 if (!strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)
1234 && strcmp(mountlist->el[currline].mountpoint, "image")) {
1235 mr_free(size_str);
1236 mr_asprintf(size_str, "%s", size_here);
1237 mr_strip_spaces(size_str);
1238 } else {
1239 mr_asprintf(size_str, "%ld", calculate_raid_device_size(mountlist, raidlist, mountlist->el[currline].device) / 1024);
1240 newtLabelSetText(sizeComp, size_str);
1241 }
1242 /* do not let user click RAID button if user has changed device_str */
1243 if (b_res == b_raid) {
1244 if (strcmp(device_str, mountlist->el[currline].device)) {
1245 /*
1246 can't change mountlist's entry from /dex/mdX to /dev/mdY: it would ugly
1247 when you try to map the changes over to the raidtab list, trust me
1248 */
1249 popup_and_OK
1250 ("You cannot edit the RAID settings until you have OK'd your change to the device node.");
1251 } else {
1252 j = find_raid_device_in_raidlist(raidlist,
1253 mountlist->el[currline].
1254 device);
1255 if (j < 0) {
1256 mr_asprintf(tmp, "/etc/raidtab does not have an entry for %s; please delete it and add it again", mountlist->el[currline].device);
1257 popup_and_OK(tmp);
1258 mr_free(tmp);
1259 } else {
1260 log_it("edit_raidlist_entry - calling");
1261 edit_raidlist_entry(mountlist, raidlist,
1262 &raidlist->el[j], currline);
1263 }
1264 }
1265 }
1266 }
1267 newtFormDestroy(myForm);
1268 newtPopHelpLine();
1269 newtPopWindow();
1270 mr_free(mountpt_used_to_be);
1271
1272 if (b_res == bCancel) {
1273 memcpy((void *) raidlist, (void *) &bkp_raidlist,
1274 sizeof(struct raidlist_itself));
1275 mr_free(device_str);
1276 mr_free(device_used_to_be);
1277 mr_free(format_str);
1278 mr_free(size_str);
1279 return;
1280 }
1281 strcpy(mountlist->el[currline].device, device_str);
1282 strcpy(mountlist->el[currline].mountpoint, mountpoint_str);
1283 mr_free(mountpoint_str);
1284
1285 strcpy(mountlist->el[currline].format, format_str);
1286 mr_free(format_str);
1287
1288 if (strcmp(mountlist->el[currline].mountpoint, "image")) {
1289 if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) {
1290 mountlist->el[currline].size =
1291 calculate_raid_device_size(mountlist, raidlist,
1292 mountlist->el[currline].device);
1293 } else {
1294 mountlist->el[currline].size = atol(size_str) * 1024L;
1295 }
1296 }
1297 mr_free(size_str);
1298 newtListboxSetEntry(listbox, (long) keylist[currline],
1299 mountlist_entry_to_string(mountlist, currline));
1300 /* if new /dev/md RAID device then do funky stuff */
1301 if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)
1302 && !strstr(device_used_to_be, RAID_DEVICE_STUB)) {
1303 initiate_new_raidlist_entry(raidlist, mountlist, currline, device_str);
1304 }
1305 /* if moving from RAID to non-RAID then do funky stuff */
1306 else if (strstr(device_used_to_be, RAID_DEVICE_STUB)
1307 && !strstr(device_str, RAID_DEVICE_STUB)) {
1308 delete_raidlist_entry(mountlist, raidlist, device_str);
1309 }
1310 /* if moving a non-RAID to another non-RAID then re-jig any RAID disks, if necessary */
1311 else if (!strstr(device_used_to_be, RAID_DEVICE_STUB)
1312 && !strstr(device_str, RAID_DEVICE_STUB)) {
1313 rejig_partition_name_in_raidlist_if_necessary(raidlist,
1314 device_used_to_be,
1315 device_str);
1316 }
1317/* else, moving a RAID to another RAID; bad idea, or so I thought */
1318#ifndef __FreeBSD__ /* It works fine under FBSD. */
1319 else if (strcmp(device_used_to_be, device_str)) {
1320 popup_and_OK("You are renaming a RAID device as another RAID device. I don't like it but I'll allow it.");
1321 }
1322#endif
1323 mr_free(device_str);
1324 mr_free(device_used_to_be);
1325
1326 redraw_mountlist(mountlist, keylist, listbox);
1327}
1328
1329
1330#if __FreeBSD__
1331/**
1332 * Add a subdisk to @p raidrec.
1333 * @param raidlist The raidlist containing information about RAID partitions.
1334 * @param raidrec The RAID device record to add the subdisk to.
1335 * @param temp The device name of the RAID disk to add it to.
1336 * @author Joshua Oreman
1337 * @ingroup restoreGuiMountlist
1338 */
1339void
1340add_raid_subdisk(struct raidlist_itself *raidlist,
1341 struct vinum_plex *raidrec, char *temp)
1342{
1343 int i;
1344 bool found = FALSE;
1345
1346 for (i = 0; i < raidlist->disks.entries; ++i) {
1347 if (!strcmp(raidlist->disks.el[i].device, temp)) {
1348 strcpy(raidrec->sd[raidrec->subdisks].which_device, raidlist->disks.el[i].name);
1349 found = TRUE;
1350 }
1351 }
1352 if (!found) {
1353 sprintf(raidlist->disks.el[raidlist->disks.entries].name, "drive%i", raidlist->disks.entries);
1354 sprintf(raidrec->sd[raidrec->subdisks].which_device, "drive%i", raidlist->disks.entries);
1355 strcpy(raidlist->disks.el[raidlist->disks.entries++].device, temp);
1356 }
1357 raidrec->subdisks++;
1358}
1359
1360
1361/**
1362 * Determine the /dev entry for @p vinum_name.
1363 * @param raidlist The raidlist containing information about RAID devices.
1364 * @param vinum_name The name of the Vinum drive to map to a /dev entry.
1365 * @return The /dev entry, or NULL if none was found.
1366 * @note The returned string points to static storage that will be overwritten with each call.
1367 * @author Joshua Oreman
1368 * @ingroup restoreUtilityGroup
1369 */
1370char *find_dev_entry_for_raid_device_name(struct raidlist_itself *raidlist,
1371 char *vinum_name)
1372{
1373 int i;
1374 for (i = 0; i < raidlist->disks.entries; ++i) {
1375 if (!strcmp(raidlist->disks.el[i].name, vinum_name)) {
1376 return raidlist->disks.el[i].device;
1377 }
1378 }
1379 return NULL;
1380}
1381
1382void
1383edit_raidlist_plex(struct mountlist_itself *mountlist,
1384 struct raidlist_itself *raidlist,
1385 struct vinum_plex *raidrec, int currline,
1386 int currline2);
1387
1388#endif
1389
1390
1391/**
1392 * Edit the entry for @p raidrec in @p raidlist.
1393 * @param mountlist The mountlist to get some information from.
1394 * @param raidlist The raidlist containing information about RAID devices.
1395 * @param raidrec The RAID device record for this partition.
1396 * @param currline The line number (starting from 0) in the mountlist of the RAID device.
1397 * @ingroup restoreGuiMountlist
1398 */
1399void
1400edit_raidlist_entry(struct mountlist_itself *mountlist,
1401 struct raidlist_itself *raidlist,
1402 struct OSSWAP (raid_device_record,
1403 vinum_volume) * raidrec, int currline)
1404{
1405
1406#ifdef __FreeBSD__
1407 /** structures ********************************************************/
1408 struct vinum_volume bkp_raidrec;
1409
1410
1411 /** buffers ***********************************************************/
1412 char title_of_editraidForm_window[MAX_STR_LEN];
1413
1414 /** newt **************************************************************/
1415 newtComponent editraidForm;
1416 newtComponent bOK;
1417 newtComponent bCancel;
1418 newtComponent bEdit;
1419 newtComponent bAdd;
1420 newtComponent bDelete;
1421 newtComponent b_res;
1422 newtComponent plexesListbox;
1423 newtComponent plexesHeader;
1424
1425 void *keylist[10];
1426 void *curr_choice;
1427 char *raidlevel = NULL;
1428 char *chunksize = NULL;
1429 char *msg = NULL;
1430
1431 int currline2 = 0;
1432 int res = 0;
1433
1434 log_it("Started edit_raidlist_entry");
1435 memcpy((void *) &bkp_raidrec, (void *) raidrec,
1436 sizeof(struct vinum_volume));
1437 sprintf(title_of_editraidForm_window, "Plexes on %s",
1438 raidrec->volname);
1439 newtPushHelpLine(" Please select a plex to edit");
1440 newtOpenWindow(13, 5, 54, 15, title_of_editraidForm_window);
1441 for (;;) {
1442 int i;
1443 char headerstr[MAX_STR_LEN];
1444 snprintf(headerstr, MAX_STR_LEN, "%-14s %-8s %11s %8s",
1445 "Plex", "Level", "Stripe Size", "Subdisks");
1446
1447 bOK = newtCompactButton(2, 13, " OK ");
1448 bCancel = newtCompactButton(12, 13, "Cancel");
1449 bAdd = newtCompactButton(22, 13, " Add ");
1450 bEdit = newtCompactButton(32, 13, " Edit ");
1451 bDelete = newtCompactButton(42, 13, "Delete");
1452
1453 plexesListbox =
1454 newtListbox(2, 3, 9, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1455 plexesHeader = newtLabel(2, 2, headerstr);
1456 editraidForm = newtForm(NULL, NULL, 0);
1457
1458 newtListboxClear(plexesListbox);
1459 for (i = 0; i < 10; ++i) {
1460 keylist[i] = (void *) i;
1461 if (i < raidrec->plexes) {
1462 char pname[64], entry[MAX_STR_LEN];
1463 switch (raidrec->plex[i].raidlevel) {
1464 case -1:
1465 mr_asprintf(raidlevel, "concat");
1466 break;
1467 case 0:
1468 mr_asprintf(raidlevel, "striped");
1469 break;
1470 case 5:
1471 mr_asprintf(raidlevel, "raid5");
1472 break;
1473 default:
1474 mr_asprintf(raidlevel, "raid%i", raidrec->plex[i].raidlevel);
1475 break;
1476 }
1477
1478 if (raidrec->plex[i].raidlevel == -1) {
1479 mr_asprintf(chunksize, "N/A");
1480 } else {
1481 mr_asprintf(chunksize, "%dk", raidrec->plex[i].stripesize);
1482 }
1483 snprintf(pname, 64, "%s.p%i", raidrec->volname, i);
1484 snprintf(entry, MAX_STR_LEN, "%-14s %-8s %11s %8d",
1485 pname, raidlevel, chunksize,
1486 raidrec->plex[i].subdisks);
1487 mr_free(raidlevel);
1488 mr_free(chunksize);
1489
1490 newtListboxAppendEntry(plexesListbox, entry, keylist[i]);
1491 }
1492 }
1493
1494 newtFormAddComponents(editraidForm, bOK, bCancel, bAdd, bEdit,
1495 bDelete, plexesListbox, plexesHeader, NULL);
1496
1497 b_res = newtRunForm(editraidForm);
1498 if (b_res == bOK || b_res == bCancel) {
1499 break;
1500 }
1501
1502 curr_choice = newtListboxGetCurrent(plexesListbox);
1503 for (currline2 = 0; currline2 < raidrec->plexes; ++currline2) {
1504 if (currline2 > 9)
1505 break;
1506 if (keylist[currline2] == curr_choice)
1507 break;
1508 }
1509
1510 if (b_res == bDelete) {
1511 mr_asprintf(msg, "Are you sure you want to delete %s.p%i?", raidrec->volname, currline2);
1512 res = ask_me_yes_or_no(msg);
1513 mr_free(msg);
1514
1515 if (res) {
1516 log_it("Deleting RAID plex");
1517 memcpy((void *) &raidrec->plex[currline2],
1518 (void *) &raidrec->plex[raidrec->plexes - 1],
1519 sizeof(struct vinum_plex));
1520 raidrec->plexes--;
1521 }
1522 continue;
1523 }
1524 if (b_res == bAdd) {
1525 raidrec->plex[raidrec->plexes].raidlevel = 0;
1526 raidrec->plex[raidrec->plexes].stripesize = 279;
1527 raidrec->plex[raidrec->plexes].subdisks = 0;
1528 currline2 = raidrec->plexes++;
1529 }
1530 edit_raidlist_plex(mountlist, raidlist, &raidrec->plex[currline2],
1531 currline, currline2);
1532 newtFormDestroy(editraidForm);
1533 }
1534 if (b_res == bCancel) {
1535 memcpy((void *) raidrec, (void *) &bkp_raidrec,
1536 sizeof(struct vinum_volume));
1537 }
1538 newtPopHelpLine();
1539 newtPopWindow();
1540 mountlist->el[currline].size =
1541 calculate_raid_device_size(mountlist, raidlist, raidrec->volname);
1542#else
1543 /** structures ********************************************************/
1544 struct raid_device_record *bkp_raidrec;
1545
1546
1547 /** buffers ***********************************************************/
1548 char *title_of_editraidForm_window;
1549 char *sz_raid_level = NULL;
1550 char *sz_data_disks = NULL;
1551 char *sz_spare_disks = NULL;
1552 char *sz_parity_disks = NULL;
1553 char *sz_failed_disks = NULL;
1554
1555 /** newt **************************************************************/
1556 newtComponent editraidForm;
1557 newtComponent bOK;
1558 newtComponent bCancel;
1559 newtComponent bAdditional;
1560 newtComponent bChangeRaid;
1561 newtComponent bSelectData;
1562 newtComponent bSelectSpare;
1563 newtComponent bSelectParity;
1564 newtComponent bSelectFailed;
1565 newtComponent b_res;
1566
1567 assert(mountlist != NULL);
1568 assert(raidlist != NULL);
1569 assert(raidrec != NULL);
1570
1571 bkp_raidrec = mr_malloc(sizeof(struct raid_device_record));
1572 log_it("Started edit_raidlist_entry");
1573
1574 memcpy((void *) bkp_raidrec, (void *) raidrec, sizeof(struct raid_device_record));
1575 mr_asprintf(title_of_editraidForm_window, "%s", raidrec->raid_device);
1576 log_msg(2, "Opening newt window");
1577 newtOpenWindow(20, 5, 40, 14, title_of_editraidForm_window);
1578 for (;;) {
1579 log_msg(2, "Main loop");
1580 mr_free(title_of_editraidForm_window);
1581 mr_asprintf(title_of_editraidForm_window, "Edit %s", raidrec->raid_device);
1582 mr_asprintf(sz_raid_level, "%s", turn_raid_level_number_to_string(raidrec->raid_level));
1583 sz_data_disks = number_of_disks_as_string(raidrec->data_disks.entries, "data");
1584 sz_spare_disks = number_of_disks_as_string(raidrec->spare_disks.entries, "spare");
1585 sz_parity_disks = number_of_disks_as_string(raidrec->parity_disks.entries, "parity");
1586 sz_failed_disks = number_of_disks_as_string(raidrec->failed_disks.entries, "failed");
1587 bSelectData = newtButton(1, 1, sz_data_disks);
1588 bSelectSpare = newtButton(20, 1, sz_spare_disks);
1589 bSelectParity = newtButton(1, 5, sz_parity_disks);
1590 bSelectFailed = newtButton(20, 5, sz_failed_disks);
1591 bChangeRaid = newtButton(1, 9, sz_raid_level);
1592 bOK = newtButton(16 + (raidrec->raid_level == -1), 9, " OK ");
1593 bCancel = newtButton(28, 9, "Cancel");
1594 bAdditional =
1595 newtCompactButton(1, 13,
1596 "Additional settings and information");
1597 newtPushHelpLine
1598 (" Edit the RAID device's settings to your heart's content, then hit OK/Cancel.");
1599 editraidForm = newtForm(NULL, NULL, 0);
1600 newtFormAddComponents(editraidForm, bSelectData, bSelectParity,
1601 bChangeRaid, bSelectSpare, bSelectFailed,
1602 bOK, bCancel, bAdditional);
1603 b_res = newtRunForm(editraidForm);
1604 if (b_res == bChangeRaid) {
1605 choose_raid_level(raidrec);
1606 } else if (b_res == bSelectData) {
1607 select_raid_disks(mountlist, raidlist, raidrec, "data", &raidrec->data_disks);
1608 } else if (b_res == bSelectSpare) {
1609 select_raid_disks(mountlist, raidlist, raidrec, "spare", &raidrec->spare_disks);
1610 } else if (b_res == bSelectParity) {
1611 select_raid_disks(mountlist, raidlist, raidrec, "parity", &raidrec->parity_disks);
1612 } else if (b_res == bSelectFailed) {
1613 select_raid_disks(mountlist, raidlist, raidrec, "failed", &raidrec->failed_disks);
1614 } else if (b_res == bAdditional) {
1615 edit_raidrec_additional_vars(raidrec);
1616 }
1617 newtFormDestroy(editraidForm);
1618 if (b_res == bOK || b_res == bCancel) {
1619 break;
1620 }
1621 mr_free(sz_data_disks);
1622 mr_free(sz_spare_disks);
1623 mr_free(sz_parity_disks);
1624 mr_free(sz_failed_disks);
1625 }
1626 if (b_res == bCancel) {
1627 memcpy((void *) raidrec, (void *) bkp_raidrec, sizeof(struct raid_device_record));
1628 }
1629 newtPopHelpLine();
1630 newtPopWindow();
1631 mountlist->el[currline].size = calculate_raid_device_size(mountlist, raidlist, raidrec->raid_device);
1632 mr_free(title_of_editraidForm_window);
1633 mr_free(sz_raid_level);
1634 paranoid_free(bkp_raidrec);
1635#endif
1636}
1637
1638#ifdef __FreeBSD__
1639
1640/**
1641 * Edit the plex @p raidrec in @p raidlist.
1642 * @param mountlist The mountlist to get some of the information from.
1643 * @param raidlist The raidlist containing information about RAID devices.
1644 * @param raidrec The plex to edit.
1645 * @param currline The line number (starting from 0) of the RAID device in @p mountlist.
1646 * @param currline2 The line number (starting from 0) of the plex within the RAID device.
1647 * @author Joshua Oreman
1648 * @ingroup restoreGuiMountlist
1649 */
1650void
1651edit_raidlist_plex(struct mountlist_itself *mountlist,
1652 struct raidlist_itself *raidlist,
1653 struct vinum_plex *raidrec, int currline, int currline2)
1654{
1655
1656 /** structures ********************************************************/
1657 struct vinum_plex bkp_raidrec;
1658
1659
1660 /** buffers ***********************************************************/
1661 char *title_of_editraidForm_window = NULL;
1662
1663 /** newt **************************************************************/
1664 newtComponent editraidForm;
1665 newtComponent bOK;
1666 newtComponent bCancel;
1667 newtComponent bEdit;
1668 newtComponent bAdd;
1669 newtComponent bDelete;
1670 newtComponent b_res;
1671 newtComponent unallocListbox, allocListbox;
1672 newtComponent bLevel, sLevel;
1673 newtComponent bStripeSize, sStripeSize;
1674 newtComponent bAlloc, bUnalloc;
1675
1676 void *keylist[ARBITRARY_MAXIMUM];
1677 void *curr_choice_a, *curr_choice_u;
1678 int currline_a, currline_u;
1679
1680 char *p = NULL;
1681 char *tmp = NULL;
1682 char *entry = NULL;
1683
1684 struct mountlist_itself *unallocparts;
1685
1686 unallocparts = malloc(sizeof(struct mountlist_itself));
1687
1688 log_it("Started edit_raidlist_entry");
1689 memcpy((void *) &bkp_raidrec, (void *) raidrec,
1690 sizeof(struct vinum_plex));
1691 mr_asprintf(title_of_editraidForm_window, "%s.p%i", raidlist->el[currline].volname, currline2);
1692 newtPushHelpLine
1693 (" Please select a subdisk to edit, or edit this plex's parameters");
1694 newtOpenWindow(13, 3, 54, 18, title_of_editraidForm_window);
1695 mr_free(title_of_editraidForm_window);
1696
1697 for (;;) {
1698 int i;
1699
1700 switch (raidrec->raidlevel) {
1701 case -1:
1702 mr_asprintf(tmp, "concat");
1703 break;
1704 case 0:
1705 mr_asprintf(tmp, "striped");
1706 break;
1707 case 5:
1708 mr_asprintf(tmp, "raid5");
1709 break;
1710 default:
1711 mr_asprintf(tmp, "unknown (%i)", raidrec->raidlevel);
1712 break;
1713 }
1714 bLevel = newtCompactButton(2, 2, " RAID level ");
1715 sLevel = newtLabel(19, 2, tmp);
1716 mr_free(tmp);
1717
1718 if (raidrec->raidlevel >= 0) {
1719 mr_asprintf(tmp, "%ik", raidrec->stripesize);
1720 bStripeSize = newtCompactButton(2, 4, " Stripe size ");
1721 } else {
1722 mr_asprintf(tmp, "N/A");
1723 bStripeSize = newtLabel(2, 4, "Stripe size:");
1724 }
1725 sStripeSize = newtLabel(19, 4, tmp);
1726 mr_free(tmp);
1727
1728 bOK = newtCompactButton(2, 16, " OK ");
1729 bCancel = newtCompactButton(12, 16, "Cancel");
1730 bAdd = newtCompactButton(22, 16, " Add ");
1731 bEdit = newtCompactButton(32, 16, " Edit ");
1732 bDelete = newtCompactButton(42, 16, "Delete");
1733
1734
1735 unallocListbox =
1736 newtListbox(2, 7, 7, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1737 allocListbox =
1738 newtListbox(33, 7, 7, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1739 bAlloc = newtButton(23, 7, " -> ");
1740 bUnalloc = newtButton(23, 11, " <- ");
1741
1742 editraidForm = newtForm(NULL, NULL, 0);
1743
1744 newtListboxClear(allocListbox);
1745 newtListboxClear(unallocListbox);
1746 bzero(unallocparts, sizeof(struct mountlist_itself));
1747 make_list_of_unallocated_raid_partitions(unallocparts, mountlist,
1748 raidlist);
1749 for (i = 0; i < ARBITRARY_MAXIMUM; ++i) {
1750 keylist[i] = (void *) i;
1751 if (i < raidrec->subdisks) {
1752 mr_asprintf(entry, "%-17s", find_dev_entry_for_raid_device_name(raidlist, raidrec->sd[i].which_device));
1753 newtListboxAppendEntry(allocListbox, entry, keylist[i]);
1754 mr_free(entry);
1755 }
1756 if (i < unallocparts->entries) {
1757 mr_asprintf(entry, "%-17s", unallocparts->el[i].device);
1758 newtListboxAppendEntry(unallocListbox, entry, keylist[i]);
1759 mr_free(entry);
1760 }
1761 }
1762
1763#define COMP(x) newtFormAddComponent (editraidForm, x)
1764#define UCOMP(x) if (unallocparts->entries > 0) COMP(x)
1765#define ACOMP(x) if (raidrec->subdisks > 0) COMP(x)
1766 editraidForm = newtForm(NULL, NULL, 0);
1767 UCOMP(unallocListbox);
1768 UCOMP(bAlloc);
1769 ACOMP(allocListbox);
1770 ACOMP(bUnalloc);
1771 COMP(bOK);
1772 COMP(bCancel);
1773 COMP(bLevel);
1774 COMP(sLevel);
1775 if (raidrec->raidlevel != -1) {
1776 COMP(bStripeSize);
1777 COMP(sStripeSize);
1778 }
1779#undef COMP
1780#undef UCOMP
1781#undef ACOMP
1782
1783 newtDrawForm(editraidForm);
1784 newtRefresh();
1785 b_res = newtRunForm(editraidForm);
1786 if (b_res == bOK || b_res == bCancel) {
1787 break;
1788 }
1789
1790 curr_choice_a = (raidrec->subdisks > 0) ?
1791 newtListboxGetCurrent(allocListbox) : (void *) 1234;
1792 curr_choice_u = (unallocparts->entries > 0) ?
1793 newtListboxGetCurrent(unallocListbox) : (void *) 1234;
1794 for (currline_a = 0; currline_a < raidrec->subdisks; ++currline_a) {
1795 if (currline_a > ARBITRARY_MAXIMUM)
1796 break;
1797 if (keylist[currline_a] == curr_choice_a)
1798 break;
1799 }
1800 for (currline_u = 0; currline_u < unallocparts->entries;
1801 ++currline_u) {
1802 if (currline_u > ARBITRARY_MAXIMUM)
1803 break;
1804 if (keylist[currline_u] == curr_choice_u)
1805 break;
1806 }
1807 if (b_res == bLevel) {
1808 choose_raid_level(raidrec);
1809 } else if (b_res == bStripeSize) {
1810 char tmp1[64];
1811 sprintf(tmp1, "%i", raidrec->stripesize);
1812 if (popup_and_get_string
1813 ("Stripe size",
1814 "Please enter the stripe size in kilobytes.", tmp1, 20)) {
1815 raidrec->stripesize = atoi(tmp1);
1816 }
1817 } else if ((b_res == bAlloc) || (b_res == unallocListbox)) {
1818 if (currline_u <= unallocparts->entries)
1819 add_raid_subdisk(raidlist, raidrec,
1820 unallocparts->el[currline_u].device);
1821 } else if ((b_res == bUnalloc) || (b_res == allocListbox)) {
1822 if (currline_a <= raidrec->subdisks) {
1823 memcpy((void *) &raidrec->sd[currline_a],
1824 (void *) &raidrec->sd[raidrec->subdisks - 1],
1825 sizeof(struct vinum_subdisk));
1826 raidrec->subdisks--;
1827 }
1828 }
1829 newtFormDestroy(editraidForm);
1830 newtRefresh();
1831}
1832
1833if (b_res == bCancel) {
1834 memcpy((void *) raidrec, (void *) &bkp_raidrec, sizeof(struct vinum_plex));
1835}
1836newtPopWindow();
1837newtPopHelpLine();
1838}
1839#else
1840/**
1841 * Edit additional RAID variable number @p lino.
1842 * @param raidrec The RAID device record to edit the variable in.
1843 * @param lino The line number (starting from 0) of the variable to edit.
1844 * @ingroup restoreGuiVarslist
1845 */
1846void edit_varslist_entry(struct raid_device_record *raidrec, int lino)
1847{
1848
1849 /** buffers ***********************************************************/
1850 char *header = NULL;
1851 char *comment = NULL;
1852 char sz_out[MAX_STR_LEN];
1853
1854 assert(raidrec != 0);
1855 assert(lino >= 0);
1856
1857 strcpy(sz_out, raidrec->additional_vars.el[lino].value);
1858 mr_asprintf(header, "Edit %s", raidrec->additional_vars.el[lino].label);
1859 mr_asprintf(comment, "Please set %s's value (currently '%s')", raidrec->additional_vars.el[lino].label, sz_out);
1860 if (popup_and_get_string(header, comment, sz_out, MAX_STR_LEN)) {
1861 strip_spaces(sz_out);
1862 strcpy(raidrec->additional_vars.el[lino].value, sz_out);
1863 }
1864 mr_free(header);
1865 mr_free(comment);
1866}
1867
1868#endif
1869
1870/**
1871 * Edit the mountlist using Newt.
1872 * @param mountlist The mountlist to edit.
1873 * @param raidlist The raidlist that goes with @p mountlist.
1874 * @return 0 if the user pressed OK, 1 if they pressed Cancel.
1875 */
1876int
1877edit_mountlist_in_newt(char *mountlist_fname,
1878 struct mountlist_itself *mountlist,
1879 struct raidlist_itself *raidlist)
1880{
1881
1882 /** newt **************************************************************/
1883 newtComponent myForm;
1884 newtComponent bAdd;
1885 newtComponent bEdit;
1886 newtComponent bDelete;
1887 newtComponent bOK;
1888 newtComponent bCancel;
1889 newtComponent b_res = NULL;
1890 newtComponent partitionsListbox;
1891 newtComponent headerMsg;
1892 newtComponent flawsLabelA;
1893 newtComponent flawsLabelB;
1894 newtComponent flawsLabelC;
1895 newtComponent bReload;
1896
1897 /** ???? *************************************************************/
1898 void *curr_choice;
1899 void *keylist[ARBITRARY_MAXIMUM];
1900
1901 /** int **************************************************************/
1902 int i = 0;
1903 int currline = 0;
1904 int finished = FALSE;
1905
1906 /** buffers **********************************************************/
1907 char *tmp = NULL;
1908 char *flaws_str = NULL;
1909 char *flaws_str_A = NULL;
1910 char *flaws_str_B = NULL;
1911 char *flaws_str_C = NULL;
1912
1913 assert(mountlist != NULL);
1914 assert(raidlist != NULL);
1915
1916 if (mountlist->entries > ARBITRARY_MAXIMUM) {
1917 log_to_screen("Arbitrary limits suck, man!");
1918 finish(1);
1919 }
1920 newtPushHelpLine("WARNING: No LVM modification possible here. Edit /tmp/i-want-my-lvm instead");
1921 i = 4;
1922 bAdd = newtCompactButton(i, 17, " Add ");
1923 bEdit = newtCompactButton(i += 11, 17, " Edit ");
1924 bDelete = newtCompactButton(i += 12, 17, "Delete");
1925 bReload = newtCompactButton(i += 12, 17, "Reload");
1926 bCancel = newtCompactButton(i += 12, 17, "Cancel");
1927 bOK = newtCompactButton(i += 12, 17, " OK ");
1928 mr_asprintf(tmp, "%-24s %-24s %-8s %s", "Device", "Mountpoint", "Format", "Size (MB)");
1929 headerMsg = newtLabel(2, 1, tmp);
1930 mr_free(tmp);
1931
1932 flawsLabelA = newtLabel(2, 13, " ");
1933 flawsLabelB = newtLabel(2, 14, " ");
1934 flawsLabelC = newtLabel(2, 15, " ");
1935 partitionsListbox = newtListbox(2, 2, 10, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1936 redraw_mountlist(mountlist, keylist, partitionsListbox);
1937 newtOpenWindow(1, 3, 77, 18, "Editing mountlist");
1938 myForm = newtForm(NULL, NULL, 0);
1939 newtFormAddComponents(myForm, headerMsg, partitionsListbox,
1940 flawsLabelA, flawsLabelB, flawsLabelC, bAdd,
1941 bEdit, bDelete, bReload, bCancel, bOK, NULL);
1942 while (!finished) {
1943 flaws_str = evaluate_mountlist(mountlist);
1944 /* flaws_str can be NULL */
1945 if ((flaws_str == NULL) || (strlen(flaws_str) == 0)) {
1946 mr_asprintf(flaws_str_A, "");
1947 } else {
1948 mr_asprintf(flaws_str_A, "%s", flaws_str + 1);
1949 }
1950 if (strlen(flaws_str_A) >= 74) {
1951 for (i = 74; flaws_str_A[i] != ' '; i--);
1952 mr_asprintf(flaws_str_B, "%s", flaws_str_A + i + 1);
1953 flaws_str_A[i] = '\0';
1954 } else {
1955 mr_asprintf(flaws_str_B, "");
1956 }
1957 if (strlen(flaws_str_B) >= 74) {
1958 for (i = 74; flaws_str_B[i] != ' '; i--);
1959 mr_asprintf(flaws_str_C, "%s", flaws_str_B + i + 1);
1960 flaws_str_B[i] = '\0';
1961 } else {
1962 mr_asprintf(flaws_str_C, "");
1963 }
1964
1965 newtLabelSetText(flawsLabelA, flaws_str_A);
1966 newtLabelSetText(flawsLabelB, flaws_str_B);
1967 newtLabelSetText(flawsLabelC, flaws_str_C);
1968 b_res = newtRunForm(myForm);
1969 mr_free(flaws_str_A);
1970 mr_free(flaws_str_B);
1971 mr_free(flaws_str_C);
1972
1973 if (b_res == bOK) {
1974 if (flaws_str != NULL) {
1975 finished = ask_me_yes_or_no("Your mountlist might not work. Continue anyway?");
1976 } else {
1977 finished = ask_me_yes_or_no("Are you sure you want to save your mountlist and continue? (No changes will be made to your partition table at this time.)");
1978 }
1979 } else if (b_res == bCancel) {
1980 finished = TRUE;
1981 } else if (b_res == bReload) {
1982 if (ask_me_yes_or_no("Reload original mountlist?")) {
1983 load_mountlist(mountlist, mountlist_fname);
1984 load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
1985 redraw_mountlist(mountlist, keylist, partitionsListbox);
1986 }
1987 } else {
1988 curr_choice = newtListboxGetCurrent(partitionsListbox);
1989 for (i = 0; i < mountlist->entries && keylist[i] != curr_choice; i++);
1990 if (i == mountlist->entries && mountlist->entries > 0) {
1991 log_to_screen("I don't know what that button does!");
1992 } else {
1993 currline = i;
1994 if (b_res == bAdd) {
1995 add_mountlist_entry(mountlist, raidlist,
1996 partitionsListbox, currline,
1997 keylist);
1998 } else if (b_res == bDelete) {
1999 delete_mountlist_entry(mountlist, raidlist,
2000 partitionsListbox, currline,
2001 keylist);
2002 } else {
2003 if (mountlist->entries > 0) {
2004 edit_mountlist_entry(mountlist, raidlist,
2005 partitionsListbox, currline,
2006 keylist);
2007 } else {
2008 popup_and_OK
2009 ("Please add an entry. Then press ENTER to edit it.");
2010 }
2011 }
2012 }
2013 }
2014 mr_free(flaws_str);
2015 }
2016 newtFormDestroy(myForm);
2017 newtPopWindow();
2018 newtPopHelpLine();
2019 if (b_res == bOK) {
2020 log_it("You pushed 'OK'. I shall now continue.");
2021 return (0);
2022 } else {
2023 /* popup_and_OK("You pushed 'cancel'. I shall now abort."); */
2024 return (1);
2025 }
2026}
2027
2028
2029
2030/**
2031 * Edit the mountlist.
2032 * @param mountlist The mountlist to edit.
2033 * @param raidlist The raidlist that goes with @p mountlist.
2034 * @return 0 if the user pressed OK, 1 if they pressed Cancel.
2035 */
2036int
2037edit_mountlist(char *mountlist_fname, struct mountlist_itself *mountlist,
2038 struct raidlist_itself *raidlist)
2039{
2040 int res = 0;
2041
2042 log_it("entering eml");
2043
2044 if (g_text_mode) {
2045 fatal_error("Don't call edit_mountlist() in text mode");
2046 } else {
2047 log_it("I'm in GUI mode, so I shall edit mountlist using edit_mountlist()");
2048 res = edit_mountlist_in_newt(mountlist_fname, mountlist, raidlist);
2049 }
2050 log_it("leaving eml");
2051 return (res);
2052}
2053
2054
2055
2056
2057#ifndef __FreeBSD__
2058/**
2059 * Edit the additional RAID variables in @p raidrec.
2060 * @param raidrec The RAID device record to edit the RAID variables in.
2061 * @ingroup restoreGuiVarslist
2062 */
2063void edit_raidrec_additional_vars(struct raid_device_record *raidrec)
2064{
2065
2066 /** structure *********************************************************/
2067 struct raid_device_record bkp_raidrec;
2068
2069 /** newt **************************************************************/
2070 newtComponent myForm;
2071 newtComponent bAdd;
2072 newtComponent bEdit;
2073 newtComponent bDelete;
2074 newtComponent bOK;
2075 newtComponent bCancel;
2076 newtComponent b_res;
2077 newtComponent varsListbox;
2078 newtComponent headerMsg;
2079
2080 /** ?? ***************************************************************/
2081 void *keylist[ARBITRARY_MAXIMUM], *curr_choice;
2082
2083 /** buffers **********************************************************/
2084 char title_of_window[MAX_STR_LEN];
2085
2086 /** int **************************************************************/
2087 int i = 0;
2088 int currline = 0;
2089
2090
2091 assert(raidrec != NULL);
2092
2093 memcpy((void *) &bkp_raidrec, (void *) raidrec,
2094 sizeof(struct raid_device_record));
2095 sprintf(title_of_window, "Additional variables");
2096 newtPushHelpLine
2097 (" Edit the additional fields to your heart's content, then click OK or Cancel.");
2098 headerMsg = newtLabel(1, 1, "Label Value");
2099 varsListbox =
2100 newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
2101 i = 1;
2102 bAdd = newtCompactButton(i, 9, " Add ");
2103 bEdit = newtCompactButton(i += 8, 9, " Edit ");
2104 bDelete = newtCompactButton(i += 9, 9, "Delete");
2105 bOK = newtCompactButton(i += 9, 9, " OK ");
2106 bCancel = newtCompactButton(i += 9, 9, "Cancel");
2107 newtOpenWindow(17, 7, 46, 10, title_of_window);
2108 myForm = newtForm(NULL, NULL, 0);
2109 newtFormAddComponents(myForm, headerMsg, varsListbox, bAdd, bEdit,
2110 bDelete, bOK, bCancel, NULL);
2111 insert_essential_additionalvars(raidrec);
2112 redraw_varslist(&raidrec->additional_vars, keylist, varsListbox);
2113 for (b_res = NULL; b_res != bOK && b_res != bCancel;) {
2114 b_res = newtRunForm(myForm);
2115 curr_choice = newtListboxGetCurrent(varsListbox);
2116 for (currline = 0;
2117 currline < raidrec->additional_vars.entries
2118 && keylist[currline] != curr_choice; currline++);
2119 if (currline == raidrec->additional_vars.entries
2120 && raidrec->additional_vars.entries > 0) {
2121 log_it("Warning - I don't know what this button does");
2122 }
2123 if (b_res == bOK) { /* do nothing */
2124 } else if (b_res == bCancel) { /* do nothing */
2125 } else if (b_res == bAdd) {
2126 add_varslist_entry(raidrec);
2127 } else if (b_res == bDelete) {
2128 delete_varslist_entry(raidrec, currline);
2129 } else {
2130 edit_varslist_entry(raidrec, currline);
2131 }
2132 redraw_varslist(&raidrec->additional_vars, keylist, varsListbox);
2133 }
2134 remove_essential_additionalvars(raidrec);
2135 newtFormDestroy(myForm);
2136 newtPopWindow();
2137 newtPopHelpLine();
2138 if (b_res == bCancel) {
2139 memcpy((void *) raidrec, (void *) &bkp_raidrec,
2140 sizeof(struct raid_device_record));
2141 }
2142 return;
2143}
2144#endif
2145
2146
2147/**
2148 * Find the next free location to place a disk in @p disklist.
2149 * @param disklist The disklist to operate on.
2150 * @return The next free location (starting from 0).
2151 * @ingroup restoreGuiDisklist
2152 */
2153int find_next_free_index_in_disklist(struct list_of_disks *disklist)
2154{
2155
2156 /** int ***************************************************************/
2157 int index = -1;
2158 int pos = 0;
2159
2160 /** bool **************************************************************/
2161 bool done;
2162
2163 assert(disklist != NULL);
2164
2165 for (done = FALSE; !done;) {
2166 for (pos = 0;
2167 pos < disklist->entries && disklist->el[pos].index <= index;
2168 pos++);
2169 if (pos >= disklist->entries) {
2170 done = TRUE;
2171 } else {
2172 index = disklist->el[pos].index;
2173 }
2174 }
2175 return (index + 1);
2176}
2177
2178
2179
2180/**
2181 * Locate @p device in @p raidlist.
2182 * @param raidlist The raidlist ot search in.
2183 * @param device The RAID device to search for.
2184 * @return The index of the device, or -1 if it could not be found.
2185 * @ingroup restoreGuiMountlist
2186 */
2187int
2188find_raid_device_in_raidlist(struct raidlist_itself *raidlist,
2189 char *device)
2190{
2191
2192 /** int ***************************************************************/
2193 int i = 0;
2194#ifdef __FreeBSD__
2195 char *vdev = NULL;
2196 int res = 0;
2197#else
2198// Linux
2199#endif
2200
2201 assert(raidlist != NULL);
2202 assert_string_is_neither_NULL_nor_zerolength(device);
2203
2204#ifdef __FreeBSD__
2205 for (i = 0; i < raidlist->entries; i++) {
2206 mr_asprintf(vdev, "/dev/vinum/%s", raidlist->el[i].volname);
2207 res = strcmp(device, vdev);
2208 mr_free(vdev);
2209
2210 if (!res)
2211 break;
2212 }
2213#else
2214
2215 for (i = 0;
2216 strcmp(raidlist->el[i].raid_device, device)
2217 && i < raidlist->entries; i++);
2218#endif
2219 if (i == raidlist->entries) {
2220 return (-1);
2221 } else {
2222 return (i);
2223 }
2224}
2225
2226
2227/**
2228 * Create a new raidtab entry for @p device in @p raidlist.
2229 * @param raidlist The raidlist to add the device to.
2230 * @param mountlist The mountlist containing information about the user's partitions.
2231 * @param currline The selected line in the mountlist.
2232 * @param device The RAID device (e.g. /dev/md0) to use.
2233 * @ingroup restoreGuiMountlist
2234 */
2235void
2236initiate_new_raidlist_entry(struct raidlist_itself *raidlist,
2237 struct mountlist_itself *mountlist,
2238 int currline, char *device)
2239{
2240
2241 /** structure *********************************************************/
2242 struct OSSWAP (raid_device_record, vinum_volume) * raidrec;
2243
2244 /** int ***************************************************************/
2245 int pos_in_raidlist = 0;
2246
2247 assert(raidlist != NULL);
2248 assert(mountlist != NULL);
2249 assert_string_is_neither_NULL_nor_zerolength(device);
2250
2251 pos_in_raidlist =
2252 find_raid_device_in_raidlist(raidlist,
2253 mountlist->el[currline].device);
2254 if (pos_in_raidlist >= 0) {
2255 fatal_error("Sorry, that RAID device already exists. Weird.");
2256 }
2257 pos_in_raidlist = raidlist->entries++;
2258 raidrec = &raidlist->el[pos_in_raidlist];
2259 initialize_raidrec(raidrec);
2260 strcpy(raidrec->OSSWAP(raid_device, volname), OSSWAP(device, basename(device)));
2261#ifndef __FreeBSD__
2262 choose_raid_level(raidrec);
2263 select_raid_disks(mountlist, raidlist, raidrec, "data",
2264 &raidrec->data_disks);
2265#endif
2266 edit_raidlist_entry(mountlist, raidlist, raidrec, currline);
2267}
2268
2269
2270#ifndef __FreeBSD__
2271/**
2272 * Insert the RAID variables not stored in the "additional RAID variables" list there too.
2273 * @param raidrec The RAID device record to operate on.
2274 * @ingroup restoreGuiVarslist
2275 */
2276void insert_essential_additionalvars(struct raid_device_record *raidrec)
2277{
2278
2279 /** int **************************************************************/
2280 int items = 0;
2281
2282 assert(raidrec != NULL);
2283
2284 items = raidrec->additional_vars.entries;
2285 write_variableINT_to_raid_var_line(raidrec, items++,
2286 "persistent-superblock",
2287 raidrec->persistent_superblock);
2288 write_variableINT_to_raid_var_line(raidrec, items++, "chunk-size",
2289 raidrec->chunk_size);
2290 raidrec->additional_vars.entries = items;
2291}
2292
2293#endif
2294
2295/**
2296 * Dummy function that proves that we can get to the point where Mondo is run.
2297 */
2298void nuke_mode_dummy()
2299{
2300
2301 /** newt *************************************************************/
2302 newtComponent myForm;
2303 newtComponent b1;
2304 newtComponent b2;
2305 newtComponent b3;
2306
2307
2308 newtPushHelpLine
2309 ("This is where I nuke your hard drives. Mhahahahaha. No-one can stop Mojo Jojo!");
2310 newtOpenWindow(24, 3, 32, 13, "Nuking");
2311 b1 = newtButton(7, 1, "Slowly");
2312 b2 = newtButton(7, 5, "Medium");
2313 b3 = newtButton(7, 9, "Quickly");
2314 myForm = newtForm(NULL, NULL, 0);
2315 newtFormAddComponents(myForm, b1, b2, b3, NULL);
2316 newtFormDestroy(myForm);
2317 newtPopWindow();
2318 newtPopHelpLine();
2319}
2320
2321
2322
2323/**
2324 * Redraw the disklist.
2325 * @param disklist The disklist to read from.
2326 * @param keylist The list of keys for @p listbox.
2327 * @param listbox The Newt listbox component to redraw.
2328 * @ingroup restoreGuiDisklist
2329 */
2330void
2331redraw_disklist(struct list_of_disks *disklist,
2332 void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox)
2333{
2334
2335 /** long **************************************************************/
2336 long i = 0;
2337
2338 assert(disklist != NULL);
2339 assert(keylist != NULL);
2340 assert(listbox != NULL);
2341
2342 newtListboxClear(listbox);
2343
2344 for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2345 keylist[i] = (void *) i;
2346 }
2347 for (i = 0; i < disklist->entries; i++) {
2348 newtListboxAppendEntry(listbox,
2349 disklist_entry_to_string(disklist, i),
2350 keylist[i]);
2351 }
2352}
2353
2354
2355/**
2356 * Redraw the mountlist.
2357 * @param mountlist The mountlist to read from.
2358 * @param keylist The list of keys for @p listbox.
2359 * @param listbox The Newt listbox component to redraw.
2360 * @ingroup restoreGuiMountlist
2361 */
2362void
2363redraw_mountlist(struct mountlist_itself *mountlist,
2364 void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox)
2365{
2366
2367 /** long **************************************************************/
2368 long i = 0;
2369
2370 assert(mountlist != NULL);
2371 assert(keylist != NULL);
2372 assert(listbox != NULL);
2373
2374 newtListboxClear(listbox);
2375// sort_mountlist_by_device (mountlist);
2376 for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2377 keylist[i] = (void *) i;
2378 }
2379 for (i = 0; i < mountlist->entries; i++) {
2380 newtListboxAppendEntry(listbox,
2381 mountlist_entry_to_string(mountlist, i),
2382 keylist[i]);
2383 }
2384}
2385
2386
2387
2388
2389/**
2390 * Redraw the list of unallocated RAID partitions.
2391 * @param unallocated_raid_partitions The mountlist containing unallocated RAID partitions.
2392 * @param keylist The list of keys for @p listbox.
2393 * @param listbox The Newt listbox component to redraw.
2394 * @ingroup restoreGuiDisklist
2395 */
2396void redraw_unallocpartnslist(struct mountlist_itself
2397 *unallocated_raid_partitions,
2398 void *keylist[ARBITRARY_MAXIMUM],
2399 newtComponent listbox)
2400{
2401
2402 /** long *************************************************************/
2403 long i = 0;
2404
2405 /** buffers **********************************************************/
2406 char tmp[MAX_STR_LEN];
2407
2408 assert(unallocated_raid_partitions != NULL);
2409 assert(keylist != NULL);
2410 assert(listbox != NULL);
2411
2412 newtListboxClear(listbox);
2413 for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2414 keylist[i] = (void *) i;
2415 }
2416 for (i = 0; i < unallocated_raid_partitions->entries; i++) {
2417 sprintf(tmp, "%-22s %8lld",
2418 unallocated_raid_partitions->el[i].device,
2419 unallocated_raid_partitions->el[i].size / 1024L);
2420 newtListboxAppendEntry(listbox, tmp, keylist[i]);
2421 }
2422}
2423
2424#ifndef __FreeBSD__
2425/**
2426 * Redraw the list of additional RAID variables.
2427 * @param additional_vars The list of additional RAID varibals.
2428 * @param keylist The list of keys for @p listbox.
2429 * @param listbox The Newt listbox component to redraw.
2430 * @ingroup restoreGuiVarslist
2431 */
2432void
2433redraw_varslist(struct additional_raid_variables *additional_vars,
2434 void *keylist[], newtComponent listbox)
2435{
2436 /** long ************************************************************/
2437 long i = 0;
2438
2439 /** buffers *********************************************************/
2440 char tmp[MAX_STR_LEN];
2441
2442 assert(additional_vars != NULL);
2443 assert(keylist != NULL);
2444 assert(listbox != NULL);
2445
2446 newtListboxClear(listbox);
2447
2448 for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2449 keylist[i] = (void *) i;
2450 }
2451 for (i = 0; i < additional_vars->entries; i++) {
2452 sprintf(tmp, "%-32s %-8s", additional_vars->el[i].label,
2453 additional_vars->el[i].value);
2454 newtListboxAppendEntry(listbox, tmp, keylist[i]);
2455 }
2456}
2457
2458
2459/**
2460 * Remove variable @p label from the RAID variables list in @p raidrec.
2461 * @param raidrec The RAID device record to remove the variable from.
2462 * @param label The variable name to remove.
2463 * @return The value of the variable removed.
2464 * @ingroup restoreUtilityGroup
2465 */
2466int
2467read_variableINT_and_remove_from_raidvars(struct
2468 OSSWAP (raid_device_record,
2469 vinum_volume) * raidrec,
2470 char *label)
2471{
2472 /** int ***************************************************************/
2473 int i = 0;
2474 int res = 0;
2475
2476
2477 assert(raidrec != NULL);
2478 assert(label != NULL);
2479
2480 for (i = 0;
2481 i < raidrec->additional_vars.entries
2482 && strcmp(raidrec->additional_vars.el[i].label, label); i++);
2483 if (i == raidrec->additional_vars.entries) {
2484 res = -1;
2485 } else {
2486 res = atoi(raidrec->additional_vars.el[i].value);
2487 for (i++; i < raidrec->additional_vars.entries; i++) {
2488 memcpy((void *) &raidrec->additional_vars.el[i - 1],
2489 (void *) &raidrec->additional_vars.el[i],
2490 sizeof(struct raid_var_line));
2491 }
2492 raidrec->additional_vars.entries--;
2493 }
2494 return (res);
2495}
2496#endif
2497
2498/**
2499 * Change all RAID devices to use @p new_dev instead of @p old_dev.
2500 * @param raidlist The raidlist to make the changes in.
2501 * @param old_dev The old name of the device (what it used to be).
2502 * @param new_dev The new name of the device (what it is now).
2503 * @ingroup restoreGuiMountlist
2504 */
2505void rejig_partition_name_in_raidlist_if_necessary(struct raidlist_itself
2506 *raidlist,
2507 char *old_dev,
2508 char *new_dev)
2509{
2510 /** int ************************************************************/
2511 int pos = 0;
2512 int j = 0;
2513
2514 assert(raidlist != NULL);
2515 assert_string_is_neither_NULL_nor_zerolength(old_dev);
2516 assert_string_is_neither_NULL_nor_zerolength(new_dev);
2517
2518 pos = which_raid_device_is_using_this_partition(raidlist, old_dev);
2519 if (pos < 0) {
2520 log_it("No need to rejig %s in raidlist: it's not listed.", old_dev);
2521 } else {
2522 if ((j =
2523 where_in_drivelist_is_drive(&raidlist->
2524 OSSWAP(el[pos].data_disks, disks),
2525 old_dev)) >= 0) {
2526 strcpy(raidlist->OSSWAP(el[pos].data_disks, disks).el[j].device, new_dev);
2527 } else
2528 if ((j =
2529 where_in_drivelist_is_drive(&raidlist->
2530 OSSWAP(el[pos].spare_disks,
2531 spares),
2532 old_dev)) >= 0) {
2533 strcpy(raidlist->OSSWAP(el[pos].spare_disks, spares).el[j].device, new_dev);
2534 }
2535#ifndef __FreeBSD__
2536 else if ((j =
2537 where_in_drivelist_is_drive(&raidlist->el[pos].
2538 parity_disks,
2539 old_dev)) >= 0) {
2540 strcpy(raidlist->el[pos].parity_disks.el[j].device, new_dev);
2541 } else
2542 if ((j =
2543 where_in_drivelist_is_drive(&raidlist->el[pos].
2544 failed_disks,
2545 old_dev)) >= 0) {
2546 strcpy(raidlist->el[pos].failed_disks.el[j].device, new_dev);
2547 }
2548#endif
2549 else {
2550 log_it("%s is supposed to be listed in this raid dev but it's not...", old_dev);
2551 }
2552 }
2553}
2554
2555
2556#ifndef __FreeBSD__
2557/**
2558 * Remove the essential RAID variables from the "additional variables" section.
2559 * If they have been changed, set them in their normal locations too.
2560 * @param raidrec The RAID device record to operate on.
2561 * @ingroup restoreUtilityVarslist
2562 */
2563void remove_essential_additionalvars(struct raid_device_record *raidrec)
2564{
2565
2566 /** int **************************************************************/
2567 int res = 0;
2568
2569 assert(raidrec != NULL);
2570
2571 res =
2572 read_variableINT_and_remove_from_raidvars(raidrec,
2573 "persistent-superblock");
2574 if (res > 0) {
2575 raidrec->persistent_superblock = res;
2576 }
2577 res = read_variableINT_and_remove_from_raidvars(raidrec, "chunk-size");
2578 if (res > 0) {
2579 raidrec->chunk_size = res;
2580 }
2581 res = read_variableINT_and_remove_from_raidvars(raidrec, "block-size");
2582}
2583
2584/**
2585 * Select the RAID disks to use in @p raidrec.
2586 * @param mountlist_dontedit The mountlist (will not be edited).
2587 * @param raidlist The raidlist to modify.
2588 * @param raidrec The RAID device record in @p raidlist to work on.
2589 * @param description_of_list The type of disks we're selecting (e.g. "data").
2590 * @param disklist The disklist to put the user-selected disks in.
2591 * @ingroup restoreGuiMountlist
2592 */
2593void
2594select_raid_disks(struct mountlist_itself *mountlist_dontedit,
2595 struct raidlist_itself *raidlist,
2596 struct raid_device_record *raidrec,
2597 char *description_of_list,
2598 struct list_of_disks *disklist)
2599{
2600 void *curr_choice;
2601
2602 /** ??? ***************************************************************/
2603
2604 /** structures ********************************************************/
2605 struct raidlist_itself *bkp_raidlist;
2606 struct raid_device_record *bkp_raidrec;
2607 struct list_of_disks *bkp_disklist;
2608 struct mountlist_itself *unallocated_raid_partitions;
2609
2610 /** newt **************************************************************/
2611 newtComponent myForm = NULL;
2612 newtComponent bAdd = NULL;
2613 newtComponent bDelete = NULL;
2614 newtComponent bOK = NULL;
2615 newtComponent bCancel = NULL;
2616 newtComponent b_res = NULL;
2617 newtComponent partitionsListbox = NULL;
2618 newtComponent headerMsg = NULL;
2619
2620 /** buffers **********************************************************/
2621 void *keylist[ARBITRARY_MAXIMUM];
2622 char *tmp = NULL;
2623 char *help_text = NULL;
2624 char *title_of_window = NULL;
2625 char sz_res[MAX_STR_LEN];
2626 char *header_text = NULL;
2627
2628 /** int **************************************************************/
2629 int i = 0;
2630 int currline = 0;
2631
2632 assert(mountlist_dontedit != NULL);
2633 assert(raidlist != NULL);
2634 assert(raidrec != NULL);
2635 assert(description_of_list != NULL);
2636 assert(disklist != NULL);
2637
2638 log_it("malloc'ing");
2639 bkp_raidrec = mr_malloc(sizeof(struct raid_device_record));
2640 bkp_disklist = mr_malloc(sizeof(struct list_of_disks));
2641 bkp_raidlist = mr_malloc(sizeof(struct raidlist_itself));
2642 unallocated_raid_partitions = mr_malloc(sizeof(struct mountlist_itself));
2643
2644 memcpy((void *) bkp_raidlist, (void *) raidlist, sizeof(struct raidlist_itself));
2645 memcpy((void *) bkp_raidrec, (void *) raidrec, sizeof(struct raid_device_record));
2646 memcpy((void *) bkp_disklist, (void *) disklist, sizeof(struct list_of_disks));
2647
2648 log_it("Post-malloc");
2649 mr_asprintf(help_text, " Edit this RAID device's list of partitions. Choose OK or Cancel when done.");
2650 mr_asprintf(header_text, "%-24s %s", "Device", "Index");
2651 mr_asprintf(title_of_window, "%s contains...", raidrec->raid_device);
2652 newtPushHelpLine(help_text);
2653 for (b_res = (newtComponent) 12345; b_res != bOK && b_res != bCancel;) {
2654 headerMsg = newtLabel(1, 1, header_text);
2655 partitionsListbox =
2656 newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
2657 redraw_disklist(disklist, keylist, partitionsListbox);
2658 i = 1;
2659 bAdd = newtCompactButton(i, 9, " Add ");
2660 bDelete = newtCompactButton(i += 8, 9, "Delete");
2661 bOK = newtCompactButton(i += 9, 9, " OK ");
2662 bCancel = newtCompactButton(i += 9, 9, "Cancel");
2663 newtOpenWindow(21, 7, 38, 10, title_of_window);
2664 myForm = newtForm(NULL, NULL, 0);
2665 if (disklist->entries == 0) {
2666 newtFormAddComponents(myForm, headerMsg, bAdd, bDelete, bOK,
2667 bCancel, NULL);
2668 } else {
2669 newtFormAddComponents(myForm, headerMsg, partitionsListbox,
2670 bAdd, bDelete, bOK, bCancel, NULL);
2671 }
2672 b_res = newtRunForm(myForm);
2673 if (b_res == bOK || b_res == bCancel) { /* do nothing */
2674// That's OK. At the end of this subroutine (after this do/while loop),
2675// we'll throw away the changes if Cancel was pushed.
2676 } else {
2677 curr_choice = newtListboxGetCurrent(partitionsListbox);
2678 for (i = 0; i < disklist->entries && keylist[i] != curr_choice;
2679 i++);
2680 if (i == disklist->entries && disklist->entries > 0) {
2681 log_to_screen("I don't know what that button does!");
2682 } else {
2683 currline = i;
2684 if (b_res == bAdd) {
2685 log_it("Making list of unallocated RAID slices");
2686 make_list_of_unallocated_raid_partitions
2687 (unallocated_raid_partitions, mountlist_dontedit,
2688 raidlist);
2689 if (unallocated_raid_partitions->entries <= 0) {
2690 popup_and_OK
2691 ("There are no unallocated partitions marked for RAID.");
2692 } else {
2693 log_it
2694 ("Done. The user may add one or more of the above to RAID device");
2695 add_disklist_entry(disklist, raidrec->raid_device,
2696 unallocated_raid_partitions);
2697 log_it("I have finished adding a disklist entry.");
2698 redraw_disklist(disklist, keylist,
2699 partitionsListbox);
2700 }
2701 } else if (b_res == bDelete) {
2702 delete_disklist_entry(disklist, raidrec->raid_device,
2703 currline);
2704 redraw_disklist(disklist, keylist, partitionsListbox);
2705 } else {
2706 mr_asprintf(tmp, "%s's index is %d. What should it be?", raidrec->raid_device, disklist->el[currline].index);
2707 sprintf(sz_res, "%d", disklist->el[currline].index);
2708 if (popup_and_get_string("Set index", tmp, sz_res, 10)) {
2709 disklist->el[currline].index = atoi(sz_res);
2710 }
2711 mr_free(tmp);
2712
2713 redraw_disklist(disklist, keylist, partitionsListbox);
2714 }
2715 }
2716 }
2717 newtFormDestroy(myForm);
2718 newtPopWindow();
2719 }
2720 newtPopHelpLine();
2721 mr_free(help_text);
2722 mr_free(header_text);
2723 mr_free(title_of_window);
2724
2725 if (b_res == bCancel) {
2726 memcpy((void *) raidlist, (void *) bkp_raidlist, sizeof(struct raidlist_itself));
2727 memcpy((void *) raidrec, (void *) bkp_raidrec, sizeof(struct raid_device_record));
2728 memcpy((void *) disklist, (void *) bkp_disklist, sizeof(struct list_of_disks));
2729 }
2730 mr_free(bkp_raidrec);
2731 mr_free(bkp_disklist);
2732 mr_free(bkp_raidlist);
2733 mr_free(unallocated_raid_partitions);
2734}
2735#endif
2736
2737
2738
2739/**
2740 * Ask the user which restore mode (nuke, interactive, or compare) we should use.
2741 * @return The mode selected: 'I' for interactive, 'N' for nuke, 'C' for compare,
2742 * or 'E' (or any other letter) for exit.
2743 */
2744char which_restore_mode()
2745{
2746
2747 /** char *************************************************************/
2748 char output = '\0';
2749 char *tmp = NULL;
2750
2751 /** newt *************************************************************/
2752
2753 newtComponent b1;
2754 newtComponent b2;
2755 newtComponent b3;
2756 newtComponent b4;
2757 newtComponent b_res;
2758 newtComponent myForm;
2759
2760 if (g_text_mode) {
2761 while (!strchr("AICE", output)) {
2762 printf("Which mode - (A)utomatic, (I)nteractive, \n(C)ompare only, or (E)xit to shell?\n--> ");
2763 mr_getline(tmp, stdin);
2764 output = tmp[0];
2765 mr_free(tmp);
2766 }
2767 return (output);
2768 }
2769
2770 newtPushHelpLine(" Do you want to 'nuke' your system, restore interactively, or just compare?");
2771 newtOpenWindow(24, 3, 32, 17, "How should I restore?");
2772 b1 = newtButton(7, 1, "Automatically");
2773 b2 = newtButton(7, 5, "Interactively");
2774 b3 = newtButton(7, 9, "Compare only!");
2775 b4 = newtButton(7, 13, "Exit to shell");
2776 myForm = newtForm(NULL, NULL, 0);
2777 newtFormAddComponents(myForm, b1, b2, b3, b4, NULL);
2778 b_res = newtRunForm(myForm);
2779 newtFormDestroy(myForm);
2780 newtPopWindow();
2781 if (b_res == b1) {
2782 output = 'N';
2783 }
2784 if (b_res == b2) {
2785 output = 'I';
2786 }
2787 if (b_res == b3) {
2788 output = 'C';
2789 }
2790 if (b_res == b4) {
2791 output = 'E';
2792 }
2793 newtPopHelpLine();
2794 return (output);
2795}
Note: See TracBrowser for help on using the repository browser.