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

Last change on this file since 3611 was 3611, checked in by Bruno Cornec, 7 years ago

Remove more static allocation

  • Property svn:keywords set to Id
File size: 71.0 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 3611 2016-11-10 20:09: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 3611 2016-11-10 20:09: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);
789if (res) {
790 mr_strcat(tmp, "...failed");
791} else {
792 mr_strcat(tmp, "...OK");
793}
794log_to_screen(tmp);
795mr_free(tmp);
796
797retval += res;
798paranoid_system("sync");
799sleep(1);
800return (retval);
801}
802
803
804/**
805 * Format all drives (except those excluded by format_device()) in @p mountlist.
806 * @param mountlist The mountlist containing partitions to be formatted.
807 * @param interactively If TRUE, then prompt the user before each partition.
808 * @return The number of errors encountered (0 for success).
809 */
810int format_everything(struct mountlist_itself *mountlist, bool interactively, struct raidlist_itself *raidlist) {
811
812/** int **************************************************************/
813int retval = 0;
814int lino;
815int res;
816
817/** long *************************************************************/
818long progress_step;
819
820/** bools ************************************************************/
821bool do_it;
822
823/** buffers **********************************************************/
824char *tmp = NULL;
825
826/** pointers *********************************************************/
827struct mountlist_line *me; // mountlist entry
828/** end **************************************************************/
829
830assert(mountlist != NULL);
831log_it("format_everything (mountlist, interactively = %s", (interactively) ? "true" : "false");
832mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
833open_progress_form("Formatting partitions", "I am now formatting your hard disk partitions.", "This may take up to five minutes.", "", mountlist->entries + 1);
834
835progress_step = (mountlist->entries > 0) ? g_maximum_progress / mountlist->entries : 1;
836// start soft-raids now (because LVM might depend on them)
837// ...and for simplicity's sake, let's format them at the same time :)
838log_msg(1, "Stopping all RAID devices");
839stop_all_raid_devices(mountlist);
840paranoid_system("sync");
841paranoid_system("sync");
842paranoid_system("sync");
843sleep(2);
844log_msg(1, "Prepare soft-RAIDs"); // prep and format too
845for (lino = 0; lino < mountlist->entries; lino++) {
846 me = &mountlist->el[lino]; // the current mountlist entry
847 log_msg(2, "Examining %s", me->device);
848 if (!strncmp(me->device, "/dev/md", 7)) {
849 if (interactively) {
850 // ask user if we should format the current device
851 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
852 do_it = ask_me_yes_or_no(tmp);
853 mr_free(tmp);
854 } else {
855 do_it = TRUE;
856 }
857 if (do_it) {
858 // NB: format_device() also stops/starts RAID device if necessary
859 retval += format_device(me->device, me->format, raidlist);
860 }
861 g_current_progress += progress_step;
862 }
863}
864paranoid_system("sync");
865paranoid_system("sync");
866paranoid_system("sync");
867sleep(2);
868// do LVMs now
869log_msg(1, "Creating LVMs");
870if (does_file_exist("/tmp/i-want-my-lvm")) {
871 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
872 log_to_screen("Configuring LVM");
873 if (!g_text_mode) {
874 newtSuspend();
875 }
876 res = do_my_funky_lvm_stuff(FALSE, TRUE);
877 if (!g_text_mode) {
878 newtResume();
879 }
880 if (!res) {
881 log_to_screen("LVM initialized OK");
882 } else {
883 log_to_screen("Failed to initialize LVM");
884 }
885 // retval += res;
886 if (res) {
887 retval++;
888 }
889 sleep(3);
890}
891// do regulars at last
892sleep(2); // woo!
893log_msg(1, "Formatting regulars");
894for (lino = 0; lino < mountlist->entries; lino++) {
895 me = &mountlist->el[lino]; // the current mountlist entry
896 if (!strcmp(me->mountpoint, "image")) {
897 log_it("Not formatting %s - it's an image", me->device);
898 } else if (!strcmp(me->format, "raid")) {
899 log_it("Not formatting %s - it's a raid-let", me->device);
900 continue;
901 } else if (!strcmp(me->format, "lvm")) {
902 log_it("Not formatting %s - it's an LVM", me->device);
903 continue;
904 } else if (!strncmp(me->device, "/dev/md", 7)) {
905 log_it("Already formatted %s - it's a soft-RAID dev", me->device);
906 continue;
907 } else if (!does_file_exist(me->device) && strncmp(me->device, "/dev/hd", 7) && strncmp(me->device, "/dev/sd", 7)) {
908 log_it("Not formatting %s yet - doesn't exist - probably an LVM", me->device);
909 continue;
910 } else {
911 if (interactively) {
912 // ask user if we should format the current device
913 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
914 do_it = ask_me_yes_or_no(tmp);
915 mr_free(tmp);
916 } else {
917 do_it = TRUE;
918 }
919
920 if (do_it)
921 retval += format_device(me->device, me->format, raidlist);
922 }
923
924 // update progress bar
925 g_current_progress += progress_step;
926}
927
928
929// update progress bar to 100% to compensate for
930// rounding errors of the progress_step calculation
931if (lino >= mountlist->entries)
932 g_current_progress = g_maximum_progress;
933
934close_progress_form();
935
936if (retval) {
937 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
938 log_to_screen("Errors may have occurred during the formatting of your hard drives.");
939} else {
940 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
941}
942
943log_it("format_everything () - %s", (retval) ? "failed!" : "finished successfully");
944
945if (g_partition_table_locked_up > 0) {
946 if (retval > 0 && !interactively) {
947//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
948 log_to_screen("Partition table locked up %d times. At least one 'mkfs' (format) command", g_partition_table_locked_up);
949 log_to_screen("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
950 log_to_screen("to refresh its copy of the partition table causes the kernel to lock the ");
951 log_to_screen("partition table. I believe this has just happened.");
952 if (ask_me_yes_or_no("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue.")) {
953 paranoid_system("sync");
954 paranoid_system("sync");
955 paranoid_system("sync");
956 paranoid_system("reboot");
957 }
958 } else {
959 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');
960 }
961}
962newtSuspend();
963paranoid_system("clear");
964newtResume();
965return (retval);
966}
967
968
969/**
970 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
971 * Each partition created is 32k in size.
972 * @param drivename The drive to create the dummy partitions on.
973 * @param devno_we_must_allow_for The lowest-numbered real partition; create
974 * dummies up to (this - 1).
975 * @return The number of errors encountered (0 for success).
976 */
977int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename, int devno_we_must_allow_for) {
978
979/** int **************************************************************/
980int current_devno;
981int previous_devno;
982int retval = 0;
983int res;
984
985assert_string_is_neither_NULL_nor_zerolength(drivename);
986
987if (devno_we_must_allow_for >= 5) {
988 log_it("Making dummy primary 1 on %s", drivename);
989 g_maximum_progress++;
990 res = partition_device(pout_to_fdisk, drivename, 1, 0, "ext2", 32000);
991 retval += res;
992 previous_devno = 1;
993 current_devno = 5;
994} else {
995 previous_devno = 0;
996 current_devno = 1;
997}
998for (; current_devno < devno_we_must_allow_for; current_devno++) {
999 log_it("Creating dummy partition %d on %s", current_devno, drivename);
1000 g_maximum_progress++;
1001 res = partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, OSSWAP("ext2", "ufs"), 32000);
1002 retval += res;
1003 previous_devno = current_devno;
1004}
1005return (previous_devno);
1006}
1007
1008
1009/**
1010 * Decide whether @p mountlist contains any RAID devices.
1011 * @param mountlist The mountlist to examine.
1012 * @return TRUE if it does, FALSE if it doesn't.
1013 */
1014bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist) {
1015
1016/** int *************************************************************/
1017int i;
1018int matching = 0;
1019
1020/** end **************************************************************/
1021
1022assert(mountlist != NULL);
1023
1024for (i = 0; i < mountlist->entries; i++) {
1025 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1026 matching++;
1027 }
1028}
1029if (matching) {
1030 return (TRUE);
1031} else {
1032 return (FALSE);
1033}
1034}
1035
1036/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1037#ifdef __FreeBSD__
1038static void display_disklabel(FILE * f, const struct disklabel *lp) {
1039
1040int i, j;
1041const struct partition *pp;
1042
1043fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1044if (lp->d_type < DKMAXTYPES)
1045 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1046else
1047 fprintf(f, "type: %u\n", lp->d_type);
1048fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename);
1049fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname);
1050fprintf(f, "flags:");
1051if (lp->d_flags & D_REMOVABLE)
1052 fprintf(f, " removeable");
1053if (lp->d_flags & D_ECC)
1054 fprintf(f, " ecc");
1055if (lp->d_flags & D_BADSECT)
1056 fprintf(f, " badsect");
1057fprintf(f, "\n");
1058fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1059fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1060fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1061fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1062fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1063fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1064fprintf(f, "rpm: %u\n", lp->d_rpm);
1065fprintf(f, "interleave: %u\n", lp->d_interleave);
1066fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1067fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1068fprintf(f, "headswitch: %lu\t\t# milliseconds\n", (u_long) lp->d_headswitch);
1069fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (u_long) lp->d_trkseek);
1070fprintf(f, "drivedata: ");
1071for (i = NDDATA - 1; i >= 0; i--)
1072 if (lp->d_drivedata[i])
1073 break;
1074if (i < 0)
1075 i = 0;
1076for (j = 0; j <= i; j++)
1077 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1078fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1079fprintf(f, "# size offset fstype [fsize bsize bps/cpg]\n");
1080pp = lp->d_partitions;
1081for (i = 0; i < lp->d_npartitions; i++, pp++) {
1082 if (pp->p_size) {
1083 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size, (u_long) pp->p_offset);
1084 if (pp->p_fstype < FSMAXTYPES)
1085 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1086 else
1087 fprintf(f, "%8d", pp->p_fstype);
1088 switch (pp->p_fstype) {
1089
1090 case FS_UNUSED: /* XXX */
1091 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), "");
1092 break;
1093
1094 case FS_BSDFFS:
1095 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1096 break;
1097
1098 case FS_BSDLFS:
1099 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1100 break;
1101
1102 default:
1103 fprintf(f, "%20.20s", "");
1104 break;
1105 }
1106 fprintf(f, "\t# (Cyl. %4lu", (u_long) (pp->p_offset / lp->d_secpercyl));
1107 if (pp->p_offset % lp->d_secpercyl)
1108 putc('*', f);
1109 else
1110 putc(' ', f);
1111 fprintf(f, "- %lu", (u_long) ((pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl - 1));
1112 if (pp->p_size % lp->d_secpercyl)
1113 putc('*', f);
1114 fprintf(f, ")\n");
1115 }
1116}
1117fflush(f);
1118}
1119
1120static struct disklabel *get_virgin_disklabel(char *dkname) {
1121
1122static struct disklabel loclab;
1123struct partition *dp;
1124char *lnamebuf = NULL;
1125int f;
1126u_int secsize, u;
1127off_t mediasize;
1128
1129mr_asprintf(lnamebuf, "%s", dkname);
1130if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1131 warn("cannot open %s", lnamebuf);
1132 mr_free(lnamebuf);
1133 return (NULL);
1134}
1135mr_free(lnamebuf);
1136
1137/* New world order */
1138if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1139 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1140 close(f);
1141 return (NULL);
1142}
1143memset(&loclab, 0, sizeof loclab);
1144loclab.d_magic = DISKMAGIC;
1145loclab.d_magic2 = DISKMAGIC;
1146loclab.d_secsize = secsize;
1147loclab.d_secperunit = mediasize / secsize;
1148
1149/*
1150 * Nobody in these enligthened days uses the CHS geometry for
1151 * anything, but nontheless try to get it right. If we fail
1152 * to get any good ideas from the device, construct something
1153 * which is IBM-PC friendly.
1154 */
1155if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1156 loclab.d_nsectors = u;
1157else
1158 loclab.d_nsectors = 63;
1159
1160if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1161 loclab.d_ntracks = u;
1162else if (loclab.d_secperunit <= 63 * 1 * 1024)
1163 loclab.d_ntracks = 1;
1164else if (loclab.d_secperunit <= 63 * 16 * 1024)
1165 loclab.d_ntracks = 16;
1166else
1167 loclab.d_ntracks = 255;
1168loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1169loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1170loclab.d_npartitions = MAXPARTITIONS;
1171
1172/* Various (unneeded) compat stuff */
1173loclab.d_rpm = 3600;
1174loclab.d_bbsize = BBSIZE;
1175loclab.d_interleave = 1;;
1176strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1177
1178 dp = &loclab.d_partitions[RAW_PART];
1179dp->p_size = loclab.d_secperunit;
1180loclab.d_checksum = dkcksum(&loclab);
1181close(f);
1182return (&loclab);
1183}
1184
1185/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1186
1187char *canonical_name(char *drivename) {
1188
1189if (drivename) {
1190 if (strncmp(drivename, "/dev/", 5) == 0) {
1191 return drivename + 5;
1192 }
1193}
1194return drivename;
1195}
1196
1197/**
1198 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1199 * @param mountlist The mountlist to get the subpartition information from.
1200 * @param drivename The drive or slice to create a disklabel on.
1201 * @param ret If non-NULL, store the created disklabel here.
1202 * @return The number of errors encountered (0 for success).
1203 */
1204int label_drive_or_slice(struct mountlist_itself *mountlist, char *drivename, struct disklabel *ret) {
1205
1206char *subdev_str = NULL;
1207char *command = NULL;
1208struct disklabel *lp;
1209int i, lo = 0;
1210int retval = 0;
1211char c;
1212FILE *ftmp;
1213
1214lp = get_virgin_disklabel(drivename);
1215for (c = 'a'; c <= 'z'; ++c) {
1216 int idx;
1217 mr_asprintf(subdev_str, "%s%c", drivename, c);
1218 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1219 lp->d_partitions[c - 'a'].p_size = 0;
1220 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1221 } else {
1222 lo = c - 'a';
1223 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1224 lp->d_partitions[c - 'a'].p_fsize = 0;
1225 lp->d_partitions[c - 'a'].p_frag = 0;
1226 lp->d_partitions[c - 'a'].p_cpg = 0;
1227 if (!strcmp(mountlist->el[idx].format, "ufs") || !strcmp(mountlist->el[idx].format, "ffs") || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1228 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1229 lp->d_partitions[c - 'a'].p_fsize = 2048;
1230 lp->d_partitions[c - 'a'].p_frag = 8;
1231 lp->d_partitions[c - 'a'].p_cpg = 64;
1232 } else if (!strcasecmp(mountlist->el[idx].format, "raid") || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1233 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1234 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1235 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1236 } else
1237 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1238 }
1239 mr_free(subdev_str);
1240}
1241
1242// fix up the offsets
1243lp->d_partitions[0].p_offset = 0;
1244lp->d_partitions[RAW_PART].p_offset = 0;
1245lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1246lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1247
1248for (i = 1; i < lp->d_npartitions; ++i) {
1249 int lastone;
1250 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1251 continue;
1252 for (lastone = i - 1; lastone >= 0; lastone--) {
1253 if ((lp->d_partitions[lastone].p_size) && (lastone != RAW_PART))
1254 break;
1255 }
1256 lp->d_partitions[i].p_offset = lp->d_partitions[lastone].p_offset + lp->d_partitions[lastone].p_size;
1257}
1258if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size > lp->d_secperunit) {
1259 lp->d_partitions[lo].p_size = lp->d_secperunit - lp->d_partitions[lo].p_offset;
1260}
1261
1262ftmp = fopen("/tmp/disklabel", "w");
1263display_disklabel(ftmp, lp);
1264fclose(ftmp);
1265mr_asprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1266retval += run_program_and_log_output(command, TRUE);
1267mr_free(command);
1268
1269mr_asprintf(command, "disklabel -R %s /tmp/disklabel", canonical_name(drivename));
1270retval += run_program_and_log_output(command, TRUE);
1271mr_free(command);
1272
1273if (ret)
1274 *ret = *lp;
1275return retval;
1276}
1277#endif
1278
1279
1280/**
1281 * Partition @p drivename based on @p mountlist.
1282 * @param mountlist The mountlist to use to guide the partitioning.
1283 * @param drivename The drive to partition.
1284 * @return 0 for success, nonzero for failure.
1285 */
1286int partition_drive(struct mountlist_itself *mountlist, char *drivename) {
1287
1288/** int *************************************************************/
1289int current_devno;
1290int previous_devno = 0;
1291int lino;
1292int retval = 0;
1293int i;
1294FILE *pout_to_fdisk = NULL;
1295char *part_table_fmt = NULL;
1296
1297#ifdef __FreeBSD__
1298bool fbsd_part = FALSE;
1299char *subdev_str = NULL;
1300#endif
1301
1302/** long long *******************************************************/
1303long long partsize;
1304
1305/** buffers *********************************************************/
1306char *device_str;
1307char *format = NULL;
1308char *tmp = NULL;
1309char *tmp1 = NULL;
1310
1311/** end *************************************************************/
1312
1313assert(mountlist != NULL);
1314assert_string_is_neither_NULL_nor_zerolength(drivename);
1315
1316
1317log_it("Partitioning drive %s", drivename);
1318
1319#if __FreeBSD__
1320 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1321 pout_to_fdisk = NULL;
1322#else
1323make_hole_for_file(FDISK_LOG);
1324mr_asprintf(tmp, "mr-parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1325pout_to_fdisk = popen(tmp, "w");
1326if (!pout_to_fdisk) {
1327 log_to_screen("Cannot call mr-parted2fdisk to configure %s", drivename);
1328 mr_free(tmp);
1329 return (1);
1330}
1331mr_free(tmp);
1332#endif
1333
1334malloc_string(device_str);
1335
1336for (current_devno = 1; current_devno < 99; current_devno++) {
1337 build_partition_name(device_str, drivename, current_devno);
1338 lino = find_device_in_mountlist(mountlist, device_str);
1339
1340 if (lino < 0) {
1341 // device not found in mountlist
1342#if __FreeBSD__
1343 // If this is the first partition (just as a sentinel value),
1344 // then see if the user has picked 'dangerously-dedicated' mode.
1345 // If so, then we just call label_drive_or_slice() and return.
1346 char c;
1347 if (current_devno == 1) {
1348 // try DangerouslyDedicated mode
1349 for (c = 'a'; c <= 'z'; c++) {
1350 mr_asprintf(subdev_str, "%s%c", drivename, c);
1351 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1352 fbsd_part = TRUE;
1353 }
1354 mr_free(subdev_str);
1355 }
1356 if (fbsd_part) {
1357 int r = label_drive_or_slice(mountlist,
1358 drivename,
1359 0);
1360 char command[MAX_STR_LEN];
1361 sprintf(command, "disklabel -B %s",
1362 basename(drivename));
1363 if (system(command)) {
1364 log_to_screen
1365 ("Warning! Unable to make the drive bootable.");
1366 }
1367 paranoid_free(device_str);
1368 return r;
1369 }
1370 }
1371 for (c = 'a'; c <= 'z'; c++) {
1372 mr_assprintf(subdev_str, "%s%c", device_str, c);
1373 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1374 fbsd_part = TRUE;
1375 }
1376 mr_free(subdev_str);
1377 }
1378 // Now we check the subpartitions of the current partition.
1379 if (fbsd_part) {
1380 int i, line;
1381
1382 mr_asprintf(format, "ufs");
1383 partsize = 0;
1384 for (i = 'a'; i < 'z'; ++i) {
1385 mr_asprintf(subdev_str, "%s%c", device_str, i);
1386 line = find_device_in_mountlist(mountlist, subdev_str);
1387 mr_free(subdev_str);
1388
1389 if (line > 0) {
1390 // We found one! Add its size to the total size.
1391 partsize += mountlist->el[line].size;
1392 }
1393 }
1394 } else {
1395 continue;
1396 }
1397#else
1398 continue;
1399#endif
1400 }
1401
1402 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1403 /* For FreeBSD, that is /dev/adXsY */
1404
1405 log_it("Found partition %s in mountlist", device_str);
1406 if (!previous_devno) {
1407
1408 log_it("Wiping %s's partition table", drivename);
1409#if __FreeBSD__
1410 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1411 file = open(drivename, O_WRONLY);
1412 if (file != -1) {
1413 log_to_screnn("Warning - unable to open %s for wiping it's partition table", drivename);
1414 }
1415
1416 for (i = 0; i < 512; i++) {
1417 if (!write(file, "\0", 1)) {
1418 log_to_screen("Warning - unable to write to %s", drivename);
1419 }
1420 }
1421 paranoid_system("sync");
1422#else
1423 log_it("New, kernel-friendly partition remover");
1424 for (i = 20; i > 0; i--) {
1425 fprintf(pout_to_fdisk, "d\n%d\n", i);
1426 fflush(pout_to_fdisk);
1427 }
1428#endif
1429 if (current_devno > 1) {
1430 previous_devno = make_dummy_partitions(pout_to_fdisk, drivename, current_devno);
1431 }
1432 }
1433#ifdef __FreeBSD__
1434 if (!fbsd_part) {
1435 mr_free(format);
1436#endif
1437
1438 mr_asprintf(format, "%s", mountlist->el[lino].format);
1439 partsize = mountlist->el[lino].size;
1440
1441#ifdef __FreeBSD__
1442 }
1443#endif
1444
1445#ifndef __IA64__
1446 part_table_fmt = which_partition_format(drivename);
1447
1448 /* MBR needs an extended partition if more than 4 partitions */
1449 if (strcmp(part_table_fmt, "MBR") == 0) {
1450 if (current_devno == 5 && previous_devno == 4) {
1451 log_to_screen("You must leave at least one partition spare as the Extended partition.");
1452 paranoid_free(device_str);
1453 mr_free(format);
1454 return (1);
1455 }
1456 }
1457 mr_free(part_table_fmt);
1458#endif
1459
1460 retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize);
1461 mr_free(format);
1462
1463#ifdef __FreeBSD__
1464 if ((current_devno <= 4) && fbsd_part) {
1465 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1466 retval += label_drive_or_slice(mountlist, device_str, 0);
1467 if (system(tmp)) {
1468 log_to_screen("Warning! Unable to make the slice bootable.");
1469 }
1470 mr_free(tmp);
1471 }
1472#endif
1473
1474 previous_devno = current_devno;
1475}
1476
1477if (pout_to_fdisk) {
1478 // close fdisk
1479 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1480 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1481 paranoid_pclose(pout_to_fdisk);
1482 paranoid_system("sync");
1483 log_msg(0,"------------------- fdisk.log looks like this ------------------");
1484 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1485 paranoid_system(tmp);
1486 mr_free(tmp);
1487
1488 // mark relevant partition as bootable
1489 mr_asprintf(tmp1,"mr-make-me-bootable /tmp/mountlist.txt %s",drivename);
1490 tmp = call_program_and_get_last_line_of_output(tmp1);
1491 mr_free(tmp1);
1492 mr_free(tmp);
1493
1494 log_msg(0,"------------------- end of fdisk.log... ------------------");
1495 paranoid_system("sync");
1496 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1497 if (!run_program_and_log_output(tmp, 5)) {
1498 g_partition_table_locked_up++;
1499 }
1500 mr_free(tmp);
1501
1502 mr_asprintf(tmp, "partprobe %s", drivename);
1503 if (!run_program_and_log_output(tmp, 5)) {
1504 g_partition_table_locked_up--;
1505 }
1506 mr_free(tmp);
1507
1508 if (g_partition_table_locked_up > 0) {
1509 log_to_screen("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1510 }
1511}
1512paranoid_free(device_str);
1513return (retval);
1514}
1515
1516/**
1517 * Create partition number @p partno on @p drive with @p fdisk.
1518 * @param drive The drive to create the partition on.
1519// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1520 * @param prev_partno The partition number of the most recently prepped partition.
1521 * @param format The filesystem type of this partition (used to set the type).
1522 * @param partsize The size of the partition in @e bytes.
1523 * @return 0 for success, nonzero for failure.
1524 */
1525int partition_device(FILE * pout_to_fdisk, const char *drive, int partno, int prev_partno, const char *format, long long partsize) {
1526
1527/** int **************************************************************/
1528int retval = 0;
1529int res = 0;
1530
1531/** buffers **********************************************************/
1532char *program = NULL;
1533char *partition_name;
1534char *tmp = NULL;
1535char *output = NULL;
1536
1537/** pointers **********************************************************/
1538char *part_table_fmt = NULL;
1539FILE *fout;
1540
1541/** end ***************************************************************/
1542
1543assert_string_is_neither_NULL_nor_zerolength(drive);
1544assert(format != NULL);
1545
1546log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting", drive, partno, prev_partno, format, partsize);
1547
1548if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1549 log_it("Not partitioning %s - it is a virtual drive", drive);
1550 return (0);
1551}
1552
1553malloc_string(partition_name);
1554build_partition_name(partition_name, drive, partno);
1555if (partsize <= 0) {
1556 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1557} else {
1558 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1559}
1560update_progress_form(tmp);
1561log_it(tmp);
1562mr_free(tmp);
1563
1564if (is_this_device_mounted(partition_name)) {
1565 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1566 paranoid_free(partition_name);
1567 return (1);
1568}
1569
1570
1571mr_asprintf(program, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1572
1573/* TODO: should not be called each time */
1574part_table_fmt = which_partition_format(drive);
1575mr_asprintf(output, "");
1576
1577/* make it a primary/extended/logical */
1578if (partno <= 4) {
1579 mr_strcat(output, "n\np\n%d\n", partno);
1580} else {
1581 /* MBR needs an extended partition if more than 4 partitions */
1582 if (strcmp(part_table_fmt, "MBR") == 0) {
1583 if (partno == 5) {
1584 if (prev_partno >= 4) {
1585 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1586 paranoid_free(partition_name);
1587 paranoid_free(output);
1588 return (1);
1589 } else {
1590 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1591 }
1592 }
1593 mr_strcat(output, "n\nl\n");
1594 } else {
1595 /* GPT allows more than 4 primary partitions */
1596 mr_strcat(output, "n\np\n%d\n", partno);
1597 }
1598}
1599mr_free(part_table_fmt);
1600
1601mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1602if (partsize > 0) {
1603 if (!strcmp(format, "7")) {
1604 log_msg(1, "Adding 512K, just in case");
1605 partsize += 512;
1606 }
1607 mr_strcat(output, "+%lldK", (long long) (partsize));
1608}
1609mr_strcat(output, "\n");
1610#if 0
1611/*
1612#endif
1613log_it("PARTSIZE = +%ld",(long)partsize);
1614log_it("---fdisk command---");
1615log_it(output);
1616log_it("---end of fdisk---");
1617#if 0
1618*/
1619#endif
1620
1621
1622if (pout_to_fdisk) {
1623 log_msg(1, "Doing the new all-in-one fdisk thing");
1624 log_msg(1, "output = '%s'", output);
1625 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1626 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1627 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1628 if (strstr(tmp, " (m ")) {
1629 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1630 } else {
1631 log_msg(1, "last line = %s", tmp);
1632 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1633 }
1634 mr_free(tmp);
1635
1636 if (!retval) {
1637 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1638 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1639 if (retval) {
1640 log_msg(1, "Failed. Trying again...");
1641 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1642 }
1643 }
1644 if (retval) {
1645 log_msg(1, "...but failed to set type");
1646 }
1647} else {
1648 mr_strcat(output, "w\n\n");
1649 if (g_fprep) {
1650 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1651 }
1652 /* write to disk; close fdisk's stream */
1653 if (!(fout = popen(program, "w"))) {
1654 log_OS_error("can't popen-out to program");
1655 } else {
1656 fputs(output, fout);
1657 paranoid_pclose(fout);
1658 }
1659
1660 if (!does_partition_exist(drive, partno) && partsize > 0) {
1661 log_it("Vaccum-packing");
1662 g_current_progress--;
1663 res = partition_device(pout_to_fdisk, drive, partno, prev_partno, format, -1);
1664 if (res) {
1665 log_it("Failed to vacuum-pack %s", partition_name);
1666 retval++;
1667 } else {
1668 retval = 0;
1669 }
1670 }
1671 if (does_partition_exist(drive, partno)) {
1672 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1673 if (retval) {
1674 log_it("Partitioned %s but failed to set its type", partition_name);
1675 } else {
1676 if (partsize > 0) {
1677 log_to_screen("Partition %s created+configured OK", partition_name);
1678 } else {
1679 log_it("Returning from a successful vacuum-pack");
1680 }
1681 }
1682 } else {
1683 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1684 if (partsize > 0) {
1685 log_to_screen(tmp);
1686 } else {
1687 log_it(tmp);
1688 }
1689 mr_free(tmp);
1690 retval++;
1691 }
1692}
1693mr_free(program);
1694paranoid_free(output);
1695
1696g_current_progress++;
1697log_it("partition_device() --- leaving");
1698paranoid_free(partition_name);
1699return (retval);
1700}
1701
1702
1703
1704/**
1705 * Create all partitions listed in @p mountlist.
1706 * @param mountlist The mountlist to use to guide the partitioning.
1707 * @return The number of errors encountered (0 for success).
1708 * @note This sets the partition types but doesn't actually do the formatting.
1709 * Use format_everything() for that.
1710 */
1711int partition_everything(struct mountlist_itself *mountlist) {
1712
1713/** int ************************************************************/
1714int lino;
1715int retval = 0;
1716int i;
1717int res;
1718
1719/** buffer *********************************************************/
1720struct list_of_disks *drivelist;
1721
1722/** end ************************************************************/
1723
1724drivelist = malloc(sizeof(struct list_of_disks));
1725assert(mountlist != NULL);
1726
1727log_it("partition_everything() --- starting");
1728mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1729
1730if (mountlist_contains_raid_devices(mountlist)) {
1731 log_msg(0, "Mountlist, including the partitions incorporated in RAID devices:-");
1732 for (i = 0; i < mountlist->entries; i++) {
1733 log_it(mountlist->el[i].device);
1734 }
1735 log_msg(0, "End of mountlist.");
1736}
1737log_msg(0, "Stopping all LVMs, just in case");
1738if (!g_text_mode) {
1739 newtSuspend();
1740}
1741do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1742if (!g_text_mode) {
1743 newtResume();
1744}
1745log_msg(0, "Stopping all software RAID devices, just in case");
1746stop_all_raid_devices(mountlist);
1747log_msg(0, "Done.");
1748
1749open_progress_form("Partitioning devices", "I am now going to partition all your drives.", "This should not take more than five minutes.", "", mountlist->entries);
1750
1751make_list_of_drives_in_mountlist(mountlist, drivelist);
1752
1753/* partition each drive */
1754for (lino = 0; lino < drivelist->entries; lino++) {
1755 res = partition_drive(mountlist, drivelist->el[lino].device);
1756 retval += res;
1757}
1758close_progress_form();
1759if (retval) {
1760 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1761 log_to_screen("Errors may have occurred during the partitioning of your hard drives.");
1762} else {
1763 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1764 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1765}
1766newtSuspend();
1767paranoid_system("clear");
1768newtResume();
1769paranoid_free(drivelist);
1770return (retval);
1771}
1772
1773
1774
1775/**
1776 * Set the type of partition number @p partno on @p drive to @p format.
1777 * @param drive The drive to change the type of a partition on.
1778 * @param partno The partition number on @p drive to change the type of.
1779 * @param format The filesystem type this partition will eventually contain.
1780 * @param partsize The size of this partition, in @e bytes (used for vfat
1781 * type calculations).
1782 * @return 0 for success, nonzero for failure.
1783 */
1784int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno, const char *format, long long partsize) {
1785
1786/** buffers *********************************************************/
1787char *partition;
1788char *command = NULL;
1789char *output = NULL;
1790char *tmp = NULL;
1791char *partcode = NULL;
1792
1793/** pointers *********************************************************/
1794FILE *fout;
1795
1796/** int **************************************************************/
1797int res = 0;
1798
1799/** end **************************************************************/
1800
1801assert_string_is_neither_NULL_nor_zerolength(drive);
1802assert(format != NULL);
1803
1804malloc_string(partition);
1805
1806build_partition_name(partition, drive, partno);
1807if (strcmp(format, "swap") == 0) {
1808 mr_asprintf(partcode, "82");
1809} else if (strcmp(format, "vfat") == 0) {
1810 if (partsize / 1024 > 8192) {
1811 mr_asprintf(partcode, "c");
1812 } else {
1813 mr_asprintf(partcode, "b");
1814 }
1815} else if (strcmp(format, "ext2") == 0
1816 || strcmp(format, "reiserfs") == 0
1817 || strcmp(format, "ext3") == 0
1818 || strcmp(format, "ext4") == 0
1819 || strcmp(format, "xfs") == 0
1820 || strcmp(format, "jfs") == 0
1821 || strcmp(format, "btrfs") == 0) {
1822 mr_asprintf(partcode, "83");
1823} else if (strcmp(format, "minix") == 0) {
1824 mr_asprintf(partcode, "81");
1825} else if (strcmp(format, "vmfs3") == 0) {
1826 mr_asprintf(partcode, "fb");
1827} else if (strcmp(format, "vmkcore") == 0) {
1828 mr_asprintf(partcode, "fc");
1829} else if (strcmp(format, "raid") == 0) {
1830 mr_asprintf(partcode, "fd");
1831} else if (strcmp(format, "ntfs") == 0) {
1832 mr_asprintf(partcode, "7");
1833} else if ((strcmp(format, "ufs") == 0)
1834 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1835 mr_asprintf(partcode, "a5");
1836} else if (strcmp(format, "lvm") == 0) {
1837 mr_asprintf(partcode, "8e");
1838} else if (format[0] == '\0') { /* LVM physical partition */
1839 mr_asprintf(partcode, "");
1840} else if (strlen(format) >= 1 && strlen(format) <= 2) {
1841 mr_asprintf(partcode, "%s", format);
1842} else {
1843 /* probably an image */
1844 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1845 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1846 mr_free(tmp);
1847
1848#ifdef __FreeBSD__
1849 mr_asprintf(partcode, "%s", format); // was a5
1850#else
1851 mr_asprintf(partcode, "%s", format); // was 83
1852#endif
1853}
1854log_msg(1, "Setting %s's type to %s (%s)", partition, format, partcode);
1855if ((strcmp(partcode,"") != 0) && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1856
1857 if (pout_to_fdisk) {
1858 res = 0;
1859 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1860 if (partno > 1
1861 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
1862 log_msg(5, "Specifying partno (%d) - yay", partno);
1863 mr_asprintf(tmp, "%d\n", partno);
1864 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1865 log_msg(5, "A - last line = '%s'", last_line_of_file(FDISK_LOG));
1866 mr_free(tmp);
1867 }
1868
1869 mr_asprintf(tmp, "%s\n", partcode);
1870 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1871 mr_free(tmp);
1872
1873 log_msg(5, "B - last line = '%s'",
1874 last_line_of_file(FDISK_LOG));
1875 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1876 log_msg(5, "C - last line = '%s'",
1877 last_line_of_file(FDISK_LOG));
1878
1879 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1880 if (!strstr(tmp, " (m ")) {
1881 log_msg(1, "last line = '%s'; part type set failed", tmp);
1882 res++;
1883 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1884 }
1885 mr_free(tmp);
1886
1887 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1888 } else {
1889 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
1890 mr_asprintf(command, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1891 log_msg(5, "output = '%s'", output);
1892 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
1893 log_msg(5, "command = '%s'", command);
1894 fout = popen(command, "w");
1895 if (!fout) {
1896 log_OS_error(command);
1897 res = 1;
1898 } else {
1899 res = 0;
1900 fprintf(fout, "%s", output);
1901 paranoid_pclose(fout);
1902 }
1903 mr_free(command);
1904 paranoid_free(output);
1905 }
1906}
1907mr_free(partcode);
1908
1909paranoid_free(partition);
1910
1911return (res);
1912}
1913
1914
1915int start_raid_device(char *raid_device) {
1916
1917/** int *************************************************************/
1918int res;
1919int retval = 0;
1920
1921/** buffers *********************************************************/
1922char *program = NULL;
1923
1924/** end *************************************************************/
1925
1926assert_string_is_neither_NULL_nor_zerolength(raid_device);
1927
1928#ifdef __FreeBSD__
1929if (is_this_device_mounted(raid_device)) {
1930 log_it("Can't start %s when it's mounted!", raid_device);
1931 return 1;
1932}
1933mr_asprintf(program, "vinum start -f %s", raid_device);
1934#else
1935mr_asprintf(program, "raidstart %s", raid_device);
1936#endif
1937log_msg(1, "program = %s", program);
1938res = run_program_and_log_output(program, 1);
1939if (g_fprep) {
1940 fprintf(g_fprep, "%s\n", program);
1941}
1942mr_free(program);
1943
1944if (res) {
1945 log_msg(1, "Warning - failed to start RAID device %s", raid_device);
1946}
1947retval += res;
1948sleep(1);
1949return (retval);
1950}
1951
1952
1953
1954/**
1955 * Stop @p raid_device using @p raidstop.
1956 * @param raid_device The software RAID device to stop.
1957 * @return 0 for success, nonzero for failure.
1958 */
1959int stop_raid_device(char *raid_device) {
1960
1961/** int *************************************************************/
1962int res;
1963int retval = 0;
1964
1965/** buffers *********************************************************/
1966char *program = NULL;
1967
1968/** end *************************************************************/
1969
1970assert_string_is_neither_NULL_nor_zerolength(raid_device);
1971
1972#ifdef __FreeBSD__
1973if (is_this_device_mounted(raid_device)) {
1974 log_it("Can't stop %s when it's mounted!", raid_device);
1975 return 1;
1976}
1977mr_asprintf(program, "vinum stop -f %s", raid_device);
1978#else
1979// use raidstop if it exists, otherwise use mdadm
1980if (run_program_and_log_output("which raidstop", FALSE)) {
1981 mr_asprintf(program, "mdadm -S %s", raid_device);
1982} else {
1983 mr_asprintf(program, "raidstop %s", raid_device);
1984}
1985#endif
1986log_msg(1, "program = %s", program);
1987res = run_program_and_log_output(program, 1);
1988if (g_fprep) {
1989 fprintf(g_fprep, "%s\n", program);
1990}
1991mr_free(program);
1992
1993if (res) {
1994 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
1995}
1996retval += res;
1997return (retval);
1998}
1999
2000
2001int start_all_raid_devices(struct mountlist_itself *mountlist) {
2002
2003int i;
2004int retval = 0;
2005int res;
2006
2007for (i = 0; i < mountlist->entries; i++) {
2008 if (!strncmp(mountlist->el[i].device, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
2009 log_msg(1, "Starting %s", mountlist->el[i].device);
2010 res = start_raid_device(mountlist->el[i].device);
2011 retval += res;
2012 }
2013}
2014if (retval) {
2015 log_msg(1, "Started all s/w raid devices OK");
2016} else {
2017 log_msg(1, "Failed to start some/all s/w raid devices");
2018}
2019return (retval);
2020}
2021
2022/**
2023 * Stop all software RAID devices listed in @p mountlist.
2024 * @param mountlist The mountlist to stop the RAID devices in.
2025 * @return The number of errors encountered (0 for success).
2026 * @bug @p mountlist is not used.
2027 */
2028int stop_all_raid_devices(struct mountlist_itself *mountlist) {
2029
2030/** int *************************************************************/
2031int retval = 0;
2032
2033/** char ************************************************************/
2034char *incoming;
2035#ifndef __FreeBSD__
2036char *dev;
2037#endif
2038/** pointers ********************************************************/
2039#ifndef __FreeBSD__
2040char *p;
2041#endif
2042FILE *fin;
2043char *q;
2044int i;
2045
2046/** end ****************************************************************/
2047
2048malloc_string(incoming);
2049assert(mountlist != NULL);
2050
2051for (i = 0; i < 3; i++) {
2052#ifdef __FreeBSD__
2053 fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r");
2054 if (!fin) {
2055 paranoid_free(incoming);
2056 return (1);
2057 }
2058 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2059 retval += stop_raid_device(incoming);
2060 }
2061#else
2062 fin = fopen("/proc/mdstat", "r");
2063 if (!fin) {
2064 log_OS_error("/proc/mdstat");
2065 paranoid_free(incoming);
2066 return (1);
2067 }
2068 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2069 for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++);
2070 if (*p != '\0') {
2071 malloc_string(dev);
2072 sprintf(dev, "/dev/%s", p);
2073 for (p = dev; *p > 32; p++);
2074 *p = '\0';
2075 retval += stop_raid_device(dev);
2076 paranoid_free(dev);
2077 }
2078 }
2079#endif
2080}
2081paranoid_fclose(fin);
2082if (retval) {
2083 log_msg(1, "Warning - unable to stop some RAID devices");
2084}
2085paranoid_free(incoming);
2086paranoid_system("sync");
2087paranoid_system("sync");
2088paranoid_system("sync");
2089sleep(1);
2090return (retval);
2091}
2092
2093
2094
2095/**
2096 * Decide which command we need to use to format a device of type @p format.
2097 * @param format The filesystem type we are about to format.
2098 * @param program Where to put the binary name for this format.
2099 * @return 0 for success, nonzero for failure.
2100 */
2101char *which_format_command_do_i_need(char *format) {
2102
2103char *program = NULL;
2104
2105assert_string_is_neither_NULL_nor_zerolength(format);
2106
2107if (strcmp(format, "swap") == 0) {
2108#ifdef __FreeBSD__
2109 mr_asprintf(program, "true");
2110#else
2111 mr_asprintf(program, "mkswap -f");
2112#endif
2113} else if (strcmp(format, "vfat") == 0) {
2114#ifdef __FreeBSD__
2115 mr_asprintf(program, "newfs_msdos -F 32");
2116#else
2117#ifdef __IA64__
2118 /* For EFI partitions on ia64 take fat16
2119 * as we want to make small ones */
2120 mr_asprintf(program, "mkfs.vfat -F 16");
2121#else
2122 /* mkfs.vfat will make the best possible choice itself */
2123 /* should avoid problems with mr-label later on when used */
2124 mr_asprintf(program, "mkfs.vfat");
2125#endif
2126#endif
2127#ifndef __FreeBSD__
2128} else if (strcmp(format, "reiserfs") == 0) {
2129 mr_asprintf(program, "mkreiserfs -ff");
2130} else if (strcmp(format, "xfs") == 0) {
2131 mr_asprintf(program, "mkfs.xfs -f -q");
2132} else if (strcmp(format, "jfs") == 0) {
2133 mr_asprintf(program, "mkfs.jfs");
2134} else if (strcmp(format, "ext3") == 0) {
2135 mr_asprintf(program, "mkfs -t ext3 -F -q");
2136} else if (strcmp(format, "ext4") == 0) {
2137 mr_asprintf(program, "mkfs -t ext4 -F -q");
2138} else if (strcmp(format, "btrfs") == 0) {
2139 mr_asprintf(program, "mkfs.btrfs");
2140} else if (strcmp(format, "minix") == 0) {
2141 mr_asprintf(program, "mkfs.minix");
2142} else if (strcmp(format, "vmfs") == 0) {
2143 mr_asprintf(program, "mkfs -t vmfs");
2144} else if (strcmp(format, "ntfs") == 0) {
2145 /*
2146 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2147 * so the default "mkfs -t %s -c" command structure fails
2148 */
2149 mr_asprintf(program, "mkfs -t ntfs");
2150} else if (strcmp(format, "ocfs2") == 0) {
2151 /*
2152 * 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.
2153 *
2154 */
2155 mr_asprintf(program, "mkfs -t ocfs2 -F");
2156#endif
2157} else if (strcmp(format, "ext2") == 0) {
2158 mr_asprintf(program, "mke2fs -F -q");
2159} else {
2160#ifdef __FreeBSD__
2161 mr_asprintf(program, "newfs_%s", format);
2162#else
2163 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2164#endif
2165 log_it("Unknown format (%s) - assuming '%s' will do", format, program);
2166}
2167return(program);
2168}
2169
2170
2171/**
2172 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2173 * There are a few problems with this function:
2174 * - It won't work if there was any unallocated space on the user's hard drive
2175 * when it was backed up.
2176 * - It won't work if the user's hard drive lies about its size (more common
2177 * than you'd think).
2178 *
2179 * @param mountlist The mountlist to use for resizing @p drive_name.
2180 * @param drive_name The drive to resize.
2181 */
2182void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist, char *drive_name) {
2183
2184/**buffers **********************************************************/
2185char *tmp = NULL;
2186
2187/** int *************************************************************/
2188int partno, lastpart;
2189
2190/** float ***********************************************************/
2191float factor;
2192long long new_size;
2193
2194/** long *************************************************************/
2195long long newsizL = 0LL;
2196long long totalsizL = 0LL;
2197long long current_size_of_drive = 0LL; /* use KB interally for precision */
2198long long original_size_of_drive = 0LL; /* use KB interally for precision */
2199struct mountlist_reference *drivemntlist;
2200
2201/** structures *******************************************************/
2202
2203/** end **************************************************************/
2204
2205assert(mountlist != NULL);
2206assert_string_is_neither_NULL_nor_zerolength(drive_name);
2207
2208if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2209 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2210 == 0) {
2211 return;
2212 }
2213}
2214
2215current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
2216
2217if (current_size_of_drive <= 0LL) {
2218 log_it("Not resizing to match %s - can't find drive", drive_name);
2219 return;
2220}
2221log_to_screen("Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
2222
2223drivemntlist = malloc(sizeof(struct mountlist_reference));
2224drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2225
2226if (!drivemntlist) {
2227 fatal_error("Cannot malloc temporary mountlist\n");
2228}
2229create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2230
2231for (partno = 0; partno < drivemntlist->entries; partno++) {
2232 if (drivemntlist->el[partno]->size > 0LL) {
2233 /* Keep KB here */
2234 original_size_of_drive += drivemntlist->el[partno]->size;
2235 }
2236}
2237
2238if (original_size_of_drive <= 0LL) {
2239 log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name);
2240 return;
2241}
2242factor = ((float)current_size_of_drive/(float)original_size_of_drive);
2243log_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);
2244
2245lastpart = drivemntlist->entries - 1;
2246for (partno = 0; partno < drivemntlist->entries; partno++) {
2247 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2248 if (!atoi(drivemntlist->el[partno]->format)) {
2249 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
2250 } else {
2251 new_size = drivemntlist->el[partno]->size;
2252 }
2253
2254 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2255 log_msg(1, "Skipping %s (%s) because it's an image",
2256 drivemntlist->el[partno]->device,
2257 drivemntlist->el[partno]->mountpoint);
2258 }
2259 newsizL = new_size;
2260
2261 /* Do not apply the factor if partition was of negative size */
2262 if (newsizL < 0LL) {
2263 newsizL = drivemntlist->el[partno]->size;
2264 }
2265 totalsizL += newsizL;
2266
2267 log_to_screen("Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2268 drivemntlist->el[partno]->size = newsizL;
2269}
2270// Ensures over-allocation alert and prompt for interactive mode does not happen
2271if (totalsizL > current_size_of_drive) {
2272 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));
2273 drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive);
2274} else if (totalsizL < current_size_of_drive) {
2275 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));
2276 drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL);
2277}
2278log_to_screen(tmp);
2279mr_free(tmp);
2280log_to_screen("final_size = %lld MB", current_size_of_drive / 1024);
2281}
2282
2283
2284/**
2285 * Resize all partitions in @p mountlist proportionately (each one
2286 * grows or shrinks by the same percentage) to fit them into the new
2287 * drives (presumably different from the old ones).
2288 * @param mountlist The mountlist to resize the drives in.
2289 */
2290void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist) {
2291
2292/** buffers *********************************************************/
2293struct list_of_disks *drivelist;
2294
2295/** int *************************************************************/
2296int driveno;
2297
2298/** end *************************************************************/
2299
2300drivelist = malloc(sizeof(struct list_of_disks));
2301assert(mountlist != NULL);
2302
2303if (g_mountlist_fname[0] == '\0') {
2304 log_it("resize_mountlist_prop...() - warning - mountlist fname is blank");
2305 log_it("That does NOT affect the functioning of this subroutine.");
2306 log_it("--- Hugo, 2002/11/20");
2307}
2308log_it("Resizing mountlist");
2309make_list_of_drives_in_mountlist(mountlist, drivelist);
2310log_it("Back from MLoDiM");
2311for (driveno = 0; driveno < drivelist->entries; driveno++) {
2312 resize_drive_proportionately_to_suit_new_drives(mountlist, drivelist->el[driveno].device);
2313}
2314log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2315paranoid_free(drivelist);
2316}
2317
2318/**
2319 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2320 * @param mountlist The complete mountlist to get the drive references from.
2321 * @param drive_name The drive to put in @p drivemntlist.
2322 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2323 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2324 * @author Ralph Grewe
2325 */
2326void create_mountlist_for_drive(struct mountlist_itself *mountlist, char *drive_name, struct mountlist_reference *drivemntlist) {
2327
2328int partno;
2329char *tmp_drive_name, *c;
2330
2331assert(mountlist != NULL);
2332assert(drive_name != NULL);
2333assert(drivemntlist != NULL);
2334
2335log_msg(1, "Creating list of partitions for drive %s", drive_name);
2336
2337tmp_drive_name = strdup(drive_name);
2338if (!tmp_drive_name)
2339 fatal_error("Out of memory");
2340
2341/* devfs devices? */
2342c = strrchr(tmp_drive_name, '/');
2343if (c && strncmp(c, "/disc", 5) == 0) {
2344 /* yup its devfs, change the "disc" to "part" so the existing code works */
2345 strcpy(c + 1, "part");
2346}
2347drivemntlist->entries = 0;
2348for (partno = 0; partno < mountlist->entries; partno++) {
2349 if (strncmp(mountlist->el[partno].device, tmp_drive_name, strlen(tmp_drive_name)) == 0) {
2350 drivemntlist->el[drivemntlist->entries] = &mountlist->el[partno];
2351 drivemntlist->entries++;
2352 }
2353}
2354if (tmp_drive_name)
2355 free(tmp_drive_name);
2356}
2357
2358/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.