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

Last change on this file since 2603 was 2603, checked in by Bruno Cornec, 14 years ago

r3757@localhost: bruno | 2010-03-17 15:05:13 +0100

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