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

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

r3336@localhost: bruno | 2009-08-11 16:32:36 +0200

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