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

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

call_program_and_get_last_line_of_output is now allocating memory and returning that string

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