source: MondoRescue/branches/stable/mondo/src/mondorestore/mondo-prep.c@ 1080

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