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

Last change on this file since 2291 was 2291, checked in by Bruno Cornec, 15 years ago
  • Fix a printing error in mindi for the tar command
  • Fix all mr_asprintf which had no second param as a string

(report bug fix done originaly in 2.2.9)

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