source: MondoRescue/branches/2.2.10/mondo/src/mondorestore/mondo-rstr-newt.c @ 2352

Last change on this file since 2352 was 2352, checked in by Bruno Cornec, 11 years ago

Change inerface of evaluate_mountlist and spread_flaws_across_three_lines in order to solve bugs linked to strings management in these functions. May fix a restoration crash seen by some customers (backport from 2.2.9)

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