source: MondoRescue/branches/2.2.9/mondo/src/mondorestore/mondo-prep.c@ 2298

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