source: MondoRescue/branches/2.05/mondo/mondo/mondorestore/mondo-prep.c@ 196

Last change on this file since 196 was 196, checked in by bcornec, 18 years ago

Usage of parted2fdisk instead of fdisk everywhere.
on ia64 this is mandatory, and simplifies the infrastructure
on other archs, it doesn't change anything as parted2fdisk here is a link to fdisk

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