source: MondoRescue/branches/3.2/mondo/src/mondorestore/mondo-prep.c@ 3448

Last change on this file since 3448 was 3448, checked in by Bruno Cornec, 9 years ago
  • Fix a typo in mondo-prep
  • is_this_device_mounted now call mr-device-mounted (a perl rewrite and improvement of this function)
  • Property svn:keywords set to Id
File size: 70.5 KB
RevLine 
[1]1/***************************************************************************
[2052]2$Id: mondo-prep.c 3448 2015-08-30 00:35:24Z bruno $
[2211]3* Functions for prepping hard drives: partitioning, formatting, etc.
4*/
[1]5
6
[1930]7#include "my-stuff.h"
[2211]8#include "mr_mem.h"
[1]9#include "../common/mondostructures.h"
10#include "mondoprep.h"
11#include "../common/libmondo.h"
[2928]12#include "../common/libmondo-tools-EXT.h"
[1]13#include "mondo-rstr-tools-EXT.h"
14#include <sys/ioctl.h>
15#include <linux/hdreg.h>
16#include <math.h>
17
18
[2192]19#define FDISK_LOG "/var/log/mondofdisk.log"
[1]20
21#ifdef __FreeBSD__
22#define DKTYPENAMES
23#define FSTYPENAMES
24#include <sys/disklabel.h>
25#include <sys/disk.h>
26#include <err.h>
27#include <libgen.h>
28#define OSSWAP(x,y) y
29#else
30#define OSSWAP(x,y) x
31#endif
32
33#define ARCHIVES_PATH MNT_CDROM"/archives"
34#define MONDO_WAS_HERE "MONDOWOZEREMONDOWOZEREMONDOWOZEREhahahaMOJOJOJO"
35
[71]36//static char cvsid[] = "$Id: mondo-prep.c 3448 2015-08-30 00:35:24Z bruno $";
[1]37
38extern char *g_mountlist_fname;
39extern long g_current_progress, g_maximum_progress;
40
41extern bool g_text_mode;
42
[128]43extern void pause_for_N_seconds(int, char *);
[1316]44extern char *MONDO_LOGFILE;
[1]45
[128]46FILE *g_fprep = NULL;
[3292]47extern char *g_mondo_cfg_file; // where mondorestore.cfg (the config file) is stored
[1]48
[128]49int g_partition_table_locked_up = 0;
[1]50
51
52
[3286]53void wipe_MBRs_and_reboot_if_necessary(struct mountlist_itself *mountlist) {
54
55char *command = NULL;
56int lino;
57int i;
58FILE *fout;
59char *buf;
60const int blocksize = 512;
61struct list_of_disks *drivelist = NULL;
62
[1]63// If LVMs are present and a zero-and-reboot wasn't recently undertaken
64// then zero & insist on reboot.
[3286]65buf = malloc(blocksize);
66if (does_file_exist("/tmp/i-want-my-lvm")) { // FIXME - cheating :)
67 drivelist = malloc(sizeof(struct list_of_disks));
68 make_list_of_drives_in_mountlist(mountlist, drivelist);
69 for (lino = 0; lino < drivelist->entries; lino++) {
70 mr_asprintf(command, "dd if=%s bs=512 count=1 2> /dev/null | grep \"%s\"", drivelist->el[lino].device, MONDO_WAS_HERE);
71 if (!run_program_and_log_output(command, 1)) {
72 log_msg(1, "Found MONDO_WAS_HERE marker on drive#%d (%s)", lino, drivelist->el[lino].device);
73 break;
74 }
75 mr_free(command);
76 }
77
78 if (lino == drivelist->entries) {
79 // zero & reboot
80 log_to_screen("I am sorry for the inconvenience but I must ask you to reboot.");
81 log_to_screen("I need to reset the Master Boot Record; in order to be");
82 log_to_screen("sure the kernel notices, I must reboot after doing it.");
83 log_to_screen("Please hit 'Enter' to reboot.");
[128]84 for (lino = 0; lino < drivelist->entries; lino++) {
[3286]85 for (i = 0; i < blocksize; i++) {
86 buf[i] = 0;
[128]87 }
[3286]88 sprintf(buf, "%s\n", MONDO_WAS_HERE);
89 fout = fopen(drivelist->el[lino].device, "w+");
90 if (!fout) {
91 log_msg(1, "Unable to open+wipe %s", drivelist->el[lino].device);
92 } else {
93 if (1 != fwrite(buf, blocksize, 1, fout)) {
94 log_msg(1, "Failed to wipe %s", drivelist->el[lino].device);
[128]95 } else {
[3286]96 log_msg(1, "Successfully wiped %s", drivelist->el[lino].device);
[128]97 }
[3286]98 fclose(fout);
[128]99 }
100 }
[3286]101 paranoid_system("sync");
102 paranoid_system("sync");
103 paranoid_system("sync");
104 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.");
105 paranoid_system("reboot");
[128]106 }
[3286]107}
[1]108// Still here? Cool!
[3286]109log_msg(1, "Cool. I didn't have to wipe anything.");
[1]110}
111
112
[3286]113int fput_string_one_char_at_a_time(FILE * fout, char *str) {
114int i, j;
115FILE *fq;
[1]116
[3286]117if (ferror(fout)) {
118 return (-1);
119}
120log_msg(5, "Writing string '%s', one char at a time", str);
121j = strlen(str);
122for (i = 0; i < j; i++) {
123 log_msg(6, "Writing %d ('%c')", str[i], str[i]);
124 if ((fq = fopen(FDISK_LOG, "a+"))) {
125 fputc(str[i], fq);
126 fclose(fq);
[128]127 }
[3286]128 fputc(str[i], fout);
129 fflush(fout);
130 usleep(1000L * 100L);
131 if (str[i] < 32) {
132 usleep(1000L * 10L);
[128]133 }
[3286]134}
135log_msg(5, "Returning");
[128]136
[3286]137return (i);
[1]138}
139
140
141/**
142 * @addtogroup prepGroup
143 * @{
144 */
145/**
146 * Execute the commands in /tmp/i-want-my-lvm.
147 * These should probably be commands to set up LVM.
148 * @return The number of errors encountered (0 for success).
149 */
150
[3286]151int do_my_funky_lvm_stuff(bool just_erase_existing_volumes, bool vacuum_pack) {
152/** buffers **********************************************/
153char *tmp;
154char *tmp1 = NULL;
155char *incoming;
156char *command;
157char *cmd = NULL;
158char *lvscan_sz = NULL;
159char *lvremove_sz = NULL;
160char *pvscan_sz = NULL;
161char *vgscan_sz = NULL;
162char *vgchange_sz = NULL;
163char *vgremove_sz = NULL;
[128]164
[3286]165/** char **************************************************/
166char *p;
167char *q;
168char *r;
[1]169
[3286]170/** int ***************************************************/
171int retval = 0;
172int res = 0;
173int i;
174int lvmversion = 1;
175long extents;
176fpos_t orig_pos;
[1]177
[3286]178/** pointers **********************************************/
179FILE *fin;
[128]180
[3286]181/** end *****************************************************/
[1]182
183#ifdef __FreeBSD__
[3287]184return (0);
[1]185#endif
186
[3286]187if (strstr(call_program_and_get_last_line_of_output("cat /proc/cmdline"), "nolvm")) {
188 return(0);
189}
190if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) {
191 log_OS_error("/tmp/i-want-my-lvm");
192 return (1);
193}
[1]194
[3286]195log_it("STARTING");
196log_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes...");
197if (find_home_of_exe("lvm")) { // found it :) cool
198 mr_asprintf(lvscan_sz, "lvm lvscan");
199 mr_asprintf(lvremove_sz, "lvm lvremove");
200 mr_asprintf(vgscan_sz, "lvm vgscan");
201 mr_asprintf(pvscan_sz, "lvm pvscan");
202 mr_asprintf(vgchange_sz, "lvm vgchange");
203 mr_asprintf(vgremove_sz, "lvm vgremove -f");
204} else {
205 mr_asprintf(lvscan_sz, "lvscan");
206 mr_asprintf(lvremove_sz, "lvremove");
207 mr_asprintf(vgscan_sz, "vgscan");
208 mr_asprintf(pvscan_sz, "pvscan");
209 mr_asprintf(vgchange_sz, "vgchange");
210 mr_asprintf(vgremove_sz, "vgremove");
211}
212mr_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);
213mr_free(lvscan_sz);
214mr_free(lvremove_sz);
215
216run_program_and_log_output(cmd, 5);
217mr_free(cmd);
218
219sleep(1);
220mr_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);
221mr_free(vgchange_sz);
222mr_free(vgremove_sz);
223
224run_program_and_log_output(cmd, 5);
225mr_free(cmd);
226
227if (just_erase_existing_volumes) {
228 paranoid_fclose(fin);
229 log_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs.");
230 retval = 0;
231} else {
232
[1]233 malloc_string(tmp);
234 malloc_string(incoming);
235 command = malloc(512);
236
237 log_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff...");
238 rewind(fin);
[3060]239 for (r = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (r != NULL); r = fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]240 fgetpos(fin, &orig_pos);
241 if (incoming[0] != '#') {
242 continue;
243 }
[128]244 if (res && strstr(command, "create") && vacuum_pack) {
245 sleep(2);
[3060]246 paranoid_system("sync");
247 paranoid_system("sync");
248 paranoid_system("sync");
[128]249 }
250 if ((p = strstr(incoming, "vgcreate"))) {
[3286]251 // include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm)
[3060]252 for (q = fgets(tmp, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(tmp, MAX_STR_LEN - 1, fin)) {
[128]253 if (tmp[0] == '#') {
254 fsetpos(fin, &orig_pos);
255 break;
256 } else {
257 fgetpos(fin, &orig_pos);
258 strcat(incoming, tmp);
259 }
[1]260 }
[128]261 for (q = incoming; *q != '\0'; q++) {
262 if (*q < 32) {
263 *q = ' ';
264 }
265 }
266 strcpy(tmp, p + strlen("vgcreate") + 1);
267 for (q = tmp; *q > 32; q++);
268 *q = '\0';
269 log_msg(1, "Deleting old entries at /dev/%s", tmp);
[3286]270 mr_asprintf(cmd, "rm -Rf /dev/%s", tmp);
271 run_program_and_log_output(cmd, 1);
272 mr_free(cmd);
273
[128]274 run_program_and_log_output(vgscan_sz, 1);
275 run_program_and_log_output(pvscan_sz, 1);
[3286]276 log_msg(3, "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'", incoming);
[128]277 }
[1]278 for (p = incoming + 1; *p == ' '; p++);
279 strcpy(command, p);
280 for (p = command; *p != '\0'; p++);
281 for (; *(p - 1) < 32; p--);
282 *p = '\0';
283 res = run_program_and_log_output(command, 5);
[128]284 if (res > 0 && (p = strstr(command, "lvm "))) {
[2933]285 log_msg(0, "%s --> %d failed so removing lvm just in case", command, res);
[128]286 *p = *(p + 1) = *(p + 2) = ' ';
287 res = run_program_and_log_output(command, 5);
288 }
[1]289 log_msg(0, "%s --> %d", command, res);
[128]290 if (res > 0) {
291 res = 1;
[1]292 }
[128]293 if (res && strstr(command, "lvcreate") && vacuum_pack) {
294 res = 0;
295 if (strstr(command, "lvm lvcreate"))
296 lvmversion = 2;
297 log_it("%s... so I'll get creative.", tmp);
298 if (lvmversion == 2) {
[3185]299 mr_asprintf(tmp1, "tail -n5 %s | grep Insufficient | tail -n1", MONDO_LOGFILE);
[1315]300 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
301 free(tmp1);
[128]302 } else {
[3185]303 mr_asprintf(tmp1, "tail -n5 %s | grep lvcreate | tail -n1", MONDO_LOGFILE);
[1315]304 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
305 free(tmp1);
[128]306 }
307 for (p = tmp; *p != '\0' && !isdigit(*p); p++);
308 extents = atol(p);
309 log_msg(5, "p='%s' --> extents=%ld", p, extents);
310 p = strstr(command, "-L");
311 if (!p) {
312 log_msg(0, "Fiddlesticks. '%s' returned %d", command, res);
313 } else {
314 if (lvmversion == 2) {
315 *p++ = '-';
316 *p++ = 'l';
317 *p++ = ' ';
318 for (q = p; *q != ' '; q++) {
319 *q = ' ';
320 }
321 sprintf(p, "%ld", extents);
322 i = strlen(p);
323 *(p + i) = ' ';
324 } else {
325 p++;
326 p++;
327 p++;
328 for (q = p; *q != ' '; q++) {
329 *(q - 1) = ' ';
330 }
331 sprintf(p, "%ld%c", extents, 'm');
332 i = strlen(p);
333 *(p + i) = ' ';
334 }
335 log_msg(5, "Retrying with '%s'", command);
336 res = run_program_and_log_output(command, 5);
337 if (res > 0) {
338 res = 1;
339 }
340 if (g_fprep) {
341 fprintf(g_fprep, "%s\n", command);
342 }
343 log_msg(0, "%s --> %d", command, res);
344 if (!res) {
345 log_msg(5, "YAY! This time, it succeeded.");
346 }
347 }
348 }
349 if (strstr(command, "vgcreate")) {
350 log_msg(0, "In case you're interested...");
351 run_program_and_log_output(vgscan_sz, 1);
352 run_program_and_log_output(pvscan_sz, 1);
353 }
354 if (res != 0 && !strstr(command, "insmod")) {
355 retval++;
356 }
[1]357 sprintf(tmp, "echo \"%s\" >> /tmp/out.sh", command);
[3060]358 paranoid_system(tmp);
[1]359 sleep(1);
360 }
[3286]361
[1]362 paranoid_fclose(fin);
363 paranoid_free(tmp);
364 paranoid_free(incoming);
365 paranoid_free(command);
[3286]366 log_msg(1, "Closed i-want-my-lvm. Finished doing funky stuff.");
[1]367}
[3286]368mr_free(pvscan_sz);
369mr_free(vgscan_sz);
[1]370
[3286]371paranoid_system("sync");
372paranoid_system("sync");
373paranoid_system("sync");
374sleep(1);
375log_it("ENDING");
376if (retval > 2) {
377 log_msg(1, "%d errors. I'm reporting this.", retval);
378 return (retval);
379} else {
380 log_msg(1, "Not many errors. Returning 0.");
381 return (0);
382}
383}
[1]384
[3286]385
[1]386/**
387 * Add RAID partitions while copying @p old_mountlist to @p new_mountlist.
388 * We go through @p old_mountlist and check if any RAID device (/dev/md? on Linux)
389 * is in it; if it is, then we put the disks contained within that RAID device
390 * into the mountlist as well.
391 * @param old_mountlist The mountlist to read.
392 * @param new_mountlist The mountlist to write, with the RAID partitions added.
393 * @return 0 for success, nonzero for failure.
394 */
[3286]395int extrapolate_mountlist_to_include_raid_partitions(struct mountlist_itself *new_mountlist, struct mountlist_itself *old_mountlist) {
[1]396
[3286]397/** pointers *********************************************************/
398FILE *fin;
[1]399
[3286]400/** int **************************************************************/
401int lino;
402int j;
[1]403
[3286]404/** buffers **********************************************************/
405char *incoming;
[1]406
[3286]407/** pointers *********************************************************/
408char *p;
409char *q;
[1]410
[3286]411/** init *************************************************************/
412new_mountlist->entries = 0;
[1]413
[3286]414/** end **************************************************************/
[1]415
[3286]416malloc_string(incoming);
417assert(new_mountlist != NULL);
418assert(old_mountlist != NULL);
419
[1]420#ifdef __FreeBSD__
[3287]421log_to_screen("I don't know how to extrapolate the mountlist on FreeBSD. Sorry.");
422return (1);
[1]423#endif
424
[3286]425for (lino = 0; lino < old_mountlist->entries; lino++) {
426 if (strstr(old_mountlist->el[lino].device, RAID_DEVICE_STUB)) // raid
427 {
428 if (!does_file_exist("/etc/raidtab")) {
429 log_to_screen
430 ("Cannot find /etc/raidtab - cannot extrapolate the fdisk entries");
431 finish(1);
432 }
433 if (!(fin = fopen("/etc/raidtab", "r"))) {
434 log_OS_error("Cannot open /etc/raidtab");
435 finish(1);
436 }
437 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL)
438 && !strstr(incoming, old_mountlist->el[lino].device);
439 q = fgets(incoming, MAX_STR_LEN - 1, fin));
440 if (!feof(fin)) {
[3287]441 log_it("Investigating %s", old_mountlist->el[lino].device);
442 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL) && !strstr(incoming, "raiddev"); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
443 if (strstr(incoming, OSSWAP("device", "drive")) && !strchr(incoming, '#')) {
[3286]444 for (p = incoming + strlen(incoming);
445 *(p - 1) <= 32; p--);
446 *p = '\0';
447 for (p--; p > incoming && *(p - 1) > 32; p--);
[3287]448 log_it("Extrapolating %s", p);
449 for (j = 0; j < new_mountlist->entries && strcmp(new_mountlist->el[j].device, p); j++);
[3286]450 if (j >= new_mountlist->entries) {
451 strcpy(new_mountlist-> el[new_mountlist->entries].device, p);
452 strcpy(new_mountlist-> el[new_mountlist->entries].mountpoint, "raid");
453 strcpy(new_mountlist-> el[new_mountlist->entries].format, "raid");
454 new_mountlist->el[new_mountlist->entries]. size = old_mountlist->el[lino].size;
455 new_mountlist->entries++;
456 } else {
[3287]457 log_it("Not adding %s to mountlist: it's already there", p);
[1]458 }
459 }
460 }
461 }
[3286]462 paranoid_fclose(fin);
463 } else {
464 strcpy(new_mountlist->el[new_mountlist->entries].device, old_mountlist->el[lino].device);
465 strcpy(new_mountlist->el[new_mountlist->entries].mountpoint, old_mountlist->el[lino].mountpoint);
466 strcpy(new_mountlist->el[new_mountlist->entries].format, old_mountlist->el[lino].format);
467 new_mountlist->el[new_mountlist->entries].size = old_mountlist->el[lino].size;
468 new_mountlist->entries++;
[1]469 }
[3286]470}
471paranoid_free(incoming);
[1]472
[3286]473return (0);
[1]474}
475
476
477/**
[558]478 * Create @p RAID device using information from @p structure.
479 * This will create the specified RAID devive using information provided in
480 * raidlist by means of the mdadm tool.
481 * @param raidlist The structure containing all RAID information
482 * @param device The RAID device to create.
483 * @return 0 for success, nonzero for failure.
484 */
[2990]485int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device, bool test) {
[2928]486
[3286]487/** int **************************************************************/
488int i = 0;
489int j = 0;
490int v = 0;
491int res = 0;
[2984]492
[3286]493/** buffers ***********************************************************/
494char *devices = NULL;
495char *level = NULL;
496char *program = NULL;
[2928]497
[3286]498// leave straight away if raidlist is initial or has no entries
499if (!raidlist || raidlist->entries == 0) {
500 log_msg(1, "No RAID arrays found.");
501 return 1;
502} else {
503 log_msg(1, "%d RAID arrays found.", raidlist->entries);
504}
505// find raidlist entry for requested device
506for (i = 0; i < raidlist->entries; i++) {
507 if (!strcmp(raidlist->el[i].raid_device, device)) break;
508}
509// check whether RAID device was found in raidlist
510if (i == raidlist->entries) {
511 log_msg(1, "RAID device %s not found in list.", device);
512 return 1;
513} else {
514 log_msg(1, "RAID device %s found in list (%d).", device, i);
515}
516
517// create device list from normal disks followed by spare ones
518if (raidlist->el[i].data_disks.el[0].device != NULL) {
519 mr_asprintf(devices, "%s", raidlist->el[i].data_disks.el[0].device);
520 log_msg(4, "Adding device %s to list", raidlist->el[i].data_disks.el[0].device);
521} else {
522 log_msg(1, "Strange, there are entries but no device");
523}
524for (j = 1; j < raidlist->el[i].data_disks.entries; j++) {
525 mr_strcat(devices, " %s", raidlist->el[i].data_disks.el[j].device);
526 log_msg(4, "Adding device %s to list", raidlist->el[i].data_disks.el[j].device);
527}
528for (j = 0; j < raidlist->el[i].spare_disks.entries; j++) {
529 mr_strcat(devices, " %s", raidlist->el[i].spare_disks.el[j].device);
530 log_msg(4, "Adding spare device %s to list", raidlist->el[i].spare_disks.el[j].device);
531}
532log_msg(4, "RAID devices: %s", devices);
533// translate RAID level
534if (raidlist->el[i].raid_level == -2) {
535 mr_asprintf(level, "multipath");
536} else if (raidlist->el[i].raid_level == -1) {
537 mr_asprintf(level, "linear");
538} else {
539 mr_asprintf(level, "raid%d", raidlist->el[i].raid_level);
540}
541// create RAID device:
542// - RAID device, number of devices and devices mandatory
543// - parity algorithm, chunk size and spare devices optional
544// - faulty devices ignored
545// - persistent superblock always used as this is recommended
546
547mr_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);
548mr_free(level);
549log_msg(4, "cmd built: %s", program);
550// Restoring the UUID and Version stored at backup time of present
551for (v = 0; v < raidlist->el[i].additional_vars.entries ; v++ ) {
552 log_msg(4,"Working on additional param #%d (Label: %s)",v,raidlist->el[i].additional_vars.el[v].label);
553 if ((raidlist->el[i].additional_vars.el[v].label != NULL) && (strcmp(raidlist->el[i].additional_vars.el[v].label,"UUID") == 0)) {
554 // We have a UUID to handle
555 if (raidlist->el[i].additional_vars.el[v].value != NULL) {
556 // force its restoration in order to avoid modifying all conf files using it
557 log_it("Managing previous UUID %s", raidlist->el[i].additional_vars.el[v].value);
558 mr_strcat(program, " --uuid %s",raidlist->el[i].additional_vars.el[v].value);
559 continue;
560 } else {
561 log_msg(1,"Unable to manage previous NULL UUID");
[2972]562 }
[3286]563 }
564 if ((raidlist->el[i].additional_vars.el[v].label != NULL) && (strcmp(raidlist->el[i].additional_vars.el[v].label,"Version") == 0)) {
565 // We have a Version to handle
566 if (raidlist->el[i].additional_vars.el[v].value != NULL) {
567 // force its restoration in order to support all complex boot loader + md format cases
568 // Also see bug #473
569 log_it("Managing previous Version %s", raidlist->el[i].additional_vars.el[v].value);
570 mr_strcat(program, " -e %s",raidlist->el[i].additional_vars.el[v].value);
571 continue;
572 } else {
573 log_msg(1,"Unable to manage previous NULL Version");
[2989]574 }
[2990]575 }
[3286]576}
577log_msg(4, "cmd built: %s", program);
578if (raidlist->el[i].parity != -1) {
579 switch(raidlist->el[i].parity) {
580 case 0:
581 mr_strcat(program, " --parity=%s", "la");
582 break;
583 case 1:
584 mr_strcat(program, " --parity=%s", "ra");
585 break;
586 case 2:
587 mr_strcat(program, " --parity=%s", "ls");
588 break;
589 case 3:
590 mr_strcat(program, " --parity=%s", "rs");
591 break;
592 default:
593 fatal_error("Unknown RAID parity algorithm.");
594 break;
[2990]595 }
[558]596}
[3286]597log_msg(4, "cmd built: %s", program);
598if (raidlist->el[i].chunk_size != -1) {
599 mr_strcat(program, " --chunk=%d", raidlist->el[i].chunk_size);
600}
601if (raidlist->el[i].spare_disks.entries > 0) {
602 mr_strcat(program, " --spare-devices=%d", raidlist->el[i].spare_disks.entries);
603}
604log_msg(4, "cmd built: %s", program);
605mr_strcat(program, " %s", devices);
[3380]606log_msg(2, "RAID device re-created with the following command:\n%s", program);
[3286]607if (test == TRUE) {
608 res = run_program_and_log_output(program, 1);
609} else {
610 // test mode, always returns TRUE without executing the mdadm command
611 res = TRUE;
612}
613// free memory
614mr_free(devices);
615mr_free(program);
616// return to calling instance
617return res;
618}
[558]619
620
621/**
[1]622 * Format @p device as a @p format filesystem.
623 * This will use the format command returned by which_format_command_do_i_need().
624 * If @p device is an LVM PV, it will not be formatted, and LVM will be started
625 * (if not already done). If it's an imagedev, software RAID component, or
626 * (under BSD) swap partition, no format will be done.
627 * @param device The device to format.
628 * @param format The filesystem type to format it as.
629 * @return 0 for success, nonzero for failure.
630 */
[3286]631int format_device(char *device, char *format, struct raidlist_itself *raidlist) {
632
633/** int **************************************************************/
[1]634#ifdef __FreeBSD__
[3287]635static bool vinum_started_yet = FALSE;
[1]636#endif
637
[3286]638/** buffers ***********************************************************/
639char *program = NULL;
640char *tmp = NULL;
641int res = 0;
[1]642
[3286]643/** end ****************************************************************/
[1]644
[3286]645assert_string_is_neither_NULL_nor_zerolength(device);
646assert(format != NULL);
[1]647
[3286]648if (strstr(format, "raid")) { // do not form RAID disks; do it to /dev/md* instead
649 log_it("Not formatting %s (it is a RAID disk)", device);
650 return (0);
651}
[1]652#ifdef __FreeBSD__
[3287]653if (strcmp(format, "swap") == 0) {
654 log_it("Not formatting %s - it's swap", device);
655 return (0);
656}
[1]657#endif
[3286]658if (strlen(format) <= 2) {
659 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);
660 return (0);
661}
662if (is_this_device_mounted(device)) {
663 log_to_screen("%s is mounted - cannot format it ", device);
664 return (1);
665}
666
667if (strstr(device, RAID_DEVICE_STUB)) {
668 newtSuspend();
[1]669#ifdef __FreeBSD__
[3287]670if (!vinum_started_yet) {
671 if (!does_file_exist("/tmp/raidconf.txt")) {
672 log_to_screen("/tmp/raidconf.txt does not exist. I therefore cannot start Vinum.");
673 } else {
674 int res;
675 res = run_program_and_log_output("vinum create /tmp/raidconf.txt", TRUE);
676 if (res) {
677 log_to_screen("`vinum create /tmp/raidconf.txt' returned errors. Please fix them and re-run mondorestore.");
678 finish(1);
[1]679 }
[3287]680 vinum_started_yet = TRUE;
[3286]681 }
[3287]682}
[1]683
[3287]684if (vinum_started_yet) {
685 FILE *fin;
686 char line[MAX_STR_LEN];
[2211]687
[3287]688 log_to_screen(tmp, "Initializing Vinum device %s (this may take a *long* time)", device);
[2211]689
[3287]690 /* format raid partition */
691 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));
692 paranoid_system(program);
693 if (g_fprep) {
694 fprintf(g_fprep, "%s\n", program);
695 }
[3300]696 mr_free(program);
[3287]697 fin = fopen("/tmp/plexes", "r");
698 while (fgets(line, MAX_STR_LEN - 1, fin)) {
699 if (strchr(line, '\n'))
700 *(strchr(line, '\n')) = '\0'; // get rid of the \n on the end
[1]701
[3287]702 mr_asprintf(tmp, "Initializing plex: %s", line);
703 open_evalcall_form(tmp);
704 mr_free(tmp);
[2211]705
[3287]706 mr_asprintf(tmp, "vinum init %s", line);
707 paranoid_system(tmp);
708 mr_free(tmp);
709
710 while (1) {
711 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);
712 FILE *pin = popen(tmp, "r");
[3286]713 mr_free(tmp);
[2211]714
[3287]715 char status[MAX_STR_LEN / 4];
716 if (fgets(status, MAX_STR_LEN / 4 - 1, pin)) {
717 // FIXME
718 }
719 pclose(pin);
[2211]720
[3287]721 if (!strcmp(status, "up")) {
722 break; /* it's done */
[1]723 }
[3287]724 update_evalcall_form(atoi(status));
725 usleep(250000);
[1]726 }
[3287]727 close_evalcall_form();
[3286]728 }
[3287]729 fclose(fin);
730 unlink("/tmp/plexes");
731}
[1]732#else
[3287]733log_to_screen("Initializing RAID device %s", device);
[1]734
[3287]735// Shouldn't be necessary.
736log_to_screen("Stopping %s", device);
737stop_raid_device(device);
738paranoid_system("sync");
739sleep(1);
740
741log_msg(1, "Making %s", device);
742// use mkraid if it exists, otherwise use mdadm
743if (run_program_and_log_output("which mkraid", FALSE)) {
744 res = create_raid_device_via_mdadm(raidlist, device, TRUE);
745 log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
746} else {
747 mr_asprintf(program, "mkraid --really-force %s", device);
748 res = run_program_and_log_output(program, 1);
749 log_msg(1, "%s returned %d", program, res);
[3286]750 paranoid_system("sync");
[3287]751 sleep(3);
752 start_raid_device(device);
753 if (g_fprep) {
754 fprintf(g_fprep, "%s\n", program);
[3286]755 }
[3300]756 mr_free(program);
[3287]757}
758paranoid_system("sync");
759sleep(2);
[1]760#endif
[3287]761paranoid_system("sync");
762sleep(1);
763newtResume();
[3286]764}
[1]765
[3286]766if (!strcmp(format, "lvm")) {
767 log_msg(1, "Don't format %s - it's part of an lvm volume", device);
768 return (0);
769}
[3300]770program = which_format_command_do_i_need(format);
[3286]771mr_asprintf(tmp, "%s %s", program, device);
772mr_free(program);
[2211]773
[3286]774mr_asprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
775mr_free(tmp);
[2211]776
[3286]777mr_asprintf(tmp, "Formatting %s as %s", device, format);
778update_progress_form(tmp);
[2297]779
[3286]780res = run_program_and_log_output(program, FALSE);
781if (res) {
782 mr_strcat(tmp, "...failed");
783} else {
784 mr_strcat(tmp, "...OK");
785}
786log_to_screen(tmp);
787mr_free(tmp);
[3448]788
[3286]789retval += res;
790paranoid_system("sync");
791sleep(1);
792return (retval);
793}
[1]794
795
796/**
797 * Format all drives (except those excluded by format_device()) in @p mountlist.
798 * @param mountlist The mountlist containing partitions to be formatted.
799 * @param interactively If TRUE, then prompt the user before each partition.
800 * @return The number of errors encountered (0 for success).
801 */
[3286]802int format_everything(struct mountlist_itself *mountlist, bool interactively, struct raidlist_itself *raidlist) {
[1]803
[3286]804/** int **************************************************************/
805int retval = 0;
806int lino;
807int res;
[1]808
[3286]809/** long *************************************************************/
810long progress_step;
[1]811
[3286]812/** bools ************************************************************/
813bool do_it;
[1]814
[3286]815/** buffers **********************************************************/
816char *tmp = NULL;
[1]817
[3286]818/** pointers *********************************************************/
819struct mountlist_line *me; // mountlist entry
820/** end **************************************************************/
[1]821
[3286]822assert(mountlist != NULL);
823log_it("format_everything (mountlist, interactively = %s", (interactively) ? "true" : "false");
824mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
825open_progress_form("Formatting partitions", "I am now formatting your hard disk partitions.", "This may take up to five minutes.", "", mountlist->entries + 1);
826
827progress_step = (mountlist->entries > 0) ? g_maximum_progress / mountlist->entries : 1;
[1]828// start soft-raids now (because LVM might depend on them)
829// ...and for simplicity's sake, let's format them at the same time :)
[3286]830log_msg(1, "Stopping all RAID devices");
831stop_all_raid_devices(mountlist);
832paranoid_system("sync");
833paranoid_system("sync");
834paranoid_system("sync");
835sleep(2);
836log_msg(1, "Prepare soft-RAIDs"); // prep and format too
837for (lino = 0; lino < mountlist->entries; lino++) {
838 me = &mountlist->el[lino]; // the current mountlist entry
839 log_msg(2, "Examining %s", me->device);
840 if (!strncmp(me->device, "/dev/md", 7)) {
841 if (interactively) {
842 // ask user if we should format the current device
843 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
844 do_it = ask_me_yes_or_no(tmp);
845 mr_free(tmp);
[128]846 } else {
[3286]847 do_it = TRUE;
[128]848 }
[3286]849 if (do_it) {
850 // NB: format_device() also stops/starts RAID device if necessary
851 retval += format_device(me->device, me->format, raidlist);
[1]852 }
[3286]853 g_current_progress += progress_step;
[1]854 }
[3286]855}
856paranoid_system("sync");
857paranoid_system("sync");
858paranoid_system("sync");
859sleep(2);
860// do LVMs now
861log_msg(1, "Creating LVMs");
862if (does_file_exist("/tmp/i-want-my-lvm")) {
863 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
864 log_to_screen("Configuring LVM");
865 if (!g_text_mode) {
866 newtSuspend();
867 }
868 res = do_my_funky_lvm_stuff(FALSE, TRUE);
869 if (!g_text_mode) {
870 newtResume();
871 }
872 if (!res) {
873 log_to_screen("LVM initialized OK");
874 } else {
875 log_to_screen("Failed to initialize LVM");
876 }
877 // retval += res;
878 if (res) {
879 retval++;
880 }
881 sleep(3);
882}
[1]883// do regulars at last
[3286]884sleep(2); // woo!
885log_msg(1, "Formatting regulars");
886for (lino = 0; lino < mountlist->entries; lino++) {
887 me = &mountlist->el[lino]; // the current mountlist entry
888 if (!strcmp(me->mountpoint, "image")) {
889 log_it("Not formatting %s - it's an image", me->device);
890 } else if (!strcmp(me->format, "raid")) {
891 log_it("Not formatting %s - it's a raid-let", me->device);
892 continue;
893 } else if (!strcmp(me->format, "lvm")) {
894 log_it("Not formatting %s - it's an LVM", me->device);
895 continue;
896 } else if (!strncmp(me->device, "/dev/md", 7)) {
897 log_it("Already formatted %s - it's a soft-RAID dev", me->device);
898 continue;
899 } else if (!does_file_exist(me->device) && strncmp(me->device, "/dev/hd", 7) && strncmp(me->device, "/dev/sd", 7)) {
900 log_it("Not formatting %s yet - doesn't exist - probably an LVM", me->device);
901 continue;
902 } else {
903 if (interactively) {
904 // ask user if we should format the current device
905 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
906 do_it = ask_me_yes_or_no(tmp);
907 mr_free(tmp);
[1]908 } else {
[3286]909 do_it = TRUE;
[1]910 }
911
[3286]912 if (do_it)
913 retval += format_device(me->device, me->format, raidlist);
[1]914 }
915
[3286]916 // update progress bar
917 g_current_progress += progress_step;
918}
[1]919
920
[3286]921// update progress bar to 100% to compensate for
922// rounding errors of the progress_step calculation
923if (lino >= mountlist->entries)
924 g_current_progress = g_maximum_progress;
[1]925
[3286]926close_progress_form();
[1]927
[3286]928if (retval) {
929 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
[3434]930 log_to_screen("Errors may have occurred during the formatting of your hard drives.");
[3286]931} else {
932 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
933}
[1]934
[3286]935log_it("format_everything () - %s", (retval) ? "failed!" : "finished successfully");
936
937if (g_partition_table_locked_up > 0) {
938 if (retval > 0 && !interactively) {
[1]939//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
[3286]940 log_to_screen("Partition table locked up %d times. At least one 'mkfs' (format) command", g_partition_table_locked_up);
941 log_to_screen("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
942 log_to_screen("to refresh its copy of the partition table causes the kernel to lock the ");
943 log_to_screen("partition table. I believe this has just happened.");
944 if (ask_me_yes_or_no("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue.")) {
945 paranoid_system("sync");
946 paranoid_system("sync");
947 paranoid_system("sync");
948 paranoid_system("reboot");
[128]949 }
[3286]950 } else {
951 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');
[128]952 }
[1]953}
[3286]954newtSuspend();
955paranoid_system("clear");
956newtResume();
957return (retval);
958}
[1]959
960
961/**
962 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
963 * Each partition created is 32k in size.
964 * @param drivename The drive to create the dummy partitions on.
965 * @param devno_we_must_allow_for The lowest-numbered real partition; create
966 * dummies up to (this - 1).
967 * @return The number of errors encountered (0 for success).
968 */
[3286]969int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename, int devno_we_must_allow_for) {
[1]970
[3287]971/** int **************************************************************/
972int current_devno;
973int previous_devno;
974int retval = 0;
975int res;
[1]976
[3287]977assert_string_is_neither_NULL_nor_zerolength(drivename);
[1]978
[3287]979if (devno_we_must_allow_for >= 5) {
980 log_it("Making dummy primary 1 on %s", drivename);
981 g_maximum_progress++;
982 res = partition_device(pout_to_fdisk, drivename, 1, 0, "ext2", 32000);
983 retval += res;
984 previous_devno = 1;
985 current_devno = 5;
986} else {
987 previous_devno = 0;
988 current_devno = 1;
[1]989}
[3287]990for (; current_devno < devno_we_must_allow_for; current_devno++) {
991 log_it("Creating dummy partition %d on %s", current_devno, drivename);
992 g_maximum_progress++;
993 res = partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, OSSWAP("ext2", "ufs"), 32000);
994 retval += res;
995 previous_devno = current_devno;
996}
997return (previous_devno);
998}
[1]999
1000
1001/**
1002 * Decide whether @p mountlist contains any RAID devices.
1003 * @param mountlist The mountlist to examine.
1004 * @return TRUE if it does, FALSE if it doesn't.
1005 */
[3287]1006bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist) {
[1]1007
[3287]1008/** int *************************************************************/
1009int i;
1010int matching = 0;
[1]1011
[3287]1012/** end **************************************************************/
[1]1013
[3287]1014assert(mountlist != NULL);
1015
1016for (i = 0; i < mountlist->entries; i++) {
1017 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1018 matching++;
[1]1019 }
1020}
[3287]1021if (matching) {
1022 return (TRUE);
1023} else {
1024 return (FALSE);
1025}
1026}
[1]1027
1028/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1029#ifdef __FreeBSD__
[3287]1030static void display_disklabel(FILE * f, const struct disklabel *lp) {
[1]1031
[3287]1032int i, j;
1033const struct partition *pp;
1034
1035fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1036if (lp->d_type < DKMAXTYPES)
1037 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1038else
1039 fprintf(f, "type: %u\n", lp->d_type);
1040fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename);
1041fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname);
1042fprintf(f, "flags:");
1043if (lp->d_flags & D_REMOVABLE)
1044 fprintf(f, " removeable");
1045if (lp->d_flags & D_ECC)
1046 fprintf(f, " ecc");
1047if (lp->d_flags & D_BADSECT)
1048 fprintf(f, " badsect");
1049fprintf(f, "\n");
1050fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1051fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1052fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1053fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1054fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1055fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1056fprintf(f, "rpm: %u\n", lp->d_rpm);
1057fprintf(f, "interleave: %u\n", lp->d_interleave);
1058fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1059fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1060fprintf(f, "headswitch: %lu\t\t# milliseconds\n", (u_long) lp->d_headswitch);
1061fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (u_long) lp->d_trkseek);
1062fprintf(f, "drivedata: ");
1063for (i = NDDATA - 1; i >= 0; i--)
1064 if (lp->d_drivedata[i])
1065 break;
1066if (i < 0)
1067 i = 0;
1068for (j = 0; j <= i; j++)
1069 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1070fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1071fprintf(f, "# size offset fstype [fsize bsize bps/cpg]\n");
1072pp = lp->d_partitions;
1073for (i = 0; i < lp->d_npartitions; i++, pp++) {
1074 if (pp->p_size) {
1075 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size, (u_long) pp->p_offset);
1076 if (pp->p_fstype < FSMAXTYPES)
1077 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1078 else
1079 fprintf(f, "%8d", pp->p_fstype);
1080 switch (pp->p_fstype) {
1081
1082 case FS_UNUSED: /* XXX */
1083 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), "");
[1]1084 break;
1085
[3287]1086 case FS_BSDFFS:
1087 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1088 break;
[1]1089
[3287]1090 case FS_BSDLFS:
1091 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1092 break;
[1]1093
[3287]1094 default:
1095 fprintf(f, "%20.20s", "");
1096 break;
[1]1097 }
[3287]1098 fprintf(f, "\t# (Cyl. %4lu", (u_long) (pp->p_offset / lp->d_secpercyl));
1099 if (pp->p_offset % lp->d_secpercyl)
1100 putc('*', f);
1101 else
1102 putc(' ', f);
1103 fprintf(f, "- %lu", (u_long) ((pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl - 1));
1104 if (pp->p_size % lp->d_secpercyl)
1105 putc('*', f);
1106 fprintf(f, ")\n");
[1]1107 }
1108}
[3287]1109fflush(f);
1110}
[1]1111
[3287]1112static struct disklabel *get_virgin_disklabel(char *dkname) {
[1]1113
[3287]1114static struct disklabel loclab;
1115struct partition *dp;
1116char *lnamebuf = NULL;
1117int f;
1118u_int secsize, u;
1119off_t mediasize;
[1]1120
[3287]1121mr_asprintf(lnamebuf, "%s", dkname);
1122if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1123 warn("cannot open %s", lnamebuf);
1124 mr_free(lnamebuf);
1125 return (NULL);
1126}
1127mr_free(lnamebuf);
[1]1128
[3287]1129/* New world order */
1130if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1131 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1132 close(f);
1133 return (NULL);
1134}
1135memset(&loclab, 0, sizeof loclab);
1136loclab.d_magic = DISKMAGIC;
1137loclab.d_magic2 = DISKMAGIC;
1138loclab.d_secsize = secsize;
1139loclab.d_secperunit = mediasize / secsize;
[1]1140
[3287]1141/*
1142 * Nobody in these enligthened days uses the CHS geometry for
1143 * anything, but nontheless try to get it right. If we fail
1144 * to get any good ideas from the device, construct something
1145 * which is IBM-PC friendly.
1146 */
1147if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1148 loclab.d_nsectors = u;
1149else
1150 loclab.d_nsectors = 63;
[1]1151
[3287]1152if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1153 loclab.d_ntracks = u;
1154else if (loclab.d_secperunit <= 63 * 1 * 1024)
1155 loclab.d_ntracks = 1;
1156else if (loclab.d_secperunit <= 63 * 16 * 1024)
1157 loclab.d_ntracks = 16;
1158else
1159 loclab.d_ntracks = 255;
1160loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1161loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1162loclab.d_npartitions = MAXPARTITIONS;
1163
1164/* Various (unneeded) compat stuff */
1165loclab.d_rpm = 3600;
1166loclab.d_bbsize = BBSIZE;
1167loclab.d_interleave = 1;;
1168strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1169
[1]1170 dp = &loclab.d_partitions[RAW_PART];
[3287]1171dp->p_size = loclab.d_secperunit;
1172loclab.d_checksum = dkcksum(&loclab);
1173close(f);
1174return (&loclab);
[1]1175}
[128]1176
[1]1177/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1178
[3287]1179char *canonical_name(char *drivename) {
1180
1181if (drivename) {
1182 if (strncmp(drivename, "/dev/", 5) == 0) {
1183 return drivename + 5;
[1]1184 }
1185}
[3287]1186return drivename;
1187}
[1]1188
1189/**
1190 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1191 * @param mountlist The mountlist to get the subpartition information from.
1192 * @param drivename The drive or slice to create a disklabel on.
1193 * @param ret If non-NULL, store the created disklabel here.
1194 * @return The number of errors encountered (0 for success).
1195 */
[3287]1196int label_drive_or_slice(struct mountlist_itself *mountlist, char *drivename, struct disklabel *ret) {
[1]1197
[3287]1198char *subdev_str = NULL;
1199char *command = NULL;
1200struct disklabel *lp;
1201int i, lo = 0;
1202int retval = 0;
1203char c;
1204FILE *ftmp;
1205
1206lp = get_virgin_disklabel(drivename);
1207for (c = 'a'; c <= 'z'; ++c) {
1208 int idx;
1209 mr_asprintf(subdev_str, "%s%c", drivename, c);
1210 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1211 lp->d_partitions[c - 'a'].p_size = 0;
1212 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1213 } else {
1214 lo = c - 'a';
1215 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1216 lp->d_partitions[c - 'a'].p_fsize = 0;
1217 lp->d_partitions[c - 'a'].p_frag = 0;
1218 lp->d_partitions[c - 'a'].p_cpg = 0;
1219 if (!strcmp(mountlist->el[idx].format, "ufs") || !strcmp(mountlist->el[idx].format, "ffs") || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1220 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1221 lp->d_partitions[c - 'a'].p_fsize = 2048;
1222 lp->d_partitions[c - 'a'].p_frag = 8;
1223 lp->d_partitions[c - 'a'].p_cpg = 64;
1224 } else if (!strcasecmp(mountlist->el[idx].format, "raid") || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1225 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1226 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1227 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1228 } else
1229 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
[1]1230 }
[3287]1231 mr_free(subdev_str);
1232}
[1]1233
[3287]1234// fix up the offsets
1235lp->d_partitions[0].p_offset = 0;
1236lp->d_partitions[RAW_PART].p_offset = 0;
1237lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1238lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
[1]1239
[3287]1240for (i = 1; i < lp->d_npartitions; ++i) {
1241 int lastone;
1242 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1243 continue;
1244 for (lastone = i - 1; lastone >= 0; lastone--) {
1245 if ((lp->d_partitions[lastone].p_size) && (lastone != RAW_PART))
1246 break;
[1]1247 }
[3287]1248 lp->d_partitions[i].p_offset = lp->d_partitions[lastone].p_offset + lp->d_partitions[lastone].p_size;
1249}
1250if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size > lp->d_secperunit) {
1251 lp->d_partitions[lo].p_size = lp->d_secperunit - lp->d_partitions[lo].p_offset;
1252}
[1]1253
[3287]1254ftmp = fopen("/tmp/disklabel", "w");
1255display_disklabel(ftmp, lp);
1256fclose(ftmp);
1257mr_asprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1258retval += run_program_and_log_output(command, TRUE);
1259mr_free(command);
1260
1261mr_asprintf(command, "disklabel -R %s /tmp/disklabel", canonical_name(drivename));
1262retval += run_program_and_log_output(command, TRUE);
1263mr_free(command);
1264
1265if (ret)
1266 *ret = *lp;
1267return retval;
[1]1268}
1269#endif
1270
1271
1272/**
1273 * Partition @p drivename based on @p mountlist.
1274 * @param mountlist The mountlist to use to guide the partitioning.
1275 * @param drivename The drive to partition.
1276 * @return 0 for success, nonzero for failure.
1277 */
[3287]1278int partition_drive(struct mountlist_itself *mountlist, char *drivename) {
[128]1279
[3287]1280/** int *************************************************************/
1281int current_devno;
1282int previous_devno = 0;
1283int lino;
1284int retval = 0;
1285int i;
1286FILE *pout_to_fdisk = NULL;
1287
[1]1288#ifdef __FreeBSD__
[3287]1289bool fbsd_part = FALSE;
1290char *subdev_str = NULL;
[1]1291#endif
1292
[3287]1293/** long long *******************************************************/
1294long long partsize;
[1]1295
[3287]1296/** buffers *********************************************************/
1297char *device_str;
1298char *format = NULL;
1299char *tmp = NULL;
1300char *tmp1 = NULL;
[1]1301
[3287]1302/** end *************************************************************/
[1]1303
[3287]1304assert(mountlist != NULL);
1305assert_string_is_neither_NULL_nor_zerolength(drivename);
[1]1306
[128]1307
[3287]1308log_it("Partitioning drive %s", drivename);
[1]1309
[128]1310#if __FreeBSD__
1311 log_it("(Not opening fdisk now; that's the Linux guy's job)");
[1]1312 pout_to_fdisk = NULL;
1313#else
[3287]1314make_hole_for_file(FDISK_LOG);
[3377]1315mr_asprintf(tmp, "mr-parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
[3287]1316pout_to_fdisk = popen(tmp, "w");
1317if (!pout_to_fdisk) {
[3377]1318 log_to_screen("Cannot call mr-parted2fdisk to configure %s", drivename);
[3287]1319 mr_free(tmp);
1320 return (1);
1321}
1322mr_free(tmp);
[1]1323#endif
1324
[3287]1325malloc_string(device_str);
1326
1327for (current_devno = 1; current_devno < 99; current_devno++) {
1328 build_partition_name(device_str, drivename, current_devno);
1329 lino = find_device_in_mountlist(mountlist, device_str);
1330
1331 if (lino < 0) {
1332 // device not found in mountlist
[1]1333#if __FreeBSD__
1334 // If this is the first partition (just as a sentinel value),
1335 // then see if the user has picked 'dangerously-dedicated' mode.
1336 // If so, then we just call label_drive_or_slice() and return.
1337 char c;
1338 if (current_devno == 1) {
1339 // try DangerouslyDedicated mode
1340 for (c = 'a'; c <= 'z'; c++) {
[3287]1341 mr_asprintf(subdev_str, "%s%c", drivename, c);
1342 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
[1]1343 fbsd_part = TRUE;
1344 }
[3287]1345 mr_free(subdev_str);
[1]1346 }
1347 if (fbsd_part) {
1348 int r = label_drive_or_slice(mountlist,
[128]1349 drivename,
1350 0);
[1]1351 char command[MAX_STR_LEN];
[128]1352 sprintf(command, "disklabel -B %s",
1353 basename(drivename));
[1]1354 if (system(command)) {
[128]1355 log_to_screen
[541]1356 ("Warning! Unable to make the drive bootable.");
[1]1357 }
1358 paranoid_free(device_str);
1359 return r;
1360 }
1361 }
1362 for (c = 'a'; c <= 'z'; c++) {
[3287]1363 mr_assprintf(subdev_str, "%s%c", device_str, c);
[1]1364 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1365 fbsd_part = TRUE;
1366 }
[3287]1367 mr_free(subdev_str);
[1]1368 }
1369 // Now we check the subpartitions of the current partition.
1370 if (fbsd_part) {
1371 int i, line;
1372
[3287]1373 mr_asprintf(format, "ufs");
[1]1374 partsize = 0;
1375 for (i = 'a'; i < 'z'; ++i) {
[3287]1376 mr_asprintf(subdev_str, "%s%c", device_str, i);
[1]1377 line = find_device_in_mountlist(mountlist, subdev_str);
[3287]1378 mr_free(subdev_str);
1379
[1]1380 if (line > 0) {
1381 // We found one! Add its size to the total size.
1382 partsize += mountlist->el[line].size;
1383 }
1384 }
1385 } else {
1386 continue;
1387 }
1388#else
1389 continue;
1390#endif
[3287]1391 }
[1]1392
[3287]1393 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1394 /* For FreeBSD, that is /dev/adXsY */
[1]1395
[3287]1396 log_it("Found partition %s in mountlist", device_str);
1397 if (!previous_devno) {
[1]1398
[3287]1399 log_it("Wiping %s's partition table", drivename);
[1]1400#if __FreeBSD__
1401 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1402 file = open(drivename, O_WRONLY);
[2205]1403 if (file != -1) {
[3287]1404 log_to_screnn("Warning - unable to open %s for wiping it's partition table", drivename);
[1]1405 }
1406
[128]1407 for (i = 0; i < 512; i++) {
1408 if (!write(file, "\0", 1)) {
[3287]1409 log_to_screen("Warning - unable to write to %s", drivename);
[1]1410 }
1411 }
[3060]1412 paranoid_system("sync");
[1]1413#else
[2230]1414 log_it("New, kernel-friendly partition remover");
[128]1415 for (i = 20; i > 0; i--) {
1416 fprintf(pout_to_fdisk, "d\n%d\n", i);
1417 fflush(pout_to_fdisk);
1418 }
1419#endif
[3287]1420 if (current_devno > 1) {
1421 previous_devno = make_dummy_partitions(pout_to_fdisk, drivename, current_devno);
[1]1422 }
[3287]1423 }
[1]1424#ifdef __FreeBSD__
[3287]1425 if (!fbsd_part) {
1426 mr_free(format);
[1]1427#endif
1428
[3287]1429 mr_asprintf(format, "%s", mountlist->el[lino].format);
1430 partsize = mountlist->el[lino].size;
[1]1431
1432#ifdef __FreeBSD__
[3287]1433 }
[1]1434#endif
1435
[71]1436#ifndef __IA64__
[3287]1437 if (current_devno == 5 && previous_devno == 4) {
1438 log_to_screen("You must leave at least one partition spare as the Extended partition.");
1439 paranoid_free(device_str);
1440 mr_free(format);
1441 return (1);
1442 }
[71]1443#endif
[1]1444
[3287]1445 retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize);
1446 mr_free(format);
[1]1447
1448#ifdef __FreeBSD__
[3287]1449 if ((current_devno <= 4) && fbsd_part) {
1450 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1451 retval += label_drive_or_slice(mountlist, device_str, 0);
1452 if (system(tmp)) {
1453 log_to_screen("Warning! Unable to make the slice bootable.");
[1]1454 }
[3287]1455 mr_free(tmp);
1456 }
[1]1457#endif
1458
[3287]1459 previous_devno = current_devno;
1460}
1461
1462if (pout_to_fdisk) {
1463 // close fdisk
1464 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1465 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1466 paranoid_pclose(pout_to_fdisk);
1467 paranoid_system("sync");
1468 log_msg(0,"------------------- fdisk.log looks like this ------------------");
1469 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1470 paranoid_system(tmp);
1471 mr_free(tmp);
1472
1473 // mark relevant partition as bootable
1474 mr_asprintf(tmp1,"make-me-bootable /tmp/mountlist.txt %s",drivename);
1475 call_program_and_get_last_line_of_output(tmp1);
1476 mr_free(tmp1);
1477
1478 log_msg(0,"------------------- end of fdisk.log... ------------------");
1479 paranoid_system("sync");
1480 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1481 if (!run_program_and_log_output(tmp, 5)) {
1482 g_partition_table_locked_up++;
[1]1483 }
[3287]1484 mr_free(tmp);
[1]1485
[3287]1486 mr_asprintf(tmp, "partprobe %s", drivename);
1487 if (!run_program_and_log_output(tmp, 5)) {
1488 g_partition_table_locked_up--;
[1]1489 }
[3287]1490 mr_free(tmp);
1491
1492 if (g_partition_table_locked_up > 0) {
1493 log_to_screen("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1494 }
[1]1495}
[3287]1496paranoid_free(device_str);
1497return (retval);
1498}
[1]1499
1500/**
1501 * Create partition number @p partno on @p drive with @p fdisk.
1502 * @param drive The drive to create the partition on.
[2990]1503// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
[1]1504 * @param prev_partno The partition number of the most recently prepped partition.
1505 * @param format The filesystem type of this partition (used to set the type).
1506 * @param partsize The size of the partition in @e bytes.
1507 * @return 0 for success, nonzero for failure.
1508 */
[3287]1509int partition_device(FILE * pout_to_fdisk, const char *drive, int partno, int prev_partno, const char *format, long long partsize) {
[1]1510
[3287]1511/** int **************************************************************/
1512int retval = 0;
1513int res = 0;
[1]1514
[3287]1515/** buffers **********************************************************/
1516char *program = NULL;
1517char *partition_name;
1518char *tmp = NULL;
1519char *output = NULL;
[1]1520
[3287]1521/** pointers **********************************************************/
1522char *part_table_fmt = NULL;
1523FILE *fout;
[1]1524
[3287]1525/** end ***************************************************************/
[128]1526
[3287]1527assert_string_is_neither_NULL_nor_zerolength(drive);
1528assert(format != NULL);
[1]1529
[3287]1530log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting", drive, partno, prev_partno, format, partsize);
[1]1531
[3287]1532if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1533 log_it("Not partitioning %s - it is a virtual drive", drive);
1534 return (0);
1535}
[1]1536
[3287]1537malloc_string(partition_name);
1538build_partition_name(partition_name, drive, partno);
1539if (partsize <= 0) {
1540 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1541} else {
1542 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1543}
1544update_progress_form(tmp);
1545log_it(tmp);
1546mr_free(tmp);
[1]1547
[3287]1548if (is_this_device_mounted(partition_name)) {
1549 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1550 paranoid_free(partition_name);
1551 return (1);
1552}
[1]1553
1554
[3377]1555mr_asprintf(program, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
[3287]1556
[3430]1557/* TODO: should not be called each time */
[3287]1558part_table_fmt = which_partition_format(drive);
1559mr_asprintf(output, "");
1560
1561/* make it a primary/extended/logical */
1562if (partno <= 4) {
1563 mr_strcat(output, "n\np\n%d\n", partno);
1564} else {
1565 /* MBR needs an extended partition if more than 4 partitions */
1566 if (strcmp(part_table_fmt, "MBR") == 0) {
1567 if (partno == 5) {
1568 if (prev_partno >= 4) {
1569 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1570 paranoid_free(partition_name);
1571 paranoid_free(output);
1572 return (1);
1573 } else {
1574 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
[88]1575 }
[1]1576 }
[3287]1577 mr_strcat(output, "n\nl\n");
1578 } else {
1579 /* GPT allows more than 4 primary partitions */
1580 mr_strcat(output, "n\np\n%d\n", partno);
[1]1581 }
[3287]1582}
1583mr_free(part_table_fmt);
[3237]1584
[3287]1585mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1586if (partsize > 0) {
1587 if (!strcmp(format, "7")) {
1588 log_msg(1, "Adding 512K, just in case");
1589 partsize += 512;
[1]1590 }
[3287]1591 mr_strcat(output, "+%lldK", (long long) (partsize));
1592}
1593mr_strcat(output, "\n");
[1]1594#if 0
1595/*
1596#endif
[3287]1597log_it("PARTSIZE = +%ld",(long)partsize);
1598log_it("---fdisk command---");
1599log_it(output);
1600log_it("---end of fdisk---");
[1]1601#if 0
1602*/
1603#endif
1604
1605
[3287]1606if (pout_to_fdisk) {
1607 log_msg(1, "Doing the new all-in-one fdisk thing");
1608 log_msg(1, "output = '%s'", output);
1609 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1610 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1611 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1612 if (strstr(tmp, " (m ")) {
1613 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1614 } else {
1615 log_msg(1, "last line = %s", tmp);
1616 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1617 }
1618 mr_free(tmp);
1619
1620 if (!retval) {
1621 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1622 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
[128]1623 if (retval) {
[3287]1624 log_msg(1, "Failed. Trying again...");
1625 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
[128]1626 }
[3287]1627 }
1628 if (retval) {
1629 log_msg(1, "...but failed to set type");
1630 }
1631} else {
1632 mr_strcat(output, "w\n\n");
1633 if (g_fprep) {
1634 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1635 }
1636 /* write to disk; close fdisk's stream */
1637 if (!(fout = popen(program, "w"))) {
1638 log_OS_error("can't popen-out to program");
[128]1639 } else {
[3287]1640 fputs(output, fout);
1641 paranoid_pclose(fout);
1642 }
1643
1644 if (!does_partition_exist(drive, partno) && partsize > 0) {
1645 log_it("Vaccum-packing");
1646 g_current_progress--;
1647 res = partition_device(pout_to_fdisk, drive, partno, prev_partno, format, -1);
1648 if (res) {
1649 log_it("Failed to vacuum-pack %s", partition_name);
1650 retval++;
[1]1651 } else {
[3287]1652 retval = 0;
[1]1653 }
[3287]1654 }
1655 if (does_partition_exist(drive, partno)) {
1656 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1657 if (retval) {
1658 log_it("Partitioned %s but failed to set its type", partition_name);
[128]1659 } else {
[1]1660 if (partsize > 0) {
[3287]1661 log_to_screen("Partition %s created+configured OK", partition_name);
[1]1662 } else {
[3287]1663 log_it("Returning from a successful vacuum-pack");
[1]1664 }
1665 }
[3287]1666 } else {
1667 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1668 if (partsize > 0) {
1669 log_to_screen(tmp);
1670 } else {
1671 log_it(tmp);
1672 }
1673 mr_free(tmp);
1674 retval++;
[1]1675 }
[3287]1676}
1677mr_free(program);
1678paranoid_free(output);
[2211]1679
[3287]1680g_current_progress++;
1681log_it("partition_device() --- leaving");
1682paranoid_free(partition_name);
1683return (retval);
[1]1684}
1685
1686
1687
1688/**
1689 * Create all partitions listed in @p mountlist.
1690 * @param mountlist The mountlist to use to guide the partitioning.
1691 * @return The number of errors encountered (0 for success).
1692 * @note This sets the partition types but doesn't actually do the formatting.
1693 * Use format_everything() for that.
1694 */
[3287]1695int partition_everything(struct mountlist_itself *mountlist) {
[1]1696
[3287]1697/** int ************************************************************/
1698int lino;
1699int retval = 0;
1700int i;
1701int res;
[1]1702
[3287]1703/** buffer *********************************************************/
1704struct list_of_disks *drivelist;
[1]1705
[3287]1706/** end ************************************************************/
[1]1707
[3287]1708drivelist = malloc(sizeof(struct list_of_disks));
1709assert(mountlist != NULL);
[128]1710
[3287]1711log_it("partition_everything() --- starting");
1712mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
[1]1713
[3287]1714if (mountlist_contains_raid_devices(mountlist)) {
1715 log_msg(0, "Mountlist, including the partitions incorporated in RAID devices:-");
1716 for (i = 0; i < mountlist->entries; i++) {
1717 log_it(mountlist->el[i].device);
[1]1718 }
[3287]1719 log_msg(0, "End of mountlist.");
1720}
1721log_msg(0, "Stopping all LVMs, just in case");
1722if (!g_text_mode) {
[1]1723 newtSuspend();
[3287]1724}
1725do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1726if (!g_text_mode) {
[1]1727 newtResume();
1728}
[3287]1729log_msg(0, "Stopping all software RAID devices, just in case");
1730stop_all_raid_devices(mountlist);
1731log_msg(0, "Done.");
[1]1732
[3287]1733open_progress_form("Partitioning devices", "I am now going to partition all your drives.", "This should not take more than five minutes.", "", mountlist->entries);
[1]1734
[3287]1735make_list_of_drives_in_mountlist(mountlist, drivelist);
[1]1736
[3287]1737/* partition each drive */
1738for (lino = 0; lino < drivelist->entries; lino++) {
1739 res = partition_drive(mountlist, drivelist->el[lino].device);
1740 retval += res;
1741}
1742close_progress_form();
1743if (retval) {
1744 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
[3434]1745 log_to_screen("Errors may have occurred during the partitioning of your hard drives.");
[3287]1746} else {
1747 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1748 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1749}
1750newtSuspend();
1751paranoid_system("clear");
1752newtResume();
1753paranoid_free(drivelist);
1754return (retval);
1755}
[1]1756
1757
1758
1759/**
1760 * Set the type of partition number @p partno on @p drive to @p format.
1761 * @param drive The drive to change the type of a partition on.
1762 * @param partno The partition number on @p drive to change the type of.
1763 * @param format The filesystem type this partition will eventually contain.
1764 * @param partsize The size of this partition, in @e bytes (used for vfat
1765 * type calculations).
1766 * @return 0 for success, nonzero for failure.
1767 */
[3287]1768int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno, const char *format, long long partsize) {
[1]1769
[3287]1770/** buffers *********************************************************/
1771char *partition;
1772char *command = NULL;
1773char *output = NULL;
1774char *tmp = NULL;
1775char *partcode = NULL;
[1]1776
[3287]1777/** pointers *********************************************************/
1778FILE *fout;
[1]1779
[3287]1780/** int **************************************************************/
1781int res = 0;
[1]1782
[3287]1783/** end **************************************************************/
[1]1784
[3287]1785assert_string_is_neither_NULL_nor_zerolength(drive);
1786assert(format != NULL);
[1]1787
[3287]1788malloc_string(partition);
1789
1790build_partition_name(partition, drive, partno);
1791if (strcmp(format, "swap") == 0) {
1792 mr_asprintf(partcode, "82");
1793} else if (strcmp(format, "vfat") == 0) {
1794 if (partsize / 1024 > 8192) {
1795 mr_asprintf(partcode, "c");
[1]1796 } else {
[3287]1797 mr_asprintf(partcode, "b");
1798 }
1799} else if (strcmp(format, "ext2") == 0
1800 || strcmp(format, "reiserfs") == 0
1801 || strcmp(format, "ext3") == 0
1802 || strcmp(format, "ext4") == 0
1803 || strcmp(format, "xfs") == 0
1804 || strcmp(format, "jfs") == 0
[3330]1805 || strcmp(format, "btrfs") == 0) {
[3287]1806 mr_asprintf(partcode, "83");
1807} else if (strcmp(format, "minix") == 0) {
1808 mr_asprintf(partcode, "81");
1809} else if (strcmp(format, "vmfs3") == 0) {
1810 mr_asprintf(partcode, "fb");
1811} else if (strcmp(format, "vmkcore") == 0) {
1812 mr_asprintf(partcode, "fc");
1813} else if (strcmp(format, "raid") == 0) {
1814 mr_asprintf(partcode, "fd");
1815} else if (strcmp(format, "ntfs") == 0) {
1816 mr_asprintf(partcode, "7");
1817} else if ((strcmp(format, "ufs") == 0)
1818 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1819 mr_asprintf(partcode, "a5");
1820} else if (strcmp(format, "lvm") == 0) {
1821 mr_asprintf(partcode, "8e");
1822} else if (format[0] == '\0') { /* LVM physical partition */
1823 mr_asprintf(partcode, "");
1824} else if (strlen(format) >= 1 && strlen(format) <= 2) {
1825 mr_asprintf(partcode, format);
1826} else {
1827 /* probably an image */
1828 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1829 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1830 mr_free(tmp);
1831
[1]1832#ifdef __FreeBSD__
[3287]1833 mr_asprintf(partcode, format); // was a5
[1]1834#else
[3287]1835 mr_asprintf(partcode, format); // was 83
[1]1836#endif
[3287]1837}
1838log_msg(1, "Setting %s's type to %s (%s)", partition, format, partcode);
1839if ((strcmp(partcode,"") != 0) && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
[128]1840
[3287]1841 if (pout_to_fdisk) {
1842 res = 0;
1843 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1844 if (partno > 1
1845 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
1846 log_msg(5, "Specifying partno (%d) - yay", partno);
1847 mr_asprintf(tmp, "%d\n", partno);
1848 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1849 log_msg(5, "A - last line = '%s'", last_line_of_file(FDISK_LOG));
1850 mr_free(tmp);
1851 }
[128]1852
[3287]1853 mr_asprintf(tmp, "%s\n", partcode);
1854 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1855 mr_free(tmp);
1856
1857 log_msg(5, "B - last line = '%s'",
1858 last_line_of_file(FDISK_LOG));
1859 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1860 log_msg(5, "C - last line = '%s'",
1861 last_line_of_file(FDISK_LOG));
1862
1863 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1864 if (!strstr(tmp, " (m ")) {
1865 log_msg(1, "last line = '%s'; part type set failed", tmp);
1866 res++;
[1]1867 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
[3287]1868 }
1869 mr_free(tmp);
[128]1870
[3287]1871 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1872 } else {
1873 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
[3377]1874 mr_asprintf(command, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
[3287]1875 log_msg(5, "output = '%s'", output);
1876 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
1877 log_msg(5, "command = '%s'", command);
1878 fout = popen(command, "w");
1879 if (!fout) {
1880 log_OS_error(command);
1881 res = 1;
[128]1882 } else {
[3287]1883 res = 0;
1884 fprintf(fout, "%s", output);
1885 paranoid_pclose(fout);
[1]1886 }
[3287]1887 mr_free(command);
1888 paranoid_free(output);
[1]1889 }
[3287]1890}
1891mr_free(partcode);
[1]1892
[3287]1893paranoid_free(partition);
[1]1894
[3287]1895return (res);
[1]1896}
1897
1898
[3287]1899int start_raid_device(char *raid_device) {
[1]1900
[3287]1901/** int *************************************************************/
1902int res;
1903int retval = 0;
[1]1904
[3287]1905/** buffers *********************************************************/
1906char *program = NULL;
[1]1907
[3287]1908/** end *************************************************************/
[128]1909
[3287]1910assert_string_is_neither_NULL_nor_zerolength(raid_device);
1911
[1]1912#ifdef __FreeBSD__
[3287]1913if (is_this_device_mounted(raid_device)) {
1914 log_it("Can't start %s when it's mounted!", raid_device);
1915 return 1;
1916}
1917mr_asprintf(program, "vinum start -f %s", raid_device);
[1]1918#else
[3287]1919mr_asprintf(program, "raidstart %s", raid_device);
[1]1920#endif
[3287]1921log_msg(1, "program = %s", program);
1922res = run_program_and_log_output(program, 1);
1923if (g_fprep) {
1924 fprintf(g_fprep, "%s\n", program);
[1]1925}
[3287]1926mr_free(program);
[1]1927
[3287]1928if (res) {
1929 log_msg(1, "Warning - failed to start RAID device %s", raid_device);
1930}
1931retval += res;
1932sleep(1);
1933return (retval);
1934}
[1]1935
1936
[3287]1937
[1]1938/**
1939 * Stop @p raid_device using @p raidstop.
1940 * @param raid_device The software RAID device to stop.
1941 * @return 0 for success, nonzero for failure.
1942 */
[3287]1943int stop_raid_device(char *raid_device) {
[1]1944
[3287]1945/** int *************************************************************/
1946int res;
1947int retval = 0;
[1]1948
[3287]1949/** buffers *********************************************************/
1950char *program = NULL;
[1]1951
[3287]1952/** end *************************************************************/
[128]1953
[3287]1954assert_string_is_neither_NULL_nor_zerolength(raid_device);
1955
[1]1956#ifdef __FreeBSD__
[3287]1957if (is_this_device_mounted(raid_device)) {
1958 log_it("Can't stop %s when it's mounted!", raid_device);
1959 return 1;
1960}
1961mr_asprintf(program, "vinum stop -f %s", raid_device);
[1]1962#else
[3287]1963// use raidstop if it exists, otherwise use mdadm
1964if (run_program_and_log_output("which raidstop", FALSE)) {
1965 mr_asprintf(program, "mdadm -S %s", raid_device);
1966} else {
1967 mr_asprintf(program, "raidstop %s", raid_device);
1968}
[1]1969#endif
[3287]1970log_msg(1, "program = %s", program);
1971res = run_program_and_log_output(program, 1);
1972if (g_fprep) {
1973 fprintf(g_fprep, "%s\n", program);
[1]1974}
[3287]1975mr_free(program);
[1]1976
[3287]1977if (res) {
1978 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
1979}
1980retval += res;
1981return (retval);
1982}
[1]1983
[128]1984
[3287]1985int start_all_raid_devices(struct mountlist_itself *mountlist) {
1986
1987int i;
1988int retval = 0;
1989int res;
1990
1991for (i = 0; i < mountlist->entries; i++) {
1992 if (!strncmp(mountlist->el[i].device, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1993 log_msg(1, "Starting %s", mountlist->el[i].device);
1994 res = start_raid_device(mountlist->el[i].device);
1995 retval += res;
[128]1996 }
[1]1997}
[3287]1998if (retval) {
1999 log_msg(1, "Started all s/w raid devices OK");
2000} else {
2001 log_msg(1, "Failed to start some/all s/w raid devices");
2002}
2003return (retval);
2004}
[1]2005
2006/**
2007 * Stop all software RAID devices listed in @p mountlist.
2008 * @param mountlist The mountlist to stop the RAID devices in.
2009 * @return The number of errors encountered (0 for success).
2010 * @bug @p mountlist is not used.
2011 */
[3287]2012int stop_all_raid_devices(struct mountlist_itself *mountlist) {
[1]2013
[3287]2014/** int *************************************************************/
2015int retval = 0;
2016
2017/** char ************************************************************/
2018char *incoming;
[1]2019#ifndef __FreeBSD__
[3287]2020char *dev;
[1]2021#endif
[3287]2022/** pointers ********************************************************/
[1]2023#ifndef __FreeBSD__
[3287]2024char *p;
[1]2025#endif
[3287]2026FILE *fin;
2027char *q;
2028int i;
[1]2029
[3287]2030/** end ****************************************************************/
[1]2031
[3287]2032malloc_string(incoming);
2033assert(mountlist != NULL);
[1]2034
[3287]2035for (i = 0; i < 3; i++) {
[1]2036#ifdef __FreeBSD__
[3287]2037 fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r");
2038 if (!fin) {
2039 paranoid_free(incoming);
2040 return (1);
2041 }
2042 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2043 retval += stop_raid_device(incoming);
2044 }
[1]2045#else
[3287]2046 fin = fopen("/proc/mdstat", "r");
2047 if (!fin) {
2048 log_OS_error("/proc/mdstat");
2049 paranoid_free(incoming);
2050 return (1);
2051 }
2052 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2053 for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++);
2054 if (*p != '\0') {
2055 malloc_string(dev);
2056 sprintf(dev, "/dev/%s", p);
2057 for (p = dev; *p > 32; p++);
2058 *p = '\0';
2059 retval += stop_raid_device(dev);
[1]2060 paranoid_free(dev);
2061 }
[3287]2062 }
[1]2063#endif
2064}
[3287]2065paranoid_fclose(fin);
2066if (retval) {
2067 log_msg(1, "Warning - unable to stop some RAID devices");
2068}
2069paranoid_free(incoming);
2070paranoid_system("sync");
2071paranoid_system("sync");
2072paranoid_system("sync");
2073sleep(1);
2074return (retval);
2075}
[1]2076
2077
2078
2079/**
2080 * Decide which command we need to use to format a device of type @p format.
2081 * @param format The filesystem type we are about to format.
2082 * @param program Where to put the binary name for this format.
2083 * @return 0 for success, nonzero for failure.
2084 */
[3300]2085char *which_format_command_do_i_need(char *format) {
[1]2086
[3301]2087char *program = NULL;
2088
[3287]2089assert_string_is_neither_NULL_nor_zerolength(format);
2090
2091if (strcmp(format, "swap") == 0) {
[1]2092#ifdef __FreeBSD__
[3300]2093 mr_asprintf(program, "true");
[1]2094#else
[3438]2095 mr_asprintf(program, "mkswap -f");
[1]2096#endif
[3287]2097} else if (strcmp(format, "vfat") == 0) {
[3436]2098#ifdef __FreeBSD__
2099 mr_asprintf(program, "newfs_msdos -F 32");
2100#else
2101#ifdef __IA64__
2102 /* For EFI or UEFI partitions take fat16
2103 * as we want to make small ones */
2104 mr_asprintf(program, "mkfs.vfat -F 16");
2105#else
2106 mr_asprintf(program, "mkfs.vfat -F 32");
2107#endif
2108#endif
[1]2109#ifndef __FreeBSD__
[3287]2110} else if (strcmp(format, "reiserfs") == 0) {
[3300]2111 mr_asprintf(program, "mkreiserfs -ff");
[3287]2112} else if (strcmp(format, "xfs") == 0) {
[3300]2113 mr_asprintf(program, "mkfs.xfs -f -q");
[3287]2114} else if (strcmp(format, "jfs") == 0) {
[3300]2115 mr_asprintf(program, "mkfs.jfs");
[3287]2116} else if (strcmp(format, "ext3") == 0) {
[3300]2117 mr_asprintf(program, "mkfs -t ext3 -F -q");
[3287]2118} else if (strcmp(format, "ext4") == 0) {
[3300]2119 mr_asprintf(program, "mkfs -t ext4 -F -q");
[3287]2120} else if (strcmp(format, "btrfs") == 0) {
[3300]2121 mr_asprintf(program, "mkfs.btrfs");
[3287]2122} else if (strcmp(format, "minix") == 0) {
[3300]2123 mr_asprintf(program, "mkfs.minix");
[3287]2124} else if (strcmp(format, "vmfs") == 0) {
[3300]2125 mr_asprintf(program, "mkfs -t vmfs");
[3287]2126} else if (strcmp(format, "ntfs") == 0) {
2127 /*
2128 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2129 * so the default "mkfs -t %s -c" command structure fails
2130 */
[3300]2131 mr_asprintf(program, "mkfs -t ntfs");
[3287]2132} else if (strcmp(format, "ocfs2") == 0) {
2133 /*
2134 * 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.
2135 *
2136 */
[3300]2137 mr_asprintf(program, "mkfs -t ocfs2 -F");
[1]2138#endif
[3287]2139} else if (strcmp(format, "ext2") == 0) {
[3300]2140 mr_asprintf(program, "mke2fs -F -q");
[3287]2141} else {
[1]2142#ifdef __FreeBSD__
[3300]2143 mr_asprintf(program, "newfs_%s", format);
[1]2144#else
[3300]2145 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
[1]2146#endif
[3287]2147 log_it("Unknown format (%s) - assuming '%s' will do", format, program);
[1]2148}
[3300]2149return(program);
[3287]2150}
[1]2151
2152
2153/**
2154 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2155 * There are a few problems with this function:
2156 * - It won't work if there was any unallocated space on the user's hard drive
[2990]2157 * when it was backed up.
[1]2158 * - It won't work if the user's hard drive lies about its size (more common
[2990]2159 * than you'd think).
[1]2160 *
2161 * @param mountlist The mountlist to use for resizing @p drive_name.
2162 * @param drive_name The drive to resize.
2163 */
[3287]2164void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist, char *drive_name) {
[1]2165
[3287]2166/**buffers **********************************************************/
2167char *tmp = NULL;
[1]2168
[3287]2169/** int *************************************************************/
2170int partno, lastpart;
[1]2171
[3287]2172/** float ***********************************************************/
2173float factor;
2174long long new_size;
[1]2175
[3287]2176/** long *************************************************************/
2177long long newsizL = 0LL;
2178long long totalsizL = 0LL;
2179long long current_size_of_drive = 0LL; /* use KB interally for precision */
2180long long original_size_of_drive = 0LL; /* use KB interally for precision */
2181struct mountlist_reference *drivemntlist;
[1]2182
[3287]2183/** structures *******************************************************/
[1]2184
[3287]2185/** end **************************************************************/
[1]2186
[3287]2187assert(mountlist != NULL);
2188assert_string_is_neither_NULL_nor_zerolength(drive_name);
[1]2189
[3287]2190if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2191 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2192 == 0) {
[1]2193 return;
2194 }
[3287]2195}
[1]2196
[3287]2197current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
[1]2198
[3287]2199if (current_size_of_drive <= 0LL) {
2200 log_it("Not resizing to match %s - can't find drive", drive_name);
2201 return;
2202}
2203log_to_screen("Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
[1]2204
[3287]2205drivemntlist = malloc(sizeof(struct mountlist_reference));
2206drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
[1]2207
[3287]2208if (!drivemntlist) {
2209 fatal_error("Cannot malloc temporary mountlist\n");
2210}
2211create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2212
2213for (partno = 0; partno < drivemntlist->entries; partno++) {
2214 if (drivemntlist->el[partno]->size > 0LL) {
2215 /* Keep KB here */
2216 original_size_of_drive += drivemntlist->el[partno]->size;
[1]2217 }
[3287]2218}
[1]2219
[3287]2220if (original_size_of_drive <= 0LL) {
2221 log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name);
2222 return;
2223}
2224factor = ((float)current_size_of_drive/(float)original_size_of_drive);
2225log_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);
[128]2226
[3287]2227lastpart = drivemntlist->entries - 1;
2228for (partno = 0; partno < drivemntlist->entries; partno++) {
2229 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2230 if (!atoi(drivemntlist->el[partno]->format)) {
2231 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
2232 } else {
2233 new_size = drivemntlist->el[partno]->size;
2234 }
[2125]2235
[3287]2236 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2237 log_msg(1, "Skipping %s (%s) because it's an image",
2238 drivemntlist->el[partno]->device,
2239 drivemntlist->el[partno]->mountpoint);
2240 }
2241 newsizL = new_size;
[2125]2242
[3287]2243 /* Do not apply the factor if partition was of negative size */
2244 if (newsizL < 0LL) {
2245 newsizL = drivemntlist->el[partno]->size;
[1]2246 }
[3287]2247 totalsizL += newsizL;
2248
2249 log_to_screen("Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2250 drivemntlist->el[partno]->size = newsizL;
[1]2251}
[3287]2252// Ensures over-allocation alert and prompt for interactive mode does not happen
2253if (totalsizL > current_size_of_drive) {
2254 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));
2255 drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive);
2256} else if (totalsizL < current_size_of_drive) {
2257 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));
2258 drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL);
2259}
2260log_to_screen(tmp);
2261mr_free(tmp);
2262log_to_screen("final_size = %lld MB", current_size_of_drive / 1024);
2263}
[1]2264
2265
2266/**
2267 * Resize all partitions in @p mountlist proportionately (each one
2268 * grows or shrinks by the same percentage) to fit them into the new
2269 * drives (presumably different from the old ones).
2270 * @param mountlist The mountlist to resize the drives in.
2271 */
[3287]2272void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist) {
[1]2273
[3287]2274/** buffers *********************************************************/
2275struct list_of_disks *drivelist;
[1]2276
[3287]2277/** int *************************************************************/
2278int driveno;
[1]2279
[3287]2280/** end *************************************************************/
[1]2281
[3287]2282drivelist = malloc(sizeof(struct list_of_disks));
2283assert(mountlist != NULL);
2284
2285if (g_mountlist_fname[0] == '\0') {
2286 log_it("resize_mountlist_prop...() - warning - mountlist fname is blank");
2287 log_it("That does NOT affect the functioning of this subroutine.");
2288 log_it("--- Hugo, 2002/11/20");
[1]2289}
[3287]2290log_it("Resizing mountlist");
2291make_list_of_drives_in_mountlist(mountlist, drivelist);
2292log_it("Back from MLoDiM");
2293for (driveno = 0; driveno < drivelist->entries; driveno++) {
2294 resize_drive_proportionately_to_suit_new_drives(mountlist, drivelist->el[driveno].device);
2295}
2296log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2297paranoid_free(drivelist);
2298}
[1]2299
2300/**
2301 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2302 * @param mountlist The complete mountlist to get the drive references from.
2303 * @param drive_name The drive to put in @p drivemntlist.
2304 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2305 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2306 * @author Ralph Grewe
2307 */
[3287]2308void create_mountlist_for_drive(struct mountlist_itself *mountlist, char *drive_name, struct mountlist_reference *drivemntlist) {
[1]2309
[3287]2310int partno;
2311char *tmp_drive_name, *c;
[1]2312
[3287]2313assert(mountlist != NULL);
2314assert(drive_name != NULL);
2315assert(drivemntlist != NULL);
[1]2316
[3287]2317log_msg(1, "Creating list of partitions for drive %s", drive_name);
[128]2318
[3287]2319tmp_drive_name = strdup(drive_name);
2320if (!tmp_drive_name)
2321 fatal_error("Out of memory");
2322
2323/* devfs devices? */
2324c = strrchr(tmp_drive_name, '/');
2325if (c && strncmp(c, "/disc", 5) == 0) {
2326 /* yup its devfs, change the "disc" to "part" so the existing code works */
2327 strcpy(c + 1, "part");
2328}
2329drivemntlist->entries = 0;
2330for (partno = 0; partno < mountlist->entries; partno++) {
2331 if (strncmp(mountlist->el[partno].device, tmp_drive_name, strlen(tmp_drive_name)) == 0) {
2332 drivemntlist->el[drivemntlist->entries] = &mountlist->el[partno];
2333 drivemntlist->entries++;
[1]2334 }
2335}
[3287]2336if (tmp_drive_name)
2337 free(tmp_drive_name);
2338}
[1]2339
2340/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.