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

Last change on this file since 2290 was 2290, checked in by Bruno Cornec, 15 years ago
  • Fix a printing error in mindi for the tar command
  • Fix all mr_asprintf which had no second param as a string
  • Property svn:keywords set to Id
File size: 74.6 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 2290 2009-07-22 12:03:44Z 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 2290 2009-07-22 12:03:44Z 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 /* retval+=res; */
793 }
794#else
795 mr_asprintf(&tmp, "Initializing RAID device %s", device);
796 log_to_screen(tmp);
797 paranoid_free(tmp);
798
799// Shouldn't be necessary.
800 log_to_screen("Stopping %s", device);
801 stop_raid_device(device);
802 system("sync");
803 sleep(1);
804 if (g_fprep) {
805 fprintf(g_fprep, "%s\n", program);
806 }
807
808 log_msg(1, "Making %s", device);
809 // use mkraid if it exists, otherwise use mdadm
810 if (run_program_and_log_output("which mkraid", FALSE)) {
811 res = create_raid_device_via_mdadm(raidlist, device);
812 log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
813 } else {
814 sprintf(program, "mkraid --really-force %s", device);
815 res = run_program_and_log_output(program, 1);
816 log_msg(1, "%s returned %d", program, res);
817 system("sync");
818 sleep(3);
819 start_raid_device(device);
820 if (g_fprep) {
821 fprintf(g_fprep, "%s\n", program);
822 }
823 }
824 system("sync");
825 sleep(2);
826// log_to_screen("Starting %s", device);
827// sprintf(program, "raidstart %s", device);
828// res = run_program_and_log_output(program, 1);
829// log_msg(1, "%s returned %d", program, res);
830// system("sync"); sleep(1);
831#endif
832 system("sync");
833 sleep(1);
834 newtResume();
835 }
836//#ifndef __FreeBSD__
837//#endif
838
839 if (!strcmp(format, "lvm")) {
840 log_msg(1, "Don't format %s - it's part of an lvm volume", device);
841 paranoid_free(program);
842 paranoid_free(tmp);
843 return (0);
844 }
845 res = which_format_command_do_i_need(format, program);
846 mr_asprintf(&tmp, "%s %s", program, device);
847 if (strstr(program, "kludge")) {
848 mr_strcat(tmp, " /");
849 }
850 sprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
851 paranoid_free(tmp);
852
853 mr_asprintf(&tmp, "Formatting %s as %s", device, format);
854 update_progress_form(tmp);
855 paranoid_free(tmp);
856
857 res = run_program_and_log_output(program, FALSE);
858 mr_asprintf(&tmp, "");
859 if (res && strstr(program, "kludge")) {
860 mr_strcat(tmp, "Kludge failed; using regular mkfs.%s to format %s",
861 format, device);
862#ifdef __FreeBSD__
863 sprintf(program, "newfs_msdos -F 32 %s", device);
864#else
865#ifdef __IA64__
866 /* For EFI partitions take fat16
867 * as we want to make small ones */
868 sprintf(program, "mkfs -t %s -F 16 %s", format, device);
869#else
870 sprintf(program, "mkfs -t %s -F 32 %s", format, device);
871#endif
872#endif
873 res = run_program_and_log_output(program, FALSE);
874 if (g_fprep) {
875 fprintf(g_fprep, "%s\n", program);
876 }
877 }
878 retval += res;
879 if (retval) {
880 mr_strcat(tmp, "...failed");
881 } else {
882 mr_strcat(tmp, "...OK");
883 }
884
885 log_to_screen(tmp);
886 paranoid_free(tmp);
887
888 paranoid_free(program);
889 system("sync");
890 sleep(1);
891 return (retval);
892}
893
894
895
896
897
898/**
899 * Format all drives (except those excluded by format_device()) in @p mountlist.
900 * @param mountlist The mountlist containing partitions to be formatted.
901 * @param interactively If TRUE, then prompt the user before each partition.
902 * @return The number of errors encountered (0 for success).
903 */
904int format_everything(struct mountlist_itself *mountlist, bool interactively,
905 struct raidlist_itself *raidlist)
906{
907 /** int **************************************************************/
908 int retval = 0;
909 int lino;
910 int res;
911// int i;
912// struct list_of_disks *drivelist;
913
914 /** long *************************************************************/
915 long progress_step;
916
917 /** bools ************************************************************/
918 bool do_it;
919
920 /** buffers **********************************************************/
921 char *tmp;
922
923 /** pointers *********************************************************/
924 struct mountlist_line *me; // mountlist entry
925 /** end **************************************************************/
926
927 assert(mountlist != NULL);
928 malloc_string(tmp);
929 sprintf(tmp, "format_everything (mountlist, interactively = %s",
930 (interactively) ? "true" : "false");
931 log_it(tmp);
932 mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
933 open_progress_form("Formatting partitions",
934 "I am now formatting your hard disk partitions.",
935 "This may take up to five minutes.", "",
936 mountlist->entries + 1);
937
938 progress_step =
939 (mountlist->entries >
940 0) ? g_maximum_progress / mountlist->entries : 1;
941// start soft-raids now (because LVM might depend on them)
942// ...and for simplicity's sake, let's format them at the same time :)
943 log_msg(1, "Stopping all RAID devices");
944 stop_all_raid_devices(mountlist);
945 system("sync");
946 system("sync");
947 system("sync");
948 sleep(2);
949 log_msg(1, "Prepare soft-RAIDs"); // prep and format too
950 for (lino = 0; lino < mountlist->entries; lino++) {
951 me = &mountlist->el[lino]; // the current mountlist entry
952 log_msg(2, "Examining %s", me->device);
953 if (!strncmp(me->device, "/dev/md", 7)) {
954 if (interactively) {
955 // ask user if we should format the current device
956 sprintf(tmp, "Shall I format %s (%s) ?", me->device,
957 me->mountpoint);
958 do_it = ask_me_yes_or_no(tmp);
959 } else {
960 do_it = TRUE;
961 }
962 if (do_it) {
963 // NB: format_device() also stops/starts RAID device if necessary
964 retval += format_device(me->device, me->format, raidlist);
965 }
966 g_current_progress += progress_step;
967 }
968 }
969 system("sync");
970 system("sync");
971 system("sync");
972 sleep(2);
973// This last step is probably necessary
974// log_to_screen("Re-starting software RAIDs...");
975// start_all_raid_devices(mountlist);
976// system("sync"); system("sync"); system("sync");
977// sleep(5);
978// do LVMs now
979 log_msg(1, "Creating LVMs");
980 if (does_file_exist("/tmp/i-want-my-lvm")) {
981 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
982 log_to_screen("Configuring LVM");
983 if (!g_text_mode) {
984 newtSuspend();
985 }
986/*
987 for(i=0; i<3; i++)
988 {
989 res = do_my_funky_lvm_stuff(FALSE, FALSE);
990 if (!res) { break; }
991 sleep(3);
992 res = do_my_funky_lvm_stuff(TRUE, FALSE);
993 sleep(3);
994 }
995 if (res) {
996 log_msg(1, "Vacuum-packing...");
997*/
998 res = do_my_funky_lvm_stuff(FALSE, TRUE);
999/*
1000 }
1001*/
1002 if (!g_text_mode) {
1003 newtResume();
1004 }
1005 if (!res) {
1006 log_to_screen("LVM initialized OK");
1007 } else {
1008 log_to_screen("Failed to initialize LVM");
1009 }
1010 // retval += res;
1011 if (res) {
1012 retval++;
1013 }
1014 sleep(3);
1015 }
1016// do regulars at last
1017 sleep(2); // woo!
1018 log_msg(1, "Formatting regulars");
1019 for (lino = 0; lino < mountlist->entries; lino++) {
1020 me = &mountlist->el[lino]; // the current mountlist entry
1021 if (!strcmp(me->mountpoint, "image")) {
1022 sprintf(tmp, "Not formatting %s - it's an image", me->device);
1023 log_it(tmp);
1024 } else if (!strcmp(me->format, "raid")) {
1025 sprintf(tmp, "Not formatting %s - it's a raid-let",
1026 me->device);
1027 log_it(tmp);
1028 continue;
1029 } else if (!strcmp(me->format, "lvm")) {
1030 sprintf(tmp, "Not formatting %s - it's an LVM", me->device);
1031 log_it(tmp);
1032 continue;
1033 } else if (!strncmp(me->device, "/dev/md", 7)) {
1034 sprintf(tmp, "Already formatted %s - it's a soft-RAID dev",
1035 me->device);
1036 log_it(tmp);
1037 continue;
1038 } else if (!does_file_exist(me->device)
1039 && strncmp(me->device, "/dev/hd", 7)
1040 && strncmp(me->device, "/dev/sd", 7)) {
1041 sprintf(tmp,
1042 "Not formatting %s yet - doesn't exist - probably an LVM",
1043 me->device);
1044 log_it(tmp);
1045 continue;
1046 } else {
1047 if (interactively) {
1048 // ask user if we should format the current device
1049 sprintf(tmp, "Shall I format %s (%s) ?", me->device,
1050 me->mountpoint);
1051 do_it = ask_me_yes_or_no(tmp);
1052 } else {
1053 do_it = TRUE;
1054 }
1055
1056 if (do_it)
1057 retval += format_device(me->device, me->format, raidlist);
1058 }
1059
1060 // update progress bar
1061 g_current_progress += progress_step;
1062 }
1063
1064
1065 // update progress bar to 100% to compensate for
1066 // rounding errors of the progress_step calculation
1067 if (lino >= mountlist->entries)
1068 g_current_progress = g_maximum_progress;
1069
1070 close_progress_form();
1071
1072 if (retval) {
1073 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1074 log_to_screen
1075 ("Errors occurred during the formatting of your hard drives.");
1076 } else {
1077 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1078 }
1079
1080 sprintf(tmp, "format_everything () - %s",
1081 (retval) ? "failed!" : "finished successfully");
1082 log_it(tmp);
1083
1084 if (g_partition_table_locked_up > 0) {
1085 if (retval > 0 && !interactively) {
1086//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
1087 log_to_screen
1088 ("Partition table locked up %d times. At least one 'mkfs' (format) command",
1089 g_partition_table_locked_up);
1090 log_to_screen
1091 ("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
1092 log_to_screen
1093 ("to refresh its copy of the partition table causes the kernel to lock the ");
1094 log_to_screen
1095 ("partition table. I believe this has just happened.");
1096 if (ask_me_yes_or_no
1097 ("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue."))
1098 {
1099 system("sync");
1100 system("sync");
1101 system("sync");
1102 system("reboot");
1103 }
1104 } else {
1105 log_to_screen
1106 ("Partition table locked up %d time%c. However, disk formatting succeeded.",
1107 g_partition_table_locked_up,
1108 (g_partition_table_locked_up == 1) ? '.' : 's');
1109 }
1110 }
1111 newtSuspend();
1112 system("clear");
1113 newtResume();
1114 paranoid_free(tmp);
1115 return (retval);
1116}
1117
1118
1119/**
1120 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
1121 * Each partition created is 32k in size.
1122 * @param drivename The drive to create the dummy partitions on.
1123 * @param devno_we_must_allow_for The lowest-numbered real partition; create
1124 * dummies up to (this - 1).
1125 * @return The number of errors encountered (0 for success).
1126 */
1127int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename,
1128 int devno_we_must_allow_for)
1129{
1130 /** int **************************************************************/
1131 int current_devno;
1132 int previous_devno;
1133 int retval = 0;
1134 int res;
1135
1136 /** buffers **********************************************************/
1137 char *tmp;
1138
1139 /** end **************************************************************/
1140
1141 malloc_string(tmp);
1142 assert_string_is_neither_NULL_nor_zerolength(drivename);
1143
1144 if (devno_we_must_allow_for >= 5) {
1145 sprintf(tmp, "Making dummy primary 1 on %s", drivename);
1146 log_it(tmp);
1147 g_maximum_progress++;
1148 res =
1149 partition_device(pout_to_fdisk, drivename, 1, 0, "ext2",
1150 32000);
1151 retval += res;
1152 previous_devno = 1;
1153 current_devno = 5;
1154 } else {
1155 previous_devno = 0;
1156 current_devno = 1;
1157 }
1158 for (; current_devno < devno_we_must_allow_for; current_devno++) {
1159 sprintf(tmp, "Creating dummy partition %d on %s", current_devno, drivename);
1160 log_it(tmp);
1161 g_maximum_progress++;
1162 res =
1163 partition_device(pout_to_fdisk, drivename, current_devno,
1164 previous_devno, OSSWAP("ext2", "ufs"), 32000);
1165 retval += res;
1166 previous_devno = current_devno;
1167 }
1168 paranoid_free(tmp);
1169 return (previous_devno);
1170}
1171
1172
1173/**
1174 * Decide whether @p mountlist contains any RAID devices.
1175 * @param mountlist The mountlist to examine.
1176 * @return TRUE if it does, FALSE if it doesn't.
1177 */
1178bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist)
1179{
1180 /** int *************************************************************/
1181 int i;
1182 int matching = 0;
1183
1184 /** end **************************************************************/
1185
1186 assert(mountlist != NULL);
1187
1188 for (i = 0; i < mountlist->entries; i++) {
1189 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1190 matching++;
1191 }
1192 }
1193 if (matching) {
1194 return (TRUE);
1195 } else {
1196 return (FALSE);
1197 }
1198}
1199
1200/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1201#ifdef __FreeBSD__
1202static void display_disklabel(FILE * f, const struct disklabel *lp)
1203{
1204 int i, j;
1205 const struct partition *pp;
1206
1207 fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1208 if (lp->d_type < DKMAXTYPES)
1209 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1210 else
1211 fprintf(f, "type: %u\n", lp->d_type);
1212 fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename),
1213 lp->d_typename);
1214 fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname),
1215 lp->d_packname);
1216 fprintf(f, "flags:");
1217 if (lp->d_flags & D_REMOVABLE)
1218 fprintf(f, " removeable");
1219 if (lp->d_flags & D_ECC)
1220 fprintf(f, " ecc");
1221 if (lp->d_flags & D_BADSECT)
1222 fprintf(f, " badsect");
1223 fprintf(f, "\n");
1224 fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1225 fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1226 fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1227 fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1228 fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1229 fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1230 fprintf(f, "rpm: %u\n", lp->d_rpm);
1231 fprintf(f, "interleave: %u\n", lp->d_interleave);
1232 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1233 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1234 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
1235 (u_long) lp->d_headswitch);
1236 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
1237 (u_long) lp->d_trkseek);
1238 fprintf(f, "drivedata: ");
1239 for (i = NDDATA - 1; i >= 0; i--)
1240 if (lp->d_drivedata[i])
1241 break;
1242 if (i < 0)
1243 i = 0;
1244 for (j = 0; j <= i; j++)
1245 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1246 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1247 fprintf(f,
1248 "# size offset fstype [fsize bsize bps/cpg]\n");
1249 pp = lp->d_partitions;
1250 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1251 if (pp->p_size) {
1252 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size,
1253 (u_long) pp->p_offset);
1254 if (pp->p_fstype < FSMAXTYPES)
1255 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1256 else
1257 fprintf(f, "%8d", pp->p_fstype);
1258 switch (pp->p_fstype) {
1259
1260 case FS_UNUSED: /* XXX */
1261 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1262 (u_long) (pp->p_fsize * pp->p_frag), "");
1263 break;
1264
1265 case FS_BSDFFS:
1266 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize,
1267 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1268 break;
1269
1270 case FS_BSDLFS:
1271 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize,
1272 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1273 break;
1274
1275 default:
1276 fprintf(f, "%20.20s", "");
1277 break;
1278 }
1279 fprintf(f, "\t# (Cyl. %4lu",
1280 (u_long) (pp->p_offset / lp->d_secpercyl));
1281 if (pp->p_offset % lp->d_secpercyl)
1282 putc('*', f);
1283 else
1284 putc(' ', f);
1285 fprintf(f, "- %lu",
1286 (u_long) ((pp->p_offset + pp->p_size +
1287 lp->d_secpercyl - 1) / lp->d_secpercyl -
1288 1));
1289 if (pp->p_size % lp->d_secpercyl)
1290 putc('*', f);
1291 fprintf(f, ")\n");
1292 }
1293 }
1294 fflush(f);
1295}
1296
1297static struct disklabel *get_virgin_disklabel(char *dkname)
1298{
1299 static struct disklabel loclab;
1300 struct partition *dp;
1301 char lnamebuf[BBSIZE];
1302 int f;
1303 u_int secsize, u;
1304 off_t mediasize;
1305
1306 (void) snprintf(lnamebuf, BBSIZE, "%s", dkname);
1307 if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1308 warn("cannot open %s", lnamebuf);
1309 return (NULL);
1310 }
1311
1312 /* New world order */
1313 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1314 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1315 close(f);
1316 return (NULL);
1317 }
1318 memset(&loclab, 0, sizeof loclab);
1319 loclab.d_magic = DISKMAGIC;
1320 loclab.d_magic2 = DISKMAGIC;
1321 loclab.d_secsize = secsize;
1322 loclab.d_secperunit = mediasize / secsize;
1323
1324 /*
1325 * Nobody in these enligthened days uses the CHS geometry for
1326 * anything, but nontheless try to get it right. If we fail
1327 * to get any good ideas from the device, construct something
1328 * which is IBM-PC friendly.
1329 */
1330 if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1331 loclab.d_nsectors = u;
1332 else
1333 loclab.d_nsectors = 63;
1334 if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1335 loclab.d_ntracks = u;
1336 else if (loclab.d_secperunit <= 63 * 1 * 1024)
1337 loclab.d_ntracks = 1;
1338 else if (loclab.d_secperunit <= 63 * 16 * 1024)
1339 loclab.d_ntracks = 16;
1340 else
1341 loclab.d_ntracks = 255;
1342 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1343 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1344 loclab.d_npartitions = MAXPARTITIONS;
1345
1346 /* Various (unneeded) compat stuff */
1347 loclab.d_rpm = 3600;
1348 loclab.d_bbsize = BBSIZE;
1349 loclab.d_interleave = 1;;
1350 strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1351
1352 dp = &loclab.d_partitions[RAW_PART];
1353 dp->p_size = loclab.d_secperunit;
1354 loclab.d_checksum = dkcksum(&loclab);
1355 close(f);
1356 return (&loclab);
1357}
1358
1359/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1360
1361char *canonical_name(char *drivename)
1362{
1363 if (drivename) {
1364 if (strncmp(drivename, "/dev/", 5) == 0) {
1365 return drivename + 5;
1366 }
1367 }
1368 return drivename;
1369}
1370
1371/**
1372 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1373 * @param mountlist The mountlist to get the subpartition information from.
1374 * @param drivename The drive or slice to create a disklabel on.
1375 * @param ret If non-NULL, store the created disklabel here.
1376 * @return The number of errors encountered (0 for success).
1377 */
1378int label_drive_or_slice(struct mountlist_itself *mountlist,
1379 char *drivename, struct disklabel *ret)
1380{
1381 char subdev_str[MAX_STR_LEN];
1382 char command[MAX_STR_LEN];
1383 struct disklabel *lp;
1384 int i, lo = 0;
1385 int retval = 0;
1386 char c;
1387 FILE *ftmp;
1388
1389 lp = get_virgin_disklabel(drivename);
1390 for (c = 'a'; c <= 'z'; ++c) {
1391 int idx;
1392 sprintf(subdev_str, "%s%c", drivename, c);
1393 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1394 lp->d_partitions[c - 'a'].p_size = 0;
1395 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1396 } else {
1397 lo = c - 'a';
1398 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1399 lp->d_partitions[c - 'a'].p_fsize = 0;
1400 lp->d_partitions[c - 'a'].p_frag = 0;
1401 lp->d_partitions[c - 'a'].p_cpg = 0;
1402 if (!strcmp(mountlist->el[idx].format, "ufs")
1403 || !strcmp(mountlist->el[idx].format, "ffs")
1404 || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1405 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1406 lp->d_partitions[c - 'a'].p_fsize = 2048;
1407 lp->d_partitions[c - 'a'].p_frag = 8;
1408 lp->d_partitions[c - 'a'].p_cpg = 64;
1409 } else if (!strcasecmp(mountlist->el[idx].format, "raid")
1410 || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1411 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1412 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1413 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1414 } else
1415 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1416 }
1417 }
1418
1419 // fix up the offsets
1420 lp->d_partitions[0].p_offset = 0;
1421 lp->d_partitions[RAW_PART].p_offset = 0;
1422 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1423 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1424
1425 for (i = 1; i < lp->d_npartitions; ++i) {
1426 int lastone;
1427 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1428 continue;
1429 for (lastone = i - 1; lastone >= 0; lastone--) {
1430 if ((lp->d_partitions[lastone].p_size)
1431 && (lastone != RAW_PART))
1432 break;
1433 }
1434 lp->d_partitions[i].p_offset =
1435 lp->d_partitions[lastone].p_offset +
1436 lp->d_partitions[lastone].p_size;
1437 }
1438 if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size >
1439 lp->d_secperunit) {
1440 lp->d_partitions[lo].p_size =
1441 lp->d_secperunit - lp->d_partitions[lo].p_offset;
1442 }
1443
1444 ftmp = fopen("/tmp/disklabel", "w");
1445 display_disklabel(ftmp, lp);
1446 fclose(ftmp);
1447 sprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1448 retval += run_program_and_log_output(command, TRUE);
1449 sprintf(command, "disklabel -R %s /tmp/disklabel",
1450 canonical_name(drivename));
1451 retval += run_program_and_log_output(command, TRUE);
1452 if (ret)
1453 *ret = *lp;
1454 return retval;
1455}
1456#endif
1457
1458
1459/**
1460 * Partition @p drivename based on @p mountlist.
1461 * @param mountlist The mountlist to use to guide the partitioning.
1462 * @param drivename The drive to partition.
1463 * @return 0 for success, nonzero for failure.
1464 */
1465int partition_drive(struct mountlist_itself *mountlist, char *drivename)
1466{
1467 /** int *************************************************************/
1468 int current_devno;
1469 int previous_devno = 0;
1470 int lino;
1471 int retval = 0;
1472 int i;
1473 FILE *pout_to_fdisk = NULL;
1474
1475#ifdef __FreeBSD__
1476 bool fbsd_part = FALSE;
1477 char subdev_str[MAX_STR_LEN];
1478#endif
1479
1480 /** long long *******************************************************/
1481 long long partsize;
1482
1483 /** buffers *********************************************************/
1484 char *device_str;
1485 char *format;
1486 char *tmp;
1487
1488 /** end *************************************************************/
1489
1490 assert(mountlist != NULL);
1491 assert_string_is_neither_NULL_nor_zerolength(drivename);
1492
1493 malloc_string(device_str);
1494 malloc_string(format);
1495 malloc_string(tmp);
1496
1497 sprintf(tmp, "Partitioning drive %s", drivename);
1498 log_it(tmp);
1499
1500#if __FreeBSD__
1501 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1502 pout_to_fdisk = NULL;
1503#else
1504 make_hole_for_file(FDISK_LOG);
1505 sprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1506 pout_to_fdisk = popen(tmp, "w");
1507 if (!pout_to_fdisk) {
1508 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
1509 paranoid_free(device_str);
1510 paranoid_free(format);
1511 paranoid_free(tmp);
1512 return (1);
1513 }
1514#endif
1515 for (current_devno = 1; current_devno < 99; current_devno++) {
1516 build_partition_name(device_str, drivename, current_devno);
1517 lino = find_device_in_mountlist(mountlist, device_str);
1518
1519 if (lino < 0) {
1520 // device not found in mountlist
1521#if __FreeBSD__
1522 // If this is the first partition (just as a sentinel value),
1523 // then see if the user has picked 'dangerously-dedicated' mode.
1524 // If so, then we just call label_drive_or_slice() and return.
1525 char c;
1526 if (current_devno == 1) {
1527 // try DangerouslyDedicated mode
1528 for (c = 'a'; c <= 'z'; c++) {
1529 sprintf(subdev_str, "%s%c", drivename, c);
1530 if (find_device_in_mountlist(mountlist, subdev_str) >
1531 0) {
1532 fbsd_part = TRUE;
1533 }
1534 }
1535 if (fbsd_part) {
1536 int r = label_drive_or_slice(mountlist,
1537 drivename,
1538 0);
1539 char command[MAX_STR_LEN];
1540 sprintf(command, "disklabel -B %s",
1541 basename(drivename));
1542 if (system(command)) {
1543 log_to_screen
1544 ("Warning! Unable to make the drive bootable.");
1545 }
1546 paranoid_free(device_str);
1547 paranoid_free(format);
1548 paranoid_free(tmp);
1549 return r;
1550 }
1551 }
1552 for (c = 'a'; c <= 'z'; c++) {
1553 sprintf(subdev_str, "%s%c", device_str, c);
1554 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1555 fbsd_part = TRUE;
1556 }
1557 }
1558 // Now we check the subpartitions of the current partition.
1559 if (fbsd_part) {
1560 int i, line;
1561
1562 strcpy(format, "ufs");
1563 partsize = 0;
1564 for (i = 'a'; i < 'z'; ++i) {
1565 sprintf(subdev_str, "%s%c", device_str, i);
1566 line = find_device_in_mountlist(mountlist, subdev_str);
1567 if (line > 0) {
1568 // We found one! Add its size to the total size.
1569 partsize += mountlist->el[line].size;
1570 }
1571 }
1572 } else {
1573 continue;
1574 }
1575#else
1576 continue;
1577#endif
1578 }
1579
1580 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1581 /* For FreeBSD, that is /dev/adXsY */
1582
1583 log_it("Found partition %s in mountlist", device_str);
1584 if (!previous_devno) {
1585
1586 log_it("Wiping %s's partition table", drivename);
1587#if __FreeBSD__
1588 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1589// sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1590// if (run_program_and_log_output(tmp, TRUE)) {
1591 file = open(drivename, O_WRONLY);
1592 if (file != -1) {
1593 sprintf(tmp,
1594 "Warning - unable to open %s for wiping it's partition table",
1595 drivename);
1596 log_to_screen(tmp);
1597 }
1598
1599 for (i = 0; i < 512; i++) {
1600 if (!write(file, "\0", 1)) {
1601 sprintf(tmp, "Warning - unable to write to %s",
1602 drivename);
1603 log_to_screen(tmp);
1604 }
1605 }
1606 system("sync");
1607#else
1608 log_it("New, kernel-friendly partition remover");
1609 for (i = 20; i > 0; i--) {
1610 fprintf(pout_to_fdisk, "d\n%d\n", i);
1611 fflush(pout_to_fdisk);
1612 }
1613// sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1614// run_program_and_log_output(tmp, 1);
1615#endif
1616 if (current_devno > 1) {
1617 previous_devno =
1618 make_dummy_partitions(pout_to_fdisk, drivename,
1619 current_devno);
1620 }
1621 }
1622#ifdef __FreeBSD__
1623 if (!fbsd_part) {
1624#endif
1625
1626 strcpy(format, mountlist->el[lino].format);
1627 partsize = mountlist->el[lino].size;
1628
1629#ifdef __FreeBSD__
1630 }
1631#endif
1632
1633#ifndef __IA64__
1634 if (current_devno == 5 && previous_devno == 4) {
1635 log_to_screen
1636 ("You must leave at least one partition spare as the Extended partition.");
1637 paranoid_free(device_str);
1638 paranoid_free(format);
1639 paranoid_free(tmp);
1640 return (1);
1641 }
1642#endif
1643
1644 retval +=
1645 partition_device(pout_to_fdisk, drivename, current_devno,
1646 previous_devno, format, partsize);
1647
1648#ifdef __FreeBSD__
1649 if ((current_devno <= 4) && fbsd_part) {
1650 sprintf(tmp, "disklabel -B %s", basename(device_str));
1651 retval += label_drive_or_slice(mountlist, device_str, 0);
1652 if (system(tmp)) {
1653 log_to_screen
1654 ("Warning! Unable to make the slice bootable.");
1655 }
1656 }
1657#endif
1658
1659 previous_devno = current_devno;
1660 }
1661
1662 if (pout_to_fdisk) {
1663// mark relevant partition as bootable
1664 sprintf(tmp, "a\n%s\n",
1665 call_program_and_get_last_line_of_output
1666 ("make-me-bootable /tmp/mountlist.txt dummy"));
1667 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1668// close fdisk
1669 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1670 system("sync");
1671 paranoid_pclose(pout_to_fdisk);
1672 log_msg(0,
1673 "------------------- fdisk.log looks like this ------------------");
1674 sprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1675 system(tmp);
1676 log_msg(0,
1677 "------------------- end of fdisk.log... word! ------------------");
1678 sprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1679 if (!run_program_and_log_output(tmp, 5)) {
1680 g_partition_table_locked_up++;
1681 }
1682 sprintf(tmp, "partprobe %s", drivename);
1683 if (!run_program_and_log_output(tmp, 5)) {
1684 g_partition_table_locked_up--;
1685 }
1686 if (g_partition_table_locked_up > 0) {
1687 log_to_screen
1688 ("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1689 }
1690 }
1691 paranoid_free(device_str);
1692 paranoid_free(format);
1693 paranoid_free(tmp);
1694 return (retval);
1695}
1696
1697/**
1698 * Create partition number @p partno on @p drive with @p fdisk.
1699 * @param drive The drive to create the partition on.
1700// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1701 * @param prev_partno The partition number of the most recently prepped partition.
1702 * @param format The filesystem type of this partition (used to set the type).
1703 * @param partsize The size of the partition in @e bytes.
1704 * @return 0 for success, nonzero for failure.
1705 */
1706int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1707 int prev_partno, const char *format,
1708 long long partsize)
1709{
1710 /** int **************************************************************/
1711 int retval = 0;
1712 int res = 0;
1713
1714 /** buffers **********************************************************/
1715 char *program;
1716 char *partition_name;
1717 char *tmp;
1718 char *logfile;
1719 char *output = NULL;
1720
1721 /** pointers **********************************************************/
1722 char *p;
1723 char *part_table_fmt;
1724 FILE *fout;
1725
1726 /** end ***************************************************************/
1727
1728 malloc_string(program);
1729 malloc_string(partition_name);
1730 malloc_string(tmp);
1731 malloc_string(logfile);
1732
1733 assert_string_is_neither_NULL_nor_zerolength(drive);
1734 assert(format != NULL);
1735
1736 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1737 drive, partno, prev_partno, format, partsize);
1738
1739 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1740 sprintf(tmp, "Not partitioning %s - it is a virtual drive", drive);
1741 log_it(tmp);
1742 paranoid_free(program);
1743 paranoid_free(partition_name);
1744 paranoid_free(tmp);
1745 paranoid_free(logfile);
1746 return (0);
1747 }
1748 build_partition_name(partition_name, drive, partno);
1749 if (partsize <= 0) {
1750 sprintf(tmp, "Partitioning device %s (max size)", partition_name);
1751 } else {
1752 sprintf(tmp, "Partitioning device %s (%lld MB)", partition_name,
1753 (long long) partsize / 1024);
1754 }
1755 update_progress_form(tmp);
1756 log_it(tmp);
1757
1758 if (is_this_device_mounted(partition_name)) {
1759 sprintf(tmp, "%s is mounted, and should not be partitioned",
1760 partition_name);
1761 log_to_screen(tmp);
1762 paranoid_free(program);
1763 paranoid_free(partition_name);
1764 paranoid_free(tmp);
1765 paranoid_free(logfile);
1766 return (1);
1767/*
1768 } else if (does_partition_exist(drive, partno)) {
1769 sprintf(tmp, "%s already has a partition", partition_name);
1770 log_to_screen(tmp);
1771 return (1);
1772*/
1773 }
1774
1775
1776 /* sprintf(tmp,"Partitioning %s ",partition_name); */
1777 /* mvaddstr_and_log_it(g_currentY+1,30,tmp); */
1778 p = (char *) strrchr(partition_name, '/');
1779 sprintf(logfile, "/tmp/fdisk.log.%s", ++p);
1780 sprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE,
1781 MONDO_LOGFILE);
1782
1783 /* BERLIOS: should not be called each time */
1784 part_table_fmt = which_partition_format(drive);
1785 mr_asprintf(&output, "");
1786 /* make it a primary/extended/logical */
1787 if (partno <= 4) {
1788 mr_strcat(output, "n\np\n%d\n", partno);
1789 } else {
1790 /* MBR needs an extended partition if more than 4 partitions */
1791 if (strcmp(part_table_fmt, "MBR") == 0) {
1792 if (partno == 5) {
1793 if (prev_partno >= 4) {
1794 log_to_screen
1795 ("You need to leave at least one partition free, for 'extended/logical'");
1796 paranoid_free(program);
1797 paranoid_free(partition_name);
1798 paranoid_free(tmp);
1799 paranoid_free(logfile);
1800 paranoid_free(output);
1801 return (1);
1802 } else {
1803 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1804 }
1805 }
1806 mr_strcat(output, "n\nl\n");
1807 } else {
1808 /* GPT allows more than 4 primary partitions */
1809 mr_strcat(output, "n\np\n%d\n", partno);
1810 }
1811 }
1812 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1813 if (partsize > 0) {
1814 if (!strcmp(format, "7")) {
1815 log_msg(1, "Adding 512K, just in case");
1816 partsize += 512;
1817 }
1818 mr_strcat(output, "+%lldK", (long long) (partsize));
1819 }
1820 mr_strcat(output, "\n");
1821#if 0
1822/*
1823#endif
1824 sprintf(tmp,"PARTSIZE = +%ld",(long)partsize);
1825 log_it(tmp);
1826 log_it("---fdisk command---");
1827 log_it(output);
1828 log_it("---end of fdisk---");
1829#if 0
1830*/
1831#endif
1832
1833
1834 if (pout_to_fdisk) {
1835 log_msg(1, "Doing the new all-in-one fdisk thing");
1836 log_msg(1, "output = '%s'", output);
1837 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1838 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1839 strcpy(tmp, last_line_of_file(FDISK_LOG));
1840 if (strstr(tmp, " (m ")) {
1841 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1842 } else {
1843 log_msg(1, "last line = %s", tmp);
1844 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1845 }
1846 if (!retval) {
1847 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1848 retval =
1849 set_partition_type(pout_to_fdisk, drive, partno, format,
1850 partsize);
1851 if (retval) {
1852 log_msg(1, "Failed. Trying again...");
1853 retval =
1854 set_partition_type(pout_to_fdisk, drive, partno,
1855 format, partsize);
1856 }
1857 }
1858 if (retval) {
1859 log_msg(1, "...but failed to set type");
1860 }
1861 } else {
1862 mr_strcat(output, "w\n\n");
1863 if (g_fprep) {
1864 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1865 }
1866 /* write to disk; close fdisk's stream */
1867 if (!(fout = popen(program, "w"))) {
1868 log_OS_error("can't popen-out to program");
1869 } else {
1870 fputs(output, fout);
1871 paranoid_pclose(fout);
1872 }
1873 if (!does_partition_exist(drive, partno) && partsize > 0) {
1874 log_it("Vaccum-packing");
1875 g_current_progress--;
1876 res =
1877 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1878 format, -1);
1879 if (res) {
1880 sprintf(tmp, "Failed to vacuum-pack %s", partition_name);
1881 log_it(tmp);
1882 retval++;
1883 } else {
1884 retval = 0;
1885 }
1886 }
1887 if (does_partition_exist(drive, partno)) {
1888 retval =
1889 set_partition_type(pout_to_fdisk, drive, partno, format,
1890 partsize);
1891 if (retval) {
1892 sprintf(tmp, "Partitioned %s but failed to set its type",
1893 partition_name);
1894 log_it(tmp);
1895 } else {
1896 if (partsize > 0) {
1897 sprintf(tmp, "Partition %s created+configured OK",
1898 partition_name);
1899 log_to_screen(tmp);
1900 } else {
1901 log_it("Returning from a successful vacuum-pack");
1902 }
1903 }
1904 } else {
1905 sprintf(tmp, "Failed to partition %s", partition_name);
1906 if (partsize > 0) {
1907 log_to_screen(tmp);
1908 } else {
1909 log_it(tmp);
1910 }
1911 retval++;
1912 }
1913 }
1914 paranoid_free(output);
1915
1916 g_current_progress++;
1917 log_it("partition_device() --- leaving");
1918 paranoid_free(program);
1919 paranoid_free(partition_name);
1920 paranoid_free(tmp);
1921 paranoid_free(logfile);
1922 return (retval);
1923}
1924
1925
1926
1927/**
1928 * Create all partitions listed in @p mountlist.
1929 * @param mountlist The mountlist to use to guide the partitioning.
1930 * @return The number of errors encountered (0 for success).
1931 * @note This sets the partition types but doesn't actually do the formatting.
1932 * Use format_everything() for that.
1933 */
1934int partition_everything(struct mountlist_itself *mountlist)
1935{
1936 /** int ************************************************************/
1937 int lino;
1938 int retval = 0;
1939 int i;
1940 int res;
1941
1942 /** buffer *********************************************************/
1943 struct list_of_disks *drivelist;
1944 /* struct mountlist_itself new_mtlist, *mountlist; */
1945
1946 /** end ************************************************************/
1947
1948 drivelist = malloc(sizeof(struct list_of_disks));
1949 assert(mountlist != NULL);
1950
1951 log_it("partition_everything() --- starting");
1952 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1953 /* mountlist=orig_mtlist; */
1954 if (mountlist_contains_raid_devices(mountlist)) {
1955 /* mountlist=&new_mtlist; */
1956 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1957 log_msg(0,
1958 "Mountlist, including the partitions incorporated in RAID devices:-");
1959 for (i = 0; i < mountlist->entries; i++) {
1960 log_it(mountlist->el[i].device);
1961 }
1962 log_msg(0, "End of mountlist.");
1963 }
1964 log_msg(0, "Stopping all LVMs, just in case");
1965 if (!g_text_mode) {
1966 newtSuspend();
1967 }
1968 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1969 if (!g_text_mode) {
1970 newtResume();
1971 }
1972 log_msg(0, "Stopping all software RAID devices, just in case");
1973 stop_all_raid_devices(mountlist);
1974 log_msg(0, "Done.");
1975
1976/*
1977 if (does_file_exist("/tmp/i-want-my-lvm"))
1978 {
1979 wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
1980 }
1981*/
1982
1983 open_progress_form("Partitioning devices",
1984 "I am now going to partition all your drives.",
1985 "This should not take more than five minutes.", "",
1986 mountlist->entries);
1987
1988 make_list_of_drives_in_mountlist(mountlist, drivelist);
1989
1990 /* partition each drive */
1991 for (lino = 0; lino < drivelist->entries; lino++) {
1992 res = partition_drive(mountlist, drivelist->el[lino].device);
1993 retval += res;
1994 }
1995 close_progress_form();
1996 if (retval) {
1997 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1998 log_to_screen
1999 ("Errors occurred during the partitioning of your hard drives.");
2000 } else {
2001 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2002 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
2003 }
2004 newtSuspend();
2005 system("clear");
2006 newtResume();
2007 paranoid_free(drivelist);
2008 return (retval);
2009}
2010
2011
2012
2013
2014
2015
2016/**
2017 * Set the type of partition number @p partno on @p drive to @p format.
2018 * @param drive The drive to change the type of a partition on.
2019 * @param partno The partition number on @p drive to change the type of.
2020 * @param format The filesystem type this partition will eventually contain.
2021 * @param partsize The size of this partition, in @e bytes (used for vfat
2022 * type calculations).
2023 * @return 0 for success, nonzero for failure.
2024 */
2025int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
2026 const char *format, long long partsize)
2027{
2028 /** buffers *********************************************************/
2029 char *partition;
2030 char *command;
2031 char *output = NULL;
2032 char *tmp;
2033 char *partcode;
2034 char *logfile;
2035
2036 /** pointers *********************************************************/
2037 char *p;
2038 FILE *fout;
2039
2040 /** int **************************************************************/
2041 int res = 0;
2042
2043 /** end **************************************************************/
2044
2045 assert_string_is_neither_NULL_nor_zerolength(drive);
2046 assert(format != NULL);
2047
2048 malloc_string(partition);
2049 malloc_string(command);
2050 malloc_string(tmp);
2051 malloc_string(partcode);
2052 malloc_string(logfile);
2053
2054 build_partition_name(partition, drive, partno);
2055 p = (char *) strrchr(partition, '/');
2056 sprintf(logfile, "/tmp/fdisk-set-type.%s.log", ++p);
2057 if (strcmp(format, "swap") == 0) {
2058 strcpy(partcode, "82");
2059 } else if (strcmp(format, "vfat") == 0) {
2060 if (partsize / 1024 > 8192) {
2061 strcpy(partcode, "c");
2062 } else {
2063 strcpy(partcode, "b");
2064 }
2065 } else if (strcmp(format, "ext2") == 0
2066 || strcmp(format, "reiserfs") == 0
2067 || strcmp(format, "ext3") == 0
2068 || strcmp(format, "ext4") == 0
2069 || strcmp(format, "xfs") == 0
2070 || strcmp(format, "jfs") == 0) {
2071 strcpy(partcode, "83");
2072 } else if (strcmp(format, "minix") == 0) {
2073 strcpy(partcode, "81");
2074 } else if (strcmp(format, "vmfs3") == 0) {
2075 strcpy(partcode, "fb");
2076 } else if (strcmp(format, "vmkcore") == 0) {
2077 strcpy(partcode, "fc");
2078 } else if (strcmp(format, "raid") == 0) {
2079 strcpy(partcode, "fd");
2080 } else if (strcmp(format, "ntfs") == 0) {
2081 strcpy(partcode, "7");
2082 } else if ((strcmp(format, "ufs") == 0)
2083 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
2084 strcpy(partcode, "a5");
2085 } else if (strcmp(format, "lvm") == 0) {
2086 strcpy(partcode, "8e");
2087 } else if (format[0] == '\0') { /* LVM physical partition */
2088 partcode[0] = '\0';
2089 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
2090 strcpy(partcode, format);
2091 } else {
2092 /* probably an image */
2093 sprintf(tmp,
2094 "Unknown format ('%s') - using supplied string anyway",
2095 format);
2096 mvaddstr_and_log_it(g_currentY++, 0, tmp);
2097#ifdef __FreeBSD__
2098 strcpy(partcode, format); // was a5
2099#else
2100 strcpy(partcode, format); // was 83
2101#endif
2102 }
2103 sprintf(tmp, "Setting %s's type to %s (%s)", partition, format,
2104 partcode);
2105 log_msg(1, tmp);
2106 if (partcode[0] != '\0' && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
2107
2108 if (pout_to_fdisk) {
2109 res = 0;
2110 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
2111 if (partno > 1
2112 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
2113 log_msg(5, "Specifying partno (%d) - yay", partno);
2114 sprintf(tmp, "%d\n", partno);
2115 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2116 log_msg(5, "A - last line = '%s'",
2117 last_line_of_file(FDISK_LOG));
2118 }
2119
2120 sprintf(tmp, "%s\n", partcode);
2121 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2122 log_msg(5, "B - last line = '%s'",
2123 last_line_of_file(FDISK_LOG));
2124 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2125 log_msg(5, "C - last line = '%s'",
2126 last_line_of_file(FDISK_LOG));
2127
2128 strcpy(tmp, last_line_of_file(FDISK_LOG));
2129 if (!strstr(tmp, " (m ")) {
2130 log_msg(1, "last line = '%s'; part type set failed", tmp);
2131 res++;
2132 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2133 }
2134 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2135 } else {
2136 mr_asprintf(&output, "t\n%d\n%s\nw\n", partno, partcode);
2137 sprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2138 MONDO_LOGFILE, MONDO_LOGFILE);
2139 log_msg(5, "output = '%s'", output);
2140 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2141 log_msg(5, "command = '%s'", command);
2142 fout = popen(command, "w");
2143 if (!fout) {
2144 log_OS_error(command);
2145 res = 1;
2146 } else {
2147 res = 0;
2148 fprintf(fout, "%s", output);
2149 paranoid_pclose(fout);
2150 }
2151 paranoid_free(output);
2152 }
2153 if (res) {
2154 log_OS_error(command);
2155 }
2156 }
2157
2158 paranoid_free(partition);
2159 paranoid_free(command);
2160 paranoid_free(tmp);
2161 paranoid_free(partcode);
2162 paranoid_free(logfile);
2163
2164 return (res);
2165}
2166
2167
2168int start_raid_device(char *raid_device)
2169{
2170 /** int *************************************************************/
2171 int res;
2172 int retval = 0;
2173
2174 /** buffers *********************************************************/
2175 char *program;
2176
2177 /** end *************************************************************/
2178
2179 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2180 malloc_string(program);
2181
2182#ifdef __FreeBSD__
2183 if (is_this_device_mounted(raid_device)) {
2184 log_it("Can't start %s when it's mounted!", raid_device);
2185 return 1;
2186 }
2187 sprintf(program, "vinum start -f %s", raid_device);
2188#else
2189 sprintf(program, "raidstart %s", raid_device);
2190#endif
2191 log_msg(1, "program = %s", program);
2192 res = run_program_and_log_output(program, 1);
2193 if (g_fprep) {
2194 fprintf(g_fprep, "%s\n", program);
2195 }
2196 if (res) {
2197 log_msg(1, "Warning - failed to start RAID device %s",
2198 raid_device);
2199 }
2200 retval += res;
2201 sleep(1);
2202 return (retval);
2203}
2204
2205
2206
2207/**
2208 * Stop @p raid_device using @p raidstop.
2209 * @param raid_device The software RAID device to stop.
2210 * @return 0 for success, nonzero for failure.
2211 */
2212int stop_raid_device(char *raid_device)
2213{
2214 /** int *************************************************************/
2215 int res;
2216 int retval = 0;
2217
2218 /** buffers *********************************************************/
2219 char *program;
2220
2221 /** end *************************************************************/
2222
2223 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2224 malloc_string(program);
2225
2226#ifdef __FreeBSD__
2227 if (is_this_device_mounted(raid_device)) {
2228 log_it("Can't stop %s when it's mounted!", raid_device);
2229 return 1;
2230 }
2231 sprintf(program, "vinum stop -f %s", raid_device);
2232#else
2233 // use raidstop if it exists, otherwise use mdadm
2234 if (run_program_and_log_output("which raidstop", FALSE)) {
2235 sprintf(program, "mdadm -S %s", raid_device);
2236 } else {
2237 sprintf(program, "raidstop %s", raid_device);
2238 }
2239#endif
2240 log_msg(1, "program = %s", program);
2241 res = run_program_and_log_output(program, 1);
2242 if (g_fprep) {
2243 fprintf(g_fprep, "%s\n", program);
2244 }
2245 if (res) {
2246 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2247 }
2248 retval += res;
2249 return (retval);
2250}
2251
2252
2253int start_all_raid_devices(struct mountlist_itself *mountlist)
2254{
2255 int i;
2256 int retval = 0;
2257 int res;
2258
2259 for (i = 0; i < mountlist->entries; i++) {
2260 if (!strncmp
2261 (mountlist->el[i].device, RAID_DEVICE_STUB,
2262 strlen(RAID_DEVICE_STUB))) {
2263 log_msg(1, "Starting %s", mountlist->el[i].device);
2264 res = start_raid_device(mountlist->el[i].device);
2265 retval += res;
2266 }
2267 }
2268 if (retval) {
2269 log_msg(1, "Started all s/w raid devices OK");
2270 } else {
2271 log_msg(1, "Failed to start some/all s/w raid devices");
2272 }
2273 return (retval);
2274}
2275
2276/**
2277 * Stop all software RAID devices listed in @p mountlist.
2278 * @param mountlist The mountlist to stop the RAID devices in.
2279 * @return The number of errors encountered (0 for success).
2280 * @bug @p mountlist is not used.
2281 */
2282int stop_all_raid_devices(struct mountlist_itself *mountlist)
2283{
2284 /** int *************************************************************/
2285 int retval = 0;
2286#ifndef __FreeBSD__
2287 int res;
2288#endif
2289
2290 /** char ************************************************************/
2291 char *incoming;
2292#ifndef __FreeBSD__
2293 char *dev;
2294#endif
2295 /** pointers ********************************************************/
2296#ifndef __FreeBSD__
2297 char *p;
2298#endif
2299 FILE *fin;
2300 int i;
2301
2302 /** end ****************************************************************/
2303
2304 malloc_string(dev);
2305 malloc_string(incoming);
2306 assert(mountlist != NULL);
2307
2308 for (i = 0; i < 3; i++) {
2309#ifdef __FreeBSD__
2310 fin =
2311 popen
2312 ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2313 "r");
2314 if (!fin) {
2315 paranoid_free(dev);
2316 paranoid_free(incoming);
2317 return (1);
2318 }
2319 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2320 fgets(incoming, MAX_STR_LEN - 1, fin)) {
2321 retval += stop_raid_device(incoming);
2322 }
2323#else
2324 fin = fopen("/proc/mdstat", "r");
2325 if (!fin) {
2326 log_OS_error("/proc/mdstat");
2327 paranoid_free(dev);
2328 paranoid_free(incoming);
2329 return (1);
2330 }
2331 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2332 fgets(incoming, MAX_STR_LEN - 1, fin)) {
2333 for (p = incoming;
2334 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2335 || !isdigit(*(p + 2))); p++);
2336 if (*p != '\0') {
2337 sprintf(dev, "/dev/%s", p);
2338 for (p = dev; *p > 32; p++);
2339 *p = '\0';
2340 res = stop_raid_device(dev);
2341 }
2342 }
2343#endif
2344 }
2345 paranoid_fclose(fin);
2346 if (retval) {
2347 log_msg(1, "Warning - unable to stop some RAID devices");
2348 }
2349 paranoid_free(dev);
2350 paranoid_free(incoming);
2351 system("sync");
2352 system("sync");
2353 system("sync");
2354 sleep(1);
2355 return (retval);
2356}
2357
2358
2359
2360/**
2361 * Decide which command we need to use to format a device of type @p format.
2362 * @param format The filesystem type we are about to format.
2363 * @param program Where to put the binary name for this format.
2364 * @return 0 for success, nonzero for failure.
2365 */
2366int which_format_command_do_i_need(char *format, char *program)
2367{
2368 /** int *************************************************************/
2369 int res = 0;
2370
2371 /** buffers *********************************************************/
2372 char *tmp;
2373
2374 /** end ***************************************************************/
2375
2376 malloc_string(tmp);
2377 assert_string_is_neither_NULL_nor_zerolength(format);
2378 assert(program != NULL);
2379
2380 if (strcmp(format, "swap") == 0) {
2381#ifdef __FreeBSD__
2382 strcpy(program, "true");
2383#else
2384 strcpy(program, "mkswap");
2385#endif
2386 } else if (strcmp(format, "vfat") == 0) {
2387 strcpy(program, "format-and-kludge-vfat");
2388#ifndef __FreeBSD__
2389 } else if (strcmp(format, "reiserfs") == 0) {
2390 strcpy(program, "mkreiserfs -ff");
2391 } else if (strcmp(format, "xfs") == 0) {
2392 strcpy(program, "mkfs.xfs -f -q");
2393 } else if (strcmp(format, "jfs") == 0) {
2394 strcpy(program, "mkfs.jfs");
2395 } else if (strcmp(format, "ext3") == 0) {
2396 strcpy(program, "mkfs -t ext3 -F -q");
2397 } else if (strcmp(format, "ext4") == 0) {
2398 strcpy(program, "mkfs -t ext4 -F -q");
2399 } else if (strcmp(format, "minix") == 0) {
2400 strcpy(program, "mkfs.minix");
2401 } else if (strcmp(format, "vmfs") == 0) {
2402 strcpy(program, "mkfs -t vmfs");
2403 } else if (strcmp(format, "ntfs") == 0) {
2404 /*
2405 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2406 * so the default "mkfs -t %s -c" command structure fails
2407 */
2408 strcpy(program, "mkfs -t ntfs");
2409 } else if (strcmp(format, "ocfs2") == 0) {
2410 /*
2411 * 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.
2412 *
2413 */
2414 strcpy(program, "mkfs -t ocfs2 -F");
2415#endif
2416 } else if (strcmp(format, "ext2") == 0) {
2417 strcpy(program, "mke2fs -F -q");
2418 } else {
2419#ifdef __FreeBSD__
2420 sprintf(program, "newfs_%s", format);
2421#else
2422 sprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2423#endif
2424 sprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format,
2425 program);
2426 log_it(tmp);
2427 res = 0;
2428 }
2429 paranoid_free(tmp);
2430 return (res);
2431}
2432
2433
2434/**
2435 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2436 * There are a few problems with this function:
2437 * - It won't work if there was any unallocated space on the user's hard drive
2438 * when it was backed up.
2439 * - It won't work if the user's hard drive lies about its size (more common
2440 * than you'd think).
2441 *
2442 * @param mountlist The mountlist to use for resizing @p drive_name.
2443 * @param drive_name The drive to resize.
2444 */
2445void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2446 *mountlist,
2447 char *drive_name)
2448{
2449 /**buffers **********************************************************/
2450 char *tmp;
2451
2452 /** int *************************************************************/
2453 int partno, lastpart;
2454 /** remove driveno, noof_drives stan benoit apr 2002**/
2455
2456 /** float ***********************************************************/
2457 float factor;
2458 float new_size;
2459// float newcylinderno;
2460
2461 /** long *************************************************************/
2462 long newsizL = 0L;
2463 long current_size_of_drive = 0L;
2464 long original_size_of_drive = 0L;
2465 long final_size = 0L; /* all in Megabytes */
2466 struct mountlist_reference *drivemntlist;
2467
2468 /** structures *******************************************************/
2469
2470 /** end **************************************************************/
2471
2472 malloc_string(tmp);
2473 assert(mountlist != NULL);
2474 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2475
2476 if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2477 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2478 == 0) {
2479 paranoid_free(tmp);
2480 return;
2481 }
2482 }
2483
2484 current_size_of_drive = get_phys_size_of_drive(drive_name);
2485
2486 if (current_size_of_drive <= 0) {
2487 log_it("Not resizing to match %s - can't find drive", drive_name);
2488 paranoid_free(tmp);
2489 return;
2490 }
2491 sprintf(tmp, "Expanding entries to suit drive %s (%ld MB)", drive_name,
2492 current_size_of_drive);
2493 log_to_screen(tmp);
2494
2495 drivemntlist = malloc(sizeof(struct mountlist_reference));
2496 drivemntlist->el =
2497 malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2498
2499 if (!drivemntlist) {
2500 fatal_error("Cannot malloc temporary mountlist\n");
2501 }
2502 create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2503
2504 for (partno = 0; partno < drivemntlist->entries; partno++) {
2505 if (drivemntlist->el[partno]->size > 0) {
2506 original_size_of_drive += (drivemntlist->el[partno]->size / 1024L);
2507 }
2508 }
2509
2510 if (original_size_of_drive <= 0) {
2511 sprintf(tmp, "Cannot resize %s's entries. Drive not found.",
2512 drive_name);
2513 log_to_screen(tmp);
2514 paranoid_free(tmp);
2515 return;
2516 }
2517 factor =
2518 (float) (current_size_of_drive) / (float) (original_size_of_drive);
2519 sprintf(tmp, "Disk %s was %ld MB; is now %ld MB; factor = %f",
2520 drive_name, original_size_of_drive, current_size_of_drive,
2521 factor);
2522 log_to_screen(tmp);
2523
2524 lastpart = drivemntlist->entries - 1;
2525 for (partno = 0; partno < drivemntlist->entries; partno++) {
2526 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2527 if (!atoi(drivemntlist->el[partno]->format)) {
2528 new_size = (float) (drivemntlist->el[partno]->size) * factor;
2529 } else {
2530 new_size = drivemntlist->el[partno]->size;
2531 }
2532
2533 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2534 log_msg(1, "Skipping %s (%s) because it's an image",
2535 drivemntlist->el[partno]->device,
2536 drivemntlist->el[partno]->mountpoint);
2537 newsizL = (long) new_size; // It looks wrong but it's not
2538 } else {
2539 newsizL = (long) new_size;
2540 }
2541
2542 /* Do not apply the factor if partition was of negative size */
2543 if (newsizL < 0) {
2544 newsizL = drivemntlist->el[partno]->size;
2545 }
2546
2547 sprintf(tmp, "Changing %s from %lld KB to %ld KB",
2548 drivemntlist->el[partno]->device,
2549 drivemntlist->el[partno]->size, newsizL);
2550 log_to_screen(tmp);
2551 drivemntlist->el[partno]->size = newsizL;
2552 }
2553 final_size = get_phys_size_of_drive(drive_name);
2554 sprintf(tmp, "final_size = %ld MB", final_size);
2555 log_to_screen(tmp);
2556 paranoid_free(tmp);
2557}
2558
2559
2560/**
2561 * Resize all partitions in @p mountlist proportionately (each one
2562 * grows or shrinks by the same percentage) to fit them into the new
2563 * drives (presumably different from the old ones).
2564 * @param mountlist The mountlist to resize the drives in.
2565 */
2566void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2567 *mountlist)
2568{
2569 /** buffers *********************************************************/
2570 struct list_of_disks *drivelist;
2571
2572 /** int *************************************************************/
2573 int driveno;
2574
2575 /** end *************************************************************/
2576
2577 drivelist = malloc(sizeof(struct list_of_disks));
2578 assert(mountlist != NULL);
2579
2580 if (g_mountlist_fname[0] == '\0') {
2581 log_it
2582 ("resize_mountlist_prop...() - warning - mountlist fname is blank");
2583 log_it("That does NOT affect the functioning of this subroutine.");
2584 log_it("--- Hugo, 2002/11/20");
2585 }
2586 log_it("Resizing mountlist");
2587 make_list_of_drives_in_mountlist(mountlist, drivelist);
2588 log_it("Back from MLoDiM");
2589 for (driveno = 0; driveno < drivelist->entries; driveno++) {
2590 resize_drive_proportionately_to_suit_new_drives(mountlist,
2591 drivelist->
2592 el[driveno].
2593 device);
2594 }
2595 log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2596 paranoid_free(drivelist);
2597}
2598
2599/**
2600 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2601 * @param mountlist The complete mountlist to get the drive references from.
2602 * @param drive_name The drive to put in @p drivemntlist.
2603 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2604 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2605 * @author Ralph Grewe
2606 */
2607void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2608 char *drive_name,
2609 struct mountlist_reference *drivemntlist)
2610{
2611 int partno;
2612 char *tmp_drive_name, *c;
2613
2614 assert(mountlist != NULL);
2615 assert(drive_name != NULL);
2616 assert(drivemntlist != NULL);
2617
2618 log_msg(1, "Creating list of partitions for drive %s", drive_name);
2619
2620 tmp_drive_name = strdup(drive_name);
2621 if (!tmp_drive_name)
2622 fatal_error("Out of memory");
2623
2624 /* devfs devices? */
2625 c = strrchr(tmp_drive_name, '/');
2626 if (c && strncmp(c, "/disc", 5) == 0) {
2627 /* yup its devfs, change the "disc" to "part" so the existing code works */
2628 strcpy(c + 1, "part");
2629 }
2630 drivemntlist->entries = 0;
2631 for (partno = 0; partno < mountlist->entries; partno++) {
2632 if (strncmp
2633 (mountlist->el[partno].device, tmp_drive_name,
2634 strlen(tmp_drive_name)) == 0) {
2635 drivemntlist->el[drivemntlist->entries] =
2636 &mountlist->el[partno];
2637 drivemntlist->entries++;
2638 }
2639 }
2640 if (tmp_drive_name)
2641 free(tmp_drive_name);
2642}
2643
2644/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.