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

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

r3342@localhost: bruno | 2009-08-14 00:46:51 +0200

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