source: MondoRescue/branches/stable/mondo/src/mondorestore/mondo-prep.c@ 1170

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

Includes are now also taken temporarily in common (to allow for ../common removal in files which is a bad practice)

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