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

Last change on this file since 2357 was 2357, checked in by Bruno Cornec, 15 years ago
  • Some more fgets => mr_getline transformations
  • XWIN define is gone
  • Property svn:keywords set to Id
File size: 70.9 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 2357 2009-08-29 01:22:10Z 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 2357 2009-08-29 01:22:10Z 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 system("sync");
121 system("sync");
122 system("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 system("sync");
280 system("sync");
281 system("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 mr_asprintf(tmp, "%s", 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 mr_asprintf(tmp, "%s", 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 system("sync");
411 system("sync");
412 system("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 system("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 system("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 system("sync");
787 sleep(2);
788#endif
789 system("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 system("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 system("sync");
904 system("sync");
905 system("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 system("sync");
928 system("sync");
929 system("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 system("sync");
1031 system("sync");
1032 system("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
1417 /** end *************************************************************/
1418
1419 assert(mountlist != NULL);
1420 assert_string_is_neither_NULL_nor_zerolength(drivename);
1421
1422 log_it("Partitioning drive %s", drivename);
1423
1424#if __FreeBSD__
1425 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1426 pout_to_fdisk = NULL;
1427#else
1428 make_hole_for_file(FDISK_LOG);
1429 mr_asprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1430 pout_to_fdisk = popen(tmp, "w");
1431 mr_free(tmp);
1432 if (!pout_to_fdisk) {
1433 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
1434 return (1);
1435 }
1436#endif
1437 for (current_devno = 1; current_devno < 99; current_devno++) {
1438 device_str = build_partition_name(drivename, current_devno);
1439 lino = find_device_in_mountlist(mountlist, device_str);
1440
1441 if (lino < 0) {
1442 // device not found in mountlist
1443#if __FreeBSD__
1444 // If this is the first partition (just as a sentinel value),
1445 // then see if the user has picked 'dangerously-dedicated' mode.
1446 // If so, then we just call label_drive_or_slice() and return.
1447 char c;
1448 if (current_devno == 1) {
1449 // try DangerouslyDedicated mode
1450 for (c = 'a'; c <= 'z'; c++) {
1451 mr_asprintf(subdev_str, "%s%c", drivename, c);
1452 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1453 fbsd_part = TRUE;
1454 }
1455 mr_free(subdev_str);
1456 }
1457 if (fbsd_part) {
1458 r = label_drive_or_slice(mountlist,
1459 drivename,
1460 0);
1461 mr_asprintf(command, "disklabel -B %s", basename(drivename));
1462 if (system(command)) {
1463 log_to_screen
1464 ("Warning! Unable to make the drive bootable.");
1465 }
1466 mr_free(command);
1467 mr_free(device_str);
1468 return r;
1469 }
1470 }
1471 for (c = 'a'; c <= 'z'; c++) {
1472 mr_asprintf(subdev_str, "%s%c", device_str, c);
1473 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1474 fbsd_part = TRUE;
1475 }
1476 mr_free(subdev_str);
1477 }
1478 // Now we check the subpartitions of the current partition.
1479 if (fbsd_part) {
1480 int i, line;
1481
1482 mr_asprintf(format, "ufs");
1483 partsize = 0;
1484 for (i = 'a'; i < 'z'; ++i) {
1485 mr_asprintf(subdev_str, "%s%c", device_str, i);
1486 line = find_device_in_mountlist(mountlist, subdev_str);
1487 mr_free(subdev_str);
1488
1489 if (line > 0) {
1490 // We found one! Add its size to the total size.
1491 partsize += mountlist->el[line].size;
1492 }
1493 }
1494 } else {
1495 mr_free(device_str);
1496 continue;
1497 }
1498#else
1499 mr_free(device_str);
1500 continue;
1501#endif
1502 }
1503
1504 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1505 /* For FreeBSD, that is /dev/adXsY */
1506
1507 log_it("Found partition %s in mountlist", device_str);
1508 if (!previous_devno) {
1509
1510 log_it("Wiping %s's partition table", drivename);
1511#if __FreeBSD__
1512 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1513 file = open(drivename, O_WRONLY);
1514 if (file != -1) {
1515 log_to_screen("Warning - unable to open %s for wiping it's partition table", drivename);
1516 }
1517
1518 for (i = 0; i < 512; i++) {
1519 if (!write(file, "\0", 1)) {
1520 log_to_screen("Warning - unable to write to %s", drivename);
1521 }
1522 }
1523 system("sync");
1524#else
1525 log_it("New, kernel-friendly partition remover");
1526 for (i = 20; i > 0; i--) {
1527 fprintf(pout_to_fdisk, "d\n%d\n", i);
1528 fflush(pout_to_fdisk);
1529 }
1530#endif
1531 if (current_devno > 1) {
1532 previous_devno =
1533 make_dummy_partitions(pout_to_fdisk, drivename,
1534 current_devno);
1535 }
1536 }
1537#ifdef __FreeBSD__
1538 if (!fbsd_part) {
1539 mr_free(format);
1540#endif
1541
1542 mr_asprintf(format, "%s", mountlist->el[lino].format);
1543 partsize = mountlist->el[lino].size;
1544
1545#ifdef __FreeBSD__
1546 }
1547#endif
1548
1549#ifndef __IA64__
1550 if (current_devno == 5 && previous_devno == 4) {
1551 log_to_screen
1552 ("You must leave at least one partition spare as the Extended partition.");
1553 mr_free(device_str);
1554 mr_free(format);
1555 return (1);
1556 }
1557#endif
1558
1559 retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize);
1560 mr_free(format);
1561
1562#ifdef __FreeBSD__
1563 if ((current_devno <= 4) && fbsd_part) {
1564 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1565 retval += label_drive_or_slice(mountlist, device_str, 0);
1566 if (system(tmp)) {
1567 log_to_screen
1568 ("Warning! Unable to make the slice bootable.");
1569 }
1570 mr_free(tmp);
1571 }
1572#endif
1573 mr_free(device_str);
1574
1575 previous_devno = current_devno;
1576 }
1577
1578 if (pout_to_fdisk) {
1579 // mark relevant partition as bootable
1580 mr_asprintf(tmp, "a\n%s\n", call_program_and_get_last_line_of_output ("make-me-bootable /tmp/mountlist.txt dummy"));
1581 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1582 mr_free(tmp);
1583
1584 // close fdisk
1585 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1586 system("sync");
1587 paranoid_pclose(pout_to_fdisk);
1588 log_msg(0,
1589 "------------------- fdisk.log looks like this ------------------");
1590 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1591 system(tmp);
1592 mr_free(tmp);
1593
1594 log_msg(0,
1595 "------------------- end of fdisk.log... word! ------------------");
1596 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1597 if (!run_program_and_log_output(tmp, 5)) {
1598 g_partition_table_locked_up++;
1599 }
1600 mr_free(tmp);
1601
1602 mr_asprintf(tmp, "partprobe %s", drivename);
1603 if (!run_program_and_log_output(tmp, 5)) {
1604 g_partition_table_locked_up--;
1605 }
1606 mr_free(tmp);
1607
1608 if (g_partition_table_locked_up > 0) {
1609 log_to_screen
1610 ("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1611 }
1612 }
1613 return (retval);
1614}
1615
1616/**
1617 * Create partition number @p partno on @p drive with @p fdisk.
1618 * @param drive The drive to create the partition on.
1619// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1620 * @param prev_partno The partition number of the most recently prepped partition.
1621 * @param format The filesystem type of this partition (used to set the type).
1622 * @param partsize The size of the partition in @e bytes.
1623 * @return 0 for success, nonzero for failure.
1624 */
1625int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1626 int prev_partno, const char *format,
1627 long long partsize)
1628{
1629 /** int **************************************************************/
1630 int retval = 0;
1631 int res = 0;
1632
1633 /** buffers **********************************************************/
1634 char *program = NULL;
1635 char *partition_name = NULL;
1636 char *tmp = NULL;
1637 char *output = NULL;
1638
1639 /** pointers **********************************************************/
1640 char *p;
1641 char *part_table_fmt = NULL;
1642 FILE *fout;
1643
1644 /** end ***************************************************************/
1645
1646 assert_string_is_neither_NULL_nor_zerolength(drive);
1647 assert(format != NULL);
1648
1649 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1650 drive, partno, prev_partno, format, partsize);
1651
1652 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1653 log_it("Not partitioning %s - it is a virtual drive", drive);
1654 return (0);
1655 }
1656 partition_name = build_partition_name(drive, partno);
1657 if (partsize <= 0) {
1658 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1659 } else {
1660 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1661 }
1662 update_progress_form(tmp);
1663 log_it(tmp);
1664 mr_free(tmp);
1665
1666 if (is_this_device_mounted(partition_name)) {
1667 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1668 mr_free(partition_name);
1669 return (1);
1670 }
1671
1672
1673 p = (char *) strrchr(partition_name, '/');
1674
1675 /* BERLIOS: should not be called each time */
1676 part_table_fmt = which_partition_format(drive);
1677 mr_asprintf(output, "");
1678 /* make it a primary/extended/logical */
1679 if (partno <= 4) {
1680 mr_strcat(output, "n\np\n%d\n", partno);
1681 } else {
1682 /* MBR needs an extended partition if more than 4 partitions */
1683 if (strcmp(part_table_fmt, "MBR") == 0) {
1684 if (partno == 5) {
1685 if (prev_partno >= 4) {
1686 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1687 mr_free(partition_name);
1688 mr_free(output);
1689 mr_free(part_table_fmt);
1690 return (1);
1691 } else {
1692 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1693 }
1694 }
1695 mr_strcat(output, "n\nl\n");
1696 } else {
1697 /* GPT allows more than 4 primary partitions */
1698 mr_strcat(output, "n\np\n%d\n", partno);
1699 }
1700 }
1701 mr_free(part_table_fmt);
1702
1703 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1704 if (partsize > 0) {
1705 if (!strcmp(format, "7")) {
1706 log_msg(1, "Adding 512K, just in case");
1707 partsize += 512;
1708 }
1709 mr_strcat(output, "+%lldK", (long long) (partsize));
1710 }
1711 mr_strcat(output, "\n");
1712 log_it("PARTSIZE = +%ld",(long)partsize);
1713
1714 log_it("---fdisk command---");
1715 log_it(output);
1716 log_it("---end of fdisk---");
1717
1718 mr_asprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1719 if (pout_to_fdisk) {
1720 log_msg(1, "Doing the new all-in-one fdisk thing");
1721 log_msg(1, "output = '%s'", output);
1722 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1723 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1724 tmp = last_line_of_file(FDISK_LOG);
1725 if (strstr(tmp, " (m ")) {
1726 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1727 } else {
1728 log_msg(1, "last line = %s", tmp);
1729 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1730 }
1731 mr_free(tmp);
1732
1733 if (!retval) {
1734 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1735 retval =
1736 set_partition_type(pout_to_fdisk, drive, partno, format,
1737 partsize);
1738 if (retval) {
1739 log_msg(1, "Failed. Trying again...");
1740 retval =
1741 set_partition_type(pout_to_fdisk, drive, partno,
1742 format, partsize);
1743 }
1744 }
1745 if (retval) {
1746 log_msg(1, "...but failed to set type");
1747 }
1748 } else {
1749 mr_strcat(output, "w\n\n");
1750 if (g_fprep) {
1751 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1752 }
1753 /* write to disk; close fdisk's stream */
1754 if (!(fout = popen(program, "w"))) {
1755 log_OS_error("can't popen-out to program");
1756 } else {
1757 fputs(output, fout);
1758 paranoid_pclose(fout);
1759 }
1760 if (!does_partition_exist(drive, partno) && partsize > 0) {
1761 log_it("Vaccum-packing");
1762 g_current_progress--;
1763 res =
1764 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1765 format, -1);
1766 if (res) {
1767 log_it("Failed to vacuum-pack %s", partition_name);
1768
1769 retval++;
1770 } else {
1771 retval = 0;
1772 }
1773 }
1774 if (does_partition_exist(drive, partno)) {
1775 retval =
1776 set_partition_type(pout_to_fdisk, drive, partno, format,
1777 partsize);
1778 if (retval) {
1779 log_it("Partitioned %s but failed to set its type", partition_name);
1780 } else {
1781 if (partsize > 0) {
1782 log_to_screen("Partition %s created+configured OK", partition_name);
1783 } else {
1784 log_it("Returning from a successful vacuum-pack");
1785 }
1786 }
1787 } else {
1788 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1789 if (partsize > 0) {
1790 log_to_screen(tmp);
1791 } else {
1792 log_it(tmp);
1793 }
1794 mr_free(tmp);
1795 retval++;
1796 }
1797 }
1798 mr_free(program);
1799 mr_free(partition_name);
1800 paranoid_free(output);
1801
1802 g_current_progress++;
1803 log_it("partition_device() --- leaving");
1804 return (retval);
1805}
1806
1807
1808
1809/**
1810 * Create all partitions listed in @p mountlist.
1811 * @param mountlist The mountlist to use to guide the partitioning.
1812 * @return The number of errors encountered (0 for success).
1813 * @note This sets the partition types but doesn't actually do the formatting.
1814 * Use format_everything() for that.
1815 */
1816int partition_everything(struct mountlist_itself *mountlist)
1817{
1818 /** int ************************************************************/
1819 int lino;
1820 int retval = 0;
1821 int i;
1822 int res;
1823
1824 /** buffer *********************************************************/
1825 struct list_of_disks *drivelist;
1826 /* struct mountlist_itself new_mtlist, *mountlist; */
1827
1828 /** end ************************************************************/
1829
1830 drivelist = malloc(sizeof(struct list_of_disks));
1831 assert(mountlist != NULL);
1832
1833 log_it("partition_everything() --- starting");
1834 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1835 /* mountlist=orig_mtlist; */
1836 if (mountlist_contains_raid_devices(mountlist)) {
1837 /* mountlist=&new_mtlist; */
1838 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1839 log_msg(0,
1840 "Mountlist, including the partitions incorporated in RAID devices:-");
1841 for (i = 0; i < mountlist->entries; i++) {
1842 log_it(mountlist->el[i].device);
1843 }
1844 log_msg(0, "End of mountlist.");
1845 }
1846 log_msg(0, "Stopping all LVMs, just in case");
1847 if (!g_text_mode) {
1848 newtSuspend();
1849 }
1850 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1851 if (!g_text_mode) {
1852 newtResume();
1853 }
1854 log_msg(0, "Stopping all software RAID devices, just in case");
1855 stop_all_raid_devices(mountlist);
1856 log_msg(0, "Done.");
1857
1858/*
1859 if (does_file_exist("/tmp/i-want-my-lvm"))
1860 {
1861 wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
1862 }
1863*/
1864
1865 open_progress_form("Partitioning devices",
1866 "I am now going to partition all your drives.",
1867 "This should not take more than five minutes.", "",
1868 mountlist->entries);
1869
1870 make_list_of_drives_in_mountlist(mountlist, drivelist);
1871
1872 /* partition each drive */
1873 for (lino = 0; lino < drivelist->entries; lino++) {
1874 res = partition_drive(mountlist, drivelist->el[lino].device);
1875 retval += res;
1876 }
1877 close_progress_form();
1878 if (retval) {
1879 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1880 log_to_screen
1881 ("Errors occurred during the partitioning of your hard drives.");
1882 } else {
1883 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1884 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1885 }
1886 newtSuspend();
1887 system("clear");
1888 newtResume();
1889 paranoid_free(drivelist);
1890 return (retval);
1891}
1892
1893
1894
1895
1896
1897
1898/**
1899 * Set the type of partition number @p partno on @p drive to @p format.
1900 * @param drive The drive to change the type of a partition on.
1901 * @param partno The partition number on @p drive to change the type of.
1902 * @param format The filesystem type this partition will eventually contain.
1903 * @param partsize The size of this partition, in @e bytes (used for vfat
1904 * type calculations).
1905 * @return 0 for success, nonzero for failure.
1906 */
1907int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
1908 const char *format, long long partsize)
1909{
1910 /** buffers *********************************************************/
1911 char *partition = NULL;
1912 char *command = NULL;
1913 char *output = NULL;
1914 char *tmp = NULL;
1915 char *tmp1 = NULL;
1916 char *partcode = NULL;
1917
1918 /** pointers *********************************************************/
1919 char *p;
1920 FILE *fout;
1921
1922 /** int **************************************************************/
1923 int res = 0;
1924
1925 /** end **************************************************************/
1926
1927 assert_string_is_neither_NULL_nor_zerolength(drive);
1928 assert(format != NULL);
1929
1930 partition = build_partition_name(drive, partno);
1931 p = (char *) strrchr(partition, '/');
1932 if (strcmp(format, "swap") == 0) {
1933 mr_asprintf(partcode, "82");
1934 } else if (strcmp(format, "vfat") == 0) {
1935 if (partsize / 1024 > 8192) {
1936 mr_asprintf(partcode, "c");
1937 } else {
1938 mr_asprintf(partcode, "b");
1939 }
1940 } else if (strcmp(format, "ext2") == 0
1941 || strcmp(format, "reiserfs") == 0
1942 || strcmp(format, "ext3") == 0
1943 || strcmp(format, "ext4") == 0
1944 || strcmp(format, "xfs") == 0
1945 || strcmp(format, "jfs") == 0) {
1946 mr_asprintf(partcode, "83");
1947 } else if (strcmp(format, "minix") == 0) {
1948 mr_asprintf(partcode, "81");
1949 } else if (strcmp(format, "vmfs3") == 0) {
1950 mr_asprintf(partcode, "fb");
1951 } else if (strcmp(format, "vmkcore") == 0) {
1952 mr_asprintf(partcode, "fc");
1953 } else if (strcmp(format, "raid") == 0) {
1954 mr_asprintf(partcode, "fd");
1955 } else if (strcmp(format, "ntfs") == 0) {
1956 mr_asprintf(partcode, "7");
1957 } else if ((strcmp(format, "ufs") == 0)
1958 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1959 mr_asprintf(partcode, "a5");
1960 } else if (strcmp(format, "lvm") == 0) {
1961 mr_asprintf(partcode, "8e");
1962 } else if (format[0] == '\0') { /* LVM physical partition */
1963 mr_asprintf(partcode, "");
1964 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
1965 mr_asprintf(partcode, "%s", format);
1966 } else {
1967 /* probably an image */
1968 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1969 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1970 mr_free(tmp);
1971#ifdef __FreeBSD__
1972 mr_asprintf(partcode, "%s", format); // was a5
1973#else
1974 mr_asprintf(partcode, "%s", format); // was 83
1975#endif
1976 }
1977 log_msg(1, tmp, "Setting %s's type to %s (%s)", partition, format, partcode);
1978 mr_free(partition);
1979
1980 if (partcode != NULL && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1981
1982 if (pout_to_fdisk) {
1983 res = 0;
1984 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1985 tmp1 = last_line_of_file(FDISK_LOG);
1986 if (partno > 1 || strstr(tmp1, " (1-4)")) {
1987 log_msg(5, "Specifying partno (%d) - yay", partno);
1988 mr_asprintf(tmp, "%d\n", partno);
1989 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1990 mr_free(tmp);
1991
1992 mr_free(tmp1);
1993 tmp1 = last_line_of_file(FDISK_LOG);
1994 log_msg(5, "A - last line = '%s'", tmp1);
1995 }
1996 mr_free(tmp1);
1997
1998 mr_asprintf(tmp, "%s\n", partcode);
1999 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2000 mr_free(tmp);
2001
2002 tmp1 = last_line_of_file(FDISK_LOG);
2003 log_msg(5, "B - last line = '%s'", tmp1);
2004 mr_free(tmp1);
2005
2006 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2007 tmp1 = last_line_of_file(FDISK_LOG);
2008 log_msg(5, "C - last line = '%s'", tmp1);
2009 mr_free(tmp1);
2010
2011 tmp1 = last_line_of_file(FDISK_LOG);
2012 if (!strstr(tmp1, " (m ")) {
2013 log_msg(1, "last line = '%s'; part type set failed", tmp1);
2014 res++;
2015 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2016 }
2017 mr_free(tmp1);
2018
2019 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2020 } else {
2021 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
2022 mr_asprintf(command, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
2023 log_msg(5, "output = '%s'", output);
2024 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2025 log_msg(5, "command = '%s'", command);
2026 fout = popen(command, "w");
2027 if (!fout) {
2028 log_OS_error(command);
2029 res = 1;
2030 } else {
2031 res = 0;
2032 fprintf(fout, "%s", output);
2033 paranoid_pclose(fout);
2034 }
2035 paranoid_free(output);
2036 mr_free(command);
2037 }
2038 }
2039
2040 mr_free(partcode);
2041 return (res);
2042}
2043
2044
2045int start_raid_device(char *raid_device)
2046{
2047 /** int *************************************************************/
2048 int res;
2049 int retval = 0;
2050
2051 /** buffers *********************************************************/
2052 char *program = NULL;
2053
2054 /** end *************************************************************/
2055
2056 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2057
2058#ifdef __FreeBSD__
2059 if (is_this_device_mounted(raid_device)) {
2060 log_it("Can't start %s when it's mounted!", raid_device);
2061 return 1;
2062 }
2063 mr_asprintf(program, "vinum start -f %s", raid_device);
2064#else
2065 mr_asprintf(program, "raidstart %s", raid_device);
2066#endif
2067 log_msg(1, "program = %s", program);
2068 res = run_program_and_log_output(program, 1);
2069 if (g_fprep) {
2070 fprintf(g_fprep, "%s\n", program);
2071 }
2072 mr_free(program);
2073
2074 if (res) {
2075 log_msg(1, "Warning - failed to start RAID device %s",
2076 raid_device);
2077 }
2078 retval += res;
2079 sleep(1);
2080 return (retval);
2081}
2082
2083
2084
2085/**
2086 * Stop @p raid_device using @p raidstop.
2087 * @param raid_device The software RAID device to stop.
2088 * @return 0 for success, nonzero for failure.
2089 */
2090int stop_raid_device(char *raid_device)
2091{
2092 /** int *************************************************************/
2093 int res;
2094 int retval = 0;
2095
2096 /** buffers *********************************************************/
2097 char *program = NULL;
2098
2099 /** end *************************************************************/
2100
2101 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2102
2103#ifdef __FreeBSD__
2104 if (is_this_device_mounted(raid_device)) {
2105 log_it("Can't stop %s when it's mounted!", raid_device);
2106 return 1;
2107 }
2108 mr_asprintf(program, "vinum stop -f %s", raid_device);
2109#else
2110 // use raidstop if it exists, otherwise use mdadm
2111 if (run_program_and_log_output("which raidstop", FALSE)) {
2112 mr_asprintf(program, "mdadm -S %s", raid_device);
2113 } else {
2114 mr_asprintf(program, "raidstop %s", raid_device);
2115 }
2116#endif
2117 log_msg(1, "program = %s", program);
2118 res = run_program_and_log_output(program, 1);
2119 if (g_fprep) {
2120 fprintf(g_fprep, "%s\n", program);
2121 }
2122 mr_free(program);
2123
2124 if (res) {
2125 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2126 }
2127 retval += res;
2128 return (retval);
2129}
2130
2131
2132int start_all_raid_devices(struct mountlist_itself *mountlist)
2133{
2134 int i;
2135 int retval = 0;
2136 int res;
2137
2138 for (i = 0; i < mountlist->entries; i++) {
2139 if (!strncmp
2140 (mountlist->el[i].device, RAID_DEVICE_STUB,
2141 strlen(RAID_DEVICE_STUB))) {
2142 log_msg(1, "Starting %s", mountlist->el[i].device);
2143 res = start_raid_device(mountlist->el[i].device);
2144 retval += res;
2145 }
2146 }
2147 if (retval) {
2148 log_msg(1, "Started all s/w raid devices OK");
2149 } else {
2150 log_msg(1, "Failed to start some/all s/w raid devices");
2151 }
2152 return (retval);
2153}
2154
2155/**
2156 * Stop all software RAID devices listed in @p mountlist.
2157 * @param mountlist The mountlist to stop the RAID devices in.
2158 * @return The number of errors encountered (0 for success).
2159 * @bug @p mountlist is not used.
2160 */
2161int stop_all_raid_devices(struct mountlist_itself *mountlist)
2162{
2163 /** int *************************************************************/
2164 int retval = 0;
2165
2166 /** char ************************************************************/
2167 char *incoming = NULL;
2168#ifndef __FreeBSD__
2169 char *dev;
2170 char *p;
2171 int res;
2172#endif
2173
2174 /** pointers ********************************************************/
2175 FILE *fin;
2176 int i;
2177
2178 /** end ****************************************************************/
2179
2180 assert(mountlist != NULL);
2181
2182 for (i = 0; i < 3; i++) {
2183#ifdef __FreeBSD__
2184 fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r");
2185 if (!fin) {
2186 return (1);
2187 }
2188 for (mr_getline(incoming, fin); !feof(fin); mr_getline(incoming, fin)) {
2189 retval += stop_raid_device(incoming);
2190 mr_free(incoming);
2191 }
2192 mr_free(incoming);
2193#else
2194 fin = fopen("/proc/mdstat", "r");
2195 if (!fin) {
2196 log_OS_error("/proc/mdstat");
2197 return (1);
2198 }
2199 for (mr_getline(incoming, fin); !feof(fin); mr_getline(incoming, fin)) {
2200 for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++);
2201 if (*p != '\0') {
2202 mr_asprintf(dev, "/dev/%s", p);
2203 for (p = dev; *p > 32; p++);
2204 *p = '\0';
2205 res = stop_raid_device(dev);
2206 mr_free(dev);
2207 }
2208 mr_free(incoming);
2209 }
2210 mr_free(incoming);
2211#endif
2212 }
2213 paranoid_fclose(fin);
2214 if (retval) {
2215 log_msg(1, "Warning - unable to stop some RAID devices");
2216 }
2217 system("sync");
2218 system("sync");
2219 system("sync");
2220 sleep(1);
2221 return (retval);
2222}
2223
2224
2225
2226/**
2227 * Decide which command we need to use to format a device of type @p format.
2228 * @param format The filesystem type we are about to format.
2229 * @param program Where to put the binary name for this format.
2230 * @return 0 for success, nonzero for failure.
2231 */
2232char *which_format_command_do_i_need(char *format)
2233{
2234 /** int *************************************************************/
2235 int res = 0;
2236
2237 /** buffers *********************************************************/
2238 char *program = NULL;
2239
2240 /** end ***************************************************************/
2241
2242 assert_string_is_neither_NULL_nor_zerolength(format);
2243
2244 if (strcmp(format, "swap") == 0) {
2245#ifdef __FreeBSD__
2246 mr_asprintf(program, "true");
2247#else
2248 mr_asprintf(program, "mkswap");
2249#endif
2250 } else if (strcmp(format, "vfat") == 0) {
2251 mr_asprintf(program, "format-and-kludge-vfat");
2252#ifndef __FreeBSD__
2253 } else if (strcmp(format, "reiserfs") == 0) {
2254 mr_asprintf(program, "mkreiserfs -ff");
2255 } else if (strcmp(format, "xfs") == 0) {
2256 mr_asprintf(program, "mkfs.xfs -f -q");
2257 } else if (strcmp(format, "jfs") == 0) {
2258 mr_asprintf(program, "mkfs.jfs");
2259 } else if (strcmp(format, "ext3") == 0) {
2260 mr_asprintf(program, "mkfs -t ext3 -F -q");
2261 } else if (strcmp(format, "ext4") == 0) {
2262 mr_asprintf(program, "mkfs -t ext4 -F -q");
2263 } else if (strcmp(format, "minix") == 0) {
2264 mr_asprintf(program, "mkfs.minix");
2265 } else if (strcmp(format, "vmfs") == 0) {
2266 mr_asprintf(program, "mkfs -t vmfs");
2267 } else if (strcmp(format, "ntfs") == 0) {
2268 /*
2269 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2270 * so the default "mkfs -t %s -c" command structure fails
2271 */
2272 mr_asprintf(program, "mkfs -t ntfs");
2273 } else if (strcmp(format, "ocfs2") == 0) {
2274 /*
2275 * 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.
2276 *
2277 */
2278 mr_asprintf(program, "mkfs -t ocfs2 -F");
2279#endif
2280 } else if (strcmp(format, "ext2") == 0) {
2281 mr_asprintf(program, "mke2fs -F -q");
2282 } else {
2283#ifdef __FreeBSD__
2284 mr_asprintf(program, "newfs_%s", format);
2285#else
2286 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2287#endif
2288 log_it("Unknown format (%s) - assuming '%s' will do", format, program);
2289 res = 0;
2290 }
2291 return (program);
2292}
2293
2294
2295/**
2296 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2297 * There are a few problems with this function:
2298 * - It won't work if there was any unallocated space on the user's hard drive
2299 * when it was backed up.
2300 * - It won't work if the user's hard drive lies about its size (more common
2301 * than you'd think).
2302 *
2303 * @param mountlist The mountlist to use for resizing @p drive_name.
2304 * @param drive_name The drive to resize.
2305 */
2306void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2307 *mountlist,
2308 char *drive_name)
2309{
2310
2311 /** int *************************************************************/
2312 int partno, lastpart;
2313 /** remove driveno, noof_drives stan benoit apr 2002**/
2314
2315 /** float ***********************************************************/
2316 float factor;
2317 float new_size;
2318// float newcylinderno;
2319
2320 /** long *************************************************************/
2321 long newsizL = 0L;
2322 long current_size_of_drive = 0L;
2323 long original_size_of_drive = 0L;
2324 long final_size = 0L; /* all in Megabytes */
2325 struct mountlist_reference *drivemntlist;
2326
2327 /** structures *******************************************************/
2328
2329 /** end **************************************************************/
2330
2331 assert(mountlist != NULL);
2332 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2333
2334 if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2335 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2336 == 0) {
2337 return;
2338 }
2339 }
2340
2341 current_size_of_drive = get_phys_size_of_drive(drive_name);
2342
2343 if (current_size_of_drive <= 0) {
2344 log_it("Not resizing to match %s - can't find drive", drive_name);
2345 return;
2346 }
2347 log_to_screen("Expanding entries to suit drive %s (%ld MB)", drive_name, current_size_of_drive);
2348
2349 drivemntlist = malloc(sizeof(struct mountlist_reference));
2350 drivemntlist->el =
2351 malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2352
2353 if (!drivemntlist) {
2354 fatal_error("Cannot malloc temporary mountlist\n");
2355 }
2356 create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2357
2358 for (partno = 0; partno < drivemntlist->entries; partno++) {
2359 if (drivemntlist->el[partno]->size > 0) {
2360 original_size_of_drive += (drivemntlist->el[partno]->size / 1024L);
2361 }
2362 }
2363
2364 if (original_size_of_drive <= 0) {
2365 log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name);
2366 return;
2367 }
2368 factor = (float) (current_size_of_drive) / (float) (original_size_of_drive);
2369 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);
2370
2371 lastpart = drivemntlist->entries - 1;
2372 for (partno = 0; partno < drivemntlist->entries; partno++) {
2373 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2374 if (!atoi(drivemntlist->el[partno]->format)) {
2375 new_size = (float) (drivemntlist->el[partno]->size) * factor;
2376 } else {
2377 new_size = drivemntlist->el[partno]->size;
2378 }
2379
2380 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2381 log_msg(1, "Skipping %s (%s) because it's an image",
2382 drivemntlist->el[partno]->device,
2383 drivemntlist->el[partno]->mountpoint);
2384 newsizL = (long) new_size; // It looks wrong but it's not
2385 } else {
2386 newsizL = (long) new_size;
2387 }
2388
2389 /* Do not apply the factor if partition was of negative size */
2390 if (newsizL < 0) {
2391 newsizL = drivemntlist->el[partno]->size;
2392 }
2393
2394 log_to_screen("Changing %s from %lld KB to %ld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2395 drivemntlist->el[partno]->size = newsizL;
2396 }
2397 final_size = get_phys_size_of_drive(drive_name);
2398 log_to_screen("final_size = %ld MB", final_size);
2399}
2400
2401
2402/**
2403 * Resize all partitions in @p mountlist proportionately (each one
2404 * grows or shrinks by the same percentage) to fit them into the new
2405 * drives (presumably different from the old ones).
2406 * @param mountlist The mountlist to resize the drives in.
2407 */
2408void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2409 *mountlist)
2410{
2411 /** buffers *********************************************************/
2412 struct list_of_disks *drivelist;
2413
2414 /** int *************************************************************/
2415 int driveno;
2416
2417 /** end *************************************************************/
2418
2419 drivelist = malloc(sizeof(struct list_of_disks));
2420 assert(mountlist != NULL);
2421
2422 if (g_mountlist_fname[0] == '\0') {
2423 log_it
2424 ("resize_mountlist_prop...() - warning - mountlist fname is blank");
2425 log_it("That does NOT affect the functioning of this subroutine.");
2426 log_it("--- Hugo, 2002/11/20");
2427 }
2428 log_it("Resizing mountlist");
2429 make_list_of_drives_in_mountlist(mountlist, drivelist);
2430 log_it("Back from MLoDiM");
2431 for (driveno = 0; driveno < drivelist->entries; driveno++) {
2432 resize_drive_proportionately_to_suit_new_drives(mountlist,
2433 drivelist->
2434 el[driveno].
2435 device);
2436 }
2437 log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2438 paranoid_free(drivelist);
2439}
2440
2441/**
2442 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2443 * @param mountlist The complete mountlist to get the drive references from.
2444 * @param drive_name The drive to put in @p drivemntlist.
2445 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2446 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2447 * @author Ralph Grewe
2448 */
2449void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2450 char *drive_name,
2451 struct mountlist_reference *drivemntlist)
2452{
2453 int partno;
2454 char *tmp_drive_name, *c;
2455
2456 assert(mountlist != NULL);
2457 assert(drive_name != NULL);
2458 assert(drivemntlist != NULL);
2459
2460 log_msg(1, "Creating list of partitions for drive %s", drive_name);
2461
2462 tmp_drive_name = strdup(drive_name);
2463 if (!tmp_drive_name)
2464 fatal_error("Out of memory");
2465
2466 /* devfs devices? */
2467 c = strrchr(tmp_drive_name, '/');
2468 if (c && strncmp(c, "/disc", 5) == 0) {
2469 /* yup its devfs, change the "disc" to "part" so the existing code works */
2470 strcpy(c + 1, "part");
2471 }
2472 drivemntlist->entries = 0;
2473 for (partno = 0; partno < mountlist->entries; partno++) {
2474 if (strncmp
2475 (mountlist->el[partno].device, tmp_drive_name,
2476 strlen(tmp_drive_name)) == 0) {
2477 drivemntlist->el[drivemntlist->entries] =
2478 &mountlist->el[partno];
2479 drivemntlist->entries++;
2480 }
2481 }
2482 if (tmp_drive_name)
2483 free(tmp_drive_name);
2484}
2485
2486/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.