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

Last change on this file since 2395 was 2395, checked in by Bruno Cornec, 11 years ago
  • Fix interface of evaluate_mountlist (remove 2nd param useless) and fix nuke mode which wasn't working.
  • Tries to add support for bzip2 and lzma initramfs (preliminary, not tested) for 2.6.30

(Backport from 2.2.9)

  • Property svn:keywords set to Id
File size: 86.4 KB
Line 
1/***************************************************************************
2 * $Id: mondo-rstr-newt.c 2395 2009-09-12 00:57:02Z 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 2395 2009-09-12 00:57:02Z 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    personalities = 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 currline = 0;
1927    int finished = FALSE;
1928
1929    /** buffers **********************************************************/
1930    char *tmp = NULL;
1931    char *flaws_str = NULL;
1932    char *flaws_str_A = NULL;
1933    char *flaws_str_B = NULL;
1934    char *flaws_str_C = NULL;
1935
1936    assert(mountlist != NULL);
1937    assert(raidlist != NULL);
1938
1939    if (mountlist->entries > ARBITRARY_MAXIMUM) {
1940        log_to_screen("Arbitrary limits suck, man!");
1941        finish(1);
1942    }
1943    newtPushHelpLine
1944        ("   Please edit the mountlist to your satisfaction, then click OK or Cancel.");
1945    i = 4;
1946    bAdd = newtCompactButton(i, 17, " Add ");
1947    bEdit = newtCompactButton(i += 11, 17, " Edit ");
1948    bDelete = newtCompactButton(i += 12, 17, "Delete");
1949    bReload = newtCompactButton(i += 12, 17, "Reload");
1950    bCancel = newtCompactButton(i += 12, 17, "Cancel");
1951    bOK = newtCompactButton(i += 12, 17, "  OK  ");
1952    mr_asprintf(tmp, "%-24s %-24s %-8s  %s", "Device", "Mountpoint", "Format", "Size (MB)");
1953    headerMsg = newtLabel(2, 1, tmp);
1954    flawsLabelA = newtLabel(2, 13, "         ");
1955    flawsLabelB = newtLabel(2, 14, "         ");
1956    flawsLabelC = newtLabel(2, 15, "         ");
1957    partitionsListbox =
1958        newtListbox(2, 2, 10, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
1959    redraw_mountlist(mountlist, keylist, partitionsListbox);
1960    newtOpenWindow(1, 3, 77, 18, "Editing mountlist");
1961    myForm = newtForm(NULL, NULL, 0);
1962    newtFormAddComponents(myForm, headerMsg, partitionsListbox,
1963                          flawsLabelA, flawsLabelB, flawsLabelC, bAdd,
1964                          bEdit, bDelete, bReload, bCancel, bOK, NULL);
1965    while (!finished) {
1966        flaws_str = evaluate_mountlist(mountlist);
1967        if (strlen(flaws_str) > 0) {
1968            mr_asprintf(flaws_str_A, "%s", flaws_str + 1);
1969        } else {
1970            mr_asprintf(flaws_str_A, "");
1971        }
1972        if (strlen(flaws_str_A) >= 74) {
1973            for (i = 74; flaws_str_A[i] != ' '; i--);
1974            mr_asprintf(flaws_str_B, "%s", flaws_str_A + i + 1);
1975            flaws_str_A[i] = '\0';
1976        } else {
1977            mr_asprintf(flaws_str_B, "");
1978        }
1979        if (strlen(flaws_str_B) >= 74) {
1980            for (i = 74; flaws_str_B[i] != ' '; i--);
1981            mr_asprintf(flaws_str_C, "%s", flaws_str_B + i + 1);
1982            flaws_str_B[i] = '\0';
1983        } else {
1984            mr_asprintf(flaws_str_C, "");
1985        }
1986        mr_free(flaws_str);
1987
1988        newtLabelSetText(flawsLabelA, flaws_str_A);
1989        newtLabelSetText(flawsLabelB, flaws_str_B);
1990        newtLabelSetText(flawsLabelC, flaws_str_C);
1991        b_res = newtRunForm(myForm);
1992        mr_free(flaws_str_A);
1993        mr_free(flaws_str_B);
1994        mr_free(flaws_str_C);
1995
1996        if (b_res == bOK) {
1997            flaws_str = evaluate_mountlist(mountlist);
1998            if (flaws_str != NULL) {
1999                mr_free(flaws_str);
2000                finished =
2001                    ask_me_yes_or_no
2002                    ("Your mountlist might not work. Continue anyway?");
2003            } else {
2004                finished =
2005                    ask_me_yes_or_no
2006                    ("Are you sure you want to save your mountlist and continue? (No changes will be made to your partition table at this time.)");
2007            }
2008        } else if (b_res == bCancel) {
2009            finished = TRUE;
2010        } else if (b_res == bReload) {
2011            if (ask_me_yes_or_no("Reload original mountlist?")) {
2012                load_mountlist(mountlist, mountlist_fname);
2013                load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME);
2014                redraw_mountlist(mountlist, keylist, partitionsListbox);
2015            }
2016        } else {
2017            curr_choice = newtListboxGetCurrent(partitionsListbox);
2018            for (i = 0;
2019                 i < mountlist->entries && keylist[i] != curr_choice; i++);
2020            if (i == mountlist->entries && mountlist->entries > 0) {
2021                log_to_screen("I don't know what that button does!");
2022            } else {
2023                currline = i;
2024                if (b_res == bAdd) {
2025                    add_mountlist_entry(mountlist, raidlist,
2026                                        partitionsListbox, currline,
2027                                        keylist);
2028                } else if (b_res == bDelete) {
2029                    delete_mountlist_entry(mountlist, raidlist,
2030                                           partitionsListbox, currline,
2031                                           keylist);
2032                } else {
2033                    if (mountlist->entries > 0) {
2034                        edit_mountlist_entry(mountlist, raidlist,
2035                                             partitionsListbox, currline,
2036                                             keylist);
2037                    } else {
2038                        popup_and_OK
2039                            ("Please add an entry. Then press ENTER to edit it.");
2040                    }
2041                }
2042            }
2043        }
2044    }
2045    newtFormDestroy(myForm);
2046
2047    mr_free(flaws_str_A);
2048    mr_free(flaws_str_B);
2049    mr_free(flaws_str_C);
2050    mr_free(tmp);
2051
2052    newtPopWindow();
2053    newtPopHelpLine();
2054    if (b_res == bOK) {
2055        log_it("You pushed 'OK'. I shall now continue.");
2056        return (0);
2057    } else {
2058        /* popup_and_OK("You pushed 'cancel'. I shall now abort."); */
2059        return (1);
2060    }
2061}
2062
2063
2064
2065/**
2066 * Edit the mountlist.
2067 * @param mountlist The mountlist to edit.
2068 * @param raidlist The raidlist that goes with @p mountlist.
2069 * @return 0 if the user pressed OK, 1 if they pressed Cancel.
2070 */
2071int
2072edit_mountlist(char *mountlist_fname, struct mountlist_itself *mountlist,
2073               struct raidlist_itself *raidlist)
2074{
2075    int res = 0;
2076
2077    log_it("entering eml");
2078
2079    if (g_text_mode) {
2080        fatal_error("Don't call edit_mountlist() in text mode");
2081    } else {
2082        log_it
2083            ("I'm in GUI mode, so I shall edit mountlist using edit_mountlist()");
2084        res = edit_mountlist_in_newt(mountlist_fname, mountlist, raidlist);
2085    }
2086    log_it("leaving eml");
2087    return (res);
2088}
2089
2090
2091
2092
2093#ifndef __FreeBSD__
2094/**
2095 * Edit the additional RAID variables in @p raidrec.
2096 * @param raidrec The RAID device record to edit the RAID variables in.
2097 * @ingroup restoreGuiVarslist
2098 */
2099void edit_raidrec_additional_vars(struct raid_device_record *raidrec)
2100{
2101
2102    /** structure *********************************************************/
2103    struct raid_device_record bkp_raidrec;
2104
2105    /** newt **************************************************************/
2106    newtComponent myForm;
2107    newtComponent bAdd;
2108    newtComponent bEdit;
2109    newtComponent bDelete;
2110    newtComponent bOK;
2111    newtComponent bCancel;
2112    newtComponent b_res;
2113    newtComponent varsListbox;
2114    newtComponent headerMsg;
2115
2116    /** ?? ***************************************************************/
2117    void *keylist[ARBITRARY_MAXIMUM], *curr_choice;
2118
2119    /** buffers **********************************************************/
2120    char title_of_window[MAX_STR_LEN];
2121
2122    /** int **************************************************************/
2123    int i = 0;
2124    int currline = 0;
2125
2126
2127    assert(raidrec != NULL);
2128
2129    memcpy((void *) &bkp_raidrec, (void *) raidrec,
2130           sizeof(struct raid_device_record));
2131    sprintf(title_of_window, "Additional variables");
2132    newtPushHelpLine
2133        ("  Edit the additional fields to your heart's content, then click OK or Cancel.");
2134    headerMsg = newtLabel(1, 1, "Label                            Value");
2135    varsListbox =
2136        newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
2137    i = 1;
2138    bAdd = newtCompactButton(i, 9, " Add ");
2139    bEdit = newtCompactButton(i += 8, 9, " Edit ");
2140    bDelete = newtCompactButton(i += 9, 9, "Delete");
2141    bOK = newtCompactButton(i += 9, 9, "  OK  ");
2142    bCancel = newtCompactButton(i += 9, 9, "Cancel");
2143    newtOpenWindow(17, 7, 46, 10, title_of_window);
2144    myForm = newtForm(NULL, NULL, 0);
2145    newtFormAddComponents(myForm, headerMsg, varsListbox, bAdd, bEdit,
2146                          bDelete, bOK, bCancel, NULL);
2147    insert_essential_additionalvars(raidrec);
2148    redraw_varslist(&raidrec->additional_vars, keylist, varsListbox);
2149    for (b_res = NULL; b_res != bOK && b_res != bCancel;) {
2150        b_res = newtRunForm(myForm);
2151        curr_choice = newtListboxGetCurrent(varsListbox);
2152        for (currline = 0;
2153             currline < raidrec->additional_vars.entries
2154             && keylist[currline] != curr_choice; currline++);
2155        if (currline == raidrec->additional_vars.entries
2156            && raidrec->additional_vars.entries > 0) {
2157            log_it("Warning - I don't know what this button does");
2158        }
2159        if (b_res == bOK) {     /* do nothing */
2160        } else if (b_res == bCancel) {  /* do nothing */
2161        } else if (b_res == bAdd) {
2162            add_varslist_entry(raidrec);
2163        } else if (b_res == bDelete) {
2164            delete_varslist_entry(raidrec, currline);
2165        } else {
2166            edit_varslist_entry(raidrec, currline);
2167        }
2168        redraw_varslist(&raidrec->additional_vars, keylist, varsListbox);
2169    }
2170    remove_essential_additionalvars(raidrec);
2171    newtFormDestroy(myForm);
2172    newtPopWindow();
2173    newtPopHelpLine();
2174    if (b_res == bCancel) {
2175        memcpy((void *) raidrec, (void *) &bkp_raidrec,
2176               sizeof(struct raid_device_record));
2177    }
2178    return;
2179}
2180#endif
2181
2182
2183/**
2184 * Find the next free location to place a disk in @p disklist.
2185 * @param disklist The disklist to operate on.
2186 * @return The next free location (starting from 0).
2187 * @ingroup restoreGuiDisklist
2188 */
2189int find_next_free_index_in_disklist(struct list_of_disks *disklist)
2190{
2191
2192    /** int ***************************************************************/
2193    int index = -1;
2194    int pos = 0;
2195
2196  /** bool **************************************************************/
2197    bool done;
2198
2199    assert(disklist != NULL);
2200
2201    for (done = FALSE; !done;) {
2202        for (pos = 0;
2203             pos < disklist->entries && disklist->el[pos].index <= index;
2204             pos++);
2205        if (pos >= disklist->entries) {
2206            done = TRUE;
2207        } else {
2208            index = disklist->el[pos].index;
2209        }
2210    }
2211    return (index + 1);
2212}
2213
2214
2215
2216/**
2217 * Locate @p device in @p raidlist.
2218 * @param raidlist The raidlist ot search in.
2219 * @param device The RAID device to search for.
2220 * @return The index of the device, or -1 if it could not be found.
2221 * @ingroup restoreGuiMountlist
2222 */
2223int
2224find_raid_device_in_raidlist(struct raidlist_itself *raidlist,
2225                             char *device)
2226{
2227
2228    /** int ***************************************************************/
2229    int i = 0;
2230#ifdef __FreeBSD__
2231    char *vdev = NULL;
2232    int res = 0;
2233#else
2234// Linux
2235#endif
2236
2237    assert(raidlist != NULL);
2238    assert_string_is_neither_NULL_nor_zerolength(device);
2239
2240#ifdef __FreeBSD__
2241    for (i = 0; i < raidlist->entries; i++) {
2242        mr_asprintf(vdev, "/dev/vinum/%s", raidlist->el[i].volname);
2243        res = strcmp(device, vdev);
2244        mr_free(vdev);
2245
2246        if (!res)
2247            break;
2248    }
2249#else
2250
2251    for (i = 0;
2252         strcmp(raidlist->el[i].raid_device, device)
2253         && i < raidlist->entries; i++);
2254#endif
2255    if (i == raidlist->entries) {
2256        return (-1);
2257    } else {
2258        return (i);
2259    }
2260}
2261
2262
2263/**
2264 * Get information about the location of ISO images from the user.
2265 * @param isodir_device Where to put the device (e.g. /dev/hda4) the user enters. Allocted by the function
2266 * @param isodir_format Where to put the format (e.g. ext2) the user enters.
2267 * @param isodir_path Where to put the path (e.g. /var/cache/mondo) the user enters.
2268 * @param nuke_me_please Whether we're planning on nuking or not.
2269 * @return TRUE if OK was pressed, FALSE otherwise.
2270 */
2271bool get_isodir_info(char *isodir_device, char *isodir_format, char *isodir_path, bool nuke_me_please) {
2272
2273    char *p = NULL;
2274    char *q = NULL;
2275    char *r = NULL;
2276    char *idev = NULL;
2277    bool ret = FALSE;       /* Should be false by default, and modfiy if conditions respected */
2278
2279    /** initialize ********************************************************/
2280
2281    assert(isodir_path != NULL);
2282
2283    log_it("isodir_path = %s", isodir_path);
2284    if (isodir_device == NULL) {
2285        mr_asprintf(idev, "/dev/");
2286    } else {
2287        mr_asprintf(idev, "%s", isodir_device);
2288    }
2289
2290    if (does_file_exist("/tmp/NETFS-SERVER-PATH")) {
2291        mr_free(idev);
2292        idev = last_line_of_file("/tmp/NETFS-SERVER-MOUNT");
2293        mr_asprintf(isodir_format, "netfs");
2294        mr_free(isodir_path);
2295        isodir_path = last_line_of_file("/tmp/NETFS-SERVER-PATH");
2296    }
2297
2298    /* modify for the caller */
2299    mr_free(isodir_device);
2300    isodir_device = idev;
2301    if (nuke_me_please) {
2302        ret = TRUE;
2303    } else {
2304        p = popup_and_get_string("ISO Mode - device", "On what device do the ISO files live?", idev);
2305        if (p != NULL) {
2306            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);
2307            mr_free(isodir_format);
2308   
2309            if (q != NULL) {
2310                r = popup_and_get_string("ISO Mode - path", "At what path on this device can the ISO files be found?", isodir_path);
2311                if (r != NULL) {
2312                    mr_strip_spaces(p);
2313                    mr_strip_spaces(q);
2314                    mr_strip_spaces(r);
2315
2316                    isodir_format = q;
2317   
2318                    /* modify for the caller */
2319                    mr_free(isodir_device);
2320                    isodir_device = p;
2321                    mr_free(isodir_path);
2322                    isodir_path = r;
2323                    log_it("isodir_device = %s - isodir_format = %s - isodir_path = %s", isodir_device, isodir_format, isodir_path);
2324   
2325                    ret = TRUE;
2326                }
2327            }
2328        }
2329        mr_free(p);
2330    }
2331    mr_free(isodir_format);
2332    return(ret);
2333}
2334
2335
2336/**
2337 * Create a new raidtab entry for @p device in @p raidlist.
2338 * @param raidlist The raidlist to add the device to.
2339 * @param mountlist The mountlist containing information about the user's partitions.
2340 * @param currline The selected line in the mountlist.
2341 * @param device The RAID device (e.g. /dev/md0) to use.
2342 * @ingroup restoreGuiMountlist
2343 */
2344void
2345initiate_new_raidlist_entry(struct raidlist_itself *raidlist,
2346                            struct mountlist_itself *mountlist,
2347                            int currline, char *device)
2348{
2349
2350    /** structure *********************************************************/
2351    struct OSSWAP (raid_device_record, vinum_volume) * raidrec;
2352
2353    /** int ***************************************************************/
2354    int pos_in_raidlist = 0;
2355
2356    assert(raidlist != NULL);
2357    assert(mountlist != NULL);
2358    assert_string_is_neither_NULL_nor_zerolength(device);
2359
2360    pos_in_raidlist =
2361        find_raid_device_in_raidlist(raidlist,
2362                                     mountlist->el[currline].device);
2363    if (pos_in_raidlist >= 0) {
2364        fatal_error("Sorry, that RAID device already exists. Weird.");
2365    }
2366    pos_in_raidlist = raidlist->entries++;
2367    raidrec = &raidlist->el[pos_in_raidlist];
2368    initialize_raidrec(raidrec);
2369    strcpy(raidrec->OSSWAP(raid_device, volname), OSSWAP(device, basename(device)));
2370#ifndef __FreeBSD__
2371    choose_raid_level(raidrec);
2372    select_raid_disks(mountlist, raidlist, raidrec, "data",
2373                      &raidrec->data_disks);
2374#endif
2375    edit_raidlist_entry(mountlist, raidlist, raidrec, currline);
2376}
2377
2378
2379#ifndef __FreeBSD__
2380/**
2381 * Insert the RAID variables not stored in the "additional RAID variables" list there too.
2382 * @param raidrec The RAID device record to operate on.
2383 * @ingroup restoreGuiVarslist
2384 */
2385void insert_essential_additionalvars(struct raid_device_record *raidrec)
2386{
2387
2388    /** int **************************************************************/
2389    int items = 0;
2390
2391    assert(raidrec != NULL);
2392
2393    items = raidrec->additional_vars.entries;
2394    write_variableINT_to_raid_var_line(raidrec, items++,
2395                                       "persistent-superblock",
2396                                       raidrec->persistent_superblock);
2397    write_variableINT_to_raid_var_line(raidrec, items++, "chunk-size",
2398                                       raidrec->chunk_size);
2399    raidrec->additional_vars.entries = items;
2400}
2401
2402#endif
2403
2404/**
2405 * Dummy function that proves that we can get to the point where Mondo is run.
2406 */
2407void nuke_mode_dummy()
2408{
2409
2410    /** newt *************************************************************/
2411    newtComponent myForm;
2412    newtComponent b1;
2413    newtComponent b2;
2414    newtComponent b3;
2415    newtComponent b_res;
2416
2417
2418    newtPushHelpLine
2419        ("This is where I nuke your hard drives. Mhahahahaha. No-one can stop Mojo Jojo!");
2420    newtOpenWindow(24, 3, 32, 13, "Nuking");
2421    b1 = newtButton(7, 1, "Slowly");
2422    b2 = newtButton(7, 5, "Medium");
2423    b3 = newtButton(7, 9, "Quickly");
2424    myForm = newtForm(NULL, NULL, 0);
2425    newtFormAddComponents(myForm, b1, b2, b3, NULL);
2426    b_res = newtRunForm(myForm);
2427    newtFormDestroy(myForm);
2428    newtPopWindow();
2429    newtPopHelpLine();
2430}
2431
2432
2433
2434/**
2435 * Redraw the disklist.
2436 * @param disklist The disklist to read from.
2437 * @param keylist The list of keys for @p listbox.
2438 * @param listbox The Newt listbox component to redraw.
2439 * @ingroup restoreGuiDisklist
2440 */
2441void
2442redraw_disklist(struct list_of_disks *disklist,
2443                void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox)
2444{
2445
2446    /** long **************************************************************/
2447    long i = 0;
2448
2449    assert(disklist != NULL);
2450    assert(keylist != NULL);
2451    assert(listbox != NULL);
2452
2453    newtListboxClear(listbox);
2454
2455    for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2456        keylist[i] = (void *) i;
2457    }
2458    for (i = 0; i < disklist->entries; i++) {
2459        newtListboxAppendEntry(listbox,
2460                               disklist_entry_to_string(disklist, i),
2461                               keylist[i]);
2462    }
2463}
2464
2465
2466/**
2467 * Redraw the mountlist.
2468 * @param mountlist The mountlist to read from.
2469 * @param keylist The list of keys for @p listbox.
2470 * @param listbox The Newt listbox component to redraw.
2471 * @ingroup restoreGuiMountlist
2472 */
2473void
2474redraw_mountlist(struct mountlist_itself *mountlist,
2475                 void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox)
2476{
2477
2478    /** long **************************************************************/
2479    long i = 0;
2480
2481    assert(mountlist != NULL);
2482    assert(keylist != NULL);
2483    assert(listbox != NULL);
2484
2485    newtListboxClear(listbox);
2486//  sort_mountlist_by_device (mountlist);
2487    for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2488        keylist[i] = (void *) i;
2489    }
2490    for (i = 0; i < mountlist->entries; i++) {
2491        newtListboxAppendEntry(listbox,
2492                               mountlist_entry_to_string(mountlist, i),
2493                               keylist[i]);
2494    }
2495}
2496
2497
2498
2499
2500/**
2501 * Redraw the list of unallocated RAID partitions.
2502 * @param unallocated_raid_partitions The mountlist containing unallocated RAID partitions.
2503 * @param keylist The list of keys for @p listbox.
2504 * @param listbox The Newt listbox component to redraw.
2505 * @ingroup restoreGuiDisklist
2506 */
2507void redraw_unallocpartnslist(struct mountlist_itself
2508                              *unallocated_raid_partitions,
2509                              void *keylist[ARBITRARY_MAXIMUM],
2510                              newtComponent listbox)
2511{
2512
2513    /** long *************************************************************/
2514    long i = 0;
2515
2516    /** buffers **********************************************************/
2517    char tmp[MAX_STR_LEN];
2518
2519    assert(unallocated_raid_partitions != NULL);
2520    assert(keylist != NULL);
2521    assert(listbox != NULL);
2522
2523    newtListboxClear(listbox);
2524    for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2525        keylist[i] = (void *) i;
2526    }
2527    for (i = 0; i < unallocated_raid_partitions->entries; i++) {
2528        sprintf(tmp, "%-22s %8lld",
2529                unallocated_raid_partitions->el[i].device,
2530                unallocated_raid_partitions->el[i].size / 1024L);
2531        newtListboxAppendEntry(listbox, tmp, keylist[i]);
2532    }
2533}
2534
2535#ifndef __FreeBSD__
2536/**
2537 * Redraw the list of additional RAID variables.
2538 * @param additional_vars The list of additional RAID varibals.
2539 * @param keylist The list of keys for @p listbox.
2540 * @param listbox The Newt listbox component to redraw.
2541 * @ingroup restoreGuiVarslist
2542 */
2543void
2544redraw_varslist(struct additional_raid_variables *additional_vars,
2545                void *keylist[], newtComponent listbox)
2546{
2547    /** long ************************************************************/
2548    long i = 0;
2549
2550    /** buffers *********************************************************/
2551    char tmp[MAX_STR_LEN];
2552
2553    assert(additional_vars != NULL);
2554    assert(keylist != NULL);
2555    assert(listbox != NULL);
2556
2557    newtListboxClear(listbox);
2558
2559    for (i = 0; i < ARBITRARY_MAXIMUM; i++) {
2560        keylist[i] = (void *) i;
2561    }
2562    for (i = 0; i < additional_vars->entries; i++) {
2563        sprintf(tmp, "%-32s %-8s", additional_vars->el[i].label,
2564                additional_vars->el[i].value);
2565        newtListboxAppendEntry(listbox, tmp, keylist[i]);
2566    }
2567}
2568
2569
2570/**
2571 * Remove variable @p label from the RAID variables list in @p raidrec.
2572 * @param raidrec The RAID device record to remove the variable from.
2573 * @param label The variable name to remove.
2574 * @return The value of the variable removed.
2575 * @ingroup restoreUtilityGroup
2576 */
2577int
2578read_variableINT_and_remove_from_raidvars(struct
2579                                          OSSWAP (raid_device_record,
2580                                                  vinum_volume) * raidrec,
2581                                          char *label)
2582{
2583    /** int ***************************************************************/
2584    int i = 0;
2585    int res = 0;
2586
2587
2588    assert(raidrec != NULL);
2589    assert(label != NULL);
2590
2591    for (i = 0;
2592         i < raidrec->additional_vars.entries
2593         && strcmp(raidrec->additional_vars.el[i].label, label); i++);
2594    if (i == raidrec->additional_vars.entries) {
2595        res = -1;
2596    } else {
2597        res = atoi(raidrec->additional_vars.el[i].value);
2598        for (i++; i < raidrec->additional_vars.entries; i++) {
2599            memcpy((void *) &raidrec->additional_vars.el[i - 1],
2600                   (void *) &raidrec->additional_vars.el[i],
2601                   sizeof(struct raid_var_line));
2602        }
2603        raidrec->additional_vars.entries--;
2604    }
2605    return (res);
2606}
2607#endif
2608
2609/**
2610 * Change all RAID devices to use @p new_dev instead of @p old_dev.
2611 * @param raidlist The raidlist to make the changes in.
2612 * @param old_dev The old name of the device (what it used to be).
2613 * @param new_dev The new name of the device (what it is now).
2614 * @ingroup restoreGuiMountlist
2615 */
2616void rejig_partition_name_in_raidlist_if_necessary(struct raidlist_itself
2617                                                   *raidlist,
2618                                                   char *old_dev,
2619                                                   char *new_dev)
2620{
2621    /** int ************************************************************/
2622    int pos = 0;
2623    int j = 0;
2624
2625    assert(raidlist != NULL);
2626    assert_string_is_neither_NULL_nor_zerolength(old_dev);
2627    assert_string_is_neither_NULL_nor_zerolength(new_dev);
2628
2629    pos = which_raid_device_is_using_this_partition(raidlist, old_dev);
2630    if (pos < 0) {
2631        log_it("No need to rejig %s in raidlist: it's not listed.", old_dev);
2632    } else {
2633        if ((j =
2634             where_in_drivelist_is_drive(&raidlist->
2635                                         OSSWAP(el[pos].data_disks, disks),
2636                                         old_dev)) >= 0) {
2637            strcpy(raidlist->OSSWAP(el[pos].data_disks, disks).el[j].device, new_dev);
2638        } else
2639            if ((j =
2640                 where_in_drivelist_is_drive(&raidlist->
2641                                             OSSWAP(el[pos].spare_disks,
2642                                                    spares),
2643                                             old_dev)) >= 0) {
2644            strcpy(raidlist->OSSWAP(el[pos].spare_disks, spares).el[j].device, new_dev);
2645        }
2646#ifndef __FreeBSD__
2647        else if ((j =
2648                  where_in_drivelist_is_drive(&raidlist->el[pos].
2649                                              parity_disks,
2650                                              old_dev)) >= 0) {
2651            strcpy(raidlist->el[pos].parity_disks.el[j].device, new_dev);
2652        } else
2653            if ((j =
2654                 where_in_drivelist_is_drive(&raidlist->el[pos].
2655                                             failed_disks,
2656                                             old_dev)) >= 0) {
2657            strcpy(raidlist->el[pos].failed_disks.el[j].device, new_dev);
2658        }
2659#endif
2660        else {
2661            log_it("%s is supposed to be listed in this raid dev but it's not...", old_dev);
2662        }
2663    }
2664}
2665
2666
2667#ifndef __FreeBSD__
2668/**
2669 * Remove the essential RAID variables from the "additional variables" section.
2670 * If they have been changed, set them in their normal locations too.
2671 * @param raidrec The RAID device record to operate on.
2672 * @ingroup restoreUtilityVarslist
2673 */
2674void remove_essential_additionalvars(struct raid_device_record *raidrec)
2675{
2676
2677    /** int **************************************************************/
2678    int res = 0;
2679
2680    assert(raidrec != NULL);
2681
2682    res =
2683        read_variableINT_and_remove_from_raidvars(raidrec,
2684                                                  "persistent-superblock");
2685    if (res > 0) {
2686        raidrec->persistent_superblock = res;
2687    }
2688    res = read_variableINT_and_remove_from_raidvars(raidrec, "chunk-size");
2689    if (res > 0) {
2690        raidrec->chunk_size = res;
2691    }
2692    res = read_variableINT_and_remove_from_raidvars(raidrec, "block-size");
2693}
2694
2695/**
2696 * Select the RAID disks to use in @p raidrec.
2697 * @param mountlist_dontedit The mountlist (will not be edited).
2698 * @param raidlist The raidlist to modify.
2699 * @param raidrec The RAID device record in @p raidlist to work on.
2700 * @param description_of_list The type of disks we're selecting (e.g. "data").
2701 * @param disklist The disklist to put the user-selected disks in.
2702 * @ingroup restoreGuiMountlist
2703 */
2704void
2705select_raid_disks(struct mountlist_itself *mountlist_dontedit,
2706                  struct raidlist_itself *raidlist,
2707                  struct raid_device_record *raidrec,
2708                  char *description_of_list,
2709                  struct list_of_disks *disklist)
2710{
2711    void *curr_choice;
2712
2713    /** ??? ***************************************************************/
2714
2715    /** structures ********************************************************/
2716    struct raidlist_itself *bkp_raidlist;
2717    struct raid_device_record *bkp_raidrec;
2718    struct list_of_disks *bkp_disklist;
2719    struct mountlist_itself *unallocated_raid_partitions;
2720
2721    /** newt **************************************************************/
2722    newtComponent myForm = NULL;
2723    newtComponent bAdd = NULL;
2724    newtComponent bDelete = NULL;
2725    newtComponent bOK = NULL;
2726    newtComponent bCancel = NULL;
2727    newtComponent b_res = NULL;
2728    newtComponent partitionsListbox = NULL;
2729    newtComponent headerMsg = NULL;
2730
2731    /** buffers **********************************************************/
2732    void *keylist[ARBITRARY_MAXIMUM];
2733    char *tmp = NULL;
2734    char *help_text = NULL;
2735    char *title_of_window = NULL;
2736    char *sz_res = NULL;
2737    char *header_text = NULL;
2738    char *p = NULL;
2739
2740  /** int **************************************************************/
2741    int i = 0;
2742    int currline = 0;
2743
2744    assert(mountlist_dontedit != NULL);
2745    assert(raidlist != NULL);
2746    assert(raidrec != NULL);
2747    assert(description_of_list != NULL);
2748    assert(disklist != NULL);
2749
2750    log_it("malloc'ing");
2751    bkp_raidrec = mr_malloc(sizeof(struct raid_device_record));
2752    bkp_disklist = mr_malloc(sizeof(struct list_of_disks));
2753    bkp_raidlist = mr_malloc(sizeof(struct raidlist_itself));
2754    unallocated_raid_partitions = mr_malloc(sizeof(struct mountlist_itself));
2755
2756    memcpy((void *) bkp_raidlist, (void *) raidlist, sizeof(struct raidlist_itself));
2757    memcpy((void *) bkp_raidrec, (void *) raidrec, sizeof(struct raid_device_record));
2758    memcpy((void *) bkp_disklist, (void *) disklist, sizeof(struct list_of_disks));
2759
2760    log_it("Post-malloc");
2761    mr_asprintf(help_text, "   Edit this RAID device's list of partitions. Choose OK or Cancel when done.");
2762    mr_asprintf(header_text, "%-24s    %s", "Device", "Index");
2763    mr_asprintf(title_of_window, "%s contains...", raidrec->raid_device);
2764    newtPushHelpLine(help_text);
2765    for (b_res = (newtComponent) 12345; b_res != bOK && b_res != bCancel;) {
2766        headerMsg = newtLabel(1, 1, header_text);
2767        partitionsListbox =
2768            newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
2769        redraw_disklist(disklist, keylist, partitionsListbox);
2770        i = 1;
2771        bAdd = newtCompactButton(i, 9, " Add ");
2772        bDelete = newtCompactButton(i += 8, 9, "Delete");
2773        bOK = newtCompactButton(i += 9, 9, "  OK  ");
2774        bCancel = newtCompactButton(i += 9, 9, "Cancel");
2775        newtOpenWindow(21, 7, 38, 10, title_of_window);
2776        myForm = newtForm(NULL, NULL, 0);
2777        if (disklist->entries == 0) {
2778            newtFormAddComponents(myForm, headerMsg, bAdd, bDelete, bOK,
2779                                  bCancel, NULL);
2780        } else {
2781            newtFormAddComponents(myForm, headerMsg, partitionsListbox,
2782                                  bAdd, bDelete, bOK, bCancel, NULL);
2783        }
2784        b_res = newtRunForm(myForm);
2785        if (b_res == bOK || b_res == bCancel) { /* do nothing */
2786// That's OK. At the end of this subroutine (after this do/while loop),
2787// we'll throw away the changes if Cancel was pushed.
2788        } else {
2789            curr_choice = newtListboxGetCurrent(partitionsListbox);
2790            for (i = 0; i < disklist->entries && keylist[i] != curr_choice;
2791                 i++);
2792            if (i == disklist->entries && disklist->entries > 0) {
2793                log_to_screen("I don't know what that button does!");
2794            } else {
2795                currline = i;
2796                if (b_res == bAdd) {
2797                    log_it("Making list of unallocated RAID slices");
2798                    make_list_of_unallocated_raid_partitions
2799                        (unallocated_raid_partitions, mountlist_dontedit,
2800                         raidlist);
2801                    if (unallocated_raid_partitions->entries <= 0) {
2802                        popup_and_OK
2803                            ("There are no unallocated partitions marked for RAID.");
2804                    } else {
2805                        log_it
2806                            ("Done. The user may add one or more of the above to RAID device");
2807                        add_disklist_entry(disklist, raidrec->raid_device,
2808                                           unallocated_raid_partitions);
2809                        log_it("I have finished adding a disklist entry.");
2810                        redraw_disklist(disklist, keylist,
2811                                        partitionsListbox);
2812                    }
2813                } else if (b_res == bDelete) {
2814                    delete_disklist_entry(disklist, raidrec->raid_device,
2815                                          currline);
2816                    redraw_disklist(disklist, keylist, partitionsListbox);
2817                } else {
2818                    mr_asprintf(tmp, "%s's index is %d. What should it be?", raidrec->raid_device, disklist->el[currline].index);
2819                    mr_asprintf(sz_res, "%d", disklist->el[currline].index);
2820                    p = popup_and_get_string("Set index", tmp, sz_res);
2821                    mr_free(tmp);
2822                    if (p != NULL) {
2823                        disklist->el[currline].index = atoi(sz_res);
2824                    }
2825                    redraw_disklist(disklist, keylist, partitionsListbox);
2826                    mr_free(sz_res);
2827                }
2828            }
2829        }
2830        newtFormDestroy(myForm);
2831        newtPopWindow();
2832    }
2833    newtPopHelpLine();
2834    mr_free(help_text);
2835    mr_free(header_text);
2836    mr_free(title_of_window);
2837
2838    if (b_res == bCancel) {
2839        memcpy((void *) raidlist, (void *) bkp_raidlist, sizeof(struct raidlist_itself));
2840        memcpy((void *) raidrec, (void *) bkp_raidrec, sizeof(struct raid_device_record));
2841        memcpy((void *) disklist, (void *) bkp_disklist, sizeof(struct list_of_disks));
2842    }
2843    mr_free(bkp_raidrec);
2844    mr_free(bkp_disklist);
2845    mr_free(bkp_raidlist);
2846    mr_free(unallocated_raid_partitions);
2847}
2848#endif
2849
2850
2851
2852/**
2853 * Ask the user which restore mode (nuke, interactive, or compare) we should use.
2854 * @return The mode selected: 'I' for interactive, 'N' for nuke, 'C' for compare,
2855 * or 'E' (or any other letter) for exit.
2856 */
2857char which_restore_mode()
2858{
2859
2860  /** char *************************************************************/
2861    char output = '\0';
2862    char *tmp = NULL;
2863
2864  /** newt *************************************************************/
2865
2866    newtComponent b1;
2867    newtComponent b2;
2868    newtComponent b3;
2869    newtComponent b4;
2870    newtComponent b_res;
2871    newtComponent myForm;
2872
2873    if (g_text_mode) {
2874        while (!strchr("AICE", output)) {
2875            printf("Which mode - (A)utomatic, (I)nteractive, \n(C)ompare only, or (E)xit to shell?\n--> ");
2876            mr_getline(tmp, stdin);
2877            output = tmp[0];
2878            free(tmp);
2879        }
2880        return (output);
2881    }
2882
2883    newtPushHelpLine("   Do you want to 'nuke' your system, restore interactively, or just compare?");
2884    newtOpenWindow(24, 3, 32, 17, "How should I restore?");
2885    b1 = newtButton(7, 1, "Automatically");
2886    b2 = newtButton(7, 5, "Interactively");
2887    b3 = newtButton(7, 9, "Compare only!");
2888    b4 = newtButton(7, 13, "Exit to shell");
2889    myForm = newtForm(NULL, NULL, 0);
2890    newtFormAddComponents(myForm, b1, b2, b3, b4, NULL);
2891    b_res = newtRunForm(myForm);
2892    newtFormDestroy(myForm);
2893    newtPopWindow();
2894    if (b_res == b1) {
2895        output = 'N';
2896    }
2897    if (b_res == b2) {
2898        output = 'I';
2899    }
2900    if (b_res == b3) {
2901        output = 'C';
2902    }
2903    if (b_res == b4) {
2904        output = 'E';
2905    }
2906    newtPopHelpLine();
2907    return (output);
2908}
Note: See TracBrowser for help on using the repository browser.