source: MondoRescue/branches/3.3/mondo/src/mondorestore/mondo-prep.c@ 3875

Last change on this file since 3875 was 3866, checked in by Bruno Cornec, 4 months ago

Change find_my_editor and find_home_of_exe to return dynamically assigned stringsi - adapt whine_if_not_found

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