/* * $Id: mondo-rstr-newt.c 1555 2007-07-24 21:16:18Z bruno $ */ #include "mr_mem.h" #include "mr_msg.h" #include "mr_str.h" #include "mr_gettext.h" extern char *g_mondo_cfg_file; // where m*ndo-restore.cfg (the config file) is stored /** * @file * Functions for handling GUI interfaces in the restore. */ #ifdef __FreeBSD__ #define OSSWAP(linux,fbsd) fbsd #else #define OSSWAP(linux,fbsd) linux #endif #include "mondo-rstr-newt.h" //static char cvsid[] = "$Id: mondo-rstr-newt.c 1555 2007-07-24 21:16:18Z bruno $"; extern char err_log_lines[NOOF_ERR_LINES][MAX_STR_LEN]; /** * @defgroup restoreGuiDisklist Disklist GUI * Functions for manipulating the disklist GUI. * @ingroup restoreGuiGroup */ /** * @defgroup restoreGuiMountlist Mountlist GUI * Functions for manipulating the mountlist/raidlist GUI. * @ingroup restoreGuiGroup */ /** * @defgroup restoreGuiVarslist RAID Variables GUI * Functions for manipulating the RAID variables GUI. * @ingroup restoreGuiGroup */ /** * @addtogroup restoreGuiGroup * @{ */ /** * Add an entry in @p disklist from the list in @p unallocated_raid_partitions. * @param disklist The disklist to add an entry to. * @param raid_device Unused; make sure it's non-NULL non-"". * @param unallocated_raid_partitions The list of unallocated RAID partitions * that the user may choose from. * @bug raid_device is unused. * @ingroup restoreGuiDisklist */ void add_disklist_entry(struct list_of_disks *disklist, char *raid_device, struct mountlist_itself *unallocated_raid_partitions) { /** buffers ***********************************************************/ char *tmp = NULL; /** newt **************************************************************/ newtComponent myForm; newtComponent bOK; newtComponent bCancel; newtComponent b_res; newtComponent partitionsListbox; newtComponent headerMsg; /** prototypes *********************************************************/ void *keylist[ARBITRARY_MAXIMUM]; void *curr_choice; /** int ****************************************************************/ int i = 0; int idx = 0; int currline = 0; int items = 0; assert(disklist != NULL); assert_string_is_neither_NULL_nor_zerolength(raid_device); assert(unallocated_raid_partitions != NULL); newtPushHelpLine (_ (" Add one of the following unallocated RAID partitions to this RAID device.")); mr_asprintf(&tmp, "%-26s %s", _("Device"), _("Size")); headerMsg = newtLabel(1, 1, tmp); mr_free(tmp); partitionsListbox = newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); redraw_unallocpartnslist(unallocated_raid_partitions, keylist, partitionsListbox); i = 7; bOK = newtCompactButton(i, 9, _(" OK ")); bCancel = newtCompactButton(i += 9, 9, _("Cancel")); newtOpenWindow(22, 6, 36, 10, _("Unallocated RAID partitions")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, headerMsg, partitionsListbox, bOK, bCancel, NULL); b_res = newtRunForm(myForm); if (b_res != bCancel) { curr_choice = newtListboxGetCurrent(partitionsListbox); for (currline = 0; currline < unallocated_raid_partitions->entries && keylist[currline] != curr_choice; currline++); if (currline == unallocated_raid_partitions->entries && unallocated_raid_partitions->entries > 0) { log_it("I don't know what this button does"); } else { idx = find_next_free_index_in_disklist(disklist); items = disklist->entries; strcpy(disklist->el[items].device, unallocated_raid_partitions->el[currline].device); disklist->el[items].index = idx; disklist->entries = ++items; } } newtFormDestroy(myForm); newtPopWindow(); newtPopHelpLine(); } /** * Add an entry to @p mountlist. * @param mountlist The mountlist to add an entry to. * @param raidlist The raidlist that accompanies @p mountlist. * @param listbox The listbox component in the mountlist editor. * @param currline The line selected in @p listbox. * @param keylist The list of keys for @p listbox. * @ingroup restoreGuiMountlist */ void add_mountlist_entry(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, newtComponent listbox, int currline, void *keylist[]) { /** int **************************************************************/ int i = 0; int num_to_add = 0; /** newt *************************************************************/ newtComponent myForm; newtComponent bOK; newtComponent bCancel; newtComponent b_res; newtComponent mountpointComp; newtComponent label0; newtComponent label1; newtComponent label2; newtComponent label3; newtComponent sizeComp; newtComponent deviceComp; newtComponent formatComp; char *drive_to_add = NULL; char *mountpoint_str = NULL; char *size_str = NULL; char *device_str = NULL; char *format_str = NULL; char *mountpoint_here = NULL; char *size_here = NULL; char *device_here = NULL; char *format_here = NULL; assert(mountlist != NULL); assert(raidlist != NULL); assert(listbox != NULL); assert(keylist != NULL); mr_asprintf(&device_str, "/dev/"); mr_asprintf(&mountpoint_str, "/"); #ifdef __FreeBSD__ mr_asprintf(&format_str, "ufs"); #else mr_asprintf(&format_str, "ext2"); #endif newtOpenWindow(20, 5, 48, 10, _("Add entry")); label0 = newtLabel(2, 1, _("Device: ")); label1 = newtLabel(2, 2, _("Mountpoint:")); label2 = newtLabel(2, 3, _("Size (MB): ")); label3 = newtLabel(2, 4, _("Format: ")); deviceComp = newtEntry(14, 1, device_str, 30, (void *) &device_here, 0); mountpointComp = newtEntry(14, 2, mountpoint_str, 30, (void *) &mountpoint_here, 0); formatComp = newtEntry(14, 4, format_str, 15, (void *) &format_here, 0); sizeComp = newtEntry(14, 3, size_str, 10, (void *) &size_here, 0); bOK = newtButton(5, 6, _(" OK ")); bCancel = newtButton(17, 6, _("Cancel")); newtPushHelpLine (_ ("To add an entry to the mountlist, please fill in these fields and then hit 'OK'")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, deviceComp, mountpointComp, sizeComp, formatComp, label0, label1, label2, label3, bOK, bCancel, NULL); for (b_res = NULL; b_res != bOK && b_res != bCancel;) { b_res = newtRunForm(myForm); mr_free(device_str); mr_asprintf(&device_str, device_here); mr_strip_spaces(device_str); mr_free(format_str); mr_asprintf(&format_str, format_here); mr_strip_spaces(format_str); mr_free(mountpoint_str); mr_asprintf(&mountpoint_str, mountpoint_here); mr_strip_spaces(mountpoint_str); mr_free(size_str); mr_asprintf(&size_str, size_here); mr_strip_spaces(size_str); if (b_res == bOK) { if (device_str[strlen(device_str) - 1] == '/') { popup_and_OK(_("You left the device nearly blank!")); b_res = NULL; } if (size_of_specific_device_in_mountlist(mountlist, device_str) >= 0) { popup_and_OK(_ ("Can't add this - you've got one already!")); b_res = NULL; } } } newtFormDestroy(myForm); newtPopHelpLine(); newtPopWindow(); if (b_res == bCancel) { mr_free(device_str); mr_free(format_str); mr_free(mountpoint_str); mr_free(size_str); return; } mr_asprintf(&drive_to_add, device_str); for (i = strlen(drive_to_add); isdigit(drive_to_add[i - 1]); i--); num_to_add = atoi(drive_to_add + i); mr_free(drive_to_add); currline = mountlist->entries; strcpy(mountlist->el[currline].device, device_str); strcpy(mountlist->el[currline].mountpoint, mountpoint_str); mr_free(mountpoint_str); strcpy(mountlist->el[currline].format, format_str); mr_free(format_str); mountlist->el[currline].size = atol(size_str) * 1024; mr_free(size_str); mountlist->entries++; if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) { initiate_new_raidlist_entry(raidlist, mountlist, currline, device_str); } mr_free(device_str); redraw_mountlist(mountlist, keylist, listbox); } #ifndef __FreeBSD__ /** * Add an entry to the additional RAID variables section of @p raidrec. * @param raidrec The RAID device record containing the RAID variables list to add to. * @ingroup restoreGuiVarslist */ void add_varslist_entry(struct raid_device_record *raidrec) { /** buffers ***********************************************************/ char *sz_out = NULL; /** int ****************************************************************/ int items = 0; int i = 0; assert(raidrec != NULL); malloc_string(sz_out); if (popup_and_get_string ("Add variable", _("Enter the name of the variable to add"), sz_out, MAX_STR_LEN)) { mr_strip_spaces(sz_out); items = raidrec->additional_vars.entries; for (i = 0; i < items && strcmp(raidrec->additional_vars.el[i].label, sz_out); i++); if (i < items) { popup_and_OK (_ ("No need to add that variable. It is already listed here.")); } else { strcpy(raidrec->additional_vars.el[items].label, sz_out); edit_varslist_entry(raidrec, items); raidrec->additional_vars.entries = ++items; } } mr_free(sz_out); } #endif /** * Calculate the size of @p raid_device. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist that goes with @p mountlist. * @param raid_device The device to calculate the size of. * @return The size of the RAID device in Kilobytes. * @ingroup restoreUtilityGroup */ long calculate_raid_device_size(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, char *raid_device) { #ifdef __FreeBSD__ /** FreeBSD-specific version of calculate_raid_device_size() **/ /** structures ********************************************************/ struct vinum_volume *raidrec = NULL; int i = 0, j = 0; int noof_partitions = 0; long total_size = 0L; long plex_size = 0L; long smallest_partition = 999999999; long smallest_plex = 999999999; long sp = 0L; char *devname = NULL; for (i = 0; i < raidlist->entries && strcmp(raidlist->el[i].volname, basename(raid_device)); i++); if (i == raidlist->entries) { log_it("Cannot calc size of raid device %s - cannot find it in raidlist", raid_device); return (0); // Isn't this more sensible than 999999999? If the raid dev !exists, // then it has no size, right? } raidrec = &raidlist->el[i]; total_size = 0; if (raidrec->plexes == 0) return 0; for (j = 0; j < raidrec->plexes; j++) { plex_size = 0; int k = 0, l = 0; for (k = 0; k < raidrec->plex[j].subdisks; ++k) { mr_asprintf(&devname, raidrec->plex[j].sd[k].which_device); for (l = 0; l < raidlist->disks.entries; ++l) { if (!strcmp(devname, raidlist->disks.el[l].name)) { switch (raidrec->plex[j].raidlevel) { case -1: plex_size += size_of_specific_device_in_mountlist(mountlist, raidlist-> disks. el[l]. device); break; case 0: case 5: if (size_of_specific_device_in_mountlist(mountlist, raidlist-> disks. el[l]. device) < smallest_partition) { smallest_partition = size_of_specific_device_in_mountlist (mountlist, raidlist->disks.el[l].device); } break; } } } mr_free(devname); } if (!is_this_raid_personality_registered (raidrec->plex[j].raidlevel)) { log_it ("%s has a really weird RAID level - couldn't calc size :(", raid_device); return (999999999); } if (raidrec->plex[j].raidlevel != -1) { plex_size = smallest_partition * (raidrec->plex[j].subdisks - (raidrec->plex[j]. raidlevel == 5 ? 1 : 0)); } if (plex_size < smallest_plex) smallest_plex = plex_size; smallest_partition = 999999999; } log_it("I have calculated %s's real size to be %ld", raid_device, (long) smallest_plex); return (smallest_plex); #else /** Linux-specific version of calculate_raid_device_size() **/ /** structures ********************************************************/ struct raid_device_record *raidrec = NULL; /** int ***************************************************************/ int i = 0; int noof_partitions = 0; /** long **************************************************************/ long total_size = 0; long smallest_partition = 999999999; long sp = 0; assert(mountlist != NULL); assert(raidlist != NULL); assert_string_is_neither_NULL_nor_zerolength(raid_device); for (i = 0; i < raidlist->entries && strcmp(raidlist->el[i].raid_device, raid_device); i++); if (i == raidlist->entries) { log_it("Cannot calc size of raid device %s - cannot find it in raidlist", raid_device); return (999999999); } raidrec = &raidlist->el[i]; noof_partitions = raidrec->data_disks.entries; if (raidrec->raid_level == -1 || raidrec->raid_level == 0) { for (total_size = 0, i = 0; i < noof_partitions; i++) { total_size += size_of_specific_device_in_mountlist(mountlist, raidrec->data_disks. el[i].device); } } else { for (i = 0; i < noof_partitions; i++) { sp = size_of_specific_device_in_mountlist(mountlist, raidrec->data_disks. el[i].device); if (smallest_partition > sp) { smallest_partition = sp; } } total_size = smallest_partition * (noof_partitions - 1); } log_it("I have calculated %s's real size to be %ld", raid_device, (long) total_size); return (total_size); #endif } /** * Choose the RAID level for the RAID device record in @p raidrec. * @param raidrec The RAID device record to set the RAID level of. * @ingroup restoreGuiMountlist */ void choose_raid_level(struct OSSWAP (raid_device_record, vinum_plex) * raidrec) { #ifdef __FreeBSD__ /** int ***************************************************************/ int res = 0; int out = 0; /** buffers ***********************************************************/ char *tmp = NULL; char *prompt = NULL; char *sz = NULL; malloc_string(tmp); mr_asprintf(&prompt, _ ("Please enter the RAID level you want. (concat, striped, raid5)")); if (raidrec->raidlevel == -1) { strcpy(tmp, "concat"); } else if (raidrec->raidlevel == 0) { strcpy(tmp, "striped"); } else { strcpy(tmp, "raid%i", raidrec->raidlevel); } for (out = 999; out == 999;) { res = popup_and_get_string(_("Specify RAID level"), prompt, tmp, 10); if (!res) { mr_free(tmp); mr_free(prompt); return; } mr_strip_spaces(tmp); /* BERLIOS: Useless ??? */ if (tmp[0] == '[' && tmp[strlen(tmp) - 1] == ']') { mr_asprintf(&sz, tmp); strncpy(tmp, sz + 1, strlen(sz) - 2); tmp[strlen(sz) - 2] = '\0'; mr_free(sz); } if (!strcmp(tmp, "concat")) { out = -1; } else if (!strcmp(tmp, "striped")) { out = 0; } else if (!strcmp(tmp, "raid5")) { out = 5; } else { continue; } log_it(tmp); if (is_this_raid_personality_registered(out)) { log_it ("Groovy. You've picked a RAID personality which is registered."); } else { if (ask_me_yes_or_no (_("You have chosen a RAID personality which is not registered with the kernel. Make another selection?"))) { out = 999; } } } mr_free(prompt); mr_free(tmp); raidrec->raidlevel = out; #else /** buffers ***********************************************************/ char *tmp = NULL; char *personalities = NULL; char *prompt = NULL; char *sz = NULL; int out = 0, res = 0; malloc_string(tmp); assert(raidrec != NULL); mr_asprintf(&tmp,"grep Pers %s > /tmp/raid-personalities.txt 2> /dev/null", MDSTAT_FILE); system(tmp); mr_free(tmp); mr_asprintf(&personalities, last_line_of_file("/tmp/raid-personalities.txt")); mr_asprintf(&prompt, _("Please enter the RAID level you want. %s"), personalities); mr_free(personalities); if (raidrec->raid_level == -1) { strcpy(tmp, "linear"); } else { sprintf(tmp, "%d", raidrec->raid_level); } for (out = 999; out != -1 && out != 0 && out != 1 && out != 4 && out != 5 && out != 10;) { res = popup_and_get_string(_("Specify RAID level"), prompt, tmp, 10); if (!res) { return; } mr_strip_spaces(tmp); /* BERLIOS: Useless ??? */ if (tmp[0] == '[' && tmp[strlen(tmp) - 1] == ']') { mr_asprintf(&sz, tmp); strncpy(tmp, sz + 1, strlen(sz) - 2); tmp[strlen(sz) - 2] = '\0'; mr_free(sz); } if (!strcmp(tmp, "linear")) { out = -1; } else if (!strncmp(tmp, "raid", 4)) { out = atoi(tmp + 4); } else { out = atoi(tmp); } log_it(tmp); if (is_this_raid_personality_registered(out)) { log_it ("Groovy. You've picked a RAID personality which is registered."); } else { if (ask_me_yes_or_no (_ ("You have chosen a RAID personality which is not registered with the kernel. Make another selection?"))) { out = 999; } } } mr_free(tmp); mr_free(prompt); raidrec->raid_level = out; #endif } /** * Delete the partitions in @p disklist from @p mountlist because they * were part of a deleted RAID device. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist that goes with @p mounntlist. * @param disklist The list of disks to remove from @p mountlist. * @ingroup restoreGuiDisklist */ void del_partns_listed_in_disklist(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, struct list_of_disks *disklist) { /** int ***************************************************************/ int i = 0; int pos = 0; assert(mountlist != NULL); assert(raidlist != NULL); assert(disklist != NULL); for (i = 0; i < disklist->entries; i++) { for (pos = 0; pos < mountlist->entries && strcmp(mountlist->el[pos].device, disklist->el[i].device); pos++); if (pos < mountlist->entries) { log_it("Deleting partition %s cos it was part of a now-defunct RAID", mountlist->el[pos].device); memcpy((void *) &mountlist->el[pos], (void *) &mountlist->el[mountlist->entries - 1], sizeof(struct mountlist_line)); mountlist->entries--; } } } /** * Delete entry number @p currline from @p disklist. * @param disklist The disklist to remove the entry from. * @param raid_device The RAID device containing the partition we're removing. * Used only in the popup "are you sure?" box. * @param currline The line number (starting from 0) of the item to delete. * @ingroup restoreGuiDisklist */ void delete_disklist_entry(struct list_of_disks *disklist, char *raid_device, int currline) { /** int ***************************************************************/ int pos = 0; /** buffers ***********************************************************/ char *tmp = NULL; assert(disklist != NULL); assert_string_is_neither_NULL_nor_zerolength(raid_device); mr_asprintf(&tmp, _("Delete %s from RAID device %s - are you sure?"), disklist->el[currline].device, raid_device); if (!ask_me_yes_or_no(tmp)) { mr_free(tmp); return; } mr_free(tmp); for (pos = currline; pos < disklist->entries - 1; pos++) { /* memcpy((void*)&disklist->el[pos], (void*)&disklist->el[pos+1], sizeof(struct s_disk)); */ strcpy(disklist->el[pos].device, disklist->el[pos + 1].device); } disklist->entries--; } /** * Delete entry number @p currline from @p mountlist. * @param mountlist The mountlist to delete the entry from. * @param raidlist The raidlist that goes with @p mountlist. * @param listbox The Newt listbox component in the mountlist editor. * @param currline The line number (starting from 0) of the item to delete. * @param keylist The list of keys for @p listbox. * @ingroup restoreGuiMountlist */ void delete_mountlist_entry(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, newtComponent listbox, int currline, void *keylist[]) { /** int ***************************************************************/ int pos = 0; /** buffers ***********************************************************/ char *tmp = NULL; char *device = NULL; assert(mountlist != NULL); assert(raidlist != NULL); assert(listbox != NULL); assert(keylist != NULL); pos = which_raid_device_is_using_this_partition(raidlist, mountlist->el[currline]. device); if (pos >= 0) { mr_asprintf(&tmp, _("Cannot delete %s: it is in use by RAID device %s"), mountlist->el[currline].device, raidlist->el[pos].OSSWAP(raid_device, volname)); popup_and_OK(tmp); mr_free(tmp); return; } mr_asprintf(&tmp, _("Delete %s - are you sure?"), mountlist->el[currline].device); if (!ask_me_yes_or_no(tmp)) { mr_free(tmp); return; } mr_free(tmp); if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) { mr_asprintf(&device, mountlist->el[currline].device); delete_raidlist_entry(mountlist, raidlist, device); for (currline = 0; currline < mountlist->entries && strcmp(mountlist->el[currline].device, device); currline++); if (currline == mountlist->entries) { log_it("Dev is gone. I can't delete it. Ho-hum"); mr_free(device); return; } mr_free(device); } memcpy((void *) &mountlist->el[currline], (void *) &mountlist->el[mountlist->entries - 1], sizeof(struct mountlist_line)); mountlist->entries--; redraw_mountlist(mountlist, keylist, listbox); } /** * Delete @p device from @p raidlist. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist containing the RAID device to delete. * @param device The device (e.g. /dev/md0) to delete. * @ingroup restoreGuiMountlist */ void delete_raidlist_entry(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, char *device) { /** int ***************************************************************/ int i = 0; int items = 0; /** bool **************************************************************/ bool delete_partitions_too; /** buffers ***********************************************************/ char *tmp = NULL; assert(mountlist != NULL); assert(raidlist != NULL); assert_string_is_neither_NULL_nor_zerolength(device); i = find_raid_device_in_raidlist(raidlist, device); if (i < 0) { return; } mr_asprintf(&tmp, _("Do you want me to delete %s's partitions, too?"), device); delete_partitions_too = ask_me_yes_or_no(tmp); if (delete_partitions_too) { #ifdef __FreeBSD__ // static so it's zeroed static struct list_of_disks d; int x, y, z; for (x = 0; x < raidlist->el[i].plexes; ++x) { for (y = 0; y < raidlist->el[i].plex[x].subdisks; ++y) { for (z = 0; z < raidlist->disks.entries; ++z) { if (!strcmp(raidlist->el[i].plex[x].sd[y].which_device, raidlist->disks.el[z].name)) { strcpy(d.el[d.entries].name, raidlist->disks.el[z].name); strcpy(d.el[d.entries++].device, raidlist->disks.el[z].device); } } } } del_partns_listed_in_disklist(mountlist, raidlist, &d); #else del_partns_listed_in_disklist(mountlist, raidlist, &raidlist->el[i].data_disks); del_partns_listed_in_disklist(mountlist, raidlist, &raidlist->el[i].spare_disks); del_partns_listed_in_disklist(mountlist, raidlist, &raidlist->el[i].parity_disks); del_partns_listed_in_disklist(mountlist, raidlist, &raidlist->el[i].failed_disks); #endif } items = raidlist->entries; if (items == 1) { items = 0; } else { log_it(tmp); memcpy((void *) &raidlist->el[i], (void *) &raidlist->el[items - 1], sizeof(struct OSSWAP (raid_device_record, vinum_volume))); items--; } mr_free(tmp); raidlist->entries = items; } #ifndef __FreeBSD__ /** * Delete entry number @p lino in the additional RAID variables section of @p raidrec. * @param raidrec The RAID device record containing the RAID variable to delete. * @param lino The line number (starting from 0) of the variable to delete. * @ingroup restoreGuiVarslist */ void delete_varslist_entry(struct raid_device_record *raidrec, int lino) { /** buffers ************************************************************/ char *tmp = NULL; /** structures *********************************************************/ struct additional_raid_variables *av = NULL; assert(raidrec != NULL); av = &raidrec->additional_vars; mr_asprintf(&tmp, _("Delete %s - are you sure?"), av->el[lino].label); if (ask_me_yes_or_no(tmp)) { if (!strcmp(av->el[lino].label, "persistent-superblock") || !strcmp(av->el[lino].label, "chunk-size")) { mr_free(tmp); mr_asprintf(&tmp, _("%s must not be deleted. It would be bad."), av->el[lino].label); popup_and_OK(tmp); } else { memcpy((void *) &av->el[lino], (void *) &av->el[av->entries--], sizeof(struct raid_var_line)); } } mr_free(tmp); } #endif /** * Redraw the filelist display. * @param filelist The filelist structure to edit. * @param keylist The list of keys for @p listbox. * @param listbox The Newt listbox component containing some of the filelist entries. * @return The number of lines currently being displayed. * @ingroup restoreGuiGroup */ int redraw_filelist(struct s_node *filelist, void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox) { /** int ***************************************************************/ static int lines_in_flist_window = 0; static int depth = 0; /** long **************************************************************/ long i = 0L; /** structures *******************************************************/ struct s_node *node = NULL; /** buffers **********************************************************/ static char current_filename[MAX_STR_LEN]; char *tmp = NULL; /** bool *************************************************************/ bool dummybool = FALSE; static bool warned_already = FALSE; assert(filelist != NULL); assert(keylist != NULL); assert(listbox != NULL); if (depth == 0) { lines_in_flist_window = 0; warned_already = FALSE; for (i = 0; i < ARBITRARY_MAXIMUM; i++) { g_strings_of_flist_window[i][0] = '\0'; g_is_path_selected[i] = FALSE; } } for (node = filelist; node != NULL; node = node->right) { current_filename[depth] = node->ch; if (node->down) { depth++; i = redraw_filelist(node->down, keylist, listbox); depth--; } if (node->ch == '\0' && node->expanded) { if (lines_in_flist_window == ARBITRARY_MAXIMUM) { if (!warned_already) { warned_already = TRUE; mr_asprintf(&tmp, _ ("Too many lines. Displaying first %d entries only. Close a directory to see more."), ARBITRARY_MAXIMUM); popup_and_OK(tmp); mr_free(tmp); } } else { strcpy(g_strings_of_flist_window[lines_in_flist_window], current_filename); g_is_path_selected[lines_in_flist_window] = node->selected; lines_in_flist_window++; } } } if (depth == 0) { if (lines_in_flist_window > ARBITRARY_MAXIMUM) { lines_in_flist_window = ARBITRARY_MAXIMUM; } /* do an elementary sort */ for (i = 1; i < lines_in_flist_window; i++) { if (strcmp (g_strings_of_flist_window[i], g_strings_of_flist_window[i - 1]) < 0) { mr_asprintf(&tmp, g_strings_of_flist_window[i]); strcpy(g_strings_of_flist_window[i], g_strings_of_flist_window[i - 1]); strcpy(g_strings_of_flist_window[i - 1], tmp); mr_free(tmp); dummybool = g_is_path_selected[i]; g_is_path_selected[i] = g_is_path_selected[i - 1]; g_is_path_selected[i - 1] = dummybool; i = 0; } } /* write list to screen */ newtListboxClear(listbox); for (i = 0; i < lines_in_flist_window; i++) { mr_asprintf(&tmp, "%c%c %-80s", (g_is_path_selected[i] ? '*' : ' '), (g_is_path_expanded[i] ? '+' : '-'), strip_path(g_strings_of_flist_window[i])); if (strlen(tmp) > 71) { tmp[70] = '\0'; } keylist[i] = (void *) i; newtListboxAppendEntry(listbox, tmp, keylist[i]); mr_free(tmp); } return (lines_in_flist_window); } else { return (0); } } /** * Strip a path to the bare minimum (^ pointing to the directory above, plus filename). * @param tmp The path to strip. * @return The stripped path. * @author Conor Daly * @ingroup restoreUtilityGroup */ char *strip_path(char *tmp) { int i = 0, j = 0, slashcount = 0; int slashloc = 0, lastslashloc = 0; while (tmp[i] != '\0') { /* Count the slashes in tmp 1 slash per dir */ if (tmp[i] == '/') { slashcount++; lastslashloc = slashloc; slashloc = i; if (tmp[i + 1] == '\0') { /* if this slash is last char, back off */ slashcount--; slashloc = lastslashloc; } } i++; } if (slashcount > 0) slashcount--; /* Keep one slash 'cos Hugh does... */ /* BERLIOS: tmpnopath and prev not defined !! How can this compile ?? */ for (i = 0; i < slashcount; i++) { /* Replace each dir with a space char */ tmpnopath[i] = ' '; } i = slashloc; j = slashcount; while (tmp[i] != '\0') { /* Now add what's left of tmp */ if ((tmpprevpath[j] == ' ' || tmpprevpath[j] == '^') && tmp[i] == '/' && tmpnopath[j - 1] != '^' && j != 0) { /* Add a pointer upwards if this is not in the same dir as line above */ tmpnopath[j - 1] = '^'; } else { tmpnopath[j++] = tmp[i++]; } } tmpnopath[j] = '\0'; strcpy(tmpprevpath, tmpnopath); /* Make a copy for next iteration */ return (tmpnopath); } /** * Allow the user to edit the filelist and choose which files to restore. * @param filelist The node structure containing the filelist. * @return 0 if the user pressed OK, 1 if they pressed Cancel. */ int edit_filelist(struct s_node *filelist) { /** newt **************************************************************/ newtComponent myForm; newtComponent bLess = NULL; newtComponent bMore = NULL; newtComponent bToggle = NULL; newtComponent bOK = NULL; newtComponent bCancel = NULL; newtComponent b_res = NULL; newtComponent filelistListbox = NULL; newtComponent bRegex = NULL; /** int ***************************************************************/ int finished = FALSE; int lines_in_flist_window = 0; int indexno = 0; int j = 0; /** ???? **************************************************************/ void *curr_choice = NULL; void *keylist[ARBITRARY_MAXIMUM]; /** bool **************************************************************/ bool dummybool = FALSE; assert(filelist != NULL); log_to_screen(_("Editing filelist")); newtPushHelpLine (_ (" Please edit the filelist to your satisfaction, then click OK or Cancel.")); j = 4; bLess = newtCompactButton(j, 17, _(" Less ")); bMore = newtCompactButton(j += 12, 17, _(" More ")); bToggle = newtCompactButton(j += 12, 17, _("Toggle")); bRegex = newtCompactButton(j += 12, 17, _("RegEx")); bCancel = newtCompactButton(j += 12, 17, _("Cancel")); bOK = newtCompactButton(j += 12, 17, _(" OK ")); filelistListbox = newtListbox(2, 1, 15, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); toggle_all_root_dirs_on(filelist); lines_in_flist_window = redraw_filelist(filelist, keylist, filelistListbox); newtOpenWindow(1, 3, 77, 18, _("Editing filelist")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, filelistListbox, bLess, bMore, bToggle, bRegex, bCancel, bOK, NULL); while (!finished) { b_res = newtRunForm(myForm); if (b_res == bOK) { finished = ask_me_yes_or_no (_("Are you happy with your file selection?")); } else if (b_res == bCancel) { finished = TRUE; } else if (b_res == bRegex) { popup_and_OK(_("I haven't implemented this yet...")); } else { curr_choice = newtListboxGetCurrent(filelistListbox); for (indexno = 0; indexno < lines_in_flist_window && keylist[indexno] != curr_choice; indexno++); if (indexno == lines_in_flist_window) { log_it ("I don't know what this button does; assuming I am to toggle 1st entry"); indexno = 0; } log_it("You selected '%s'", g_strings_of_flist_window[indexno]); if (b_res == bMore) { g_is_path_expanded[indexno] = TRUE; toggle_path_expandability(filelist, g_strings_of_flist_window [indexno], TRUE); lines_in_flist_window = redraw_filelist(filelist, keylist, filelistListbox); newtListboxSetCurrentByKey(filelistListbox, curr_choice); } else if (b_res == bLess) { g_is_path_expanded[indexno] = FALSE; toggle_path_expandability(filelist, g_strings_of_flist_window [indexno], FALSE); lines_in_flist_window = redraw_filelist(filelist, keylist, filelistListbox); newtListboxSetCurrentByKey(filelistListbox, curr_choice); } else { if (!strcmp(g_strings_of_flist_window[indexno], "/")) { dummybool = !g_is_path_selected[indexno]; for (j = 1; j < lines_in_flist_window; j++) { toggle_path_selection(filelist, g_strings_of_flist_window[j], dummybool); } } else { toggle_path_selection(filelist, g_strings_of_flist_window [indexno], !g_is_path_selected[indexno]); lines_in_flist_window = redraw_filelist(filelist, keylist, filelistListbox); } newtListboxSetCurrentByKey(filelistListbox, curr_choice); } for (indexno = 0; indexno < lines_in_flist_window && keylist[indexno] != curr_choice; indexno++); if (indexno == lines_in_flist_window) { log_it ("Layout of table has changed. Y pointer is reverting to zero."); indexno = 0; } } } newtFormDestroy(myForm); newtPopWindow(); newtPopHelpLine(); if (b_res == bOK) { return (0); } else { return (1); } } /** * Edit an entry in @p mountlist. * @param mountlist The mountlist containing information about the user's partitions. * @param raidlist The raidlist to accompany @p mountlist. * @param listbox The Newt listbox component in the mountlist editor. * @param currline The selected line (starting from 0) in @p listbox. * @param keylist The list of keys for @p listbox. * @ingroup restoreGuiMountlist */ void edit_mountlist_entry(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, newtComponent listbox, int currline, void *keylist[]) { /** structures ********************************************************/ static struct raidlist_itself bkp_raidlist; /** newt **************************************************************/ newtComponent myForm; newtComponent bOK; newtComponent bCancel; newtComponent b_res; newtComponent mountpointComp; newtComponent label0; newtComponent label1; newtComponent label2; newtComponent label3; newtComponent sizeComp; newtComponent deviceComp; newtComponent formatComp; newtComponent b_raid = NULL; char *device_str = NULL; char *mountpoint_str = NULL; char *size_str = NULL; char *format_str = NULL; char *tmp = NULL; char *device_used_to_be = NULL; char *mountpt_used_to_be = NULL; char *device_here = NULL; char *mountpoint_here = NULL; char *size_here = NULL; char *format_here = NULL; int j = 0; assert(mountlist != NULL); assert(raidlist != NULL); assert(listbox != NULL); assert(keylist != NULL); memcpy((void *) &bkp_raidlist, (void *) raidlist, sizeof(struct raidlist_itself)); mr_asprintf(&device_str, mountlist->el[currline].device); mr_asprintf(&device_used_to_be, mountlist->el[currline].device); mr_asprintf(&mountpoint_str, mountlist->el[currline].mountpoint); mr_asprintf(&mountpt_used_to_be, mountlist->el[currline].mountpoint); mr_asprintf(&format_str, mountlist->el[currline].format); mr_asprintf(&size_str, "%lld", mountlist->el[currline].size / 1024); newtOpenWindow(20, 5, 48, 10, _("Edit entry")); label0 = newtLabel(2, 1, _("Device:")); label1 = newtLabel(2, 2, _("Mountpoint:")); label2 = newtLabel(2, 3, _("Size (MB): ")); label3 = newtLabel(2, 4, _("Format: ")); deviceComp = newtEntry(14, 1, device_str, 30, (void *) &device_here, 0); mr_free(device_str); mountpointComp = newtEntry(14, 2, mountpoint_str, 30, (void *) &mountpoint_here, 0); mr_free(mountpoint_str); formatComp = newtEntry(14, 4, format_str, 15, (void *) &format_here, 0); mr_free(format_str); if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB) || !strcmp(mountlist->el[currline].mountpoint, "image")) { sizeComp = newtLabel(14, 3, size_str); } else { sizeComp = newtEntry(14, 3, size_str, 10, (void *) &size_here, 0); } mr_free(size_str); bOK = newtButton(2, 6, _(" OK ")); bCancel = newtButton(14, 6, _("Cancel")); if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) { b_raid = newtButton(26, 6, "RAID.."); } newtPushHelpLine (_ (" Edit this partition's mountpoint, size and format; then click 'OK'.")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, deviceComp, mountpointComp, sizeComp, formatComp, label0, label1, label2, label3, bOK, bCancel, b_raid, NULL); for (b_res = NULL; b_res != bOK && b_res != bCancel;) { b_res = newtRunForm(myForm); mr_free(device_str); mr_asprintf(&device_str, device_here); mr_strip_spaces(device_str); mr_free(mountpoint_str); mr_asprintf(&mountpoint_str, mountpoint_here); mr_strip_spaces(mountpoint_str); mr_free(format_str); mr_asprintf(&format_str, format_here); mr_strip_spaces(format_str); if (b_res == bOK && strstr(device_str, RAID_DEVICE_STUB) && strstr(device_used_to_be, RAID_DEVICE_STUB) && strcmp(device_str, device_used_to_be)) { popup_and_OK(_("You can't change /dev/mdX to /dev/mdY.")); b_res = NULL; continue; } else if (b_res == bOK && !strcmp(mountpoint_str, "image") && strcmp(mountpt_used_to_be, "image")) { popup_and_OK(_ ("You can't change a regular device to an image.")); b_res = NULL; continue; } mr_free(mountpt_used_to_be); mr_free(size_str); if (!strstr(mountlist->el[currline].device, RAID_DEVICE_STUB) && strcmp(mountlist->el[currline].mountpoint, "image")) { mr_asprintf(&size_str, size_here); mr_strip_spaces(size_str); } else { mr_asprintf(&size_str, "%ld", calculate_raid_device_size(mountlist, raidlist, mountlist->el[currline]. device) / 1024); newtLabelSetText(sizeComp, size_str); } /* do not let user click RAID button if user has changed device_str */ if (b_res == b_raid) { if (strcmp(device_str, mountlist->el[currline].device)) { /* can't change mountlist's entry from /dex/mdX to /dev/mdY: it would ugly when you try to map the changes over to the raidtab list, trust me */ popup_and_OK (_ ("You cannot edit the RAID settings until you have OK'd your change to the device node.")); } else { j = find_raid_device_in_raidlist(raidlist, mountlist->el[currline]. device); if (j < 0) { mr_asprintf(&tmp, _ ("/etc/raidtab does not have an entry for %s; please delete it and add it again"), mountlist->el[currline].device); popup_and_OK(tmp); mr_free(tmp); } else { log_it(_("edit_raidlist_entry - calling")); edit_raidlist_entry(mountlist, raidlist, &raidlist->el[j], currline); } } } } newtFormDestroy(myForm); newtPopHelpLine(); newtPopWindow(); if (b_res == bCancel) { memcpy((void *) raidlist, (void *) &bkp_raidlist, sizeof(struct raidlist_itself)); return; } strcpy(mountlist->el[currline].device, device_str); strcpy(mountlist->el[currline].mountpoint, mountpoint_str); mr_free(mountpoint_str); strcpy(mountlist->el[currline].format, format_str); mr_free(format_str); if (strcmp(mountlist->el[currline].mountpoint, "image")) { if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB)) { mountlist->el[currline].size = calculate_raid_device_size(mountlist, raidlist, mountlist->el[currline].device); } else { mountlist->el[currline].size = atol(size_str) * 1024; } } mr_free(size_str); newtListboxSetEntry(listbox, (long) keylist[currline], mountlist_entry_to_string(mountlist, currline)); /* if new /dev/md RAID device then do funky stuff */ if (strstr(mountlist->el[currline].device, RAID_DEVICE_STUB) && !strstr(device_used_to_be, RAID_DEVICE_STUB)) { initiate_new_raidlist_entry(raidlist, mountlist, currline, device_str); } /* if moving from RAID to non-RAID then do funky stuff */ else if (strstr(device_used_to_be, RAID_DEVICE_STUB) && !strstr(device_str, RAID_DEVICE_STUB)) { delete_raidlist_entry(mountlist, raidlist, device_str); } /* if moving a non-RAID to another non-RAID then re-jig any RAID disks, if necessary */ else if (!strstr(device_used_to_be, RAID_DEVICE_STUB) && !strstr(device_str, RAID_DEVICE_STUB)) { rejig_partition_name_in_raidlist_if_necessary(raidlist, device_used_to_be, device_str); } /* else, moving a RAID to another RAID; bad idea, or so I thought */ #ifndef __FreeBSD__ /* It works fine under FBSD. */ else if (strcmp(device_used_to_be, device_str)) { popup_and_OK (_ ("You are renaming a RAID device as another RAID device. I don't like it but I'll allow it.")); } #endif redraw_mountlist(mountlist, keylist, listbox); mr_free(device_str); mr_free(device_used_to_be); } #if __FreeBSD__ /** * Add a subdisk to @p raidrec. * @param raidlist The raidlist containing information about RAID partitions. * @param raidrec The RAID device record to add the subdisk to. * @param temp The device name of the RAID disk to add it to. * @author Joshua Oreman * @ingroup restoreGuiMountlist */ void add_raid_subdisk(struct raidlist_itself *raidlist, struct vinum_plex *raidrec, char *temp) { int i = 0; bool found = FALSE; for (i = 0; i < raidlist->disks.entries; ++i) { if (!strcmp(raidlist->disks.el[i].device, temp)) { strcpy(raidrec->sd[raidrec->subdisks].which_device, raidlist->disks.el[i].name); found = TRUE; } } if (!found) { sprintf(raidlist->disks.el[raidlist->disks.entries].name, "drive%i", raidlist->disks.entries); sprintf(raidrec->sd[raidrec->subdisks].which_device, "drive%i", raidlist->disks.entries); strcpy(raidlist->disks.el[raidlist->disks.entries++].device, temp); } raidrec->subdisks++; } /** * Determine the /dev entry for @p vinum_name. * @param raidlist The raidlist containing information about RAID devices. * @param vinum_name The name of the Vinum drive to map to a /dev entry. * @return The /dev entry, or NULL if none was found. * @note The returned string points to static storage that will be overwritten with each call. * @author Joshua Oreman * @ingroup restoreUtilityGroup */ char *find_dev_entry_for_raid_device_name(struct raidlist_itself *raidlist, char *vinum_name) { int i; for (i = 0; i < raidlist->disks.entries; ++i) { if (!strcmp(raidlist->disks.el[i].name, vinum_name)) { return raidlist->disks.el[i].device; } } return NULL; } void edit_raidlist_plex(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, struct vinum_plex *raidrec, int currline, int currline2); #endif /** * Edit the entry for @p raidrec in @p raidlist. * @param mountlist The mountlist to get some information from. * @param raidlist The raidlist containing information about RAID devices. * @param raidrec The RAID device record for this partition. * @param currline The line number (starting from 0) in the mountlist of the RAID device. * @ingroup restoreGuiMountlist */ void edit_raidlist_entry(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, struct OSSWAP (raid_device_record, vinum_volume) * raidrec, int currline) { #ifdef __FreeBSD__ /** structures ********************************************************/ struct vinum_volume bkp_raidrec; /** buffers ***********************************************************/ char *title_of_editraidForm_window = NULL; /** newt **************************************************************/ newtComponent editraidForm; newtComponent bOK; newtComponent bCancel; newtComponent bEdit; newtComponent bAdd; newtComponent bDelete; newtComponent b_res; newtComponent plexesListbox; newtComponent plexesHeader; void *keylist[10]; void *curr_choice = NULL; int currline2 = 0; char *pname = NULL; char *raidlevel = NULL; char *chunksize = NULL; char *entry = NULL; char *msg = NULL; int i = 0; char *headerstr = NULL; log_it(_("Started edit_raidlist_entry")); memcpy((void *) &bkp_raidrec, (void *) raidrec, sizeof(struct vinum_volume)); mr_asprintf(&title_of_editraidForm_window, _("Plexes on %s"), raidrec->volname); newtPushHelpLine(_(" Please select a plex to edit")); newtOpenWindow(13, 5, 54, 15, title_of_editraidForm_window); mr_free(title_of_editraidForm_window); for (;;) { mr_asprintf(&headerstr, "%-14s %-8s %11s %8s", _("Plex"), _("Level",) _("Stripe Size"), _("Subdisks")); bOK = newtCompactButton(2, 13, _(" OK ")); bCancel = newtCompactButton(12, 13, _("Cancel")); bAdd = newtCompactButton(22, 13, _(" Add ")); bEdit = newtCompactButton(32, 13, _(" Edit ")); bDelete = newtCompactButton(42, 13, _("Delete")); plexesListbox = newtListbox(2, 3, 9, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); plexesHeader = newtLabel(2, 2, headerstr); mr_free(headerstr); editraidForm = newtForm(NULL, NULL, 0); newtListboxClear(plexesListbox); for (i = 0; i < 10; ++i) { keylist[i] = (void *) i; if (i < raidrec->plexes) { switch (raidrec->plex[i].raidlevel) { case -1: mr_asprintf(&raidlevel, "concat"); break; case 0: mr_asprintf(&raidlevel, "striped"); break; case 5: mr_asprintf(&raidlevel, "raid5"); break; default: mr_asprintf(&raidlevel, "raid%i", raidrec->plex[i].raidlevel); break; } if (raidrec->plex[i].raidlevel == -1) { mr_asprintf(&chunksize, "N/A"); } else { mr_asprintf(&chunksize, "%dk", raidrec->plex[i].stripesize); } mr_asprintf(&pname, "%s.p%i", raidrec->volname, i); mr_asprintf(&entry, "%-14s %-8s %11s %8d", pname, raidlevel, chunksize, raidrec->plex[i].subdisks); mr_free(pname); mr_free(chunksize); mr_free(raidlevel); newtListboxAppendEntry(plexesListbox, entry, keylist[i]); /* BERLIOS : hope it's not necessary anymore */ mr_free(entry); } } newtFormAddComponents(editraidForm, bOK, bCancel, bAdd, bEdit, bDelete, plexesListbox, plexesHeader, NULL); b_res = newtRunForm(editraidForm); if (b_res == bOK || b_res == bCancel) { break; } curr_choice = newtListboxGetCurrent(plexesListbox); for (currline2 = 0; currline2 < raidrec->plexes; ++currline2) { if (currline2 > 9) break; if (keylist[currline2] == curr_choice) break; } if (b_res == bDelete) { mr_asprintf(&msg, _("Are you sure you want to delete %s.p%i?"), raidrec->volname, currline2); if (ask_me_yes_or_no(msg)) { log_it(_("Deleting RAID plex")); memcpy((void *) &raidrec->plex[currline2], (void *) &raidrec->plex[raidrec->plexes - 1], sizeof(struct vinum_plex)); raidrec->plexes--; } mr_free(msg); continue; } if (b_res == bAdd) { raidrec->plex[raidrec->plexes].raidlevel = 0; raidrec->plex[raidrec->plexes].stripesize = 279; raidrec->plex[raidrec->plexes].subdisks = 0; currline2 = raidrec->plexes++; } edit_raidlist_plex(mountlist, raidlist, &raidrec->plex[currline2], currline, currline2); newtFormDestroy(editraidForm); } if (b_res == bCancel) { memcpy((void *) raidrec, (void *) &bkp_raidrec, sizeof(struct vinum_volume)); } newtPopHelpLine(); newtPopWindow(); mountlist->el[currline].size = calculate_raid_device_size(mountlist, raidlist, raidrec->volname); #else /** structures ********************************************************/ struct raid_device_record *bkp_raidrec = NULL; /** buffers ***********************************************************/ char *title_of_editraidForm_window = NULL; char *sz_raid_level = NULL; char *sz_data_disks = NULL; char *sz_spare_disks = NULL; char *sz_parity_disks = NULL; char *sz_failed_disks = NULL; /** newt **************************************************************/ newtComponent editraidForm; newtComponent bOK; newtComponent bCancel; newtComponent bAdditional; newtComponent bChangeRaid; newtComponent bSelectData; newtComponent bSelectSpare; newtComponent bSelectParity; newtComponent bSelectFailed; newtComponent b_res; assert(mountlist != NULL); assert(raidlist != NULL); assert(raidrec != NULL); bkp_raidrec = mr_malloc(sizeof(struct raid_device_record)); log_it("Started edit_raidlist_entry"); memcpy((void *) bkp_raidrec, (void *) raidrec, sizeof(struct raid_device_record)); mr_asprintf(&title_of_editraidForm_window, _("Edit %s"), raidrec->raid_device); mr_msg(2, "Opening newt window"); newtOpenWindow(20, 5, 40, 14, title_of_editraidForm_window); mr_free(title_of_editraidForm_window); for (;;) { mr_msg(2, "Main loop"); mr_asprintf(&sz_raid_level, turn_raid_level_number_to_string(raidrec->raid_level)); mr_asprintf(&sz_data_disks, number_of_disks_as_string(raidrec->data_disks.entries, _("data"))); mr_asprintf(&sz_spare_disks, number_of_disks_as_string(raidrec->spare_disks.entries, _("spare"))); mr_asprintf(&sz_parity_disks, number_of_disks_as_string(raidrec->parity_disks.entries, _("parity"))); mr_asprintf(&sz_failed_disks, number_of_disks_as_string(raidrec->failed_disks.entries, _("failed"))); bSelectData = newtButton(1, 1, sz_data_disks); bSelectSpare = newtButton(20, 1, sz_spare_disks); bSelectParity = newtButton(1, 5, sz_parity_disks); bSelectFailed = newtButton(20, 5, sz_failed_disks); bChangeRaid = newtButton(1, 9, sz_raid_level); mr_free(sz_raid_level); mr_free(sz_data_disks); mr_free(sz_spare_disks); mr_free(sz_parity_disks); mr_free(sz_failed_disks); bOK = newtButton(16 + (raidrec->raid_level == -1), 9, _(" OK ")); bCancel = newtButton(28, 9, _("Cancel")); bAdditional = newtCompactButton(1, 13, _("Additional settings and information")); newtPushHelpLine (_ (" Edit the RAID device's settings to your heart's content, then hit OK/Cancel.")); editraidForm = newtForm(NULL, NULL, 0); newtFormAddComponents(editraidForm, bSelectData, bSelectParity, bChangeRaid, bSelectSpare, bSelectFailed, bOK, bCancel, bAdditional); b_res = newtRunForm(editraidForm); if (b_res == bChangeRaid) { choose_raid_level(raidrec); } else if (b_res == bSelectData) { select_raid_disks(mountlist, raidlist, raidrec, _("data"), &raidrec->data_disks); } else if (b_res == bSelectSpare) { select_raid_disks(mountlist, raidlist, raidrec, _("spare"), &raidrec->spare_disks); } else if (b_res == bSelectParity) { select_raid_disks(mountlist, raidlist, raidrec, _("parity"), &raidrec->parity_disks); } else if (b_res == bSelectFailed) { select_raid_disks(mountlist, raidlist, raidrec, _("failed"), &raidrec->failed_disks); } else if (b_res == bAdditional) { edit_raidrec_additional_vars(raidrec); } newtFormDestroy(editraidForm); if (b_res == bOK || b_res == bCancel) { break; } } if (b_res == bCancel) { memcpy((void *) raidrec, (void *) bkp_raidrec, sizeof(struct raid_device_record)); } newtPopHelpLine(); newtPopWindow(); mountlist->el[currline].size = calculate_raid_device_size(mountlist, raidlist, raidrec->raid_device); mr_free(bkp_raidrec); #endif } #ifdef __FreeBSD__ /** * Edit the plex @p raidrec in @p raidlist. * @param mountlist The mountlist to get some of the information from. * @param raidlist The raidlist containing information about RAID devices. * @param raidrec The plex to edit. * @param currline The line number (starting from 0) of the RAID device in @p mountlist. * @param currline2 The line number (starting from 0) of the plex within the RAID device. * @author Joshua Oreman * @ingroup restoreGuiMountlist */ void edit_raidlist_plex(struct mountlist_itself *mountlist, struct raidlist_itself *raidlist, struct vinum_plex *raidrec, int currline, int currline2) { /** structures ********************************************************/ struct vinum_plex bkp_raidrec; /** buffers ***********************************************************/ char *title_of_editraidForm_window = NULL; char *tmp = NULL; char *entry = NULL; /** newt **************************************************************/ newtComponent editraidForm; newtComponent bOK; newtComponent bCancel; newtComponent bEdit; newtComponent bAdd; newtComponent bDelete; newtComponent b_res; newtComponent unallocListbox, allocListbox; newtComponent bLevel, sLevel; newtComponent bStripeSize, sStripeSize; newtComponent bAlloc, bUnalloc; void *keylist[ARBITRARY_MAXIMUM]; void *curr_choice_a = NULL, *curr_choice_u = NULL; int currline_a = 0, currline_u = 0; int i = 0; struct mountlist_itself *unallocparts = NULL; unallocparts = mr_malloc(sizeof(struct mountlist_itself)); log_it("Started edit_raidlist_entry"); memcpy((void *) &bkp_raidrec, (void *) raidrec, sizeof(struct vinum_plex)); mr_asprintf(&title_of_editraidForm_window, "%s.p%i", raidlist->el[currline].volname, currline2); newtPushHelpLine (_ (" Please select a subdisk to edit, or edit this plex's parameters")); newtOpenWindow(13, 3, 54, 18, title_of_editraidForm_window); mr_free(title_of_editraidForm_window); for (;;) { switch (raidrec->raidlevel) { case -1: mr_asprintf(&tmp, _("concat")); break; case 0: mr_asprintf(&tmp, _("striped")); break; case 5: mr_asprintf(&tmp, _("raid5")); break; default: mr_asprintf(&tmp, _("unknown (%i)"), raidrec->raidlevel); break; } bLevel = newtCompactButton(2, 2, _(" RAID level ")); sLevel = newtLabel(19, 2, tmp); mr_free(tmp); if (raidrec->raidlevel >= 0) { mr_asprintf(&tmp, "%ik", raidrec->stripesize); bStripeSize = newtCompactButton(2, 4, _(" Stripe size ")); } else { mr_asprintf(&tmp, "N/A"); bStripeSize = newtLabel(2, 4, _("Stripe size:")); } sStripeSize = newtLabel(19, 4, tmp); mr_free(tmp); bOK = newtCompactButton(2, 16, _(" OK ")); bCancel = newtCompactButton(12, 16, _("Cancel")); bAdd = newtCompactButton(22, 16, _(" Add ")); bEdit = newtCompactButton(32, 16, _(" Edit ")); bDelete = newtCompactButton(42, 16, _("Delete")); unallocListbox = newtListbox(2, 7, 7, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); allocListbox = newtListbox(33, 7, 7, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); bAlloc = newtButton(23, 7, " -> "); bUnalloc = newtButton(23, 11, " <- "); editraidForm = newtForm(NULL, NULL, 0); newtListboxClear(allocListbox); newtListboxClear(unallocListbox); bzero(unallocparts, sizeof(struct mountlist_itself)); make_list_of_unallocated_raid_partitions(unallocparts, mountlist, raidlist); for (i = 0; i < ARBITRARY_MAXIMUM; ++i) { keylist[i] = (void *) i; if (i < raidrec->subdisks) { mr_asprintf(&entry, "%-17s", find_dev_entry_for_raid_device_name(raidlist, raidrec-> sd[i]. which_device)); newtListboxAppendEntry(allocListbox, entry, keylist[i]); mr_free(entry); } if (i < unallocparts->entries) { mr_asprintf(&entry, "%-17s", unallocparts->el[i].device); newtListboxAppendEntry(unallocListbox, entry, keylist[i]); mr_free(entry); } } #define COMP(x) newtFormAddComponent (editraidForm, x) #define UCOMP(x) if (unallocparts->entries > 0) COMP(x) #define ACOMP(x) if (raidrec->subdisks > 0) COMP(x) editraidForm = newtForm(NULL, NULL, 0); UCOMP(unallocListbox); UCOMP(bAlloc); ACOMP(allocListbox); ACOMP(bUnalloc); COMP(bOK); COMP(bCancel); COMP(bLevel); COMP(sLevel); if (raidrec->raidlevel != -1) { COMP(bStripeSize); COMP(sStripeSize); } #undef COMP #undef UCOMP #undef ACOMP newtRefresh(); b_res = newtRunForm(editraidForm); if (b_res == bOK || b_res == bCancel) { break; } curr_choice_a = (raidrec->subdisks > 0) ? newtListboxGetCurrent(allocListbox) : (void *) 1234; curr_choice_u = (unallocparts->entries > 0) ? newtListboxGetCurrent(unallocListbox) : (void *) 1234; for (currline_a = 0; currline_a < raidrec->subdisks; ++currline_a) { if (currline_a > ARBITRARY_MAXIMUM) break; if (keylist[currline_a] == curr_choice_a) break; } for (currline_u = 0; currline_u < unallocparts->entries; ++currline_u) { if (currline_u > ARBITRARY_MAXIMUM) break; if (keylist[currline_u] == curr_choice_u) break; } if (b_res == bLevel) { choose_raid_level(raidrec); } else if (b_res == bStripeSize) { malloc_string(tmp); sprintf(tmp, "%i", raidrec->stripesize); if (popup_and_get_string (_("Stripe size"), _("Please enter the stripe size in kilobytes."), tmp, 20)) { raidrec->stripesize = atoi(tmp); } mr_free(tmp); } else if ((b_res == bAlloc) || (b_res == unallocListbox)) { if (currline_u <= unallocparts->entries) add_raid_subdisk(raidlist, raidrec, unallocparts->el[currline_u].device); } else if ((b_res == bUnalloc) || (b_res == allocListbox)) { if (currline_a <= raidrec->subdisks) { memcpy((void *) &raidrec->sd[currline_a], (void *) &raidrec->sd[raidrec->subdisks - 1], sizeof(struct vinum_subdisk)); raidrec->subdisks--; } } #if 0 } else { edit_raid_subdisk(raidlist, raidrec, &raidrec->sd[currline3], currline3); } #endif newtFormDestroy(editraidForm); newtRefresh(); } if (b_res == bCancel) { memcpy((void *) raidrec, (void *) &bkp_raidrec, sizeof(struct vinum_plex)); } newtPopWindow(); newtPopHelpLine(); } #else /** * Edit additional RAID variable number @p lino. * @param raidrec The RAID device record to edit the variable in. * @param lino The line number (starting from 0) of the variable to edit. * @ingroup restoreGuiVarslist */ void edit_varslist_entry(struct raid_device_record *raidrec, int lino) { /** buffers ***********************************************************/ char *header = NULL; char *comment = NULL; char *sz_out = NULL; assert(raidrec != 0); assert(lino >= 0); malloc_string(sz_out); strcpy(sz_out, raidrec->additional_vars.el[lino].value); mr_asprintf(&header, _("Edit %s"), raidrec->additional_vars.el[lino].label); mr_asprintf(&comment, _("Please set %s's value (currently '%s')"), raidrec->additional_vars.el[lino].label, sz_out); if (popup_and_get_string(header, comment, sz_out, MAX_STR_LEN)) { mr_strip_spaces(sz_out); strcpy(raidrec->additional_vars.el[lino].value, sz_out); } mr_free(sz_out); mr_free(header); mr_free(comment); } #endif /** * Edit the mountlist using Newt. * @param mountlist The mountlist to edit. * @param raidlist The raidlist that goes with @p mountlist. * @return 0 if the user pressed OK, 1 if they pressed Cancel. */ int edit_mountlist_in_newt(char *mountlist_fname, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist) { /** newt **************************************************************/ newtComponent myForm; newtComponent bAdd; newtComponent bEdit; newtComponent bDelete; newtComponent bOK; newtComponent bCancel; newtComponent b_res = NULL; newtComponent partitionsListbox; newtComponent headerMsg; newtComponent flawsLabelA; newtComponent flawsLabelB; newtComponent flawsLabelC; newtComponent bReload; /** ???? *************************************************************/ void *curr_choice = NULL; void *keylist[ARBITRARY_MAXIMUM]; /** int **************************************************************/ int i = 0; int currline = 0; int finished = FALSE; int res = 0; /** buffers **********************************************************/ char *tmp = NULL; char *flaws_str_A = NULL; char *flaws_str_B = NULL; char *flaws_str_C = NULL; assert(mountlist != NULL); assert(raidlist != NULL); mr_asprintf(&flaws_str_A, "xxxxxxxxx"); mr_asprintf(&flaws_str_B, "xxxxxxxxx"); mr_asprintf(&flaws_str_C, "xxxxxxxxx"); if (mountlist->entries > ARBITRARY_MAXIMUM) { log_to_screen(_("Arbitrary limits suck, man!")); finish(1); } newtPushHelpLine (_ (" Please edit the mountlist to your satisfaction, then click OK or Cancel.")); i = 4; bAdd = newtCompactButton(i, 17, _(" Add ")); bEdit = newtCompactButton(i += 11, 17, _(" Edit ")); bDelete = newtCompactButton(i += 12, 17, _("Delete")); bReload = newtCompactButton(i += 12, 17, _("Reload")); bCancel = newtCompactButton(i += 12, 17, _("Cancel")); bOK = newtCompactButton(i += 12, 17, _(" OK ")); mr_asprintf(&tmp, "%-24s %-24s %-8s %s", _("Device"), _("Mountpoint"), _("Format"), _("Size (MB)")); headerMsg = newtLabel(2, 1, tmp); flawsLabelA = newtLabel(2, 13, flaws_str_A); flawsLabelB = newtLabel(2, 14, flaws_str_B); flawsLabelC = newtLabel(2, 15, flaws_str_C); mr_free(flaws_str_A); mr_free(flaws_str_B); mr_free(flaws_str_C); partitionsListbox = newtListbox(2, 2, 10, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); redraw_mountlist(mountlist, keylist, partitionsListbox); newtOpenWindow(1, 3, 77, 18, _("Editing mountlist")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, headerMsg, partitionsListbox, flawsLabelA, flawsLabelB, flawsLabelC, bAdd, bEdit, bDelete, bReload, bCancel, bOK, NULL); malloc_string(flaws_str_A); malloc_string(flaws_str_B); malloc_string(flaws_str_C); while (!finished) { evaluate_mountlist(mountlist, flaws_str_A, flaws_str_B, flaws_str_C); newtLabelSetText(flawsLabelA, flaws_str_A); newtLabelSetText(flawsLabelB, flaws_str_B); newtLabelSetText(flawsLabelC, flaws_str_C); b_res = newtRunForm(myForm); if (b_res == bOK) { if (!evaluate_mountlist (mountlist, flaws_str_A, flaws_str_B, flaws_str_C)) { finished = ask_me_yes_or_no (_("Your mountlist might not work. Continue anyway?")); } else { finished = ask_me_yes_or_no (_ ("Are you sure you want to save your mountlist and continue? (No changes will be made to your partition table at this time.)")); } } else if (b_res == bCancel) { finished = TRUE; } else if (b_res == bReload) { if (ask_me_yes_or_no(_("Reload original mountlist?"))) { load_mountlist(mountlist, mountlist_fname); load_raidtab_into_raidlist(raidlist, RAIDTAB_FNAME); redraw_mountlist(mountlist, keylist, partitionsListbox); } } else { curr_choice = newtListboxGetCurrent(partitionsListbox); for (i = 0; i < mountlist->entries && keylist[i] != curr_choice; i++); if (i == mountlist->entries && mountlist->entries > 0) { log_to_screen(_("I don't know what that button does!")); } else { currline = i; if (b_res == bAdd) { add_mountlist_entry(mountlist, raidlist, partitionsListbox, currline, keylist); } else if (b_res == bDelete) { delete_mountlist_entry(mountlist, raidlist, partitionsListbox, currline, keylist); } else { if (mountlist->entries > 0) { edit_mountlist_entry(mountlist, raidlist, partitionsListbox, currline, keylist); } else { popup_and_OK (_ ("Please add an entry. Then press ENTER to edit it.")); } } } } } newtFormDestroy(myForm); newtPopWindow(); newtPopHelpLine(); if (b_res == bOK) { log_it(_("You pushed 'OK'. I shall now continue.")); return (0); } else { return (1); } } /** * Edit the mountlist. * @param mountlist The mountlist to edit. * @param raidlist The raidlist that goes with @p mountlist. * @return 0 if the user pressed OK, 1 if they pressed Cancel. */ int edit_mountlist(char *mountlist_fname, struct mountlist_itself *mountlist, struct raidlist_itself *raidlist) { int res = 0; iamhere("entering eml"); if (g_text_mode) { fatal_error("Don't call edit_mountlist() in text mode"); } else { log_it ("I'm in GUI mode, so I shall edit mountlist using edit_mountlist()"); res = edit_mountlist_in_newt(mountlist_fname, mountlist, raidlist); } iamhere("leaving eml"); return (res); } #ifndef __FreeBSD__ /** * Edit the additional RAID variables in @p raidrec. * @param raidrec The RAID device record to edit the RAID variables in. * @ingroup restoreGuiVarslist */ void edit_raidrec_additional_vars(struct raid_device_record *raidrec) { /** structure *********************************************************/ struct raid_device_record bkp_raidrec; /** newt **************************************************************/ newtComponent myForm; newtComponent bAdd; newtComponent bEdit; newtComponent bDelete; newtComponent bOK; newtComponent bCancel; newtComponent b_res; newtComponent varsListbox; newtComponent headerMsg; /** ?? ***************************************************************/ void *keylist[ARBITRARY_MAXIMUM], *curr_choice = NULL; /** buffers **********************************************************/ char *title_of_window = NULL; /** int **************************************************************/ int i = 0; int currline = 0; assert(raidrec != NULL); memcpy((void *) &bkp_raidrec, (void *) raidrec, sizeof(struct raid_device_record)); mr_asprintf(&title_of_window, "Additional variables"); newtPushHelpLine (_ (" Edit the additional fields to your heart's content, then click OK or Cancel.")); headerMsg = newtLabel(1, 1, _("Label Value")); varsListbox = newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); i = 1; bAdd = newtCompactButton(i, 9, _(" Add ")); bEdit = newtCompactButton(i += 8, 9, _(" Edit ")); bDelete = newtCompactButton(i += 9, 9, _("Delete")); bOK = newtCompactButton(i += 9, 9, _(" OK ")); bCancel = newtCompactButton(i += 9, 9, _("Cancel")); newtOpenWindow(17, 7, 46, 10, title_of_window); mr_free(title_of_window); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, headerMsg, varsListbox, bAdd, bEdit, bDelete, bOK, bCancel, NULL); insert_essential_additionalvars(raidrec); redraw_varslist(&raidrec->additional_vars, keylist, varsListbox); for (b_res = NULL; b_res != bOK && b_res != bCancel;) { b_res = newtRunForm(myForm); curr_choice = newtListboxGetCurrent(varsListbox); for (currline = 0; currline < raidrec->additional_vars.entries && keylist[currline] != curr_choice; currline++); if (currline == raidrec->additional_vars.entries && raidrec->additional_vars.entries > 0) { log_it("Warning - I don't know what this button does"); } if (b_res == bOK) { /* do nothing */ } else if (b_res == bCancel) { /* do nothing */ } else if (b_res == bAdd) { add_varslist_entry(raidrec); } else if (b_res == bDelete) { delete_varslist_entry(raidrec, currline); } else { edit_varslist_entry(raidrec, currline); } redraw_varslist(&raidrec->additional_vars, keylist, varsListbox); } remove_essential_additionalvars(raidrec); newtFormDestroy(myForm); newtPopWindow(); newtPopHelpLine(); if (b_res == bCancel) { memcpy((void *) raidrec, (void *) &bkp_raidrec, sizeof(struct raid_device_record)); } return; } #endif /** * Find the next free location to place a disk in @p disklist. * @param disklist The disklist to operate on. * @return The next free location (starting from 0). * @ingroup restoreGuiDisklist */ int find_next_free_index_in_disklist(struct list_of_disks *disklist) { /** int ***************************************************************/ int idx = -1; int pos = 0; /** bool **************************************************************/ bool done = FALSE; assert(disklist != NULL); for (done = FALSE; !done;) { for (pos = 0; pos < disklist->entries && disklist->el[pos].index <= idx; pos++); if (pos >= disklist->entries) { done = TRUE; } else { idx = disklist->el[pos].index; } } return (idx + 1); } /** * Locate @p device in @p raidlist. * @param raidlist The raidlist ot search in. * @param device The RAID device to search for. * @return The index of the device, or -1 if it could not be found. * @ingroup restoreGuiMountlist */ int find_raid_device_in_raidlist(struct raidlist_itself *raidlist, char *device) { /** int ***************************************************************/ int i = 0; #ifdef __FreeBSD__ char *vdev = NULL; #endif assert(raidlist != NULL); assert_string_is_neither_NULL_nor_zerolength(device); #ifdef __FreeBSD__ for (i = 0; i < raidlist->entries; i++) { mr_asprintf(&vdev, "/dev/vinum/%s", raidlist->el[i].volname); if (!strcmp(device, vdev)) { mr_free(vdev); break; } mr_free(vdev); } #else for (i = 0; strcmp(raidlist->el[i].raid_device, device) && i < raidlist->entries; i++); #endif if (i == raidlist->entries) { return (-1); } else { return (i); } } /** * Get information about the location of ISO images from the user. * @param isodir_device Where to put the device (e.g. /dev/hda4) the user enters. * @param isodir_format Where to put the format (e.g. ext2) the user enters. * @param isodir_path Where to put the path (e.g. /var/cache/mondo) the user enters. * @param nuke_me_please Whether we're planning on nuking or not. * @return TRUE if OK was pressed, FALSE otherwise. */ bool get_isodir_info(char *isodir_device, char *isodir_format, char *isodir_path, bool nuke_me_please) { char *value = NULL; /** initialize ********************************************************/ malloc_string(value); assert(isodir_device != NULL); assert(isodir_format != NULL); assert(isodir_path != NULL); log_it("%d - AAA - isodir_path = %s", __LINE__, isodir_path); isodir_format[0] = '\0'; if (isodir_device[0] == '\0') { strcpy(isodir_device, "/dev/"); } if (isodir_path[0] == '\0') { strcpy(isodir_path, "/"); } if (read_cfg_var(g_mondo_cfg_file, "nfs-server-path", value) == 0) { read_cfg_var(g_mondo_cfg_file, "nfs-server-mount", isodir_device); strcpy(isodir_format, "nfs"); strcpy(isodir_path, value); } mr_free(value); if (nuke_me_please) { return (TRUE); } if (popup_and_get_string (_("ISO Mode - device"), _("On what device do the ISO files live?"), isodir_device, MAX_STR_LEN / 4)) { if (popup_and_get_string (_("ISO Mode - format"), _("What is the disk format of the device? (Hit ENTER if you don't know.)"), isodir_format, 16)) { if (popup_and_get_string (_("ISO Mode - path"), _("At what path on this device can the ISO files be found?"), isodir_path, MAX_STR_LEN / 4)) { mr_strip_spaces(isodir_device); mr_strip_spaces(isodir_format); mr_strip_spaces(isodir_path); log_it("%d - BBB - isodir_path = %s", isodir_path); return (TRUE); } } } return (FALSE); } /** * Create a new raidtab entry for @p device in @p raidlist. * @param raidlist The raidlist to add the device to. * @param mountlist The mountlist containing information about the user's partitions. * @param currline The selected line in the mountlist. * @param device The RAID device (e.g. /dev/md0) to use. * @ingroup restoreGuiMountlist */ void initiate_new_raidlist_entry(struct raidlist_itself *raidlist, struct mountlist_itself *mountlist, int currline, char *device) { /** structure *********************************************************/ struct OSSWAP (raid_device_record, vinum_volume) * raidrec; /** int ***************************************************************/ int pos_in_raidlist = 0; assert(raidlist != NULL); assert(mountlist != NULL); assert_string_is_neither_NULL_nor_zerolength(device); pos_in_raidlist = find_raid_device_in_raidlist(raidlist, mountlist->el[currline].device); if (pos_in_raidlist >= 0) { fatal_error("Sorry, that RAID device already exists. Weird."); } pos_in_raidlist = raidlist->entries++; raidrec = &raidlist->el[pos_in_raidlist]; initialize_raidrec(raidrec); strcpy(raidrec->OSSWAP(raid_device, volname), OSSWAP(device, basename(device))); #ifndef __FreeBSD__ choose_raid_level(raidrec); select_raid_disks(mountlist, raidlist, raidrec, "data", &raidrec->data_disks); #endif edit_raidlist_entry(mountlist, raidlist, raidrec, currline); } #ifndef __FreeBSD__ /** * Insert the RAID variables not stored in the "additional RAID variables" list there too. * @param raidrec The RAID device record to operate on. * @ingroup restoreGuiVarslist */ void insert_essential_additionalvars(struct raid_device_record *raidrec) { /** int **************************************************************/ int items = 0; assert(raidrec != NULL); items = raidrec->additional_vars.entries; write_variableINT_to_raid_var_line(raidrec, items++, "persistent-superblock", raidrec->persistent_superblock); write_variableINT_to_raid_var_line(raidrec, items++, "chunk-size", raidrec->chunk_size); raidrec->additional_vars.entries = items; } #endif /** * Dummy function that proves that we can get to the point where Mondo is run. */ void nuke_mode_dummy(void) { /** newt *************************************************************/ newtComponent myForm; newtComponent b1; newtComponent b2; newtComponent b3; newtComponent b_res; newtPushHelpLine (_ ("This is where I nuke your hard drives. Mhahahahaha. No-one can stop Mojo Jojo!")); newtOpenWindow(24, 3, 32, 13, _("Nuking")); b1 = newtButton(7, 1, _("Slowly")); b2 = newtButton(7, 5, _("Medium")); b3 = newtButton(7, 9, _("Quickly")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, b1, b2, b3, NULL); b_res = newtRunForm(myForm); newtFormDestroy(myForm); newtPopWindow(); newtPopHelpLine(); } /** * Redraw the disklist. * @param disklist The disklist to read from. * @param keylist The list of keys for @p listbox. * @param listbox The Newt listbox component to redraw. * @ingroup restoreGuiDisklist */ void redraw_disklist(struct list_of_disks *disklist, void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox) { /** long **************************************************************/ long i = 0; assert(disklist != NULL); assert(keylist != NULL); assert(listbox != NULL); newtListboxClear(listbox); for (i = 0; i < ARBITRARY_MAXIMUM; i++) { keylist[i] = (void *) i; } for (i = 0; i < disklist->entries; i++) { newtListboxAppendEntry(listbox, disklist_entry_to_string(disklist, i), keylist[i]); } } /** * Redraw the mountlist. * @param mountlist The mountlist to read from. * @param keylist The list of keys for @p listbox. * @param listbox The Newt listbox component to redraw. * @ingroup restoreGuiMountlist */ void redraw_mountlist(struct mountlist_itself *mountlist, void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox) { /** long **************************************************************/ long i = 0; assert(mountlist != NULL); assert(keylist != NULL); assert(listbox != NULL); newtListboxClear(listbox); for (i = 0; i < ARBITRARY_MAXIMUM; i++) { keylist[i] = (void *) i; } for (i = 0; i < mountlist->entries; i++) { newtListboxAppendEntry(listbox, mountlist_entry_to_string(mountlist, i), keylist[i]); } } /** * Redraw the list of unallocated RAID partitions. * @param unallocated_raid_partitions The mountlist containing unallocated RAID partitions. * @param keylist The list of keys for @p listbox. * @param listbox The Newt listbox component to redraw. * @ingroup restoreGuiDisklist */ void redraw_unallocpartnslist(struct mountlist_itself *unallocated_raid_partitions, void *keylist[ARBITRARY_MAXIMUM], newtComponent listbox) { /** long *************************************************************/ long i = 0; /** buffers **********************************************************/ char *tmp = NULL; assert(unallocated_raid_partitions != NULL); assert(keylist != NULL); assert(listbox != NULL); newtListboxClear(listbox); for (i = 0; i < ARBITRARY_MAXIMUM; i++) { keylist[i] = (void *) i; } for (i = 0; i < unallocated_raid_partitions->entries; i++) { mr_asprintf(&tmp, "%-22s %8lld", unallocated_raid_partitions->el[i].device, unallocated_raid_partitions->el[i].size / 1024); newtListboxAppendEntry(listbox, tmp, keylist[i]); mr_free(tmp); } } #ifndef __FreeBSD__ /** * Redraw the list of additional RAID variables. * @param additional_vars The list of additional RAID varibals. * @param keylist The list of keys for @p listbox. * @param listbox The Newt listbox component to redraw. * @ingroup restoreGuiVarslist */ void redraw_varslist(struct additional_raid_variables *additional_vars, void *keylist[], newtComponent listbox) { /** long ************************************************************/ long i = 0; /** buffers *********************************************************/ char *tmp; assert(additional_vars != NULL); assert(keylist != NULL); assert(listbox != NULL); newtListboxClear(listbox); for (i = 0; i < ARBITRARY_MAXIMUM; i++) { keylist[i] = (void *) i; } for (i = 0; i < additional_vars->entries; i++) { mr_asprintf(&tmp, "%-32s %-8s", additional_vars->el[i].label, additional_vars->el[i].value); newtListboxAppendEntry(listbox, tmp, keylist[i]); mr_free(tmp); } } /** * Remove variable @p label from the RAID variables list in @p raidrec. * @param raidrec The RAID device record to remove the variable from. * @param label The variable name to remove. * @return The value of the variable removed. * @ingroup restoreUtilityGroup */ int read_variableINT_and_remove_from_raidvars(struct OSSWAP (raid_device_record, vinum_volume) * raidrec, char *label) { /** int ***************************************************************/ int i = 0; int res = 0; assert(raidrec != NULL); assert(label != NULL); for (i = 0; i < raidrec->additional_vars.entries && strcmp(raidrec->additional_vars.el[i].label, label); i++); if (i == raidrec->additional_vars.entries) { res = -1; } else { res = atoi(raidrec->additional_vars.el[i].value); for (i++; i < raidrec->additional_vars.entries; i++) { memcpy((void *) &raidrec->additional_vars.el[i - 1], (void *) &raidrec->additional_vars.el[i], sizeof(struct raid_var_line)); } raidrec->additional_vars.entries--; } return (res); } #endif /** * Change all RAID devices to use @p new_dev instead of @p old_dev. * @param raidlist The raidlist to make the changes in. * @param old_dev The old name of the device (what it used to be). * @param new_dev The new name of the device (what it is now). * @ingroup restoreGuiMountlist */ void rejig_partition_name_in_raidlist_if_necessary(struct raidlist_itself *raidlist, char *old_dev, char *new_dev) { /** int ************************************************************/ int pos = 0; int j = 0; assert(raidlist != NULL); assert_string_is_neither_NULL_nor_zerolength(old_dev); assert_string_is_neither_NULL_nor_zerolength(new_dev); pos = which_raid_device_is_using_this_partition(raidlist, old_dev); if (pos < 0) { log_it("No need to rejig %s in raidlist: it's not listed.", old_dev); } else { if ((j = where_in_drivelist_is_drive(&raidlist-> OSSWAP(el[pos].data_disks, disks), old_dev)) >= 0) { strcpy(raidlist->OSSWAP(el[pos].data_disks, disks).el[j]. device, new_dev); } else if ((j = where_in_drivelist_is_drive(&raidlist-> OSSWAP(el[pos].spare_disks, spares), old_dev)) >= 0) { strcpy(raidlist->OSSWAP(el[pos].spare_disks, spares).el[j]. device, new_dev); } #ifndef __FreeBSD__ else if ((j = where_in_drivelist_is_drive(&raidlist->el[pos]. parity_disks, old_dev)) >= 0) { strcpy(raidlist->el[pos].parity_disks.el[j].device, new_dev); } else if ((j = where_in_drivelist_is_drive(&raidlist->el[pos]. failed_disks, old_dev)) >= 0) { strcpy(raidlist->el[pos].failed_disks.el[j].device, new_dev); } #endif else { log_it("%s is supposed to be listed in this raid dev but it's not...", old_dev); } } } #ifndef __FreeBSD__ /** * Remove the essential RAID variables from the "additional variables" section. * If they have been changed, set them in their normal locations too. * @param raidrec The RAID device record to operate on. * @ingroup restoreUtilityVarslist */ void remove_essential_additionalvars(struct raid_device_record *raidrec) { /** int **************************************************************/ int res = 0; assert(raidrec != NULL); res = read_variableINT_and_remove_from_raidvars(raidrec, "persistent-superblock"); if (res > 0) { raidrec->persistent_superblock = res; } res = read_variableINT_and_remove_from_raidvars(raidrec, "chunk-size"); if (res > 0) { raidrec->chunk_size = res; } res = read_variableINT_and_remove_from_raidvars(raidrec, "block-size"); } /** * Select the RAID disks to use in @p raidrec. * @param mountlist_dontedit The mountlist (will not be edited). * @param raidlist The raidlist to modify. * @param raidrec The RAID device record in @p raidlist to work on. * @param description_of_list The type of disks we're selecting (e.g. "data"). * @param disklist The disklist to put the user-selected disks in. * @ingroup restoreGuiMountlist */ void select_raid_disks(struct mountlist_itself *mountlist_dontedit, struct raidlist_itself *raidlist, struct raid_device_record *raidrec, char *description_of_list, struct list_of_disks *disklist) { void *curr_choice = NULL; /** structures ********************************************************/ struct raidlist_itself *bkp_raidlist = NULL; struct raid_device_record *bkp_raidrec = NULL; struct list_of_disks *bkp_disklist = NULL; struct mountlist_itself *unallocated_raid_partitions = NULL; /** newt **************************************************************/ newtComponent myForm = NULL; newtComponent bAdd = NULL; newtComponent bDelete = NULL; newtComponent bOK = NULL; newtComponent bCancel = NULL; newtComponent b_res = NULL; newtComponent partitionsListbox = NULL; newtComponent headerMsg = NULL; /** buffers **********************************************************/ void *keylist[ARBITRARY_MAXIMUM]; char *tmp = NULL; char *help_text = NULL; char *title_of_window = NULL; char *sz_res = NULL; char *header_text = NULL; /** int **************************************************************/ int i = 0; int currline = 0; assert(mountlist_dontedit != NULL); assert(raidlist != NULL); assert(raidrec != NULL); assert(description_of_list != NULL); assert(disklist != NULL); iamhere("malloc'ing"); bkp_raidrec = mr_malloc(sizeof(struct raid_device_record)); bkp_disklist = mr_malloc(sizeof(struct list_of_disks)); bkp_raidlist = mr_malloc(sizeof(struct raidlist_itself)); unallocated_raid_partitions = mr_malloc(sizeof(struct mountlist_itself)); memcpy((void *) bkp_raidlist, (void *) raidlist, sizeof(struct raidlist_itself)); memcpy((void *) bkp_raidrec, (void *) raidrec, sizeof(struct raid_device_record)); memcpy((void *) bkp_disklist, (void *) disklist, sizeof(struct list_of_disks)); iamhere("Post-malloc"); mr_asprintf(&help_text, _ (" Edit this RAID device's list of partitions. Choose OK or Cancel when done.")); mr_asprintf(&header_text, "%-24s %s", _("Device"), _("Index")); mr_asprintf(&title_of_window, _("%s contains..."), raidrec->raid_device); newtPushHelpLine(help_text); mr_free(help_text); for (b_res = (newtComponent) 12345; b_res != bOK && b_res != bCancel;) { headerMsg = newtLabel(1, 1, header_text); partitionsListbox = newtListbox(1, 2, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); redraw_disklist(disklist, keylist, partitionsListbox); i = 1; bAdd = newtCompactButton(i, 9, _(" Add ")); bDelete = newtCompactButton(i += 8, 9, _("Delete")); bOK = newtCompactButton(i += 9, 9, _(" OK ")); bCancel = newtCompactButton(i += 9, 9, _("Cancel")); newtOpenWindow(21, 7, 38, 10, title_of_window); myForm = newtForm(NULL, NULL, 0); if (disklist->entries == 0) { newtFormAddComponents(myForm, headerMsg, bAdd, bDelete, bOK, bCancel, NULL); } else { newtFormAddComponents(myForm, headerMsg, partitionsListbox, bAdd, bDelete, bOK, bCancel, NULL); } b_res = newtRunForm(myForm); if (b_res == bOK || b_res == bCancel) { /* do nothing */ // That's OK. At the end of this subroutine (after this do/while loop), // we'll throw away the changes if Cancel was pushed. } else { curr_choice = newtListboxGetCurrent(partitionsListbox); for (i = 0; i < disklist->entries && keylist[i] != curr_choice; i++); if (i == disklist->entries && disklist->entries > 0) { log_to_screen(_("I don't know what that button does!")); } else { currline = i; if (b_res == bAdd) { log_it(_("Making list of unallocated RAID slices")); make_list_of_unallocated_raid_partitions (unallocated_raid_partitions, mountlist_dontedit, raidlist); if (unallocated_raid_partitions->entries <= 0) { popup_and_OK (_ ("There are no unallocated partitions marked for RAID.")); } else { log_it (_ ("Done. The user may add one or more of the above to RAID device")); add_disklist_entry(disklist, raidrec->raid_device, unallocated_raid_partitions); log_it(_ ("I have finished adding a disklist entry.")); redraw_disklist(disklist, keylist, partitionsListbox); } } else if (b_res == bDelete) { delete_disklist_entry(disklist, raidrec->raid_device, currline); redraw_disklist(disklist, keylist, partitionsListbox); } else { mr_asprintf(&tmp, _("%s's index is %d. What should it be?"), raidrec->raid_device, disklist->el[currline].index); malloc_string(sz_res); sprintf(sz_res, "%d", disklist->el[currline].index); if (popup_and_get_string (_("Set index"), tmp, sz_res, 10)) { disklist->el[currline].index = atoi(sz_res); } mr_free(tmp); mr_free(sz_res); redraw_disklist(disklist, keylist, partitionsListbox); } } } newtFormDestroy(myForm); newtPopWindow(); } mr_free(title_of_window); mr_free(header_text); newtPopHelpLine(); if (b_res == bCancel) { memcpy((void *) raidlist, (void *) bkp_raidlist, sizeof(struct raidlist_itself)); memcpy((void *) raidrec, (void *) bkp_raidrec, sizeof(struct raid_device_record)); memcpy((void *) disklist, (void *) bkp_disklist, sizeof(struct list_of_disks)); } mr_free(bkp_raidrec); mr_free(bkp_disklist); mr_free(bkp_raidlist); mr_free(unallocated_raid_partitions); } #endif /** * Ask the user which restore mode (nuke, interactive, or compare) we should use. * @return The mode selected: 'I' for interactive, 'N' for nuke, 'C' for compare, * or 'E' (or any other letter) for exit. */ char which_restore_mode() { /** char *************************************************************/ char output = '\0'; char *tmp = NULL; size_t n = 0; /** newt *************************************************************/ newtComponent b1; newtComponent b2; newtComponent b3; newtComponent b4; newtComponent b_res; newtComponent myForm; if (g_text_mode) { for (output = 'z'; !strchr("AICE", output); output = tmp[0]) { printf (_ ("Which mode - (A)utomatic, (I)nteractive, \n(C)ompare only, or (E)xit to shell?\n--> ")); mr_getline(&tmp, &n, stdin); } mr_free(tmp); return (output); } newtPushHelpLine (_ (" Do you want to 'nuke' your system, restore interactively, or just compare?")); newtOpenWindow(24, 3, 32, 17, _("How should I restore?")); b1 = newtButton(7, 1, _("Automatically")); b2 = newtButton(7, 5, _("Interactively")); b3 = newtButton(7, 9, _("Compare only!")); b4 = newtButton(7, 13, _("Exit to shell")); myForm = newtForm(NULL, NULL, 0); newtFormAddComponents(myForm, b1, b2, b3, b4, NULL); b_res = newtRunForm(myForm); newtFormDestroy(myForm); newtPopWindow(); if (b_res == b1) { output = 'N'; } if (b_res == b2) { output = 'I'; } if (b_res == b3) { output = 'C'; } if (b_res == b4) { output = 'E'; } newtPopHelpLine(); return (output); }