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

Last change on this file was 3893, checked in by Bruno Cornec, 7 weeks ago

Remove more warnings - switch and size_t/int comparisons

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