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

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