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

Last change on this file since 3885 was 3885, checked in by Bruno Cornec, 3 months ago

Removes support for ia64 depracated in upstream kernel, and elilo

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