source: branches/stable/mondo/src/mondorestore/mondo-rstr-newt.c @ 1125

Last change on this file since 1125 was 1125, checked in by Bruno Cornec, 13 years ago

Still linker fixes (grrr)

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