/*************************************************************************** $Id: mondo-prep.c 3434 2015-08-28 13:26:19Z bruno $ * Functions for prepping hard drives: partitioning, formatting, etc. */ #include "my-stuff.h" #include "mr_mem.h" #include "../common/mondostructures.h" #include "mondoprep.h" #include "../common/libmondo.h" #include "../common/libmondo-tools-EXT.h" #include "mondo-rstr-tools-EXT.h" #include #include #include #define FDISK_LOG "/var/log/mondofdisk.log" #ifdef __FreeBSD__ #define DKTYPENAMES #define FSTYPENAMES #include #include #include #include #define OSSWAP(x,y) y #else #define OSSWAP(x,y) x #endif #define ARCHIVES_PATH MNT_CDROM"/archives" #define MONDO_WAS_HERE "MONDOWOZEREMONDOWOZEREMONDOWOZEREhahahaMOJOJOJO" //static char cvsid[] = "$Id: mondo-prep.c 3434 2015-08-28 13:26:19Z bruno $"; extern char *g_mountlist_fname; extern long g_current_progress, g_maximum_progress; extern bool g_text_mode; extern void pause_for_N_seconds(int, char *); extern char *MONDO_LOGFILE; FILE *g_fprep = NULL; extern char *g_mondo_cfg_file; // where mondorestore.cfg (the config file) is stored int g_partition_table_locked_up = 0; void wipe_MBRs_and_reboot_if_necessary(struct mountlist_itself *mountlist) { char *command = NULL; int lino; int i; FILE *fout; char *buf; const int blocksize = 512; struct list_of_disks *drivelist = NULL; // If LVMs are present and a zero-and-reboot wasn't recently undertaken // then zero & insist on reboot. buf = malloc(blocksize); if (does_file_exist("/tmp/i-want-my-lvm")) { // FIXME - cheating :) drivelist = malloc(sizeof(struct list_of_disks)); make_list_of_drives_in_mountlist(mountlist, drivelist); for (lino = 0; lino < drivelist->entries; lino++) { mr_asprintf(command, "dd if=%s bs=512 count=1 2> /dev/null | grep \"%s\"", drivelist->el[lino].device, MONDO_WAS_HERE); if (!run_program_and_log_output(command, 1)) { log_msg(1, "Found MONDO_WAS_HERE marker on drive#%d (%s)", lino, drivelist->el[lino].device); break; } mr_free(command); } if (lino == drivelist->entries) { // zero & reboot log_to_screen("I am sorry for the inconvenience but I must ask you to reboot."); log_to_screen("I need to reset the Master Boot Record; in order to be"); log_to_screen("sure the kernel notices, I must reboot after doing it."); log_to_screen("Please hit 'Enter' to reboot."); for (lino = 0; lino < drivelist->entries; lino++) { for (i = 0; i < blocksize; i++) { buf[i] = 0; } sprintf(buf, "%s\n", MONDO_WAS_HERE); fout = fopen(drivelist->el[lino].device, "w+"); if (!fout) { log_msg(1, "Unable to open+wipe %s", drivelist->el[lino].device); } else { if (1 != fwrite(buf, blocksize, 1, fout)) { log_msg(1, "Failed to wipe %s", drivelist->el[lino].device); } else { log_msg(1, "Successfully wiped %s", drivelist->el[lino].device); } fclose(fout); } } paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); popup_and_OK("I must now reboot. Please leave the boot media in the drive and repeat your actions - e.g. type 'nuke' - and it should work fine."); paranoid_system("reboot"); } } // Still here? Cool! log_msg(1, "Cool. I didn't have to wipe anything."); } int fput_string_one_char_at_a_time(FILE * fout, char *str) { int i, j; FILE *fq; if (ferror(fout)) { return (-1); } log_msg(5, "Writing string '%s', one char at a time", str); j = strlen(str); for (i = 0; i < j; i++) { log_msg(6, "Writing %d ('%c')", str[i], str[i]); if ((fq = fopen(FDISK_LOG, "a+"))) { fputc(str[i], fq); fclose(fq); } fputc(str[i], fout); fflush(fout); usleep(1000L * 100L); if (str[i] < 32) { usleep(1000L * 10L); } } log_msg(5, "Returning"); return (i); } /** * @addtogroup prepGroup * @{ */ /** * Execute the commands in /tmp/i-want-my-lvm. * These should probably be commands to set up LVM. * @return The number of errors encountered (0 for success). */ int do_my_funky_lvm_stuff(bool just_erase_existing_volumes, bool vacuum_pack) { /** buffers **********************************************/ char *tmp; char *tmp1 = NULL; char *incoming; char *command; char *cmd = NULL; char *lvscan_sz = NULL; char *lvremove_sz = NULL; char *pvscan_sz = NULL; char *vgscan_sz = NULL; char *vgchange_sz = NULL; char *vgremove_sz = NULL; /** char **************************************************/ char *p; char *q; char *r; /** int ***************************************************/ int retval = 0; int res = 0; int i; int lvmversion = 1; long extents; fpos_t orig_pos; /** pointers **********************************************/ FILE *fin; /** end *****************************************************/ #ifdef __FreeBSD__ return (0); #endif if (strstr(call_program_and_get_last_line_of_output("cat /proc/cmdline"), "nolvm")) { return(0); } if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) { log_OS_error("/tmp/i-want-my-lvm"); return (1); } log_it("STARTING"); log_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes..."); if (find_home_of_exe("lvm")) { // found it :) cool mr_asprintf(lvscan_sz, "lvm lvscan"); mr_asprintf(lvremove_sz, "lvm lvremove"); mr_asprintf(vgscan_sz, "lvm vgscan"); mr_asprintf(pvscan_sz, "lvm pvscan"); mr_asprintf(vgchange_sz, "lvm vgchange"); mr_asprintf(vgremove_sz, "lvm vgremove -f"); } else { mr_asprintf(lvscan_sz, "lvscan"); mr_asprintf(lvremove_sz, "lvremove"); mr_asprintf(vgscan_sz, "vgscan"); mr_asprintf(pvscan_sz, "pvscan"); mr_asprintf(vgchange_sz, "vgchange"); mr_asprintf(vgremove_sz, "vgremove"); } mr_asprintf(cmd, "for i in `%s | cut -d\"'\" -f2 | sort -r` ; do echo \"Shutting down lv $i\" >> %s ; %s -f $i; done", lvscan_sz, MONDO_LOGFILE, lvremove_sz); mr_free(lvscan_sz); mr_free(lvremove_sz); run_program_and_log_output(cmd, 5); mr_free(cmd); sleep(1); mr_asprintf(cmd, "for i in `%s | grep -i lvm | cut -d'\"' -f2` ; do %s -a n $i ; %s $i; echo \"Shutting down vg $i\" >> %s ; done", vgscan_sz, vgchange_sz, vgremove_sz, MONDO_LOGFILE); mr_free(vgchange_sz); mr_free(vgremove_sz); run_program_and_log_output(cmd, 5); mr_free(cmd); if (just_erase_existing_volumes) { paranoid_fclose(fin); log_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs."); retval = 0; } else { malloc_string(tmp); malloc_string(incoming); command = malloc(512); log_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff..."); rewind(fin); for (r = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (r != NULL); r = fgets(incoming, MAX_STR_LEN - 1, fin)) { fgetpos(fin, &orig_pos); if (incoming[0] != '#') { continue; } if (res && strstr(command, "create") && vacuum_pack) { sleep(2); paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); } if ((p = strstr(incoming, "vgcreate"))) { // include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm) for (q = fgets(tmp, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(tmp, MAX_STR_LEN - 1, fin)) { if (tmp[0] == '#') { fsetpos(fin, &orig_pos); break; } else { fgetpos(fin, &orig_pos); strcat(incoming, tmp); } } for (q = incoming; *q != '\0'; q++) { if (*q < 32) { *q = ' '; } } strcpy(tmp, p + strlen("vgcreate") + 1); for (q = tmp; *q > 32; q++); *q = '\0'; log_msg(1, "Deleting old entries at /dev/%s", tmp); mr_asprintf(cmd, "rm -Rf /dev/%s", tmp); run_program_and_log_output(cmd, 1); mr_free(cmd); run_program_and_log_output(vgscan_sz, 1); run_program_and_log_output(pvscan_sz, 1); log_msg(3, "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'", incoming); } for (p = incoming + 1; *p == ' '; p++); strcpy(command, p); for (p = command; *p != '\0'; p++); for (; *(p - 1) < 32; p--); *p = '\0'; res = run_program_and_log_output(command, 5); if (res > 0 && (p = strstr(command, "lvm "))) { log_msg(0, "%s --> %d failed so removing lvm just in case", command, res); *p = *(p + 1) = *(p + 2) = ' '; res = run_program_and_log_output(command, 5); } log_msg(0, "%s --> %d", command, res); if (res > 0) { res = 1; } if (res && strstr(command, "lvcreate") && vacuum_pack) { res = 0; if (strstr(command, "lvm lvcreate")) lvmversion = 2; log_it("%s... so I'll get creative.", tmp); if (lvmversion == 2) { mr_asprintf(tmp1, "tail -n5 %s | grep Insufficient | tail -n1", MONDO_LOGFILE); strcpy(tmp, call_program_and_get_last_line_of_output(tmp1)); free(tmp1); } else { mr_asprintf(tmp1, "tail -n5 %s | grep lvcreate | tail -n1", MONDO_LOGFILE); strcpy(tmp, call_program_and_get_last_line_of_output(tmp1)); free(tmp1); } for (p = tmp; *p != '\0' && !isdigit(*p); p++); extents = atol(p); log_msg(5, "p='%s' --> extents=%ld", p, extents); p = strstr(command, "-L"); if (!p) { log_msg(0, "Fiddlesticks. '%s' returned %d", command, res); } else { if (lvmversion == 2) { *p++ = '-'; *p++ = 'l'; *p++ = ' '; for (q = p; *q != ' '; q++) { *q = ' '; } sprintf(p, "%ld", extents); i = strlen(p); *(p + i) = ' '; } else { p++; p++; p++; for (q = p; *q != ' '; q++) { *(q - 1) = ' '; } sprintf(p, "%ld%c", extents, 'm'); i = strlen(p); *(p + i) = ' '; } log_msg(5, "Retrying with '%s'", command); res = run_program_and_log_output(command, 5); if (res > 0) { res = 1; } if (g_fprep) { fprintf(g_fprep, "%s\n", command); } log_msg(0, "%s --> %d", command, res); if (!res) { log_msg(5, "YAY! This time, it succeeded."); } } } if (strstr(command, "vgcreate")) { log_msg(0, "In case you're interested..."); run_program_and_log_output(vgscan_sz, 1); run_program_and_log_output(pvscan_sz, 1); } if (res != 0 && !strstr(command, "insmod")) { retval++; } sprintf(tmp, "echo \"%s\" >> /tmp/out.sh", command); paranoid_system(tmp); sleep(1); } paranoid_fclose(fin); paranoid_free(tmp); paranoid_free(incoming); paranoid_free(command); log_msg(1, "Closed i-want-my-lvm. Finished doing funky stuff."); } mr_free(pvscan_sz); mr_free(vgscan_sz); paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); sleep(1); log_it("ENDING"); if (retval > 2) { log_msg(1, "%d errors. I'm reporting this.", retval); return (retval); } else { log_msg(1, "Not many errors. Returning 0."); return (0); } } /** * Add RAID partitions while copying @p old_mountlist to @p new_mountlist. * We go through @p old_mountlist and check if any RAID device (/dev/md? on Linux) * is in it; if it is, then we put the disks contained within that RAID device * into the mountlist as well. * @param old_mountlist The mountlist to read. * @param new_mountlist The mountlist to write, with the RAID partitions added. * @return 0 for success, nonzero for failure. */ int extrapolate_mountlist_to_include_raid_partitions(struct mountlist_itself *new_mountlist, struct mountlist_itself *old_mountlist) { /** pointers *********************************************************/ FILE *fin; /** int **************************************************************/ int lino; int j; /** buffers **********************************************************/ char *incoming; /** pointers *********************************************************/ char *p; char *q; /** init *************************************************************/ new_mountlist->entries = 0; /** end **************************************************************/ malloc_string(incoming); assert(new_mountlist != NULL); assert(old_mountlist != NULL); #ifdef __FreeBSD__ log_to_screen("I don't know how to extrapolate the mountlist on FreeBSD. Sorry."); return (1); #endif for (lino = 0; lino < old_mountlist->entries; lino++) { if (strstr(old_mountlist->el[lino].device, RAID_DEVICE_STUB)) // raid { if (!does_file_exist("/etc/raidtab")) { log_to_screen ("Cannot find /etc/raidtab - cannot extrapolate the fdisk entries"); finish(1); } if (!(fin = fopen("/etc/raidtab", "r"))) { log_OS_error("Cannot open /etc/raidtab"); finish(1); } for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL) && !strstr(incoming, old_mountlist->el[lino].device); q = fgets(incoming, MAX_STR_LEN - 1, fin)); if (!feof(fin)) { log_it("Investigating %s", old_mountlist->el[lino].device); for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL) && !strstr(incoming, "raiddev"); q = fgets(incoming, MAX_STR_LEN - 1, fin)) { if (strstr(incoming, OSSWAP("device", "drive")) && !strchr(incoming, '#')) { for (p = incoming + strlen(incoming); *(p - 1) <= 32; p--); *p = '\0'; for (p--; p > incoming && *(p - 1) > 32; p--); log_it("Extrapolating %s", p); for (j = 0; j < new_mountlist->entries && strcmp(new_mountlist->el[j].device, p); j++); if (j >= new_mountlist->entries) { strcpy(new_mountlist-> el[new_mountlist->entries].device, p); strcpy(new_mountlist-> el[new_mountlist->entries].mountpoint, "raid"); strcpy(new_mountlist-> el[new_mountlist->entries].format, "raid"); new_mountlist->el[new_mountlist->entries]. size = old_mountlist->el[lino].size; new_mountlist->entries++; } else { log_it("Not adding %s to mountlist: it's already there", p); } } } } paranoid_fclose(fin); } else { strcpy(new_mountlist->el[new_mountlist->entries].device, old_mountlist->el[lino].device); strcpy(new_mountlist->el[new_mountlist->entries].mountpoint, old_mountlist->el[lino].mountpoint); strcpy(new_mountlist->el[new_mountlist->entries].format, old_mountlist->el[lino].format); new_mountlist->el[new_mountlist->entries].size = old_mountlist->el[lino].size; new_mountlist->entries++; } } paranoid_free(incoming); return (0); } /** * Create @p RAID device using information from @p structure. * This will create the specified RAID devive using information provided in * raidlist by means of the mdadm tool. * @param raidlist The structure containing all RAID information * @param device The RAID device to create. * @return 0 for success, nonzero for failure. */ int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device, bool test) { /** int **************************************************************/ int i = 0; int j = 0; int v = 0; int res = 0; /** buffers ***********************************************************/ char *devices = NULL; char *level = NULL; char *program = NULL; // leave straight away if raidlist is initial or has no entries if (!raidlist || raidlist->entries == 0) { log_msg(1, "No RAID arrays found."); return 1; } else { log_msg(1, "%d RAID arrays found.", raidlist->entries); } // find raidlist entry for requested device for (i = 0; i < raidlist->entries; i++) { if (!strcmp(raidlist->el[i].raid_device, device)) break; } // check whether RAID device was found in raidlist if (i == raidlist->entries) { log_msg(1, "RAID device %s not found in list.", device); return 1; } else { log_msg(1, "RAID device %s found in list (%d).", device, i); } // create device list from normal disks followed by spare ones if (raidlist->el[i].data_disks.el[0].device != NULL) { mr_asprintf(devices, "%s", raidlist->el[i].data_disks.el[0].device); log_msg(4, "Adding device %s to list", raidlist->el[i].data_disks.el[0].device); } else { log_msg(1, "Strange, there are entries but no device"); } for (j = 1; j < raidlist->el[i].data_disks.entries; j++) { mr_strcat(devices, " %s", raidlist->el[i].data_disks.el[j].device); log_msg(4, "Adding device %s to list", raidlist->el[i].data_disks.el[j].device); } for (j = 0; j < raidlist->el[i].spare_disks.entries; j++) { mr_strcat(devices, " %s", raidlist->el[i].spare_disks.el[j].device); log_msg(4, "Adding spare device %s to list", raidlist->el[i].spare_disks.el[j].device); } log_msg(4, "RAID devices: %s", devices); // translate RAID level if (raidlist->el[i].raid_level == -2) { mr_asprintf(level, "multipath"); } else if (raidlist->el[i].raid_level == -1) { mr_asprintf(level, "linear"); } else { mr_asprintf(level, "raid%d", raidlist->el[i].raid_level); } // create RAID device: // - RAID device, number of devices and devices mandatory // - parity algorithm, chunk size and spare devices optional // - faulty devices ignored // - persistent superblock always used as this is recommended mr_asprintf(program, "mdadm --create --force --run --auto=yes %s --level=%s --raid-devices=%d", raidlist->el[i].raid_device, level, raidlist->el[i].data_disks.entries); mr_free(level); log_msg(4, "cmd built: %s", program); // Restoring the UUID and Version stored at backup time of present for (v = 0; v < raidlist->el[i].additional_vars.entries ; v++ ) { log_msg(4,"Working on additional param #%d (Label: %s)",v,raidlist->el[i].additional_vars.el[v].label); if ((raidlist->el[i].additional_vars.el[v].label != NULL) && (strcmp(raidlist->el[i].additional_vars.el[v].label,"UUID") == 0)) { // We have a UUID to handle if (raidlist->el[i].additional_vars.el[v].value != NULL) { // force its restoration in order to avoid modifying all conf files using it log_it("Managing previous UUID %s", raidlist->el[i].additional_vars.el[v].value); mr_strcat(program, " --uuid %s",raidlist->el[i].additional_vars.el[v].value); continue; } else { log_msg(1,"Unable to manage previous NULL UUID"); } } if ((raidlist->el[i].additional_vars.el[v].label != NULL) && (strcmp(raidlist->el[i].additional_vars.el[v].label,"Version") == 0)) { // We have a Version to handle if (raidlist->el[i].additional_vars.el[v].value != NULL) { // force its restoration in order to support all complex boot loader + md format cases // Also see bug #473 log_it("Managing previous Version %s", raidlist->el[i].additional_vars.el[v].value); mr_strcat(program, " -e %s",raidlist->el[i].additional_vars.el[v].value); continue; } else { log_msg(1,"Unable to manage previous NULL Version"); } } } log_msg(4, "cmd built: %s", program); if (raidlist->el[i].parity != -1) { switch(raidlist->el[i].parity) { case 0: mr_strcat(program, " --parity=%s", "la"); break; case 1: mr_strcat(program, " --parity=%s", "ra"); break; case 2: mr_strcat(program, " --parity=%s", "ls"); break; case 3: mr_strcat(program, " --parity=%s", "rs"); break; default: fatal_error("Unknown RAID parity algorithm."); break; } } log_msg(4, "cmd built: %s", program); if (raidlist->el[i].chunk_size != -1) { mr_strcat(program, " --chunk=%d", raidlist->el[i].chunk_size); } if (raidlist->el[i].spare_disks.entries > 0) { mr_strcat(program, " --spare-devices=%d", raidlist->el[i].spare_disks.entries); } log_msg(4, "cmd built: %s", program); mr_strcat(program, " %s", devices); log_msg(2, "RAID device re-created with the following command:\n%s", program); if (test == TRUE) { res = run_program_and_log_output(program, 1); } else { // test mode, always returns TRUE without executing the mdadm command res = TRUE; } // free memory mr_free(devices); mr_free(program); // return to calling instance return res; } /** * Format @p device as a @p format filesystem. * This will use the format command returned by which_format_command_do_i_need(). * If @p device is an LVM PV, it will not be formatted, and LVM will be started * (if not already done). If it's an imagedev, software RAID component, or * (under BSD) swap partition, no format will be done. * @param device The device to format. * @param format The filesystem type to format it as. * @return 0 for success, nonzero for failure. */ int format_device(char *device, char *format, struct raidlist_itself *raidlist) { /** int **************************************************************/ #ifdef __FreeBSD__ static bool vinum_started_yet = FALSE; #endif /** buffers ***********************************************************/ char *program = NULL; char *tmp = NULL; int res = 0; int retval = 0; /** end ****************************************************************/ assert_string_is_neither_NULL_nor_zerolength(device); assert(format != NULL); if (strstr(format, "raid")) { // do not form RAID disks; do it to /dev/md* instead log_it("Not formatting %s (it is a RAID disk)", device); return (0); } #ifdef __FreeBSD__ if (strcmp(format, "swap") == 0) { log_it("Not formatting %s - it's swap", device); return (0); } #endif if (strlen(format) <= 2) { log_it("%s has a really small format type ('%s') - this is probably a hexadecimal string, which would suggest the partition is an image --- I shouldn't format it", device, format); return (0); } if (is_this_device_mounted(device)) { log_to_screen("%s is mounted - cannot format it ", device); return (1); } if (strstr(device, RAID_DEVICE_STUB)) { newtSuspend(); #ifdef __FreeBSD__ if (!vinum_started_yet) { if (!does_file_exist("/tmp/raidconf.txt")) { log_to_screen("/tmp/raidconf.txt does not exist. I therefore cannot start Vinum."); } else { int res; res = run_program_and_log_output("vinum create /tmp/raidconf.txt", TRUE); if (res) { log_to_screen("`vinum create /tmp/raidconf.txt' returned errors. Please fix them and re-run mondorestore."); finish(1); } vinum_started_yet = TRUE; } } if (vinum_started_yet) { FILE *fin; char line[MAX_STR_LEN]; log_to_screen(tmp, "Initializing Vinum device %s (this may take a *long* time)", device); /* format raid partition */ mr_asprintf(program, "for plex in `vinum lv -r %s | grep '^P' | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f2`; do echo $plex; done > /tmp/plexes", basename(device)); paranoid_system(program); if (g_fprep) { fprintf(g_fprep, "%s\n", program); } mr_free(program); fin = fopen("/tmp/plexes", "r"); while (fgets(line, MAX_STR_LEN - 1, fin)) { if (strchr(line, '\n')) *(strchr(line, '\n')) = '\0'; // get rid of the \n on the end mr_asprintf(tmp, "Initializing plex: %s", line); open_evalcall_form(tmp); mr_free(tmp); mr_asprintf(tmp, "vinum init %s", line); paranoid_system(tmp); mr_free(tmp); while (1) { mr_asprintf(tmp, "vinum lp -r %s | grep '^S' | head -1 | tr -s ' ' | cut -d: -f2 | cut -f1 | sed 's/^ //' | sed 's/I //' | sed 's/%%//'", line); FILE *pin = popen(tmp, "r"); mr_free(tmp); char status[MAX_STR_LEN / 4]; if (fgets(status, MAX_STR_LEN / 4 - 1, pin)) { // FIXME } pclose(pin); if (!strcmp(status, "up")) { break; /* it's done */ } update_evalcall_form(atoi(status)); usleep(250000); } close_evalcall_form(); } fclose(fin); unlink("/tmp/plexes"); } #else log_to_screen("Initializing RAID device %s", device); // Shouldn't be necessary. log_to_screen("Stopping %s", device); stop_raid_device(device); paranoid_system("sync"); sleep(1); log_msg(1, "Making %s", device); // use mkraid if it exists, otherwise use mdadm if (run_program_and_log_output("which mkraid", FALSE)) { res = create_raid_device_via_mdadm(raidlist, device, TRUE); log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res); } else { mr_asprintf(program, "mkraid --really-force %s", device); res = run_program_and_log_output(program, 1); log_msg(1, "%s returned %d", program, res); paranoid_system("sync"); sleep(3); start_raid_device(device); if (g_fprep) { fprintf(g_fprep, "%s\n", program); } mr_free(program); } paranoid_system("sync"); sleep(2); #endif paranoid_system("sync"); sleep(1); newtResume(); } if (!strcmp(format, "lvm")) { log_msg(1, "Don't format %s - it's part of an lvm volume", device); return (0); } program = which_format_command_do_i_need(format); mr_asprintf(tmp, "%s %s", program, device); if (strstr(program, "kludge")) { mr_strcat(tmp, " /"); } mr_free(program); mr_asprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp); mr_free(tmp); mr_asprintf(tmp, "Formatting %s as %s", device, format); update_progress_form(tmp); res = run_program_and_log_output(program, FALSE); if (res) { mr_strcat(tmp, "...failed"); } else { mr_strcat(tmp, "...OK"); } log_to_screen(tmp); mr_free(tmp); if (res && strstr(program, "kludge")) { mr_asprintf(tmp, "Kludge failed; using regular mkfs.%s to format %s", format, device); mr_free(program); #ifdef __FreeBSD__ mr_asprintf(program, "newfs_msdos -F 32 %s", device); #else #ifdef __IA64__ /* For EFI or UEFI partitions take fat16 * as we want to make small ones */ mr_asprintf(program, "mkfs -t %s -F 16 %s", format, device); #else mr_asprintf(program, "mkfs -t %s -F 32 %s", format, device); #endif #endif res = run_program_and_log_output(program, FALSE); if (g_fprep) { fprintf(g_fprep, "%s\n", program); } mr_free(program); if (retval) { mr_strcat(tmp, "...failed"); } else { mr_strcat(tmp, "...OK"); } log_to_screen(tmp); mr_free(tmp); } retval += res; paranoid_system("sync"); sleep(1); return (retval); } /** * Format all drives (except those excluded by format_device()) in @p mountlist. * @param mountlist The mountlist containing partitions to be formatted. * @param interactively If TRUE, then prompt the user before each partition. * @return The number of errors encountered (0 for success). */ int format_everything(struct mountlist_itself *mountlist, bool interactively, struct raidlist_itself *raidlist) { /** int **************************************************************/ int retval = 0; int lino; int res; /** long *************************************************************/ long progress_step; /** bools ************************************************************/ bool do_it; /** buffers **********************************************************/ char *tmp = NULL; /** pointers *********************************************************/ struct mountlist_line *me; // mountlist entry /** end **************************************************************/ assert(mountlist != NULL); log_it("format_everything (mountlist, interactively = %s", (interactively) ? "true" : "false"); mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions "); open_progress_form("Formatting partitions", "I am now formatting your hard disk partitions.", "This may take up to five minutes.", "", mountlist->entries + 1); progress_step = (mountlist->entries > 0) ? g_maximum_progress / mountlist->entries : 1; // start soft-raids now (because LVM might depend on them) // ...and for simplicity's sake, let's format them at the same time :) log_msg(1, "Stopping all RAID devices"); stop_all_raid_devices(mountlist); paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); sleep(2); log_msg(1, "Prepare soft-RAIDs"); // prep and format too for (lino = 0; lino < mountlist->entries; lino++) { me = &mountlist->el[lino]; // the current mountlist entry log_msg(2, "Examining %s", me->device); if (!strncmp(me->device, "/dev/md", 7)) { if (interactively) { // ask user if we should format the current device mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint); do_it = ask_me_yes_or_no(tmp); mr_free(tmp); } else { do_it = TRUE; } if (do_it) { // NB: format_device() also stops/starts RAID device if necessary retval += format_device(me->device, me->format, raidlist); } g_current_progress += progress_step; } } paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); sleep(2); // do LVMs now log_msg(1, "Creating LVMs"); if (does_file_exist("/tmp/i-want-my-lvm")) { wait_until_software_raids_are_prepped("/proc/mdstat", 100); log_to_screen("Configuring LVM"); if (!g_text_mode) { newtSuspend(); } res = do_my_funky_lvm_stuff(FALSE, TRUE); if (!g_text_mode) { newtResume(); } if (!res) { log_to_screen("LVM initialized OK"); } else { log_to_screen("Failed to initialize LVM"); } // retval += res; if (res) { retval++; } sleep(3); } // do regulars at last sleep(2); // woo! log_msg(1, "Formatting regulars"); for (lino = 0; lino < mountlist->entries; lino++) { me = &mountlist->el[lino]; // the current mountlist entry if (!strcmp(me->mountpoint, "image")) { log_it("Not formatting %s - it's an image", me->device); } else if (!strcmp(me->format, "raid")) { log_it("Not formatting %s - it's a raid-let", me->device); continue; } else if (!strcmp(me->format, "lvm")) { log_it("Not formatting %s - it's an LVM", me->device); continue; } else if (!strncmp(me->device, "/dev/md", 7)) { log_it("Already formatted %s - it's a soft-RAID dev", me->device); continue; } else if (!does_file_exist(me->device) && strncmp(me->device, "/dev/hd", 7) && strncmp(me->device, "/dev/sd", 7)) { log_it("Not formatting %s yet - doesn't exist - probably an LVM", me->device); continue; } else { if (interactively) { // ask user if we should format the current device mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint); do_it = ask_me_yes_or_no(tmp); mr_free(tmp); } else { do_it = TRUE; } if (do_it) retval += format_device(me->device, me->format, raidlist); } // update progress bar g_current_progress += progress_step; } // update progress bar to 100% to compensate for // rounding errors of the progress_step calculation if (lino >= mountlist->entries) g_current_progress = g_maximum_progress; close_progress_form(); if (retval) { mvaddstr_and_log_it(g_currentY++, 74, "Failed."); log_to_screen("Errors may have occurred during the formatting of your hard drives."); } else { mvaddstr_and_log_it(g_currentY++, 74, "Done."); } log_it("format_everything () - %s", (retval) ? "failed!" : "finished successfully"); if (g_partition_table_locked_up > 0) { if (retval > 0 && !interactively) { //123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 log_to_screen("Partition table locked up %d times. At least one 'mkfs' (format) command", g_partition_table_locked_up); log_to_screen("failed. I think these two events are related. Sometimes, fdisk's ioctl() call"); log_to_screen("to refresh its copy of the partition table causes the kernel to lock the "); log_to_screen("partition table. I believe this has just happened."); if (ask_me_yes_or_no("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue.")) { paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); paranoid_system("reboot"); } } else { log_to_screen("Partition table locked up %d time%c. However, disk formatting succeeded.", g_partition_table_locked_up, (g_partition_table_locked_up == 1) ? '.' : 's'); } } newtSuspend(); paranoid_system("clear"); newtResume(); return (retval); } /** * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename. * Each partition created is 32k in size. * @param drivename The drive to create the dummy partitions on. * @param devno_we_must_allow_for The lowest-numbered real partition; create * dummies up to (this - 1). * @return The number of errors encountered (0 for success). */ int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename, int devno_we_must_allow_for) { /** int **************************************************************/ int current_devno; int previous_devno; int retval = 0; int res; assert_string_is_neither_NULL_nor_zerolength(drivename); if (devno_we_must_allow_for >= 5) { log_it("Making dummy primary 1 on %s", drivename); g_maximum_progress++; res = partition_device(pout_to_fdisk, drivename, 1, 0, "ext2", 32000); retval += res; previous_devno = 1; current_devno = 5; } else { previous_devno = 0; current_devno = 1; } for (; current_devno < devno_we_must_allow_for; current_devno++) { log_it("Creating dummy partition %d on %s", current_devno, drivename); g_maximum_progress++; res = partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, OSSWAP("ext2", "ufs"), 32000); retval += res; previous_devno = current_devno; } return (previous_devno); } /** * Decide whether @p mountlist contains any RAID devices. * @param mountlist The mountlist to examine. * @return TRUE if it does, FALSE if it doesn't. */ bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist) { /** int *************************************************************/ int i; int matching = 0; /** end **************************************************************/ assert(mountlist != NULL); for (i = 0; i < mountlist->entries; i++) { if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) { matching++; } } if (matching) { return (TRUE); } else { return (FALSE); } } /* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */ #ifdef __FreeBSD__ static void display_disklabel(FILE * f, const struct disklabel *lp) { int i, j; const struct partition *pp; fprintf(f, "# %s\n", "Generated by Mondo Rescue"); if (lp->d_type < DKMAXTYPES) fprintf(f, "type: %s\n", dktypenames[lp->d_type]); else fprintf(f, "type: %u\n", lp->d_type); fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename); fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname); fprintf(f, "flags:"); if (lp->d_flags & D_REMOVABLE) fprintf(f, " removeable"); if (lp->d_flags & D_ECC) fprintf(f, " ecc"); if (lp->d_flags & D_BADSECT) fprintf(f, " badsect"); fprintf(f, "\n"); fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize); fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors); fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks); fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl); fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders); fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit); fprintf(f, "rpm: %u\n", lp->d_rpm); fprintf(f, "interleave: %u\n", lp->d_interleave); fprintf(f, "trackskew: %u\n", lp->d_trackskew); fprintf(f, "cylinderskew: %u\n", lp->d_cylskew); fprintf(f, "headswitch: %lu\t\t# milliseconds\n", (u_long) lp->d_headswitch); fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (u_long) lp->d_trkseek); fprintf(f, "drivedata: "); for (i = NDDATA - 1; i >= 0; i--) if (lp->d_drivedata[i]) break; if (i < 0) i = 0; for (j = 0; j <= i; j++) fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]); fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions); fprintf(f, "# size offset fstype [fsize bsize bps/cpg]\n"); pp = lp->d_partitions; for (i = 0; i < lp->d_npartitions; i++, pp++) { if (pp->p_size) { fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size, (u_long) pp->p_offset); if (pp->p_fstype < FSMAXTYPES) fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); else fprintf(f, "%8d", pp->p_fstype); switch (pp->p_fstype) { case FS_UNUSED: /* XXX */ fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), ""); break; case FS_BSDFFS: fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg); break; case FS_BSDLFS: fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg); break; default: fprintf(f, "%20.20s", ""); break; } fprintf(f, "\t# (Cyl. %4lu", (u_long) (pp->p_offset / lp->d_secpercyl)); if (pp->p_offset % lp->d_secpercyl) putc('*', f); else putc(' ', f); fprintf(f, "- %lu", (u_long) ((pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl - 1)); if (pp->p_size % lp->d_secpercyl) putc('*', f); fprintf(f, ")\n"); } } fflush(f); } static struct disklabel *get_virgin_disklabel(char *dkname) { static struct disklabel loclab; struct partition *dp; char *lnamebuf = NULL; int f; u_int secsize, u; off_t mediasize; mr_asprintf(lnamebuf, "%s", dkname); if ((f = open(lnamebuf, O_RDONLY)) == -1) { warn("cannot open %s", lnamebuf); mr_free(lnamebuf); return (NULL); } mr_free(lnamebuf); /* New world order */ if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) { close(f); return (NULL); } memset(&loclab, 0, sizeof loclab); loclab.d_magic = DISKMAGIC; loclab.d_magic2 = DISKMAGIC; loclab.d_secsize = secsize; loclab.d_secperunit = mediasize / secsize; /* * Nobody in these enligthened days uses the CHS geometry for * anything, but nontheless try to get it right. If we fail * to get any good ideas from the device, construct something * which is IBM-PC friendly. */ if (ioctl(f, DIOCGFWSECTORS, &u) == 0) loclab.d_nsectors = u; else loclab.d_nsectors = 63; if (ioctl(f, DIOCGFWHEADS, &u) == 0) loclab.d_ntracks = u; else if (loclab.d_secperunit <= 63 * 1 * 1024) loclab.d_ntracks = 1; else if (loclab.d_secperunit <= 63 * 16 * 1024) loclab.d_ntracks = 16; else loclab.d_ntracks = 255; loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors; loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl; loclab.d_npartitions = MAXPARTITIONS; /* Various (unneeded) compat stuff */ loclab.d_rpm = 3600; loclab.d_bbsize = BBSIZE; loclab.d_interleave = 1;; strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename)); dp = &loclab.d_partitions[RAW_PART]; dp->p_size = loclab.d_secperunit; loclab.d_checksum = dkcksum(&loclab); close(f); return (&loclab); } /* End stolen from /usr/src/sbin/disklabel/disklabel.c. */ char *canonical_name(char *drivename) { if (drivename) { if (strncmp(drivename, "/dev/", 5) == 0) { return drivename + 5; } } return drivename; } /** * (BSD only) Create a disklabel on @p drivename according to @p mountlist. * @param mountlist The mountlist to get the subpartition information from. * @param drivename The drive or slice to create a disklabel on. * @param ret If non-NULL, store the created disklabel here. * @return The number of errors encountered (0 for success). */ int label_drive_or_slice(struct mountlist_itself *mountlist, char *drivename, struct disklabel *ret) { char *subdev_str = NULL; char *command = NULL; struct disklabel *lp; int i, lo = 0; int retval = 0; char c; FILE *ftmp; lp = get_virgin_disklabel(drivename); for (c = 'a'; c <= 'z'; ++c) { int idx; mr_asprintf(subdev_str, "%s%c", drivename, c); if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) { lp->d_partitions[c - 'a'].p_size = 0; lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED; } else { lo = c - 'a'; lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2; lp->d_partitions[c - 'a'].p_fsize = 0; lp->d_partitions[c - 'a'].p_frag = 0; lp->d_partitions[c - 'a'].p_cpg = 0; if (!strcmp(mountlist->el[idx].format, "ufs") || !strcmp(mountlist->el[idx].format, "ffs") || !strcmp(mountlist->el[idx].format, "4.2BSD")) { lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS; lp->d_partitions[c - 'a'].p_fsize = 2048; lp->d_partitions[c - 'a'].p_frag = 8; lp->d_partitions[c - 'a'].p_cpg = 64; } else if (!strcasecmp(mountlist->el[idx].format, "raid") || !strcasecmp(mountlist->el[idx].format, "vinum")) { lp->d_partitions[c - 'a'].p_fstype = FS_VINUM; } else if (!strcmp(mountlist->el[idx].format, "swap")) { lp->d_partitions[c - 'a'].p_fstype = FS_SWAP; } else lp->d_partitions[c - 'a'].p_fstype = FS_OTHER; } mr_free(subdev_str); } // fix up the offsets lp->d_partitions[0].p_offset = 0; lp->d_partitions[RAW_PART].p_offset = 0; lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; for (i = 1; i < lp->d_npartitions; ++i) { int lastone; if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0)) continue; for (lastone = i - 1; lastone >= 0; lastone--) { if ((lp->d_partitions[lastone].p_size) && (lastone != RAW_PART)) break; } lp->d_partitions[i].p_offset = lp->d_partitions[lastone].p_offset + lp->d_partitions[lastone].p_size; } if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size > lp->d_secperunit) { lp->d_partitions[lo].p_size = lp->d_secperunit - lp->d_partitions[lo].p_offset; } ftmp = fopen("/tmp/disklabel", "w"); display_disklabel(ftmp, lp); fclose(ftmp); mr_asprintf(command, "disklabel -wr %s auto", canonical_name(drivename)); retval += run_program_and_log_output(command, TRUE); mr_free(command); mr_asprintf(command, "disklabel -R %s /tmp/disklabel", canonical_name(drivename)); retval += run_program_and_log_output(command, TRUE); mr_free(command); if (ret) *ret = *lp; return retval; } #endif /** * Partition @p drivename based on @p mountlist. * @param mountlist The mountlist to use to guide the partitioning. * @param drivename The drive to partition. * @return 0 for success, nonzero for failure. */ int partition_drive(struct mountlist_itself *mountlist, char *drivename) { /** int *************************************************************/ int current_devno; int previous_devno = 0; int lino; int retval = 0; int i; FILE *pout_to_fdisk = NULL; #ifdef __FreeBSD__ bool fbsd_part = FALSE; char *subdev_str = NULL; #endif /** long long *******************************************************/ long long partsize; /** buffers *********************************************************/ char *device_str; char *format = NULL; char *tmp = NULL; char *tmp1 = NULL; /** end *************************************************************/ assert(mountlist != NULL); assert_string_is_neither_NULL_nor_zerolength(drivename); log_it("Partitioning drive %s", drivename); #if __FreeBSD__ log_it("(Not opening fdisk now; that's the Linux guy's job)"); pout_to_fdisk = NULL; #else make_hole_for_file(FDISK_LOG); mr_asprintf(tmp, "mr-parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG); pout_to_fdisk = popen(tmp, "w"); if (!pout_to_fdisk) { log_to_screen("Cannot call mr-parted2fdisk to configure %s", drivename); mr_free(tmp); return (1); } mr_free(tmp); #endif malloc_string(device_str); for (current_devno = 1; current_devno < 99; current_devno++) { build_partition_name(device_str, drivename, current_devno); lino = find_device_in_mountlist(mountlist, device_str); if (lino < 0) { // device not found in mountlist #if __FreeBSD__ // If this is the first partition (just as a sentinel value), // then see if the user has picked 'dangerously-dedicated' mode. // If so, then we just call label_drive_or_slice() and return. char c; if (current_devno == 1) { // try DangerouslyDedicated mode for (c = 'a'; c <= 'z'; c++) { mr_asprintf(subdev_str, "%s%c", drivename, c); if (find_device_in_mountlist(mountlist, subdev_str) > 0) { fbsd_part = TRUE; } mr_free(subdev_str); } if (fbsd_part) { int r = label_drive_or_slice(mountlist, drivename, 0); char command[MAX_STR_LEN]; sprintf(command, "disklabel -B %s", basename(drivename)); if (system(command)) { log_to_screen ("Warning! Unable to make the drive bootable."); } paranoid_free(device_str); return r; } } for (c = 'a'; c <= 'z'; c++) { mr_assprintf(subdev_str, "%s%c", device_str, c); if (find_device_in_mountlist(mountlist, subdev_str) > 0) { fbsd_part = TRUE; } mr_free(subdev_str); } // Now we check the subpartitions of the current partition. if (fbsd_part) { int i, line; mr_asprintf(format, "ufs"); partsize = 0; for (i = 'a'; i < 'z'; ++i) { mr_asprintf(subdev_str, "%s%c", device_str, i); line = find_device_in_mountlist(mountlist, subdev_str); mr_free(subdev_str); if (line > 0) { // We found one! Add its size to the total size. partsize += mountlist->el[line].size; } } } else { continue; } #else continue; #endif } /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */ /* For FreeBSD, that is /dev/adXsY */ log_it("Found partition %s in mountlist", device_str); if (!previous_devno) { log_it("Wiping %s's partition table", drivename); #if __FreeBSD__ // FreeBSD doesn't let you write to blk devices in <512byte chunks. file = open(drivename, O_WRONLY); if (file != -1) { log_to_screnn("Warning - unable to open %s for wiping it's partition table", drivename); } for (i = 0; i < 512; i++) { if (!write(file, "\0", 1)) { log_to_screen("Warning - unable to write to %s", drivename); } } paranoid_system("sync"); #else log_it("New, kernel-friendly partition remover"); for (i = 20; i > 0; i--) { fprintf(pout_to_fdisk, "d\n%d\n", i); fflush(pout_to_fdisk); } #endif if (current_devno > 1) { previous_devno = make_dummy_partitions(pout_to_fdisk, drivename, current_devno); } } #ifdef __FreeBSD__ if (!fbsd_part) { mr_free(format); #endif mr_asprintf(format, "%s", mountlist->el[lino].format); partsize = mountlist->el[lino].size; #ifdef __FreeBSD__ } #endif #ifndef __IA64__ if (current_devno == 5 && previous_devno == 4) { log_to_screen("You must leave at least one partition spare as the Extended partition."); paranoid_free(device_str); mr_free(format); return (1); } #endif retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize); mr_free(format); #ifdef __FreeBSD__ if ((current_devno <= 4) && fbsd_part) { mr_asprintf(tmp, "disklabel -B %s", basename(device_str)); retval += label_drive_or_slice(mountlist, device_str, 0); if (system(tmp)) { log_to_screen("Warning! Unable to make the slice bootable."); } mr_free(tmp); } #endif previous_devno = current_devno; } if (pout_to_fdisk) { // close fdisk fput_string_one_char_at_a_time(pout_to_fdisk, "p\n"); fput_string_one_char_at_a_time(pout_to_fdisk, "w\n"); paranoid_pclose(pout_to_fdisk); paranoid_system("sync"); log_msg(0,"------------------- fdisk.log looks like this ------------------"); mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE); paranoid_system(tmp); mr_free(tmp); // mark relevant partition as bootable mr_asprintf(tmp1,"make-me-bootable /tmp/mountlist.txt %s",drivename); call_program_and_get_last_line_of_output(tmp1); mr_free(tmp1); log_msg(0,"------------------- end of fdisk.log... ------------------"); paranoid_system("sync"); mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG); if (!run_program_and_log_output(tmp, 5)) { g_partition_table_locked_up++; } mr_free(tmp); mr_asprintf(tmp, "partprobe %s", drivename); if (!run_program_and_log_output(tmp, 5)) { g_partition_table_locked_up--; } mr_free(tmp); if (g_partition_table_locked_up > 0) { log_to_screen("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-("); } } paranoid_free(device_str); return (retval); } /** * Create partition number @p partno on @p drive with @p fdisk. * @param drive The drive to create the partition on. // * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical). * @param prev_partno The partition number of the most recently prepped partition. * @param format The filesystem type of this partition (used to set the type). * @param partsize The size of the partition in @e bytes. * @return 0 for success, nonzero for failure. */ int partition_device(FILE * pout_to_fdisk, const char *drive, int partno, int prev_partno, const char *format, long long partsize) { /** int **************************************************************/ int retval = 0; int res = 0; /** buffers **********************************************************/ char *program = NULL; char *partition_name; char *tmp = NULL; char *output = NULL; /** pointers **********************************************************/ char *part_table_fmt = NULL; FILE *fout; /** end ***************************************************************/ assert_string_is_neither_NULL_nor_zerolength(drive); assert(format != NULL); log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting", drive, partno, prev_partno, format, partsize); if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) { log_it("Not partitioning %s - it is a virtual drive", drive); return (0); } malloc_string(partition_name); build_partition_name(partition_name, drive, partno); if (partsize <= 0) { mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name); } else { mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024); } update_progress_form(tmp); log_it(tmp); mr_free(tmp); if (is_this_device_mounted(partition_name)) { log_to_screen("%s is mounted, and should not be partitioned", partition_name); paranoid_free(partition_name); return (1); } mr_asprintf(program, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE); /* TODO: should not be called each time */ part_table_fmt = which_partition_format(drive); mr_asprintf(output, ""); /* make it a primary/extended/logical */ if (partno <= 4) { mr_strcat(output, "n\np\n%d\n", partno); } else { /* MBR needs an extended partition if more than 4 partitions */ if (strcmp(part_table_fmt, "MBR") == 0) { if (partno == 5) { if (prev_partno >= 4) { log_to_screen("You need to leave at least one partition free, for 'extended/logical'"); paranoid_free(partition_name); paranoid_free(output); return (1); } else { mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1); } } mr_strcat(output, "n\nl\n"); } else { /* GPT allows more than 4 primary partitions */ mr_strcat(output, "n\np\n%d\n", partno); } } mr_free(part_table_fmt); mr_strcat(output, "\n"); /*start block (ENTER for next free blk */ if (partsize > 0) { if (!strcmp(format, "7")) { log_msg(1, "Adding 512K, just in case"); partsize += 512; } mr_strcat(output, "+%lldK", (long long) (partsize)); } mr_strcat(output, "\n"); #if 0 /* #endif log_it("PARTSIZE = +%ld",(long)partsize); log_it("---fdisk command---"); log_it(output); log_it("---end of fdisk---"); #if 0 */ #endif if (pout_to_fdisk) { log_msg(1, "Doing the new all-in-one fdisk thing"); log_msg(1, "output = '%s'", output); fput_string_one_char_at_a_time(pout_to_fdisk, output); fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n"); mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG)); if (strstr(tmp, " (m ")) { log_msg(1, "Successfully created partition %d on %s", partno, drive); } else { log_msg(1, "last line = %s", tmp); log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive); } mr_free(tmp); if (!retval) { log_msg(1, "Trying to set partition %d type now on %s", partno, drive); retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize); if (retval) { log_msg(1, "Failed. Trying again..."); retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize); } } if (retval) { log_msg(1, "...but failed to set type"); } } else { mr_strcat(output, "w\n\n"); if (g_fprep) { fprintf(g_fprep, "echo \"%s\" | %s\n", output, program); } /* write to disk; close fdisk's stream */ if (!(fout = popen(program, "w"))) { log_OS_error("can't popen-out to program"); } else { fputs(output, fout); paranoid_pclose(fout); } if (!does_partition_exist(drive, partno) && partsize > 0) { log_it("Vaccum-packing"); g_current_progress--; res = partition_device(pout_to_fdisk, drive, partno, prev_partno, format, -1); if (res) { log_it("Failed to vacuum-pack %s", partition_name); retval++; } else { retval = 0; } } if (does_partition_exist(drive, partno)) { retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize); if (retval) { log_it("Partitioned %s but failed to set its type", partition_name); } else { if (partsize > 0) { log_to_screen("Partition %s created+configured OK", partition_name); } else { log_it("Returning from a successful vacuum-pack"); } } } else { mr_asprintf(tmp, "Failed to partition %s", partition_name); if (partsize > 0) { log_to_screen(tmp); } else { log_it(tmp); } mr_free(tmp); retval++; } } mr_free(program); paranoid_free(output); g_current_progress++; log_it("partition_device() --- leaving"); paranoid_free(partition_name); return (retval); } /** * Create all partitions listed in @p mountlist. * @param mountlist The mountlist to use to guide the partitioning. * @return The number of errors encountered (0 for success). * @note This sets the partition types but doesn't actually do the formatting. * Use format_everything() for that. */ int partition_everything(struct mountlist_itself *mountlist) { /** int ************************************************************/ int lino; int retval = 0; int i; int res; /** buffer *********************************************************/ struct list_of_disks *drivelist; /** end ************************************************************/ drivelist = malloc(sizeof(struct list_of_disks)); assert(mountlist != NULL); log_it("partition_everything() --- starting"); mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives "); if (mountlist_contains_raid_devices(mountlist)) { log_msg(0, "Mountlist, including the partitions incorporated in RAID devices:-"); for (i = 0; i < mountlist->entries; i++) { log_it(mountlist->el[i].device); } log_msg(0, "End of mountlist."); } log_msg(0, "Stopping all LVMs, just in case"); if (!g_text_mode) { newtSuspend(); } do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions if (!g_text_mode) { newtResume(); } log_msg(0, "Stopping all software RAID devices, just in case"); stop_all_raid_devices(mountlist); log_msg(0, "Done."); open_progress_form("Partitioning devices", "I am now going to partition all your drives.", "This should not take more than five minutes.", "", mountlist->entries); make_list_of_drives_in_mountlist(mountlist, drivelist); /* partition each drive */ for (lino = 0; lino < drivelist->entries; lino++) { res = partition_drive(mountlist, drivelist->el[lino].device); retval += res; } close_progress_form(); if (retval) { mvaddstr_and_log_it(g_currentY++, 74, "Failed."); log_to_screen("Errors may have occurred during the partitioning of your hard drives."); } else { mvaddstr_and_log_it(g_currentY++, 74, "Done."); paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null"); } newtSuspend(); paranoid_system("clear"); newtResume(); paranoid_free(drivelist); return (retval); } /** * Set the type of partition number @p partno on @p drive to @p format. * @param drive The drive to change the type of a partition on. * @param partno The partition number on @p drive to change the type of. * @param format The filesystem type this partition will eventually contain. * @param partsize The size of this partition, in @e bytes (used for vfat * type calculations). * @return 0 for success, nonzero for failure. */ int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno, const char *format, long long partsize) { /** buffers *********************************************************/ char *partition; char *command = NULL; char *output = NULL; char *tmp = NULL; char *partcode = NULL; /** pointers *********************************************************/ FILE *fout; /** int **************************************************************/ int res = 0; /** end **************************************************************/ assert_string_is_neither_NULL_nor_zerolength(drive); assert(format != NULL); malloc_string(partition); build_partition_name(partition, drive, partno); if (strcmp(format, "swap") == 0) { mr_asprintf(partcode, "82"); } else if (strcmp(format, "vfat") == 0) { if (partsize / 1024 > 8192) { mr_asprintf(partcode, "c"); } else { mr_asprintf(partcode, "b"); } } else if (strcmp(format, "ext2") == 0 || strcmp(format, "reiserfs") == 0 || strcmp(format, "ext3") == 0 || strcmp(format, "ext4") == 0 || strcmp(format, "xfs") == 0 || strcmp(format, "jfs") == 0 || strcmp(format, "btrfs") == 0) { mr_asprintf(partcode, "83"); } else if (strcmp(format, "minix") == 0) { mr_asprintf(partcode, "81"); } else if (strcmp(format, "vmfs3") == 0) { mr_asprintf(partcode, "fb"); } else if (strcmp(format, "vmkcore") == 0) { mr_asprintf(partcode, "fc"); } else if (strcmp(format, "raid") == 0) { mr_asprintf(partcode, "fd"); } else if (strcmp(format, "ntfs") == 0) { mr_asprintf(partcode, "7"); } else if ((strcmp(format, "ufs") == 0) || (strcmp(format, "ffs") == 0)) { /* raid autodetect */ mr_asprintf(partcode, "a5"); } else if (strcmp(format, "lvm") == 0) { mr_asprintf(partcode, "8e"); } else if (format[0] == '\0') { /* LVM physical partition */ mr_asprintf(partcode, ""); } else if (strlen(format) >= 1 && strlen(format) <= 2) { mr_asprintf(partcode, format); } else { /* probably an image */ mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format); mvaddstr_and_log_it(g_currentY++, 0, tmp); mr_free(tmp); #ifdef __FreeBSD__ mr_asprintf(partcode, format); // was a5 #else mr_asprintf(partcode, format); // was 83 #endif } log_msg(1, "Setting %s's type to %s (%s)", partition, format, partcode); if ((strcmp(partcode,"") != 0) && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */ if (pout_to_fdisk) { res = 0; fput_string_one_char_at_a_time(pout_to_fdisk, "t\n"); if (partno > 1 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) { log_msg(5, "Specifying partno (%d) - yay", partno); mr_asprintf(tmp, "%d\n", partno); fput_string_one_char_at_a_time(pout_to_fdisk, tmp); log_msg(5, "A - last line = '%s'", last_line_of_file(FDISK_LOG)); mr_free(tmp); } mr_asprintf(tmp, "%s\n", partcode); fput_string_one_char_at_a_time(pout_to_fdisk, tmp); mr_free(tmp); log_msg(5, "B - last line = '%s'", last_line_of_file(FDISK_LOG)); fput_string_one_char_at_a_time(pout_to_fdisk, "\n"); log_msg(5, "C - last line = '%s'", last_line_of_file(FDISK_LOG)); mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG)); if (!strstr(tmp, " (m ")) { log_msg(1, "last line = '%s'; part type set failed", tmp); res++; fput_string_one_char_at_a_time(pout_to_fdisk, "\n"); } mr_free(tmp); fput_string_one_char_at_a_time(pout_to_fdisk, "p\n"); } else { mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode); mr_asprintf(command, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE); log_msg(5, "output = '%s'", output); log_msg(5, "partno=%d; partcode=%s", partno, partcode); log_msg(5, "command = '%s'", command); fout = popen(command, "w"); if (!fout) { log_OS_error(command); res = 1; } else { res = 0; fprintf(fout, "%s", output); paranoid_pclose(fout); } mr_free(command); paranoid_free(output); } } mr_free(partcode); paranoid_free(partition); return (res); } int start_raid_device(char *raid_device) { /** int *************************************************************/ int res; int retval = 0; /** buffers *********************************************************/ char *program = NULL; /** end *************************************************************/ assert_string_is_neither_NULL_nor_zerolength(raid_device); #ifdef __FreeBSD__ if (is_this_device_mounted(raid_device)) { log_it("Can't start %s when it's mounted!", raid_device); return 1; } mr_asprintf(program, "vinum start -f %s", raid_device); #else mr_asprintf(program, "raidstart %s", raid_device); #endif log_msg(1, "program = %s", program); res = run_program_and_log_output(program, 1); if (g_fprep) { fprintf(g_fprep, "%s\n", program); } mr_free(program); if (res) { log_msg(1, "Warning - failed to start RAID device %s", raid_device); } retval += res; sleep(1); return (retval); } /** * Stop @p raid_device using @p raidstop. * @param raid_device The software RAID device to stop. * @return 0 for success, nonzero for failure. */ int stop_raid_device(char *raid_device) { /** int *************************************************************/ int res; int retval = 0; /** buffers *********************************************************/ char *program = NULL; /** end *************************************************************/ assert_string_is_neither_NULL_nor_zerolength(raid_device); #ifdef __FreeBSD__ if (is_this_device_mounted(raid_device)) { log_it("Can't stop %s when it's mounted!", raid_device); return 1; } mr_asprintf(program, "vinum stop -f %s", raid_device); #else // use raidstop if it exists, otherwise use mdadm if (run_program_and_log_output("which raidstop", FALSE)) { mr_asprintf(program, "mdadm -S %s", raid_device); } else { mr_asprintf(program, "raidstop %s", raid_device); } #endif log_msg(1, "program = %s", program); res = run_program_and_log_output(program, 1); if (g_fprep) { fprintf(g_fprep, "%s\n", program); } mr_free(program); if (res) { log_msg(1, "Warning - failed to stop RAID device %s", raid_device); } retval += res; return (retval); } int start_all_raid_devices(struct mountlist_itself *mountlist) { int i; int retval = 0; int res; for (i = 0; i < mountlist->entries; i++) { if (!strncmp(mountlist->el[i].device, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) { log_msg(1, "Starting %s", mountlist->el[i].device); res = start_raid_device(mountlist->el[i].device); retval += res; } } if (retval) { log_msg(1, "Started all s/w raid devices OK"); } else { log_msg(1, "Failed to start some/all s/w raid devices"); } return (retval); } /** * Stop all software RAID devices listed in @p mountlist. * @param mountlist The mountlist to stop the RAID devices in. * @return The number of errors encountered (0 for success). * @bug @p mountlist is not used. */ int stop_all_raid_devices(struct mountlist_itself *mountlist) { /** int *************************************************************/ int retval = 0; /** char ************************************************************/ char *incoming; #ifndef __FreeBSD__ char *dev; #endif /** pointers ********************************************************/ #ifndef __FreeBSD__ char *p; #endif FILE *fin; char *q; int i; /** end ****************************************************************/ malloc_string(incoming); assert(mountlist != NULL); for (i = 0; i < 3; i++) { #ifdef __FreeBSD__ fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r"); if (!fin) { paranoid_free(incoming); return (1); } for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) { retval += stop_raid_device(incoming); } #else fin = fopen("/proc/mdstat", "r"); if (!fin) { log_OS_error("/proc/mdstat"); paranoid_free(incoming); return (1); } for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) { for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++); if (*p != '\0') { malloc_string(dev); sprintf(dev, "/dev/%s", p); for (p = dev; *p > 32; p++); *p = '\0'; retval += stop_raid_device(dev); paranoid_free(dev); } } #endif } paranoid_fclose(fin); if (retval) { log_msg(1, "Warning - unable to stop some RAID devices"); } paranoid_free(incoming); paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync"); sleep(1); return (retval); } /** * Decide which command we need to use to format a device of type @p format. * @param format The filesystem type we are about to format. * @param program Where to put the binary name for this format. * @return 0 for success, nonzero for failure. */ char *which_format_command_do_i_need(char *format) { char *program = NULL; assert_string_is_neither_NULL_nor_zerolength(format); if (strcmp(format, "swap") == 0) { #ifdef __FreeBSD__ mr_asprintf(program, "true"); #else mr_asprintf(program, "mkswap"); #endif } else if (strcmp(format, "vfat") == 0) { mr_asprintf(program, "format-and-kludge-vfat"); #ifndef __FreeBSD__ } else if (strcmp(format, "reiserfs") == 0) { mr_asprintf(program, "mkreiserfs -ff"); } else if (strcmp(format, "xfs") == 0) { mr_asprintf(program, "mkfs.xfs -f -q"); } else if (strcmp(format, "jfs") == 0) { mr_asprintf(program, "mkfs.jfs"); } else if (strcmp(format, "ext3") == 0) { mr_asprintf(program, "mkfs -t ext3 -F -q"); } else if (strcmp(format, "ext4") == 0) { mr_asprintf(program, "mkfs -t ext4 -F -q"); } else if (strcmp(format, "btrfs") == 0) { mr_asprintf(program, "mkfs.btrfs"); } else if (strcmp(format, "minix") == 0) { mr_asprintf(program, "mkfs.minix"); } else if (strcmp(format, "vmfs") == 0) { mr_asprintf(program, "mkfs -t vmfs"); } else if (strcmp(format, "ntfs") == 0) { /* * mkfs.ntfs treats the '-c' switch as 'specify cluster size' * so the default "mkfs -t %s -c" command structure fails */ mr_asprintf(program, "mkfs -t ntfs"); } else if (strcmp(format, "ocfs2") == 0) { /* * For existing OCFS2 volumes, mkfs.ocfs2 ensures the volume is not mounted on any node in the cluster before formatting. For that to work, mkfs.ocfs2 expects the O2CB cluster service to be running. Specify this option to disable this check. * */ mr_asprintf(program, "mkfs -t ocfs2 -F"); #endif } else if (strcmp(format, "ext2") == 0) { mr_asprintf(program, "mke2fs -F -q"); } else { #ifdef __FreeBSD__ mr_asprintf(program, "newfs_%s", format); #else mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks #endif log_it("Unknown format (%s) - assuming '%s' will do", format, program); } return(program); } /** * Resize a drive's entries in @p mountlist proportionately to fit its new size. * There are a few problems with this function: * - It won't work if there was any unallocated space on the user's hard drive * when it was backed up. * - It won't work if the user's hard drive lies about its size (more common * than you'd think). * * @param mountlist The mountlist to use for resizing @p drive_name. * @param drive_name The drive to resize. */ void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist, char *drive_name) { /**buffers **********************************************************/ char *tmp = NULL; /** int *************************************************************/ int partno, lastpart; /** float ***********************************************************/ float factor; long long new_size; /** long *************************************************************/ long long newsizL = 0LL; long long totalsizL = 0LL; long long current_size_of_drive = 0LL; /* use KB interally for precision */ long long original_size_of_drive = 0LL; /* use KB interally for precision */ struct mountlist_reference *drivemntlist; /** structures *******************************************************/ /** end **************************************************************/ assert(mountlist != NULL); assert_string_is_neither_NULL_nor_zerolength(drive_name); if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) { if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB)) == 0) { return; } } current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL; if (current_size_of_drive <= 0LL) { log_it("Not resizing to match %s - can't find drive", drive_name); return; } log_to_screen("Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024); drivemntlist = malloc(sizeof(struct mountlist_reference)); drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES); if (!drivemntlist) { fatal_error("Cannot malloc temporary mountlist\n"); } create_mountlist_for_drive(mountlist, drive_name, drivemntlist); for (partno = 0; partno < drivemntlist->entries; partno++) { if (drivemntlist->el[partno]->size > 0LL) { /* Keep KB here */ original_size_of_drive += drivemntlist->el[partno]->size; } } if (original_size_of_drive <= 0LL) { log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name); return; } factor = ((float)current_size_of_drive/(float)original_size_of_drive); log_to_screen("Disk %s was %lld MB; is now %lld MB; Proportionally resizing partitions (factor ~= %.5f)", drive_name, original_size_of_drive/1024, current_size_of_drive/1024, factor); lastpart = drivemntlist->entries - 1; for (partno = 0; partno < drivemntlist->entries; partno++) { /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */ if (!atoi(drivemntlist->el[partno]->format)) { new_size = (long long)((drivemntlist->el[partno]->size) * factor); } else { new_size = drivemntlist->el[partno]->size; } if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) { log_msg(1, "Skipping %s (%s) because it's an image", drivemntlist->el[partno]->device, drivemntlist->el[partno]->mountpoint); } newsizL = new_size; /* Do not apply the factor if partition was of negative size */ if (newsizL < 0LL) { newsizL = drivemntlist->el[partno]->size; } totalsizL += newsizL; log_to_screen("Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL); drivemntlist->el[partno]->size = newsizL; } // Ensures over-allocation alert and prompt for interactive mode does not happen if (totalsizL > current_size_of_drive) { mr_asprintf(tmp, "Last partition size calculated would be over-allocated, reducing %s from %lld KB to %lld KB.", drivemntlist->el[lastpart]->device, drivemntlist->el[lastpart]->size, drivemntlist->el[lastpart]->size - (totalsizL - current_size_of_drive)); drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive); } else if (totalsizL < current_size_of_drive) { mr_asprintf(tmp, "Last partition size calculated would be under-allocated, increasing %s from %lld KB to %lld KB.",drivemntlist->el[lastpart]->device, drivemntlist->el[lastpart]->size, drivemntlist->el[lastpart]->size + (current_size_of_drive - totalsizL)); drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL); } log_to_screen(tmp); mr_free(tmp); log_to_screen("final_size = %lld MB", current_size_of_drive / 1024); } /** * Resize all partitions in @p mountlist proportionately (each one * grows or shrinks by the same percentage) to fit them into the new * drives (presumably different from the old ones). * @param mountlist The mountlist to resize the drives in. */ void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist) { /** buffers *********************************************************/ struct list_of_disks *drivelist; /** int *************************************************************/ int driveno; /** end *************************************************************/ drivelist = malloc(sizeof(struct list_of_disks)); assert(mountlist != NULL); if (g_mountlist_fname[0] == '\0') { log_it("resize_mountlist_prop...() - warning - mountlist fname is blank"); log_it("That does NOT affect the functioning of this subroutine."); log_it("--- Hugo, 2002/11/20"); } log_it("Resizing mountlist"); make_list_of_drives_in_mountlist(mountlist, drivelist); log_it("Back from MLoDiM"); for (driveno = 0; driveno < drivelist->entries; driveno++) { resize_drive_proportionately_to_suit_new_drives(mountlist, drivelist->el[driveno].device); } log_to_screen("Mountlist adjusted to suit current hard drive(s)"); paranoid_free(drivelist); } /** * Create a mountlist_reference structure for @p drive_name in @p mountlist. * @param mountlist The complete mountlist to get the drive references from. * @param drive_name The drive to put in @p drivemntlist. * @param drivemntlist The mountlist_reference structure to put the drive's entries in. * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller. * @author Ralph Grewe */ void create_mountlist_for_drive(struct mountlist_itself *mountlist, char *drive_name, struct mountlist_reference *drivemntlist) { int partno; char *tmp_drive_name, *c; assert(mountlist != NULL); assert(drive_name != NULL); assert(drivemntlist != NULL); log_msg(1, "Creating list of partitions for drive %s", drive_name); tmp_drive_name = strdup(drive_name); if (!tmp_drive_name) fatal_error("Out of memory"); /* devfs devices? */ c = strrchr(tmp_drive_name, '/'); if (c && strncmp(c, "/disc", 5) == 0) { /* yup its devfs, change the "disc" to "part" so the existing code works */ strcpy(c + 1, "part"); } drivemntlist->entries = 0; for (partno = 0; partno < mountlist->entries; partno++) { if (strncmp(mountlist->el[partno].device, tmp_drive_name, strlen(tmp_drive_name)) == 0) { drivemntlist->el[drivemntlist->entries] = &mountlist->el[partno]; drivemntlist->entries++; } } if (tmp_drive_name) free(tmp_drive_name); } /* @} - end of prepGroup */