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

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