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

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

r3341@localhost: bruno | 2009-08-13 22:36:24 +0200

  • Replacement of some strcpy
  • Change allocation done in resolve_softlinks_to_get_to_actual_device_file(), where_is_root_mounted(), bkptype_to_string(), which_boot_loader()
  • Property svn:keywords set to Id
File size: 71.4 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 2330 2009-08-18 13:20:49Z 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 2330 2009-08-18 13:20:49Z 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
451 /** pointers *********************************************************/
452 char *p;
453
454 /** init *************************************************************/
455 new_mountlist->entries = 0;
456
457 /** end **************************************************************/
458
459 malloc_string(incoming);
460 assert(new_mountlist != NULL);
461 assert(old_mountlist != NULL);
462
463#ifdef __FreeBSD__
464 log_to_screen
465 ("I don't know how to extrapolate the mountlist on FreeBSD. Sorry.");
466 return (1);
467#endif
468
469 for (lino = 0; lino < old_mountlist->entries; lino++) {
470 if (strstr(old_mountlist->el[lino].device, RAID_DEVICE_STUB)) // raid
471 {
472 if (!does_file_exist("/etc/raidtab")) {
473 log_to_screen
474 ("Cannot find /etc/raidtab - cannot extrapolate the fdisk entries");
475 finish(1);
476 }
477 if (!(fin = fopen("/etc/raidtab", "r"))) {
478 log_OS_error("Cannot open /etc/raidtab");
479 finish(1);
480 }
481 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin)
482 && !strstr(incoming, old_mountlist->el[lino].device);
483 fgets(incoming, MAX_STR_LEN - 1, fin));
484 if (!feof(fin)) {
485 log_it("Investigating %s", old_mountlist->el[lino].device);
486
487 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin)
488 && !strstr(incoming, "raiddev");
489 fgets(incoming, MAX_STR_LEN - 1, fin)) {
490 if (strstr(incoming, OSSWAP("device", "drive"))
491 && !strchr(incoming, '#')) {
492 for (p = incoming + strlen(incoming);
493 *(p - 1) <= 32; p--);
494 *p = '\0';
495 for (p--; p > incoming && *(p - 1) > 32; p--);
496 log_it("Extrapolating %s", p);
497
498 for (j = 0;
499 j < new_mountlist->entries
500 && strcmp(new_mountlist->el[j].device, p);
501 j++);
502 if (j >= new_mountlist->entries) {
503 strcpy(new_mountlist->
504 el[new_mountlist->entries].device, p);
505 strcpy(new_mountlist->
506 el[new_mountlist->entries].mountpoint,
507 "raid");
508 strcpy(new_mountlist->
509 el[new_mountlist->entries].format,
510 "raid");
511 new_mountlist->el[new_mountlist->entries].
512 size = old_mountlist->el[lino].size;
513 new_mountlist->entries++;
514 } else {
515 log_it("Not adding %s to mountlist: it's already there", p);
516 }
517 }
518 }
519 }
520 paranoid_fclose(fin);
521 } else {
522 strcpy(new_mountlist->el[new_mountlist->entries].device,
523 old_mountlist->el[lino].device);
524 strcpy(new_mountlist->el[new_mountlist->entries].mountpoint,
525 old_mountlist->el[lino].mountpoint);
526 strcpy(new_mountlist->el[new_mountlist->entries].format,
527 old_mountlist->el[lino].format);
528 new_mountlist->el[new_mountlist->entries].size =
529 old_mountlist->el[lino].size;
530 new_mountlist->entries++;
531 }
532 }
533 paranoid_free(incoming);
534
535 return (0);
536}
537
538
539/**
540 * Create @p RAID device using information from @p structure.
541 * This will create the specified RAID devive using information provided in
542 * raidlist by means of the mdadm tool.
543 * @param raidlist The structure containing all RAID information
544 * @param device The RAID device to create.
545 * @return 0 for success, nonzero for failure.
546 */
547int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device)
548{
549 /** int **************************************************************/
550 int i = 0;
551 int j = 0;
552 int res = 0;
553
554 /** buffers ***********************************************************/
555 char *devices = NULL;
556 char *strtmp = NULL;
557 char *level = NULL;
558 char *program = NULL;
559
560 // leave straight away if raidlist is initial or has no entries
561 if (!raidlist || raidlist->entries == 0) {
562 log_msg(1, "No RAID arrays found.");
563 return 1;
564 } else {
565 log_msg(1, "%d RAID arrays found.", raidlist->entries);
566 }
567 // find raidlist entry for requested device
568 for (i = 0; i < raidlist->entries; i++) {
569 if (!strcmp(raidlist->el[i].raid_device, device)) break;
570 }
571 // check whether RAID device was found in raidlist
572 if (i == raidlist->entries) {
573 log_msg(1, "RAID device %s not found in list.", device);
574 return 1;
575 }
576 // create device list from normal disks followed by spare ones
577 mr_asprintf(devices, "%s", raidlist->el[i].data_disks.el[0].device);
578 for (j = 1; j < raidlist->el[i].data_disks.entries; j++) {
579 mr_asprintf(strtmp, "%s", devices);
580 mr_free(devices);
581 mr_asprintf(devices, "%s %s", strtmp, raidlist->el[i].data_disks.el[j].device);
582 mr_free(strtmp);
583 }
584 for (j = 0; j < raidlist->el[i].spare_disks.entries; j++) {
585 mr_asprintf(strtmp, "%s", devices);
586 mr_free(devices);
587 mr_asprintf(devices, "%s %s", strtmp, raidlist->el[i].spare_disks.el[j].device);
588 mr_free(strtmp);
589 }
590 // translate RAID level
591 if (raidlist->el[i].raid_level == -2) {
592 mr_asprintf(level, "multipath");
593 } else if (raidlist->el[i].raid_level == -1) {
594 mr_asprintf(level, "linear");
595 } else {
596 mr_asprintf(level, "raid%d", raidlist->el[i].raid_level);
597 }
598 // create RAID device:
599 // - RAID device, number of devices and devices mandatory
600 // - parity algorithm, chunk size and spare devices optional
601 // - faulty devices ignored
602 // - persistent superblock always used as this is recommended
603 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);
604 if (raidlist->el[i].parity != -1) {
605 mr_asprintf(strtmp, "%s", program);
606 mr_free(program);
607 switch(raidlist->el[i].parity) {
608 case 0:
609 mr_asprintf(program, "%s --parity=%s", strtmp, "la");
610 break;
611 case 1:
612 mr_asprintf(program, "%s --parity=%s", strtmp, "ra");
613 break;
614 case 2:
615 mr_asprintf(program, "%s --parity=%s", strtmp, "ls");
616 break;
617 case 3:
618 mr_asprintf(program, "%s --parity=%s", strtmp, "rs");
619 break;
620 default:
621 fatal_error("Unknown RAID parity algorithm.");
622 break;
623 }
624 paranoid_free(strtmp);
625 }
626 if (raidlist->el[i].chunk_size != -1) {
627 mr_asprintf(strtmp, "%s", program);
628 mr_free(program);
629 mr_asprintf(program, "%s --chunk=%d", strtmp, raidlist->el[i].chunk_size);
630 mr_free(strtmp);
631 }
632 if (raidlist->el[i].spare_disks.entries > 0) {
633 mr_asprintf(strtmp, "%s", program);
634 mr_free(program);
635 mr_asprintf(program, "%s --spare-devices=%d", strtmp, raidlist->el[i].spare_disks.entries);
636 mr_free(strtmp);
637 }
638 mr_asprintf(strtmp, "%s", program);
639 mr_free(program);
640 mr_asprintf(program, "%s %s", strtmp, devices);
641 mr_free(strtmp);
642 res = run_program_and_log_output(program, 1);
643 mr_free(devices);
644 mr_free(level);
645 mr_free(program);
646 return res;
647}
648
649
650/**
651 * Format @p device as a @p format filesystem.
652 * This will use the format command returned by which_format_command_do_i_need().
653 * If @p device is an LVM PV, it will not be formatted, and LVM will be started
654 * (if not already done). If it's an imagedev, software RAID component, or
655 * (under BSD) swap partition, no format will be done.
656 * @param device The device to format.
657 * @param format The filesystem type to format it as.
658 * @return 0 for success, nonzero for failure.
659 */
660int format_device(char *device, char *format, struct raidlist_itself *raidlist)
661{
662 /** int **************************************************************/
663#ifdef __FreeBSD__
664 static bool vinum_started_yet = FALSE;
665#endif
666
667 /** buffers ***********************************************************/
668 char *program = NULL;
669 char *tmp = NULL;
670 int res = 0;
671 int retval = 0;
672
673 /** end ****************************************************************/
674
675 assert_string_is_neither_NULL_nor_zerolength(device);
676 assert(format != NULL);
677
678 if (strstr(format, "raid")) { // do not form RAID disks; do it to /dev/md* instead
679 log_it("Not formatting %s (it is a RAID disk)", device);
680 return (0);
681 }
682#ifdef __FreeBSD__
683 if (strcmp(format, "swap") == 0) {
684 log_it("Not formatting %s - it's swap", device);
685 return (0);
686 }
687#endif
688 if (strlen(format) <= 2) {
689 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);
690 return (0);
691 }
692 if (is_this_device_mounted(device)) {
693 log_to_screen("%s is mounted - cannot format it ", device);
694 return (1);
695 }
696 if (strstr(device, RAID_DEVICE_STUB)) {
697 newtSuspend();
698#ifdef __FreeBSD__
699 if (!vinum_started_yet) {
700 if (!does_file_exist("/tmp/raidconf.txt")) {
701 log_to_screen
702 ("/tmp/raidconf.txt does not exist. I therefore cannot start Vinum.");
703 } else {
704 int res;
705 res =
706 run_program_and_log_output
707 ("vinum create /tmp/raidconf.txt", TRUE);
708 if (res) {
709 log_to_screen
710 ("`vinum create /tmp/raidconf.txt' returned errors. Please fix them and re-run mondorestore.");
711 finish(1);
712 }
713 vinum_started_yet = TRUE;
714 }
715 }
716
717 if (vinum_started_yet) {
718 FILE *fin;
719 char line[MAX_STR_LEN];
720
721 log_to_screen("Initializing Vinum device %s (this may take a *long* time)", device);
722
723 /* format raid partition */
724 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));
725 system(program);
726 if (g_fprep) {
727 fprintf(g_fprep, "%s\n", program);
728 }
729 mr_free(program);
730
731 fin = fopen("/tmp/plexes", "r");
732 while (fgets(line, MAX_STR_LEN - 1, fin)) {
733 if (strchr(line, '\n'))
734 *(strchr(line, '\n')) = '\0'; // get rid of the \n on the end
735
736 mr_asprintf(tmp, "Initializing plex: %s", line);
737 open_evalcall_form(tmp);
738 mr_free(tmp);
739
740 mr_asprintf(tmp, "vinum init %s", line);
741 system(tmp);
742 mr_free(tmp);
743
744 while (1) {
745 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);
746 FILE *pin = popen(tmp, "r");
747 mr_free(tmp);
748
749 char status[MAX_STR_LEN / 4];
750 fgets(status, MAX_STR_LEN / 4 - 1, pin);
751 pclose(pin);
752
753 if (!strcmp(status, "up")) {
754 break; /* it's done */
755 }
756 update_evalcall_form(atoi(status));
757 usleep(250000);
758 }
759 close_evalcall_form();
760 }
761 fclose(fin);
762 unlink("/tmp/plexes");
763 }
764#else
765 log_to_screen(tmp, "Initializing RAID device %s", device);
766 log_to_screen(tmp);
767 mr_free(tmp);
768
769// Shouldn't be necessary.
770 log_to_screen("Stopping %s", device);
771 stop_raid_device(device);
772 system("sync");
773 sleep(1);
774
775 log_msg(1, "Making %s", device);
776 // use mkraid if it exists, otherwise use mdadm
777 if (run_program_and_log_output("which mkraid", FALSE)) {
778 res = create_raid_device_via_mdadm(raidlist, device);
779 log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
780 } else {
781 mr_asprintf(program, "mkraid --really-force %s", device);
782 res = run_program_and_log_output(program, 1);
783 log_msg(1, "%s returned %d", program, res);
784 system("sync");
785 sleep(3);
786 start_raid_device(device);
787 if (g_fprep) {
788 fprintf(g_fprep, "%s\n", program);
789 }
790 mr_free(program);
791 }
792 system("sync");
793 sleep(2);
794#endif
795 system("sync");
796 sleep(1);
797 newtResume();
798 }
799
800 if (!strcmp(format, "lvm")) {
801 log_msg(1, "Don't format %s - it's part of an lvm volume", device);
802 return (0);
803 }
804 program = which_format_command_do_i_need(format);
805 mr_asprintf(tmp, "%s %s", program, device);
806 if (strstr(program, "kludge")) {
807 mr_strcat(tmp, " /");
808 }
809 mr_free(program);
810
811 mr_asprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
812 mr_free(tmp);
813
814 mr_asprintf(tmp, "Formatting %s as %s", device, format);
815 update_progress_form(tmp);
816 mr_free(tmp);
817
818 res = run_program_and_log_output(program, FALSE);
819 if (res) {
820 mr_strcat(tmp, "...failed");
821 } else {
822 mr_strcat(tmp, "...OK");
823 }
824 log_to_screen(tmp);
825 mr_free(tmp);
826
827 if (res && strstr(program, "kludge")) {
828 mr_asprintf(&tmp, "Kludge failed; using regular mkfs.%s to format %s", format, device);
829 mr_free(program);
830#ifdef __FreeBSD__
831 mr_asprintf(program, "newfs_msdos -F 32 %s", device);
832#else
833#ifdef __IA64__
834 /* For EFI partitions take fat16
835 * as we want to make small ones */
836 mr_asprintf(program, "mkfs -t %s -F 16 %s", format, device);
837#else
838 mr_asprintf(program, "mkfs -t %s -F 32 %s", format, device);
839#endif
840#endif
841 res = run_program_and_log_output(program, FALSE);
842 if (g_fprep) {
843 fprintf(g_fprep, "%s\n", program);
844 }
845 if (retval) {
846 mr_strcat(tmp, "...failed");
847 } else {
848 mr_strcat(tmp, "...OK");
849 }
850
851 log_to_screen(tmp);
852 mr_free(tmp);
853
854 }
855 mr_free(program);
856 retval += res;
857 system("sync");
858 sleep(1);
859 return (retval);
860}
861
862
863
864
865
866/**
867 * Format all drives (except those excluded by format_device()) in @p mountlist.
868 * @param mountlist The mountlist containing partitions to be formatted.
869 * @param interactively If TRUE, then prompt the user before each partition.
870 * @return The number of errors encountered (0 for success).
871 */
872int format_everything(struct mountlist_itself *mountlist, bool interactively,
873 struct raidlist_itself *raidlist)
874{
875 /** int **************************************************************/
876 int retval = 0;
877 int lino;
878 int res;
879
880 /** long *************************************************************/
881 long progress_step;
882
883 /** bools ************************************************************/
884 bool do_it;
885
886 /** buffers **********************************************************/
887 char *tmp = NULL;
888
889 /** pointers *********************************************************/
890 struct mountlist_line *me; // mountlist entry
891 /** end **************************************************************/
892
893 assert(mountlist != NULL);
894 mr_asprintf(tmp, "format_everything (mountlist, interactively = %s", (interactively) ? "true" : "false");
895 log_it(tmp);
896 mr_free(tmp);
897
898 mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
899 open_progress_form("Formatting partitions",
900 "I am now formatting your hard disk partitions.",
901 "This may take up to five minutes.", "",
902 mountlist->entries + 1);
903
904 progress_step =
905 (mountlist->entries >
906 0) ? g_maximum_progress / mountlist->entries : 1;
907 // start soft-raids now (because LVM might depend on them)
908 // ...and for simplicity's sake, let's format them at the same time :)
909 log_msg(1, "Stopping all RAID devices");
910 stop_all_raid_devices(mountlist);
911 system("sync");
912 system("sync");
913 system("sync");
914 sleep(2);
915 log_msg(1, "Prepare soft-RAIDs"); // prep and format too
916 for (lino = 0; lino < mountlist->entries; lino++) {
917 me = &mountlist->el[lino]; // the current mountlist entry
918 log_msg(2, "Examining %s", me->device);
919 if (!strncmp(me->device, "/dev/md", 7)) {
920 if (interactively) {
921 // ask user if we should format the current device
922 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
923 do_it = ask_me_yes_or_no(tmp);
924 mr_free(tmp);
925 } else {
926 do_it = TRUE;
927 }
928 if (do_it) {
929 // NB: format_device() also stops/starts RAID device if necessary
930 retval += format_device(me->device, me->format, raidlist);
931 }
932 g_current_progress += progress_step;
933 }
934 }
935 system("sync");
936 system("sync");
937 system("sync");
938 sleep(2);
939// This last step is probably necessary
940// log_to_screen("Re-starting software RAIDs...");
941// start_all_raid_devices(mountlist);
942// system("sync"); system("sync"); system("sync");
943// sleep(5);
944// do LVMs now
945 log_msg(1, "Creating LVMs");
946 if (does_file_exist("/tmp/i-want-my-lvm")) {
947 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
948 log_to_screen("Configuring LVM");
949 if (!g_text_mode) {
950 newtSuspend();
951 }
952 res = do_my_funky_lvm_stuff(FALSE, TRUE);
953 if (!g_text_mode) {
954 newtResume();
955 }
956 if (!res) {
957 log_to_screen("LVM initialized OK");
958 } else {
959 log_to_screen("Failed to initialize LVM");
960 }
961 if (res) {
962 retval++;
963 }
964 sleep(3);
965 }
966 // do regulars at last
967 sleep(2); // woo!
968 log_msg(1, "Formatting regulars");
969 for (lino = 0; lino < mountlist->entries; lino++) {
970 me = &mountlist->el[lino]; // the current mountlist entry
971 if (!strcmp(me->mountpoint, "image")) {
972 log_it("Not formatting %s - it's an image", me->device);
973 } else if (!strcmp(me->format, "raid")) {
974 log_it("Not formatting %s - it's a raid-let", me->device);
975 continue;
976 } else if (!strcmp(me->format, "lvm")) {
977 log_it("Not formatting %s - it's an LVM", me->device);
978 continue;
979 } else if (!strncmp(me->device, "/dev/md", 7)) {
980 log_it("Already formatted %s - it's a soft-RAID dev", me->device);
981 continue;
982 } else if (!does_file_exist(me->device)
983 && strncmp(me->device, "/dev/hd", 7)
984 && strncmp(me->device, "/dev/sd", 7)) {
985 log_it("Not formatting %s yet - doesn't exist - probably an LVM", me->device);
986 continue;
987 } else {
988 if (interactively) {
989 // ask user if we should format the current device
990 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
991 do_it = ask_me_yes_or_no(tmp);
992 mr_free(tmp);
993 } else {
994 do_it = TRUE;
995 }
996
997 if (do_it)
998 retval += format_device(me->device, me->format, raidlist);
999 }
1000
1001 // update progress bar
1002 g_current_progress += progress_step;
1003 }
1004
1005
1006 // update progress bar to 100% to compensate for
1007 // rounding errors of the progress_step calculation
1008 if (lino >= mountlist->entries)
1009 g_current_progress = g_maximum_progress;
1010
1011 close_progress_form();
1012
1013 if (retval) {
1014 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1015 log_to_screen
1016 ("Errors occurred during the formatting of your hard drives.");
1017 } else {
1018 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1019 }
1020
1021 log_it("format_everything () - %s", (retval) ? "failed!" : "finished successfully");
1022
1023 if (g_partition_table_locked_up > 0) {
1024 if (retval > 0 && !interactively) {
1025//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
1026 log_to_screen
1027 ("Partition table locked up %d times. At least one 'mkfs' (format) command",
1028 g_partition_table_locked_up);
1029 log_to_screen
1030 ("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
1031 log_to_screen
1032 ("to refresh its copy of the partition table causes the kernel to lock the ");
1033 log_to_screen
1034 ("partition table. I believe this has just happened.");
1035 if (ask_me_yes_or_no
1036 ("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue."))
1037 {
1038 system("sync");
1039 system("sync");
1040 system("sync");
1041 system("reboot");
1042 }
1043 } else {
1044 log_to_screen
1045 ("Partition table locked up %d time%c. However, disk formatting succeeded.",
1046 g_partition_table_locked_up,
1047 (g_partition_table_locked_up == 1) ? '.' : 's');
1048 }
1049 }
1050 newtSuspend();
1051 system("clear");
1052 newtResume();
1053 return (retval);
1054}
1055
1056
1057/**
1058 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
1059 * Each partition created is 32k in size.
1060 * @param drivename The drive to create the dummy partitions on.
1061 * @param devno_we_must_allow_for The lowest-numbered real partition; create
1062 * dummies up to (this - 1).
1063 * @return The number of errors encountered (0 for success).
1064 */
1065int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename,
1066 int devno_we_must_allow_for)
1067{
1068 /** int **************************************************************/
1069 int current_devno;
1070 int previous_devno;
1071 int retval = 0;
1072 int res;
1073
1074 /** end **************************************************************/
1075
1076 assert_string_is_neither_NULL_nor_zerolength(drivename);
1077
1078 if (devno_we_must_allow_for >= 5) {
1079 log_it("Making dummy primary 1 on %s", drivename);
1080
1081 g_maximum_progress++;
1082 res =
1083 partition_device(pout_to_fdisk, drivename, 1, 0, "ext2",
1084 32000);
1085 retval += res;
1086 previous_devno = 1;
1087 current_devno = 5;
1088 } else {
1089 previous_devno = 0;
1090 current_devno = 1;
1091 }
1092 for (; current_devno < devno_we_must_allow_for; current_devno++) {
1093 log_it("Creating dummy partition %d on %s", current_devno, drivename);
1094 g_maximum_progress++;
1095 res =
1096 partition_device(pout_to_fdisk, drivename, current_devno,
1097 previous_devno, OSSWAP("ext2", "ufs"), 32000);
1098 retval += res;
1099 previous_devno = current_devno;
1100 }
1101 return (previous_devno);
1102}
1103
1104
1105/**
1106 * Decide whether @p mountlist contains any RAID devices.
1107 * @param mountlist The mountlist to examine.
1108 * @return TRUE if it does, FALSE if it doesn't.
1109 */
1110bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist)
1111{
1112 /** int *************************************************************/
1113 int i;
1114 int matching = 0;
1115
1116 /** end **************************************************************/
1117
1118 assert(mountlist != NULL);
1119
1120 for (i = 0; i < mountlist->entries; i++) {
1121 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1122 matching++;
1123 }
1124 }
1125 if (matching) {
1126 return (TRUE);
1127 } else {
1128 return (FALSE);
1129 }
1130}
1131
1132/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1133#ifdef __FreeBSD__
1134static void display_disklabel(FILE * f, const struct disklabel *lp)
1135{
1136 int i, j;
1137 const struct partition *pp;
1138
1139 fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1140 if (lp->d_type < DKMAXTYPES)
1141 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1142 else
1143 fprintf(f, "type: %u\n", lp->d_type);
1144 fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename),
1145 lp->d_typename);
1146 fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname),
1147 lp->d_packname);
1148 fprintf(f, "flags:");
1149 if (lp->d_flags & D_REMOVABLE)
1150 fprintf(f, " removeable");
1151 if (lp->d_flags & D_ECC)
1152 fprintf(f, " ecc");
1153 if (lp->d_flags & D_BADSECT)
1154 fprintf(f, " badsect");
1155 fprintf(f, "\n");
1156 fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1157 fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1158 fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1159 fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1160 fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1161 fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1162 fprintf(f, "rpm: %u\n", lp->d_rpm);
1163 fprintf(f, "interleave: %u\n", lp->d_interleave);
1164 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1165 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1166 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
1167 (u_long) lp->d_headswitch);
1168 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
1169 (u_long) lp->d_trkseek);
1170 fprintf(f, "drivedata: ");
1171 for (i = NDDATA - 1; i >= 0; i--)
1172 if (lp->d_drivedata[i])
1173 break;
1174 if (i < 0)
1175 i = 0;
1176 for (j = 0; j <= i; j++)
1177 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1178 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1179 fprintf(f,
1180 "# size offset fstype [fsize bsize bps/cpg]\n");
1181 pp = lp->d_partitions;
1182 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1183 if (pp->p_size) {
1184 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size,
1185 (u_long) pp->p_offset);
1186 if (pp->p_fstype < FSMAXTYPES)
1187 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1188 else
1189 fprintf(f, "%8d", pp->p_fstype);
1190 switch (pp->p_fstype) {
1191
1192 case FS_UNUSED: /* XXX */
1193 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1194 (u_long) (pp->p_fsize * pp->p_frag), "");
1195 break;
1196
1197 case FS_BSDFFS:
1198 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize,
1199 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1200 break;
1201
1202 case FS_BSDLFS:
1203 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize,
1204 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1205 break;
1206
1207 default:
1208 fprintf(f, "%20.20s", "");
1209 break;
1210 }
1211 fprintf(f, "\t# (Cyl. %4lu",
1212 (u_long) (pp->p_offset / lp->d_secpercyl));
1213 if (pp->p_offset % lp->d_secpercyl)
1214 putc('*', f);
1215 else
1216 putc(' ', f);
1217 fprintf(f, "- %lu",
1218 (u_long) ((pp->p_offset + pp->p_size +
1219 lp->d_secpercyl - 1) / lp->d_secpercyl -
1220 1));
1221 if (pp->p_size % lp->d_secpercyl)
1222 putc('*', f);
1223 fprintf(f, ")\n");
1224 }
1225 }
1226 fflush(f);
1227}
1228
1229static struct disklabel *get_virgin_disklabel(char *dkname)
1230{
1231 static struct disklabel loclab;
1232 struct partition *dp;
1233 char lnamebuf[BBSIZE];
1234 int f;
1235 u_int secsize, u;
1236 off_t mediasize;
1237
1238 (void) snprintf(lnamebuf, BBSIZE, "%s", dkname);
1239 if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1240 warn("cannot open %s", lnamebuf);
1241 return (NULL);
1242 }
1243
1244 /* New world order */
1245 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1246 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1247 close(f);
1248 return (NULL);
1249 }
1250 memset(&loclab, 0, sizeof loclab);
1251 loclab.d_magic = DISKMAGIC;
1252 loclab.d_magic2 = DISKMAGIC;
1253 loclab.d_secsize = secsize;
1254 loclab.d_secperunit = mediasize / secsize;
1255
1256 /*
1257 * Nobody in these enligthened days uses the CHS geometry for
1258 * anything, but nontheless try to get it right. If we fail
1259 * to get any good ideas from the device, construct something
1260 * which is IBM-PC friendly.
1261 */
1262 if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1263 loclab.d_nsectors = u;
1264 else
1265 loclab.d_nsectors = 63;
1266 if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1267 loclab.d_ntracks = u;
1268 else if (loclab.d_secperunit <= 63 * 1 * 1024)
1269 loclab.d_ntracks = 1;
1270 else if (loclab.d_secperunit <= 63 * 16 * 1024)
1271 loclab.d_ntracks = 16;
1272 else
1273 loclab.d_ntracks = 255;
1274 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1275 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1276 loclab.d_npartitions = MAXPARTITIONS;
1277
1278 /* Various (unneeded) compat stuff */
1279 loclab.d_rpm = 3600;
1280 loclab.d_bbsize = BBSIZE;
1281 loclab.d_interleave = 1;;
1282 strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1283
1284 dp = &loclab.d_partitions[RAW_PART];
1285 dp->p_size = loclab.d_secperunit;
1286 loclab.d_checksum = dkcksum(&loclab);
1287 close(f);
1288 return (&loclab);
1289}
1290
1291/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1292
1293char *canonical_name(char *drivename)
1294{
1295 if (drivename) {
1296 if (strncmp(drivename, "/dev/", 5) == 0) {
1297 return drivename + 5;
1298 }
1299 }
1300 return drivename;
1301}
1302
1303/**
1304 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1305 * @param mountlist The mountlist to get the subpartition information from.
1306 * @param drivename The drive or slice to create a disklabel on.
1307 * @param ret If non-NULL, store the created disklabel here.
1308 * @return The number of errors encountered (0 for success).
1309 */
1310int label_drive_or_slice(struct mountlist_itself *mountlist,
1311 char *drivename, struct disklabel *ret)
1312{
1313 char *subdev_str = NULL
1314 char *command = NULL;
1315 struct disklabel *lp;
1316 int i, lo = 0;
1317 int retval = 0;
1318 char c;
1319 FILE *ftmp;
1320
1321 lp = get_virgin_disklabel(drivename);
1322 for (c = 'a'; c <= 'z'; ++c) {
1323 int idx;
1324 mr_asprintf(subdev_str, "%s%c", drivename, c);
1325 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1326 lp->d_partitions[c - 'a'].p_size = 0;
1327 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1328 } else {
1329 lo = c - 'a';
1330 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1331 lp->d_partitions[c - 'a'].p_fsize = 0;
1332 lp->d_partitions[c - 'a'].p_frag = 0;
1333 lp->d_partitions[c - 'a'].p_cpg = 0;
1334 if (!strcmp(mountlist->el[idx].format, "ufs")
1335 || !strcmp(mountlist->el[idx].format, "ffs")
1336 || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1337 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1338 lp->d_partitions[c - 'a'].p_fsize = 2048;
1339 lp->d_partitions[c - 'a'].p_frag = 8;
1340 lp->d_partitions[c - 'a'].p_cpg = 64;
1341 } else if (!strcasecmp(mountlist->el[idx].format, "raid")
1342 || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1343 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1344 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1345 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1346 } else
1347 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1348 }
1349 mr_free(subdev_str);
1350 }
1351
1352 // fix up the offsets
1353 lp->d_partitions[0].p_offset = 0;
1354 lp->d_partitions[RAW_PART].p_offset = 0;
1355 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1356 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1357
1358 for (i = 1; i < lp->d_npartitions; ++i) {
1359 int lastone;
1360 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1361 continue;
1362 for (lastone = i - 1; lastone >= 0; lastone--) {
1363 if ((lp->d_partitions[lastone].p_size)
1364 && (lastone != RAW_PART))
1365 break;
1366 }
1367 lp->d_partitions[i].p_offset =
1368 lp->d_partitions[lastone].p_offset +
1369 lp->d_partitions[lastone].p_size;
1370 }
1371 if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size >
1372 lp->d_secperunit) {
1373 lp->d_partitions[lo].p_size =
1374 lp->d_secperunit - lp->d_partitions[lo].p_offset;
1375 }
1376
1377 ftmp = fopen("/tmp/disklabel", "w");
1378 display_disklabel(ftmp, lp);
1379 fclose(ftmp);
1380 mr_asprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1381 retval += run_program_and_log_output(command, TRUE);
1382 mr_free(command);
1383
1384 mr_asprintf(command, "disklabel -R %s /tmp/disklabel", canonical_name(drivename));
1385 retval += run_program_and_log_output(command, TRUE);
1386 mr_free(command);
1387 if (ret)
1388 *ret = *lp;
1389 return retval;
1390}
1391#endif
1392
1393
1394/**
1395 * Partition @p drivename based on @p mountlist.
1396 * @param mountlist The mountlist to use to guide the partitioning.
1397 * @param drivename The drive to partition.
1398 * @return 0 for success, nonzero for failure.
1399 */
1400int partition_drive(struct mountlist_itself *mountlist, char *drivename)
1401{
1402 /** int *************************************************************/
1403 int current_devno;
1404 int previous_devno = 0;
1405 int lino;
1406 int retval = 0;
1407 int i;
1408 FILE *pout_to_fdisk = NULL;
1409
1410#ifdef __FreeBSD__
1411 bool fbsd_part = FALSE;
1412 char *subdev_str = NULL;
1413 char *command = NULL;
1414 int r = 0;
1415#endif
1416
1417 /** long long *******************************************************/
1418 long long partsize;
1419
1420 /** buffers *********************************************************/
1421 char *device_str = NULL;
1422 char *format;
1423 char *tmp = NULL;
1424
1425 /** end *************************************************************/
1426
1427 assert(mountlist != NULL);
1428 assert_string_is_neither_NULL_nor_zerolength(drivename);
1429
1430 malloc_string(format);
1431
1432 log_it("Partitioning drive %s", drivename);
1433
1434#if __FreeBSD__
1435 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1436 pout_to_fdisk = NULL;
1437#else
1438 make_hole_for_file(FDISK_LOG);
1439 mr_asprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1440 pout_to_fdisk = popen(tmp, "w");
1441 mr_free(tmp);
1442 if (!pout_to_fdisk) {
1443 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
1444 paranoid_free(format);
1445 return (1);
1446 }
1447#endif
1448 for (current_devno = 1; current_devno < 99; current_devno++) {
1449 device_str = build_partition_name(drivename, current_devno);
1450 lino = find_device_in_mountlist(mountlist, device_str);
1451
1452 if (lino < 0) {
1453 // device not found in mountlist
1454#if __FreeBSD__
1455 // If this is the first partition (just as a sentinel value),
1456 // then see if the user has picked 'dangerously-dedicated' mode.
1457 // If so, then we just call label_drive_or_slice() and return.
1458 char c;
1459 if (current_devno == 1) {
1460 // try DangerouslyDedicated mode
1461 for (c = 'a'; c <= 'z'; c++) {
1462 mr_asprintf(subdev_str, "%s%c", drivename, c);
1463 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1464 fbsd_part = TRUE;
1465 }
1466 mr_free(subdev_str);
1467 }
1468 if (fbsd_part) {
1469 r = label_drive_or_slice(mountlist,
1470 drivename,
1471 0);
1472 mr_asprintf(command, "disklabel -B %s", basename(drivename));
1473 if (system(command)) {
1474 log_to_screen
1475 ("Warning! Unable to make the drive bootable.");
1476 }
1477 mr_free(command);
1478 mr_free(device_str);
1479 paranoid_free(format);
1480 return r;
1481 }
1482 }
1483 for (c = 'a'; c <= 'z'; c++) {
1484 mr_asprintf(subdev_str, "%s%c", device_str, c);
1485 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1486 fbsd_part = TRUE;
1487 }
1488 mr_free(subdev_str);
1489 }
1490 // Now we check the subpartitions of the current partition.
1491 if (fbsd_part) {
1492 int i, line;
1493
1494 strcpy(format, "ufs");
1495 partsize = 0;
1496 for (i = 'a'; i < 'z'; ++i) {
1497 mr_asprintf(subdev_str, "%s%c", device_str, i);
1498 line = find_device_in_mountlist(mountlist, subdev_str);
1499 mr_free(subdev_str);
1500
1501 if (line > 0) {
1502 // We found one! Add its size to the total size.
1503 partsize += mountlist->el[line].size;
1504 }
1505 }
1506 } else {
1507 mr_free(device_str);
1508 continue;
1509 }
1510#else
1511 mr_free(device_str);
1512 continue;
1513#endif
1514 }
1515
1516 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1517 /* For FreeBSD, that is /dev/adXsY */
1518
1519 log_it("Found partition %s in mountlist", device_str);
1520 if (!previous_devno) {
1521
1522 log_it("Wiping %s's partition table", drivename);
1523#if __FreeBSD__
1524 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1525 file = open(drivename, O_WRONLY);
1526 if (file != -1) {
1527 log_to_screen("Warning - unable to open %s for wiping it's partition table", drivename);
1528 }
1529
1530 for (i = 0; i < 512; i++) {
1531 if (!write(file, "\0", 1)) {
1532 log_to_screen("Warning - unable to write to %s", drivename);
1533 }
1534 }
1535 system("sync");
1536#else
1537 log_it("New, kernel-friendly partition remover");
1538 for (i = 20; i > 0; i--) {
1539 fprintf(pout_to_fdisk, "d\n%d\n", i);
1540 fflush(pout_to_fdisk);
1541 }
1542#endif
1543 if (current_devno > 1) {
1544 previous_devno =
1545 make_dummy_partitions(pout_to_fdisk, drivename,
1546 current_devno);
1547 }
1548 }
1549#ifdef __FreeBSD__
1550 if (!fbsd_part) {
1551#endif
1552
1553 strcpy(format, mountlist->el[lino].format);
1554 partsize = mountlist->el[lino].size;
1555
1556#ifdef __FreeBSD__
1557 }
1558#endif
1559
1560#ifndef __IA64__
1561 if (current_devno == 5 && previous_devno == 4) {
1562 log_to_screen
1563 ("You must leave at least one partition spare as the Extended partition.");
1564 mr_free(device_str);
1565 paranoid_free(format);
1566 return (1);
1567 }
1568#endif
1569
1570 retval +=
1571 partition_device(pout_to_fdisk, drivename, current_devno,
1572 previous_devno, format, partsize);
1573
1574#ifdef __FreeBSD__
1575 if ((current_devno <= 4) && fbsd_part) {
1576 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1577 retval += label_drive_or_slice(mountlist, device_str, 0);
1578 if (system(tmp)) {
1579 log_to_screen
1580 ("Warning! Unable to make the slice bootable.");
1581 }
1582 mr_free(tmp);
1583 }
1584#endif
1585 mr_free(device_str);
1586
1587 previous_devno = current_devno;
1588 }
1589
1590 if (pout_to_fdisk) {
1591 // mark relevant partition as bootable
1592 mr_asprintf(tmp, "a\n%s\n", call_program_and_get_last_line_of_output ("make-me-bootable /tmp/mountlist.txt dummy"));
1593 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1594 mr_free(tmp);
1595
1596 // close fdisk
1597 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1598 system("sync");
1599 paranoid_pclose(pout_to_fdisk);
1600 log_msg(0,
1601 "------------------- fdisk.log looks like this ------------------");
1602 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1603 system(tmp);
1604 mr_free(tmp);
1605
1606 log_msg(0,
1607 "------------------- end of fdisk.log... word! ------------------");
1608 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1609 if (!run_program_and_log_output(tmp, 5)) {
1610 g_partition_table_locked_up++;
1611 }
1612 mr_free(tmp);
1613
1614 mr_asprintf(tmp, "partprobe %s", drivename);
1615 if (!run_program_and_log_output(tmp, 5)) {
1616 g_partition_table_locked_up--;
1617 }
1618 mr_free(tmp);
1619
1620 if (g_partition_table_locked_up > 0) {
1621 log_to_screen
1622 ("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1623 }
1624 }
1625 paranoid_free(format);
1626 return (retval);
1627}
1628
1629/**
1630 * Create partition number @p partno on @p drive with @p fdisk.
1631 * @param drive The drive to create the partition on.
1632// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1633 * @param prev_partno The partition number of the most recently prepped partition.
1634 * @param format The filesystem type of this partition (used to set the type).
1635 * @param partsize The size of the partition in @e bytes.
1636 * @return 0 for success, nonzero for failure.
1637 */
1638int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1639 int prev_partno, const char *format,
1640 long long partsize)
1641{
1642 /** int **************************************************************/
1643 int retval = 0;
1644 int res = 0;
1645
1646 /** buffers **********************************************************/
1647 char *program = NULL;
1648 char *partition_name = NULL;
1649 char *tmp = NULL;
1650 char *output = NULL;
1651
1652 /** pointers **********************************************************/
1653 char *p;
1654 char *part_table_fmt = NULL;
1655 FILE *fout;
1656
1657 /** end ***************************************************************/
1658
1659 assert_string_is_neither_NULL_nor_zerolength(drive);
1660 assert(format != NULL);
1661
1662 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1663 drive, partno, prev_partno, format, partsize);
1664
1665 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1666 log_it("Not partitioning %s - it is a virtual drive", drive);
1667 return (0);
1668 }
1669 partition_name = build_partition_name(drive, partno);
1670 if (partsize <= 0) {
1671 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1672 } else {
1673 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1674 }
1675 update_progress_form(tmp);
1676 log_it(tmp);
1677 mr_free(tmp);
1678
1679 if (is_this_device_mounted(partition_name)) {
1680 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1681 mr_free(partition_name);
1682 return (1);
1683 }
1684
1685
1686 p = (char *) strrchr(partition_name, '/');
1687
1688 /* BERLIOS: should not be called each time */
1689 part_table_fmt = which_partition_format(drive);
1690 mr_asprintf(output, "");
1691 /* make it a primary/extended/logical */
1692 if (partno <= 4) {
1693 mr_strcat(output, "n\np\n%d\n", partno);
1694 } else {
1695 /* MBR needs an extended partition if more than 4 partitions */
1696 if (strcmp(part_table_fmt, "MBR") == 0) {
1697 if (partno == 5) {
1698 if (prev_partno >= 4) {
1699 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1700 mr_free(partition_name);
1701 mr_free(output);
1702 mr_free(part_table_fmt);
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_free(part_table_fmt);
1715
1716 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1717 if (partsize > 0) {
1718 if (!strcmp(format, "7")) {
1719 log_msg(1, "Adding 512K, just in case");
1720 partsize += 512;
1721 }
1722 mr_strcat(output, "+%lldK", (long long) (partsize));
1723 }
1724 mr_strcat(output, "\n");
1725 log_it("PARTSIZE = +%ld",(long)partsize);
1726
1727 log_it("---fdisk command---");
1728 log_it(output);
1729 log_it("---end of fdisk---");
1730
1731 mr_asprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1732 if (pout_to_fdisk) {
1733 log_msg(1, "Doing the new all-in-one fdisk thing");
1734 log_msg(1, "output = '%s'", output);
1735 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1736 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1737 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1738 if (strstr(tmp, " (m ")) {
1739 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1740 } else {
1741 log_msg(1, "last line = %s", tmp);
1742 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1743 }
1744 mr_free(tmp);
1745
1746 if (!retval) {
1747 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1748 retval =
1749 set_partition_type(pout_to_fdisk, drive, partno, format,
1750 partsize);
1751 if (retval) {
1752 log_msg(1, "Failed. Trying again...");
1753 retval =
1754 set_partition_type(pout_to_fdisk, drive, partno,
1755 format, partsize);
1756 }
1757 }
1758 if (retval) {
1759 log_msg(1, "...but failed to set type");
1760 }
1761 } else {
1762 mr_strcat(output, "w\n\n");
1763 if (g_fprep) {
1764 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1765 }
1766 /* write to disk; close fdisk's stream */
1767 if (!(fout = popen(program, "w"))) {
1768 log_OS_error("can't popen-out to program");
1769 } else {
1770 fputs(output, fout);
1771 paranoid_pclose(fout);
1772 }
1773 if (!does_partition_exist(drive, partno) && partsize > 0) {
1774 log_it("Vaccum-packing");
1775 g_current_progress--;
1776 res =
1777 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1778 format, -1);
1779 if (res) {
1780 log_it("Failed to vacuum-pack %s", partition_name);
1781
1782 retval++;
1783 } else {
1784 retval = 0;
1785 }
1786 }
1787 if (does_partition_exist(drive, partno)) {
1788 retval =
1789 set_partition_type(pout_to_fdisk, drive, partno, format,
1790 partsize);
1791 if (retval) {
1792 log_it("Partitioned %s but failed to set its type", partition_name);
1793 } else {
1794 if (partsize > 0) {
1795 log_to_screen("Partition %s created+configured OK", partition_name);
1796 } else {
1797 log_it("Returning from a successful vacuum-pack");
1798 }
1799 }
1800 } else {
1801 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1802 if (partsize > 0) {
1803 log_to_screen(tmp);
1804 } else {
1805 log_it(tmp);
1806 }
1807 mr_free(tmp);
1808 retval++;
1809 }
1810 }
1811 mr_free(program);
1812 mr_free(partition_name);
1813 paranoid_free(output);
1814
1815 g_current_progress++;
1816 log_it("partition_device() --- leaving");
1817 return (retval);
1818}
1819
1820
1821
1822/**
1823 * Create all partitions listed in @p mountlist.
1824 * @param mountlist The mountlist to use to guide the partitioning.
1825 * @return The number of errors encountered (0 for success).
1826 * @note This sets the partition types but doesn't actually do the formatting.
1827 * Use format_everything() for that.
1828 */
1829int partition_everything(struct mountlist_itself *mountlist)
1830{
1831 /** int ************************************************************/
1832 int lino;
1833 int retval = 0;
1834 int i;
1835 int res;
1836
1837 /** buffer *********************************************************/
1838 struct list_of_disks *drivelist;
1839 /* struct mountlist_itself new_mtlist, *mountlist; */
1840
1841 /** end ************************************************************/
1842
1843 drivelist = malloc(sizeof(struct list_of_disks));
1844 assert(mountlist != NULL);
1845
1846 log_it("partition_everything() --- starting");
1847 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1848 /* mountlist=orig_mtlist; */
1849 if (mountlist_contains_raid_devices(mountlist)) {
1850 /* mountlist=&new_mtlist; */
1851 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1852 log_msg(0,
1853 "Mountlist, including the partitions incorporated in RAID devices:-");
1854 for (i = 0; i < mountlist->entries; i++) {
1855 log_it(mountlist->el[i].device);
1856 }
1857 log_msg(0, "End of mountlist.");
1858 }
1859 log_msg(0, "Stopping all LVMs, just in case");
1860 if (!g_text_mode) {
1861 newtSuspend();
1862 }
1863 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1864 if (!g_text_mode) {
1865 newtResume();
1866 }
1867 log_msg(0, "Stopping all software RAID devices, just in case");
1868 stop_all_raid_devices(mountlist);
1869 log_msg(0, "Done.");
1870
1871/*
1872 if (does_file_exist("/tmp/i-want-my-lvm"))
1873 {
1874 wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
1875 }
1876*/
1877
1878 open_progress_form("Partitioning devices",
1879 "I am now going to partition all your drives.",
1880 "This should not take more than five minutes.", "",
1881 mountlist->entries);
1882
1883 make_list_of_drives_in_mountlist(mountlist, drivelist);
1884
1885 /* partition each drive */
1886 for (lino = 0; lino < drivelist->entries; lino++) {
1887 res = partition_drive(mountlist, drivelist->el[lino].device);
1888 retval += res;
1889 }
1890 close_progress_form();
1891 if (retval) {
1892 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1893 log_to_screen
1894 ("Errors occurred during the partitioning of your hard drives.");
1895 } else {
1896 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1897 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1898 }
1899 newtSuspend();
1900 system("clear");
1901 newtResume();
1902 paranoid_free(drivelist);
1903 return (retval);
1904}
1905
1906
1907
1908
1909
1910
1911/**
1912 * Set the type of partition number @p partno on @p drive to @p format.
1913 * @param drive The drive to change the type of a partition on.
1914 * @param partno The partition number on @p drive to change the type of.
1915 * @param format The filesystem type this partition will eventually contain.
1916 * @param partsize The size of this partition, in @e bytes (used for vfat
1917 * type calculations).
1918 * @return 0 for success, nonzero for failure.
1919 */
1920int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
1921 const char *format, long long partsize)
1922{
1923 /** buffers *********************************************************/
1924 char *partition = NULL;
1925 char *command = NULL;
1926 char *output = NULL;
1927 char *tmp = NULL;
1928 char *partcode = NULL;
1929
1930 /** pointers *********************************************************/
1931 char *p;
1932 FILE *fout;
1933
1934 /** int **************************************************************/
1935 int res = 0;
1936
1937 /** end **************************************************************/
1938
1939 assert_string_is_neither_NULL_nor_zerolength(drive);
1940 assert(format != NULL);
1941
1942 partition = build_partition_name(drive, partno);
1943 p = (char *) strrchr(partition, '/');
1944 if (strcmp(format, "swap") == 0) {
1945 mr_asprintf(partcode, "82");
1946 } else if (strcmp(format, "vfat") == 0) {
1947 if (partsize / 1024 > 8192) {
1948 mr_asprintf(partcode, "c");
1949 } else {
1950 mr_asprintf(partcode, "b");
1951 }
1952 } else if (strcmp(format, "ext2") == 0
1953 || strcmp(format, "reiserfs") == 0
1954 || strcmp(format, "ext3") == 0
1955 || strcmp(format, "ext4") == 0
1956 || strcmp(format, "xfs") == 0
1957 || strcmp(format, "jfs") == 0) {
1958 mr_asprintf(partcode, "83");
1959 } else if (strcmp(format, "minix") == 0) {
1960 mr_asprintf(partcode, "81");
1961 } else if (strcmp(format, "vmfs3") == 0) {
1962 mr_asprintf(partcode, "fb");
1963 } else if (strcmp(format, "vmkcore") == 0) {
1964 mr_asprintf(partcode, "fc");
1965 } else if (strcmp(format, "raid") == 0) {
1966 mr_asprintf(partcode, "fd");
1967 } else if (strcmp(format, "ntfs") == 0) {
1968 mr_asprintf(partcode, "7");
1969 } else if ((strcmp(format, "ufs") == 0)
1970 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1971 mr_asprintf(partcode, "a5");
1972 } else if (strcmp(format, "lvm") == 0) {
1973 mr_asprintf(partcode, "8e");
1974 } else if (format[0] == '\0') { /* LVM physical partition */
1975 mr_asprintf(partcode, "");
1976 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
1977 mr_asprintf(partcode, format);
1978 } else {
1979 /* probably an image */
1980 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1981 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1982 mr_free(tmp);
1983#ifdef __FreeBSD__
1984 mr_asprintf(partcode, format); // was a5
1985#else
1986 mr_asprintf(partcode, format); // was 83
1987#endif
1988 }
1989 log_msg(1, tmp, "Setting %s's type to %s (%s)", partition, format, partcode);
1990 mr_free(partition);
1991
1992 if (partcode != NULL && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1993
1994 if (pout_to_fdisk) {
1995 res = 0;
1996 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1997 if (partno > 1
1998 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
1999 log_msg(5, "Specifying partno (%d) - yay", partno);
2000 mr_asprintf(tmp, "%d\n", partno);
2001 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2002 mr_free(tmp);
2003
2004 log_msg(5, "A - last line = '%s'",
2005 last_line_of_file(FDISK_LOG));
2006 }
2007
2008 mr_asprintf(tmp, "%s\n", partcode);
2009 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2010 mr_free(tmp);
2011
2012 log_msg(5, "B - last line = '%s'",
2013 last_line_of_file(FDISK_LOG));
2014 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2015 log_msg(5, "C - last line = '%s'",
2016 last_line_of_file(FDISK_LOG));
2017
2018 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
2019 if (!strstr(tmp, " (m ")) {
2020 log_msg(1, "last line = '%s'; part type set failed", tmp);
2021 res++;
2022 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2023 }
2024 mr_free(tmp);
2025
2026 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2027 } else {
2028 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
2029 mr_asprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2030 MONDO_LOGFILE, MONDO_LOGFILE);
2031 log_msg(5, "output = '%s'", output);
2032 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2033 log_msg(5, "command = '%s'", command);
2034 fout = popen(command, "w");
2035 if (!fout) {
2036 log_OS_error(command);
2037 res = 1;
2038 } else {
2039 res = 0;
2040 fprintf(fout, "%s", output);
2041 paranoid_pclose(fout);
2042 }
2043 paranoid_free(output);
2044 mr_free(command);
2045 }
2046 }
2047
2048 mr_free(partcode);
2049 return (res);
2050}
2051
2052
2053int start_raid_device(char *raid_device)
2054{
2055 /** int *************************************************************/
2056 int res;
2057 int retval = 0;
2058
2059 /** buffers *********************************************************/
2060 char *program = NULL;
2061
2062 /** end *************************************************************/
2063
2064 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2065
2066#ifdef __FreeBSD__
2067 if (is_this_device_mounted(raid_device)) {
2068 log_it("Can't start %s when it's mounted!", raid_device);
2069 return 1;
2070 }
2071 mr_asprintf(program, "vinum start -f %s", raid_device);
2072#else
2073 mr_asprintf(program, "raidstart %s", raid_device);
2074#endif
2075 log_msg(1, "program = %s", program);
2076 res = run_program_and_log_output(program, 1);
2077 if (g_fprep) {
2078 fprintf(g_fprep, "%s\n", program);
2079 }
2080 mr_free(program);
2081
2082 if (res) {
2083 log_msg(1, "Warning - failed to start RAID device %s",
2084 raid_device);
2085 }
2086 retval += res;
2087 sleep(1);
2088 return (retval);
2089}
2090
2091
2092
2093/**
2094 * Stop @p raid_device using @p raidstop.
2095 * @param raid_device The software RAID device to stop.
2096 * @return 0 for success, nonzero for failure.
2097 */
2098int stop_raid_device(char *raid_device)
2099{
2100 /** int *************************************************************/
2101 int res;
2102 int retval = 0;
2103
2104 /** buffers *********************************************************/
2105 char *program = NULL;
2106
2107 /** end *************************************************************/
2108
2109 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2110
2111#ifdef __FreeBSD__
2112 if (is_this_device_mounted(raid_device)) {
2113 log_it("Can't stop %s when it's mounted!", raid_device);
2114 return 1;
2115 }
2116 mr_asprintf(program, "vinum stop -f %s", raid_device);
2117#else
2118 // use raidstop if it exists, otherwise use mdadm
2119 if (run_program_and_log_output("which raidstop", FALSE)) {
2120 mr_asprintf(program, "mdadm -S %s", raid_device);
2121 } else {
2122 mr_asprintf(program, "raidstop %s", raid_device);
2123 }
2124#endif
2125 log_msg(1, "program = %s", program);
2126 res = run_program_and_log_output(program, 1);
2127 if (g_fprep) {
2128 fprintf(g_fprep, "%s\n", program);
2129 }
2130 mr_free(program);
2131
2132 if (res) {
2133 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2134 }
2135 retval += res;
2136 return (retval);
2137}
2138
2139
2140int start_all_raid_devices(struct mountlist_itself *mountlist)
2141{
2142 int i;
2143 int retval = 0;
2144 int res;
2145
2146 for (i = 0; i < mountlist->entries; i++) {
2147 if (!strncmp
2148 (mountlist->el[i].device, RAID_DEVICE_STUB,
2149 strlen(RAID_DEVICE_STUB))) {
2150 log_msg(1, "Starting %s", mountlist->el[i].device);
2151 res = start_raid_device(mountlist->el[i].device);
2152 retval += res;
2153 }
2154 }
2155 if (retval) {
2156 log_msg(1, "Started all s/w raid devices OK");
2157 } else {
2158 log_msg(1, "Failed to start some/all s/w raid devices");
2159 }
2160 return (retval);
2161}
2162
2163/**
2164 * Stop all software RAID devices listed in @p mountlist.
2165 * @param mountlist The mountlist to stop the RAID devices in.
2166 * @return The number of errors encountered (0 for success).
2167 * @bug @p mountlist is not used.
2168 */
2169int stop_all_raid_devices(struct mountlist_itself *mountlist)
2170{
2171 /** int *************************************************************/
2172 int retval = 0;
2173#ifndef __FreeBSD__
2174 int res;
2175#endif
2176
2177 /** char ************************************************************/
2178 char *incoming;
2179#ifndef __FreeBSD__
2180 char *dev;
2181#endif
2182 /** pointers ********************************************************/
2183#ifndef __FreeBSD__
2184 char *p;
2185#endif
2186 FILE *fin;
2187 int i;
2188
2189 /** end ****************************************************************/
2190
2191 malloc_string(dev);
2192 malloc_string(incoming);
2193 assert(mountlist != NULL);
2194
2195 for (i = 0; i < 3; i++) {
2196#ifdef __FreeBSD__
2197 fin =
2198 popen
2199 ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2200 "r");
2201 if (!fin) {
2202 paranoid_free(dev);
2203 paranoid_free(incoming);
2204 return (1);
2205 }
2206 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2207 fgets(incoming, MAX_STR_LEN - 1, fin)) {
2208 retval += stop_raid_device(incoming);
2209 }
2210#else
2211 fin = fopen("/proc/mdstat", "r");
2212 if (!fin) {
2213 log_OS_error("/proc/mdstat");
2214 paranoid_free(dev);
2215 paranoid_free(incoming);
2216 return (1);
2217 }
2218 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2219 fgets(incoming, MAX_STR_LEN - 1, fin)) {
2220 for (p = incoming;
2221 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2222 || !isdigit(*(p + 2))); p++);
2223 if (*p != '\0') {
2224 sprintf(dev, "/dev/%s", p);
2225 for (p = dev; *p > 32; p++);
2226 *p = '\0';
2227 res = stop_raid_device(dev);
2228 }
2229 }
2230#endif
2231 }
2232 paranoid_fclose(fin);
2233 if (retval) {
2234 log_msg(1, "Warning - unable to stop some RAID devices");
2235 }
2236 paranoid_free(dev);
2237 paranoid_free(incoming);
2238 system("sync");
2239 system("sync");
2240 system("sync");
2241 sleep(1);
2242 return (retval);
2243}
2244
2245
2246
2247/**
2248 * Decide which command we need to use to format a device of type @p format.
2249 * @param format The filesystem type we are about to format.
2250 * @param program Where to put the binary name for this format.
2251 * @return 0 for success, nonzero for failure.
2252 */
2253char *which_format_command_do_i_need(char *format)
2254{
2255 /** int *************************************************************/
2256 int res = 0;
2257
2258 /** buffers *********************************************************/
2259 char *tmp = NULL;
2260 char *program = NULL;
2261
2262 /** end ***************************************************************/
2263
2264 assert_string_is_neither_NULL_nor_zerolength(format);
2265
2266 if (strcmp(format, "swap") == 0) {
2267#ifdef __FreeBSD__
2268 mr_asprintf(program, "true");
2269#else
2270 mr_asprintf(program, "mkswap");
2271#endif
2272 } else if (strcmp(format, "vfat") == 0) {
2273 mr_asprintf(program, "format-and-kludge-vfat");
2274#ifndef __FreeBSD__
2275 } else if (strcmp(format, "reiserfs") == 0) {
2276 mr_asprintf(program, "mkreiserfs -ff");
2277 } else if (strcmp(format, "xfs") == 0) {
2278 mr_asprintf(program, "mkfs.xfs -f -q");
2279 } else if (strcmp(format, "jfs") == 0) {
2280 mr_asprintf(program, "mkfs.jfs");
2281 } else if (strcmp(format, "ext3") == 0) {
2282 mr_asprintf(program, "mkfs -t ext3 -F -q");
2283 } else if (strcmp(format, "ext4") == 0) {
2284 mr_asprintf(program, "mkfs -t ext4 -F -q");
2285 } else if (strcmp(format, "minix") == 0) {
2286 mr_asprintf(program, "mkfs.minix");
2287 } else if (strcmp(format, "vmfs") == 0) {
2288 mr_asprintf(program, "mkfs -t vmfs");
2289 } else if (strcmp(format, "ntfs") == 0) {
2290 /*
2291 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2292 * so the default "mkfs -t %s -c" command structure fails
2293 */
2294 mr_asprintf(program, "mkfs -t ntfs");
2295 } else if (strcmp(format, "ocfs2") == 0) {
2296 /*
2297 * 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.
2298 *
2299 */
2300 mr_asprintf(program, "mkfs -t ocfs2 -F");
2301#endif
2302 } else if (strcmp(format, "ext2") == 0) {
2303 mr_asprintf(program, "mke2fs -F -q");
2304 } else {
2305#ifdef __FreeBSD__
2306 mr_asprintf(program, "newfs_%s", format);
2307#else
2308 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2309#endif
2310 mr_asprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format, program);
2311 log_it(tmp);
2312 mr_free(tmp);
2313 res = 0;
2314 }
2315 return (program);
2316}
2317
2318
2319/**
2320 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2321 * There are a few problems with this function:
2322 * - It won't work if there was any unallocated space on the user's hard drive
2323 * when it was backed up.
2324 * - It won't work if the user's hard drive lies about its size (more common
2325 * than you'd think).
2326 *
2327 * @param mountlist The mountlist to use for resizing @p drive_name.
2328 * @param drive_name The drive to resize.
2329 */
2330void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2331 *mountlist,
2332 char *drive_name)
2333{
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.