source: MondoRescue/branches/2.2.10/mondo/src/mondorestore/mondo-prep.c@ 2405

Last change on this file since 2405 was 2405, checked in by Bruno Cornec, 15 years ago

Removes some malloc_string static allocation

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