source: MondoRescue/branches/3.1/mondo/src/mondorestore/mondo-prep.c@ 3161

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