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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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