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

Last change on this file since 3741 was 3741, checked in by Bruno Cornec, 4 years ago

Call the btrfs subvol functions after mounting the base FS

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