source: MondoRescue/branches/2.2.8/mondo/src/mondorestore/mondo-prep.c@ 2053

Last change on this file since 2053 was 2052, checked in by Bruno Cornec, 15 years ago

Adds support for dm devices in truncate_to_drive_name

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