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

Last change on this file since 688 was 688, checked in by bcornec, 18 years ago

Huge memory management patch.
Still not finished but a lot as been done.
What remains is around some functions returning strings, and some structure members.
(Could not finish due to laptop failure !)

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