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

Last change on this file since 2400 was 2400, checked in by Bruno Cornec, 11 years ago
  • Use protocol name when displaying restore progress instead of netfs
  • Ask for network protocol name at restore time

(Backport from 2.2.9)

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