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

Last change on this file since 3879 was 3879, checked in by Bruno Cornec, 4 months ago

Fix all remaining compiler errors

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