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

Last change on this file since 783 was 783, checked in by Bruno Cornec, 18 years ago
  • Massive rewrite continues for memory management.
  • main structure should now have all parameters allocated dynamically
  • new lib libmr.a + dir + build process reviewed to support it.
  • new include subdir to host external definitions of the new lib
  • code now compiles. Still one remaining link issues for mondorestore. This should allow for some tests soon.

(goal is to separate completely reviewed code and functions and provide clean interfaces)

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