source: MondoRescue/branches/2.2.10/mondo/src/mondorestore/mondo-prep.c@ 2324

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

r3335@localhost: bruno | 2009-08-08 23:04:12 +0200

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