source: trunk/mondo/mondo/mondorestore/mondo-rstr-newt.c @ 30

Last change on this file since 30 was 30, checked in by bcornec, 14 years ago

Id property added on files to allow for better conf. management

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