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

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