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

Last change on this file since 3148 was 3148, checked in by Bruno Cornec, 11 years ago

2nd phase for svn merge -r 2935:3146 ../3.0

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