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

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