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

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

r3369@localhost: bruno | 2009-08-18 16:57:27 +0200

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