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

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