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

Last change on this file since 3859 was 3859, checked in by Bruno Cornec, 2 months ago

Fix build_partition_name to allocate dynamically and change proto accordingly

  • Property svn:keywords set to Id
File size: 71.4 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 3859 2024-03-07 00:33:54Z 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 3859 2024-03-07 00:33:54Z 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 = NULL;
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
1353for (current_devno = 1; current_devno < 99; current_devno++) {
1354 device_str = build_partition_name(drivename, current_devno);
1355 lino = find_device_in_mountlist(mountlist, device_str);
1356
1357 if (lino < 0) {
1358 // device not found in mountlist
1359#if __FreeBSD__
1360 // If this is the first partition (just as a sentinel value),
1361 // then see if the user has picked 'dangerously-dedicated' mode.
1362 // If so, then we just call label_drive_or_slice() and return.
1363 char c;
1364 if (current_devno == 1) {
1365 // try DangerouslyDedicated mode
1366 for (c = 'a'; c <= 'z'; c++) {
1367 mr_asprintf(subdev_str, "%s%c", drivename, c);
1368 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1369 fbsd_part = TRUE;
1370 }
1371 mr_free(subdev_str);
1372 }
1373 if (fbsd_part) {
1374 int r = label_drive_or_slice(mountlist,
1375 drivename,
1376 0);
1377 mr_asprintf(command, "disklabel -B %s", basename(drivename));
1378 if (system(command)) {
1379 log_to_screen
1380 ("Warning! Unable to make the drive bootable.");
1381 }
1382 mr_free(command);
1383 mr_free(device_str);
1384 return r;
1385 }
1386 }
1387 for (c = 'a'; c <= 'z'; c++) {
1388 mr_asprintf(subdev_str, "%s%c", device_str, c);
1389 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1390 fbsd_part = TRUE;
1391 }
1392 mr_free(subdev_str);
1393 }
1394 // Now we check the subpartitions of the current partition.
1395 if (fbsd_part) {
1396 int i, line;
1397
1398 mr_asprintf(format, "ufs");
1399 partsize = 0;
1400 for (i = 'a'; i < 'z'; ++i) {
1401 mr_asprintf(subdev_str, "%s%c", device_str, i);
1402 line = find_device_in_mountlist(mountlist, subdev_str);
1403 mr_free(subdev_str);
1404
1405 if (line > 0) {
1406 // We found one! Add its size to the total size.
1407 partsize += mountlist->el[line].size;
1408 }
1409 }
1410 } else {
1411 continue;
1412 }
1413#else
1414 continue;
1415#endif
1416 }
1417
1418 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1419 /* For FreeBSD, that is /dev/adXsY */
1420
1421 log_it("Found partition %s in mountlist", device_str);
1422 if (!previous_devno) {
1423
1424 log_it("Wiping %s's partition table", drivename);
1425#if __FreeBSD__
1426 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1427 file = open(drivename, O_WRONLY);
1428 if (file != -1) {
1429 log_to_screnn("Warning - unable to open %s for wiping it's partition table", drivename);
1430 }
1431
1432 for (i = 0; i < 512; i++) {
1433 if (!write(file, "\0", 1)) {
1434 log_to_screen("Warning - unable to write to %s", drivename);
1435 }
1436 }
1437 paranoid_system("sync");
1438#else
1439 log_it("New, kernel-friendly partition remover");
1440 for (i = 20; i > 0; i--) {
1441 fprintf(pout_to_fdisk, "d\n%d\n", i);
1442 fflush(pout_to_fdisk);
1443 }
1444#endif
1445 if (current_devno > 1) {
1446 previous_devno = make_dummy_partitions(pout_to_fdisk, drivename, current_devno);
1447 }
1448 }
1449#ifdef __FreeBSD__
1450 if (!fbsd_part) {
1451 mr_free(format);
1452#endif
1453
1454 mr_asprintf(format, "%s", mountlist->el[lino].format);
1455 partsize = mountlist->el[lino].size;
1456
1457#ifdef __FreeBSD__
1458 }
1459#endif
1460
1461#ifndef __IA64__
1462 part_table_fmt = which_partition_format(drivename);
1463
1464 /* MBR needs an extended partition if more than 4 partitions */
1465 if (strcmp(part_table_fmt, "MBR") == 0) {
1466 if (current_devno == 5 && previous_devno == 4) {
1467 log_to_screen("You must leave at least one partition spare as the Extended partition.");
1468 mr_free(device_str);
1469 mr_free(format);
1470 return (1);
1471 }
1472 }
1473 mr_free(part_table_fmt);
1474#endif
1475
1476 retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize);
1477 mr_free(format);
1478
1479#ifdef __FreeBSD__
1480 if ((current_devno <= 4) && fbsd_part) {
1481 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1482 retval += label_drive_or_slice(mountlist, device_str, 0);
1483 if (system(tmp)) {
1484 log_to_screen("Warning! Unable to make the slice bootable.");
1485 }
1486 mr_free(tmp);
1487 }
1488#endif
1489
1490 previous_devno = current_devno;
1491 mr_free(device_str);
1492}
1493
1494if (pout_to_fdisk) {
1495 // close fdisk
1496 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1497 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1498 paranoid_pclose(pout_to_fdisk);
1499 paranoid_system("sync");
1500 log_msg(0,"------------------- fdisk.log looks like this ------------------");
1501 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1502 paranoid_system(tmp);
1503 mr_free(tmp);
1504
1505 // mark relevant partition as bootable
1506 mr_asprintf(tmp1,"mr-make-me-bootable /tmp/mountlist.txt %s",drivename);
1507 tmp = call_program_and_get_last_line_of_output(tmp1);
1508 mr_free(tmp1);
1509 mr_free(tmp);
1510
1511 log_msg(0,"------------------- end of fdisk.log... ------------------");
1512 paranoid_system("sync");
1513 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1514 if (!run_program_and_log_output(tmp, 5)) {
1515 g_partition_table_locked_up++;
1516 }
1517 mr_free(tmp);
1518
1519 mr_asprintf(tmp, "partprobe %s", drivename);
1520 if (!run_program_and_log_output(tmp, 5)) {
1521 g_partition_table_locked_up--;
1522 }
1523 mr_free(tmp);
1524
1525 if (g_partition_table_locked_up > 0) {
1526 log_to_screen("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1527 }
1528}
1529return (retval);
1530}
1531
1532/**
1533 * Create partition number @p partno on @p drive with @p fdisk.
1534 * @param drive The drive to create the partition on.
1535// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1536 * @param prev_partno The partition number of the most recently prepped partition.
1537 * @param format The filesystem type of this partition (used to set the type).
1538 * @param partsize The size of the partition in @e bytes.
1539 * @return 0 for success, nonzero for failure.
1540 */
1541int partition_device(FILE * pout_to_fdisk, const char *drive, int partno, int prev_partno, const char *format, long long partsize) {
1542
1543/** int **************************************************************/
1544int retval = 0;
1545int res = 0;
1546
1547/** buffers **********************************************************/
1548char *program = NULL;
1549char *partition_name = NULL;
1550char *tmp = NULL;
1551char *output = NULL;
1552
1553/** pointers **********************************************************/
1554char *part_table_fmt = NULL;
1555FILE *fout;
1556
1557/** end ***************************************************************/
1558
1559assert_string_is_neither_NULL_nor_zerolength(drive);
1560assert(format != NULL);
1561
1562log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting", drive, partno, prev_partno, format, partsize);
1563
1564if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1565 log_it("Not partitioning %s - it is a virtual drive", drive);
1566 return (0);
1567}
1568
1569partition_name = build_partition_name(drive, partno);
1570if (partsize <= 0) {
1571 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1572} else {
1573 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1574}
1575update_progress_form(tmp);
1576log_it(tmp);
1577mr_free(tmp);
1578
1579if (is_this_device_mounted(partition_name)) {
1580 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1581 mr_free(partition_name);
1582 return (1);
1583}
1584
1585
1586mr_asprintf(program, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1587
1588/* TODO: should not be called each time */
1589part_table_fmt = which_partition_format(drive);
1590mr_asprintf(output, "");
1591
1592/* make it a primary/extended/logical */
1593if (partno <= 4) {
1594 mr_strcat(output, "n\np\n%d\n", partno);
1595} else {
1596 /* MBR needs an extended partition if more than 4 partitions */
1597 if (strcmp(part_table_fmt, "MBR") == 0) {
1598 if (partno == 5) {
1599 if (prev_partno >= 4) {
1600 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1601 mr_free(partition_name);
1602 paranoid_free(output);
1603 return (1);
1604 } else {
1605 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1606 }
1607 }
1608 mr_strcat(output, "n\nl\n");
1609 } else {
1610 /* GPT allows more than 4 primary partitions */
1611 mr_strcat(output, "n\np\n%d\n", partno);
1612 }
1613}
1614mr_free(part_table_fmt);
1615
1616mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1617if (partsize > 0) {
1618 if (!strcmp(format, "7")) {
1619 log_msg(1, "Adding 512K, just in case");
1620 partsize += 512;
1621 }
1622 mr_strcat(output, "+%lldK", (long long) (partsize));
1623}
1624mr_strcat(output, "\n");
1625#if 0
1626/*
1627#endif
1628log_it("PARTSIZE = +%ld",(long)partsize);
1629log_it("---fdisk command---");
1630log_it(output);
1631log_it("---end of fdisk---");
1632#if 0
1633*/
1634#endif
1635
1636
1637if (pout_to_fdisk) {
1638 log_msg(1, "Doing the new all-in-one fdisk thing");
1639 mr_strcat(output, "\n\np\n\n");
1640 log_msg(1, "output = '%s'", output);
1641 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1642 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1643 if (strstr(tmp, " (m ")) {
1644 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1645 } else {
1646 log_msg(1, "last line = %s", tmp);
1647 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1648 }
1649 mr_free(tmp);
1650
1651 if (!retval) {
1652 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1653 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1654 if (retval) {
1655 log_msg(1, "Failed. Trying again...");
1656 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1657 }
1658 }
1659 if (retval) {
1660 log_msg(1, "...but failed to set type");
1661 }
1662} else {
1663 mr_strcat(output, "w\n\n");
1664 if (g_fprep) {
1665 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1666 }
1667 /* write to disk; close fdisk's stream */
1668 if (!(fout = popen(program, "w"))) {
1669 log_OS_error("can't popen-out to program");
1670 } else {
1671 fputs(output, fout);
1672 paranoid_pclose(fout);
1673 }
1674
1675 if (!does_partition_exist(drive, partno) && partsize > 0) {
1676 log_it("Vaccum-packing");
1677 g_current_progress--;
1678 res = partition_device(pout_to_fdisk, drive, partno, prev_partno, format, -1);
1679 if (res) {
1680 log_it("Failed to vacuum-pack %s", partition_name);
1681 retval++;
1682 } else {
1683 retval = 0;
1684 }
1685 }
1686 if (does_partition_exist(drive, partno)) {
1687 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1688 if (retval) {
1689 log_it("Partitioned %s but failed to set its type", partition_name);
1690 } else {
1691 if (partsize > 0) {
1692 log_to_screen("Partition %s created+configured OK", partition_name);
1693 } else {
1694 log_it("Returning from a successful vacuum-pack");
1695 }
1696 }
1697 } else {
1698 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1699 if (partsize > 0) {
1700 log_to_screen(tmp);
1701 } else {
1702 log_it(tmp);
1703 }
1704 mr_free(tmp);
1705 retval++;
1706 }
1707}
1708mr_free(program);
1709mr_free(output);
1710mr_free(partition_name);
1711
1712g_current_progress++;
1713log_it("partition_device() --- leaving");
1714return (retval);
1715}
1716
1717
1718
1719/**
1720 * Create all partitions listed in @p mountlist.
1721 * @param mountlist The mountlist to use to guide the partitioning.
1722 * @return The number of errors encountered (0 for success).
1723 * @note This sets the partition types but doesn't actually do the formatting.
1724 * Use format_everything() for that.
1725 */
1726int partition_everything(struct mountlist_itself *mountlist) {
1727
1728/** int ************************************************************/
1729int lino;
1730int retval = 0;
1731int i;
1732int res;
1733
1734/** buffer *********************************************************/
1735struct list_of_disks *drivelist;
1736
1737/** end ************************************************************/
1738
1739drivelist = malloc(sizeof(struct list_of_disks));
1740assert(mountlist != NULL);
1741
1742log_it("partition_everything() --- starting");
1743mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1744
1745if (mountlist_contains_raid_devices(mountlist)) {
1746 log_msg(0, "Mountlist, including the partitions incorporated in RAID devices:-");
1747 for (i = 0; i < mountlist->entries; i++) {
1748 log_it(mountlist->el[i].device);
1749 }
1750 log_msg(0, "End of mountlist.");
1751}
1752log_msg(0, "Stopping all LVMs, just in case");
1753if (!g_text_mode) {
1754 newtSuspend();
1755}
1756do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1757if (!g_text_mode) {
1758 newtResume();
1759}
1760log_msg(0, "Stopping all software RAID devices, just in case");
1761stop_all_raid_devices(mountlist);
1762log_msg(0, "Done.");
1763
1764open_progress_form("Partitioning devices", "I am now going to partition all your drives.", "This should not take more than five minutes.", "", mountlist->entries);
1765
1766make_list_of_drives_in_mountlist(mountlist, drivelist);
1767
1768/* partition each drive */
1769for (lino = 0; lino < drivelist->entries; lino++) {
1770 res = partition_drive(mountlist, drivelist->el[lino].device);
1771 retval += res;
1772}
1773close_progress_form();
1774if (retval) {
1775 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1776 log_to_screen("Errors may have occurred during the partitioning of your hard drives.");
1777} else {
1778 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1779 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1780}
1781newtSuspend();
1782paranoid_system("clear");
1783newtResume();
1784paranoid_free(drivelist);
1785return (retval);
1786}
1787
1788
1789
1790/**
1791 * Set the type of partition number @p partno on @p drive to @p format.
1792 * @param drive The drive to change the type of a partition on.
1793 * @param partno The partition number on @p drive to change the type of.
1794 * @param format The filesystem type this partition will eventually contain.
1795 * @param partsize The size of this partition, in @e bytes (used for vfat
1796 * type calculations).
1797 * @return 0 for success, nonzero for failure.
1798 */
1799int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno, const char *format, long long partsize) {
1800
1801/** buffers *********************************************************/
1802char *partition = NULL;
1803char *command = NULL;
1804char *output = NULL;
1805char *tmp = NULL;
1806char *partcode = NULL;
1807
1808/** pointers *********************************************************/
1809FILE *fout;
1810
1811/** int **************************************************************/
1812int res = 0;
1813
1814/** end **************************************************************/
1815
1816assert_string_is_neither_NULL_nor_zerolength(drive);
1817assert(format != NULL);
1818
1819partition = build_partition_name(drive, partno);
1820if (strcmp(format, "swap") == 0) {
1821 mr_asprintf(partcode, "82");
1822} else if (strcmp(format, "vfat") == 0) {
1823 if (partsize / 1024 > 8192) {
1824 mr_asprintf(partcode, "c");
1825 } else {
1826 mr_asprintf(partcode, "b");
1827 }
1828} else if (strcmp(format, "ext2") == 0
1829 || strcmp(format, "reiserfs") == 0
1830 || strcmp(format, "ext3") == 0
1831 || strcmp(format, "ext4") == 0
1832 || strcmp(format, "xfs") == 0
1833 || strcmp(format, "jfs") == 0
1834 || strcmp(format, "btrfs") == 0) {
1835 mr_asprintf(partcode, "83");
1836} else if (strcmp(format, "minix") == 0) {
1837 mr_asprintf(partcode, "81");
1838} else if (strcmp(format, "vmfs3") == 0) {
1839 mr_asprintf(partcode, "fb");
1840} else if (strcmp(format, "vmkcore") == 0) {
1841 mr_asprintf(partcode, "fc");
1842} else if (strcmp(format, "raid") == 0) {
1843 mr_asprintf(partcode, "fd");
1844} else if (strcmp(format, "ntfs") == 0) {
1845 mr_asprintf(partcode, "7");
1846} else if ((strcmp(format, "ufs") == 0)
1847 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1848 mr_asprintf(partcode, "a5");
1849} else if (strcmp(format, "lvm") == 0) {
1850 mr_asprintf(partcode, "8e");
1851} else if (format[0] == '\0') { /* LVM physical partition */
1852 mr_asprintf(partcode, "");
1853} else if (strlen(format) >= 1 && strlen(format) <= 2) {
1854 mr_asprintf(partcode, "%s", format);
1855} else {
1856 /* probably an image */
1857 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1858 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1859 mr_free(tmp);
1860
1861#ifdef __FreeBSD__
1862 mr_asprintf(partcode, "%s", format); // was a5
1863#else
1864 mr_asprintf(partcode, "%s", format); // was 83
1865#endif
1866}
1867log_msg(1, "Setting %s's type to %s (%s)", partition, format, partcode);
1868mr_free(partition);
1869
1870if ((strcmp(partcode,"") != 0) && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1871
1872 if (pout_to_fdisk) {
1873 res = 0;
1874 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1875 if (partno > 1
1876 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
1877 log_msg(5, "Specifying partno (%d) - yay", partno);
1878 mr_asprintf(tmp, "%d\n", partno);
1879 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1880 log_msg(5, "A - last line = '%s'", last_line_of_file(FDISK_LOG));
1881 mr_free(tmp);
1882 }
1883
1884 mr_asprintf(tmp, "%s\n", partcode);
1885 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1886 mr_free(tmp);
1887
1888 log_msg(5, "B - last line = '%s'",
1889 last_line_of_file(FDISK_LOG));
1890 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1891 log_msg(5, "C - last line = '%s'",
1892 last_line_of_file(FDISK_LOG));
1893
1894 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1895 if (!strstr(tmp, " (m ")) {
1896 log_msg(1, "last line = '%s'; part type set failed", tmp);
1897 res++;
1898 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1899 }
1900 mr_free(tmp);
1901
1902 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1903 } else {
1904 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
1905 mr_asprintf(command, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1906 log_msg(5, "output = '%s'", output);
1907 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
1908 log_msg(5, "command = '%s'", command);
1909 fout = popen(command, "w");
1910 if (!fout) {
1911 log_OS_error(command);
1912 res = 1;
1913 } else {
1914 res = 0;
1915 fprintf(fout, "%s", output);
1916 paranoid_pclose(fout);
1917 }
1918 mr_free(command);
1919 paranoid_free(output);
1920 }
1921}
1922mr_free(partcode);
1923
1924return (res);
1925}
1926
1927
1928int start_raid_device(char *raid_device) {
1929
1930/** int *************************************************************/
1931int res;
1932int retval = 0;
1933
1934/** buffers *********************************************************/
1935char *program = NULL;
1936
1937/** end *************************************************************/
1938
1939assert_string_is_neither_NULL_nor_zerolength(raid_device);
1940
1941#ifdef __FreeBSD__
1942if (is_this_device_mounted(raid_device)) {
1943 log_it("Can't start %s when it's mounted!", raid_device);
1944 return 1;
1945}
1946mr_asprintf(program, "vinum start -f %s", raid_device);
1947#else
1948mr_asprintf(program, "raidstart %s", raid_device);
1949#endif
1950log_msg(1, "program = %s", program);
1951res = run_program_and_log_output(program, 1);
1952if (g_fprep) {
1953 fprintf(g_fprep, "%s\n", program);
1954}
1955mr_free(program);
1956
1957if (res) {
1958 log_msg(1, "Warning - failed to start RAID device %s", raid_device);
1959}
1960retval += res;
1961sleep(1);
1962return (retval);
1963}
1964
1965
1966
1967/**
1968 * Stop @p raid_device using @p raidstop.
1969 * @param raid_device The software RAID device to stop.
1970 * @return 0 for success, nonzero for failure.
1971 */
1972int stop_raid_device(char *raid_device) {
1973
1974/** int *************************************************************/
1975int res;
1976int retval = 0;
1977
1978/** buffers *********************************************************/
1979char *program = NULL;
1980
1981/** end *************************************************************/
1982
1983assert_string_is_neither_NULL_nor_zerolength(raid_device);
1984
1985#ifdef __FreeBSD__
1986if (is_this_device_mounted(raid_device)) {
1987 log_it("Can't stop %s when it's mounted!", raid_device);
1988 return 1;
1989}
1990mr_asprintf(program, "vinum stop -f %s", raid_device);
1991#else
1992// use raidstop if it exists, otherwise use mdadm
1993if (run_program_and_log_output("which raidstop", FALSE)) {
1994 mr_asprintf(program, "mdadm -S %s", raid_device);
1995} else {
1996 mr_asprintf(program, "raidstop %s", raid_device);
1997}
1998#endif
1999log_msg(1, "program = %s", program);
2000res = run_program_and_log_output(program, 1);
2001if (g_fprep) {
2002 fprintf(g_fprep, "%s\n", program);
2003}
2004mr_free(program);
2005
2006if (res) {
2007 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2008}
2009retval += res;
2010return (retval);
2011}
2012
2013
2014int start_all_raid_devices(struct mountlist_itself *mountlist) {
2015
2016int i;
2017int retval = 0;
2018int res;
2019
2020for (i = 0; i < mountlist->entries; i++) {
2021 if (!strncmp(mountlist->el[i].device, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
2022 log_msg(1, "Starting %s", mountlist->el[i].device);
2023 res = start_raid_device(mountlist->el[i].device);
2024 retval += res;
2025 }
2026}
2027if (retval) {
2028 log_msg(1, "Started all s/w raid devices OK");
2029} else {
2030 log_msg(1, "Failed to start some/all s/w raid devices");
2031}
2032return (retval);
2033}
2034
2035/**
2036 * Stop all software RAID devices listed in @p mountlist.
2037 * @param mountlist The mountlist to stop the RAID devices in.
2038 * @return The number of errors encountered (0 for success).
2039 * @bug @p mountlist is not used.
2040 */
2041int stop_all_raid_devices(struct mountlist_itself *mountlist) {
2042
2043/** int *************************************************************/
2044int retval = 0;
2045
2046/** char ************************************************************/
2047char *incoming;
2048#ifndef __FreeBSD__
2049char *dev;
2050#endif
2051/** pointers ********************************************************/
2052#ifndef __FreeBSD__
2053char *p;
2054#endif
2055FILE *fin;
2056char *q;
2057int i;
2058
2059/** end ****************************************************************/
2060
2061malloc_string(incoming);
2062assert(mountlist != NULL);
2063
2064for (i = 0; i < 3; i++) {
2065#ifdef __FreeBSD__
2066 fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r");
2067 if (!fin) {
2068 paranoid_free(incoming);
2069 return (1);
2070 }
2071 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2072 retval += stop_raid_device(incoming);
2073 }
2074#else
2075 fin = fopen("/proc/mdstat", "r");
2076 if (!fin) {
2077 log_OS_error("/proc/mdstat");
2078 paranoid_free(incoming);
2079 return (1);
2080 }
2081 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2082 for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++);
2083 if (*p != '\0') {
2084 malloc_string(dev);
2085 sprintf(dev, "/dev/%s", p);
2086 for (p = dev; *p > 32; p++);
2087 *p = '\0';
2088 retval += stop_raid_device(dev);
2089 paranoid_free(dev);
2090 }
2091 }
2092#endif
2093}
2094paranoid_fclose(fin);
2095if (retval) {
2096 log_msg(1, "Warning - unable to stop some RAID devices");
2097}
2098paranoid_free(incoming);
2099paranoid_system("sync");
2100paranoid_system("sync");
2101paranoid_system("sync");
2102sleep(1);
2103return (retval);
2104}
2105
2106
2107
2108/**
2109 * Decide which command we need to use to format a device of type @p format.
2110 * @param format The filesystem type we are about to format.
2111 * @param program Where to put the binary name for this format.
2112 * @return 0 for success, nonzero for failure.
2113 */
2114char *which_format_command_do_i_need(char *format) {
2115
2116char *program = NULL;
2117
2118assert_string_is_neither_NULL_nor_zerolength(format);
2119
2120if (strcmp(format, "swap") == 0) {
2121#ifdef __FreeBSD__
2122 mr_asprintf(program, "true");
2123#else
2124 mr_asprintf(program, "mkswap -f");
2125#endif
2126} else if (strcmp(format, "vfat") == 0) {
2127#ifdef __FreeBSD__
2128 mr_asprintf(program, "newfs_msdos -F 32");
2129#else
2130#ifdef __IA64__
2131 /* For EFI partitions on ia64 take fat16
2132 * as we want to make small ones */
2133 mr_asprintf(program, "mkfs.vfat -F 16");
2134#else
2135 /* mkfs.vfat will make the best possible choice itself */
2136 /* should avoid problems with mr-label later on when used */
2137 mr_asprintf(program, "mkfs.vfat");
2138#endif
2139#endif
2140#ifndef __FreeBSD__
2141} else if (strcmp(format, "reiserfs") == 0) {
2142 mr_asprintf(program, "mkreiserfs -ff");
2143} else if (strcmp(format, "xfs") == 0) {
2144 /* Cf: https://bugzilla.redhat.com/show_bug.cgi?id=1309498 */
2145 mr_asprintf(program, "mkfs.xfs -f -q -m crc=0 -n ftype=0");
2146} else if (strcmp(format, "jfs") == 0) {
2147 mr_asprintf(program, "mkfs.jfs");
2148} else if (strcmp(format, "ext3") == 0) {
2149 mr_asprintf(program, "mkfs -t ext3 -F -q");
2150} else if (strcmp(format, "ext4") == 0) {
2151 mr_asprintf(program, "mkfs -t ext4 -F -q");
2152} else if (strcmp(format, "btrfs") == 0) {
2153 mr_asprintf(program, "mkfs.btrfs -f");
2154} else if (strcmp(format, "minix") == 0) {
2155 mr_asprintf(program, "mkfs.minix");
2156} else if (strcmp(format, "vmfs") == 0) {
2157 mr_asprintf(program, "mkfs -t vmfs");
2158} else if (strcmp(format, "ntfs") == 0) {
2159 /*
2160 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2161 * so the default "mkfs -t %s -c" command structure fails
2162 */
2163 mr_asprintf(program, "mkfs -t ntfs");
2164} else if (strcmp(format, "ocfs2") == 0) {
2165 /*
2166 * 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.
2167 *
2168 */
2169 mr_asprintf(program, "mkfs -t ocfs2 -F");
2170#endif
2171} else if (strcmp(format, "ext2") == 0) {
2172 mr_asprintf(program, "mke2fs -F -q");
2173} else {
2174#ifdef __FreeBSD__
2175 mr_asprintf(program, "newfs_%s", format);
2176#else
2177 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2178#endif
2179 log_it("Unknown format (%s) - assuming '%s' will do", format, program);
2180}
2181return(program);
2182}
2183
2184
2185/**
2186 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2187 * There are a few problems with this function:
2188 * - It won't work if there was any unallocated space on the user's hard drive
2189 * when it was backed up.
2190 * - It won't work if the user's hard drive lies about its size (more common
2191 * than you'd think).
2192 *
2193 * @param mountlist The mountlist to use for resizing @p drive_name.
2194 * @param drive_name The drive to resize.
2195 */
2196void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist, char *drive_name) {
2197
2198/**buffers **********************************************************/
2199char *tmp = NULL;
2200
2201/** int *************************************************************/
2202int partno, lastpart;
2203
2204/** float ***********************************************************/
2205float factor;
2206long long new_size;
2207
2208/** long *************************************************************/
2209long long newsizL = 0LL;
2210long long totalsizL = 0LL;
2211long long current_size_of_drive = 0LL; /* use KB interally for precision */
2212long long original_size_of_drive = 0LL; /* use KB interally for precision */
2213struct mountlist_reference *drivemntlist;
2214
2215/** structures *******************************************************/
2216
2217/** end **************************************************************/
2218
2219assert(mountlist != NULL);
2220assert_string_is_neither_NULL_nor_zerolength(drive_name);
2221
2222if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2223 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2224 == 0) {
2225 return;
2226 }
2227}
2228
2229current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
2230
2231if (current_size_of_drive <= 0LL) {
2232 log_it("Not resizing to match %s - can't find drive", drive_name);
2233 return;
2234}
2235log_to_screen("Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
2236
2237drivemntlist = malloc(sizeof(struct mountlist_reference));
2238drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2239
2240if (!drivemntlist) {
2241 fatal_error("Cannot malloc temporary mountlist\n");
2242}
2243create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2244
2245for (partno = 0; partno < drivemntlist->entries; partno++) {
2246 if (drivemntlist->el[partno]->size > 0LL) {
2247 /* Keep KB here */
2248 original_size_of_drive += drivemntlist->el[partno]->size;
2249 }
2250}
2251
2252if (original_size_of_drive <= 0LL) {
2253 log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name);
2254 return;
2255}
2256factor = ((float)current_size_of_drive/(float)original_size_of_drive);
2257log_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);
2258
2259lastpart = drivemntlist->entries - 1;
2260for (partno = 0; partno < drivemntlist->entries; partno++) {
2261 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2262 if (!atoi(drivemntlist->el[partno]->format)) {
2263 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
2264 } else {
2265 new_size = drivemntlist->el[partno]->size;
2266 }
2267
2268 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2269 log_msg(1, "Skipping %s (%s) because it's an image",
2270 drivemntlist->el[partno]->device,
2271 drivemntlist->el[partno]->mountpoint);
2272 }
2273 newsizL = new_size;
2274
2275 /* Do not apply the factor if partition was of negative size */
2276 if (newsizL < 0LL) {
2277 newsizL = drivemntlist->el[partno]->size;
2278 }
2279 totalsizL += newsizL;
2280
2281 log_to_screen("Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2282 drivemntlist->el[partno]->size = newsizL;
2283}
2284// Ensures over-allocation alert and prompt for interactive mode does not happen
2285if (totalsizL > current_size_of_drive) {
2286 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));
2287 drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive);
2288} else if (totalsizL < current_size_of_drive) {
2289 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));
2290 drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL);
2291}
2292log_to_screen(tmp);
2293mr_free(tmp);
2294log_to_screen("final_size = %lld MB", current_size_of_drive / 1024);
2295}
2296
2297
2298/**
2299 * Resize all partitions in @p mountlist proportionately (each one
2300 * grows or shrinks by the same percentage) to fit them into the new
2301 * drives (presumably different from the old ones).
2302 * @param mountlist The mountlist to resize the drives in.
2303 */
2304void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist) {
2305
2306/** buffers *********************************************************/
2307struct list_of_disks *drivelist;
2308
2309/** int *************************************************************/
2310int driveno;
2311
2312/** end *************************************************************/
2313
2314drivelist = malloc(sizeof(struct list_of_disks));
2315assert(mountlist != NULL);
2316
2317if (g_mountlist_fname[0] == '\0') {
2318 log_it("resize_mountlist_prop...() - warning - mountlist fname is blank");
2319 log_it("That does NOT affect the functioning of this subroutine.");
2320 log_it("--- Hugo, 2002/11/20");
2321}
2322log_it("Resizing mountlist");
2323make_list_of_drives_in_mountlist(mountlist, drivelist);
2324log_it("Back from MLoDiM");
2325for (driveno = 0; driveno < drivelist->entries; driveno++) {
2326 resize_drive_proportionately_to_suit_new_drives(mountlist, drivelist->el[driveno].device);
2327}
2328log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2329paranoid_free(drivelist);
2330}
2331
2332/**
2333 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2334 * @param mountlist The complete mountlist to get the drive references from.
2335 * @param drive_name The drive to put in @p drivemntlist.
2336 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2337 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2338 * @author Ralph Grewe
2339 */
2340void create_mountlist_for_drive(struct mountlist_itself *mountlist, char *drive_name, struct mountlist_reference *drivemntlist) {
2341
2342int partno;
2343char *tmp_drive_name, *c;
2344
2345assert(mountlist != NULL);
2346assert(drive_name != NULL);
2347assert(drivemntlist != NULL);
2348
2349log_msg(1, "Creating list of partitions for drive %s", drive_name);
2350
2351tmp_drive_name = strdup(drive_name);
2352if (!tmp_drive_name)
2353 fatal_error("Out of memory");
2354
2355/* devfs devices? */
2356c = strrchr(tmp_drive_name, '/');
2357if (c && strncmp(c, "/disc", 5) == 0) {
2358 /* yup its devfs, change the "disc" to "part" so the existing code works */
2359 strcpy(c + 1, "part");
2360}
2361drivemntlist->entries = 0;
2362for (partno = 0; partno < mountlist->entries; partno++) {
2363 if (strncmp(mountlist->el[partno].device, tmp_drive_name, strlen(tmp_drive_name)) == 0) {
2364 drivemntlist->el[drivemntlist->entries] = &mountlist->el[partno];
2365 drivemntlist->entries++;
2366 }
2367}
2368if (tmp_drive_name)
2369 free(tmp_drive_name);
2370}
2371
2372/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.