source: MondoRescue/trunk/mondo/src/mondorestore/mondo-prep.c@ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 17 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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