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

Last change on this file since 3147 was 3147, checked in by Bruno Cornec, 11 years ago
  • First pass on svn merge -r 2935:3146 ../3.0
  • Property svn:keywords set to Id
File size: 72.6 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 3147 2013-06-19 06:34:46Z 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 3147 2013-06-19 06:34:46Z 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
1424 /** end *************************************************************/
1425
1426 assert(mountlist != NULL);
1427 assert_string_is_neither_NULL_nor_zerolength(drivename);
1428
1429 log_it("Partitioning drive %s", drivename);
1430
1431#if __FreeBSD__
1432 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1433 pout_to_fdisk = NULL;
1434#else
1435 make_hole_for_file(FDISK_LOG);
1436 mr_asprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1437 pout_to_fdisk = popen(tmp, "w");
1438 mr_free(tmp);
1439 if (!pout_to_fdisk) {
1440 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
1441 return (1);
1442 }
1443#endif
1444 for (current_devno = 1; current_devno < 99; current_devno++) {
1445 device_str = build_partition_name(drivename, current_devno);
1446 lino = find_device_in_mountlist(mountlist, device_str);
1447
1448 if (lino < 0) {
1449 // device not found in mountlist
1450#if __FreeBSD__
1451 // If this is the first partition (just as a sentinel value),
1452 // then see if the user has picked 'dangerously-dedicated' mode.
1453 // If so, then we just call label_drive_or_slice() and return.
1454 char c;
1455 if (current_devno == 1) {
1456 // try DangerouslyDedicated mode
1457 for (c = 'a'; c <= 'z'; c++) {
1458 mr_asprintf(subdev_str, "%s%c", drivename, c);
1459 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1460 fbsd_part = TRUE;
1461 }
1462 mr_free(subdev_str);
1463 }
1464 if (fbsd_part) {
1465 r = label_drive_or_slice(mountlist,
1466 drivename,
1467 0);
1468 mr_asprintf(command, "disklabel -B %s", basename(drivename));
1469 if (system(command)) {
1470 log_to_screen("Warning! Unable to make the drive bootable.");
1471 }
1472 mr_free(command);
1473 mr_free(device_str);
1474 return r;
1475 }
1476 }
1477 for (c = 'a'; c <= 'z'; c++) {
1478 mr_asprintf(subdev_str, "%s%c", device_str, c);
1479 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1480 fbsd_part = TRUE;
1481 }
1482 mr_free(subdev_str);
1483 }
1484 // Now we check the subpartitions of the current partition.
1485 if (fbsd_part) {
1486 int i, line;
1487
1488 mr_asprintf(format, "ufs");
1489 partsize = 0;
1490 for (i = 'a'; i < 'z'; ++i) {
1491 mr_asprintf(subdev_str, "%s%c", device_str, i);
1492 line = find_device_in_mountlist(mountlist, subdev_str);
1493 mr_free(subdev_str);
1494
1495 if (line > 0) {
1496 // We found one! Add its size to the total size.
1497 partsize += mountlist->el[line].size;
1498 }
1499 }
1500 } else {
1501 mr_free(device_str);
1502 continue;
1503 }
1504#else
1505 mr_free(device_str);
1506 continue;
1507#endif
1508 }
1509
1510 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1511 /* For FreeBSD, that is /dev/adXsY */
1512
1513 log_it("Found partition %s in mountlist", device_str);
1514 if (!previous_devno) {
1515
1516 log_it("Wiping %s's partition table", drivename);
1517#if __FreeBSD__
1518 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1519 file = open(drivename, O_WRONLY);
1520 if (file != -1) {
1521 log_to_screen("Warning - unable to open %s for wiping it's partition table", drivename);
1522 }
1523
1524 for (i = 0; i < 512; i++) {
1525 if (!write(file, "\0", 1)) {
1526 log_to_screen("Warning - unable to write to %s", drivename);
1527 }
1528 }
1529 sync();
1530#else
1531 log_it("New, kernel-friendly partition remover");
1532 for (i = 20; i > 0; i--) {
1533 fprintf(pout_to_fdisk, "d\n%d\n", i);
1534 fflush(pout_to_fdisk);
1535 }
1536#endif
1537 if (current_devno > 1) {
1538 previous_devno =
1539 make_dummy_partitions(pout_to_fdisk, drivename,
1540 current_devno);
1541 }
1542 }
1543#ifdef __FreeBSD__
1544 if (!fbsd_part) {
1545 mr_free(format);
1546#endif
1547
1548 mr_asprintf(format, "%s", mountlist->el[lino].format);
1549 partsize = mountlist->el[lino].size;
1550
1551#ifdef __FreeBSD__
1552 }
1553#endif
1554
1555#ifndef __IA64__
1556 if (current_devno == 5 && previous_devno == 4) {
1557 log_to_screen("You must leave at least one partition spare as the Extended partition.");
1558 mr_free(device_str);
1559 mr_free(format);
1560 return (1);
1561 }
1562#endif
1563
1564 retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize);
1565 mr_free(format);
1566
1567#ifdef __FreeBSD__
1568 if ((current_devno <= 4) && fbsd_part) {
1569 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1570 retval += label_drive_or_slice(mountlist, device_str, 0);
1571 if (system(tmp)) {
1572 log_to_screen("Warning! Unable to make the slice bootable.");
1573 }
1574 mr_free(tmp);
1575 }
1576#endif
1577 mr_free(device_str);
1578
1579 previous_devno = current_devno;
1580 }
1581
1582 if (pout_to_fdisk) {
1583 // mark relevant partition as bootable
1584 tmp1 = call_program_and_get_last_line_of_output ("make-me-bootable "MINDI_CACHE"/mountlist.txt dummy",TRUE);
1585 mr_asprintf(tmp, "a\n%s\n", tmp1);
1586 mr_free(tmp1);
1587
1588 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1589 mr_free(tmp);
1590
1591 // close fdisk
1592 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1593 sync();
1594 paranoid_pclose(pout_to_fdisk);
1595 paranoid_system("sync");
1596 log_msg(0,"------------------- fdisk.log looks like this ------------------");
1597 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1598 system(tmp);
1599 mr_free(tmp);
1600
1601 log_msg(0,
1602 "------------------- end of fdisk.log... word! ------------------");
1603 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1604 if (!run_program_and_log_output(tmp, 5)) {
1605 g_partition_table_locked_up++;
1606 }
1607 mr_free(tmp);
1608
1609 mr_asprintf(tmp, "partprobe %s", drivename);
1610 if (!run_program_and_log_output(tmp, 5)) {
1611 g_partition_table_locked_up--;
1612 }
1613 mr_free(tmp);
1614
1615 if (g_partition_table_locked_up > 0) {
1616 log_to_screen("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1617 }
1618 }
1619 return (retval);
1620}
1621
1622/**
1623 * Create partition number @p partno on @p drive with @p fdisk.
1624 * @param drive The drive to create the partition on.
1625// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1626 * @param prev_partno The partition number of the most recently prepped partition.
1627 * @param format The filesystem type of this partition (used to set the type).
1628 * @param partsize The size of the partition in @e bytes.
1629 * @return 0 for success, nonzero for failure.
1630 */
1631int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1632 int prev_partno, const char *format,
1633 long long partsize)
1634{
1635 /** int **************************************************************/
1636 int retval = 0;
1637 int res = 0;
1638
1639 /** buffers **********************************************************/
1640 char *program = NULL;
1641 char *partition_name = NULL;
1642 char *tmp = NULL;
1643 char *output = NULL;
1644
1645 /** pointers **********************************************************/
1646 char *p;
1647 char *part_table_fmt = NULL;
1648 FILE *fout;
1649
1650 /** end ***************************************************************/
1651
1652 assert_string_is_neither_NULL_nor_zerolength(drive);
1653 assert(format != NULL);
1654
1655 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1656 drive, partno, prev_partno, format, partsize);
1657
1658 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1659 log_it("Not partitioning %s - it is a virtual drive", drive);
1660 return (0);
1661 }
1662 partition_name = build_partition_name(drive, partno);
1663 if (partsize <= 0) {
1664 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1665 } else {
1666 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1667 }
1668 update_progress_form(tmp);
1669 log_it(tmp);
1670 mr_free(tmp);
1671
1672 if (is_this_device_mounted(partition_name)) {
1673 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1674 mr_free(partition_name);
1675 return (1);
1676 }
1677
1678
1679 p = (char *) strrchr(partition_name, '/');
1680
1681 /* BERLIOS: should not be called each time */
1682 part_table_fmt = which_partition_format(drive);
1683 mr_asprintf(output, "");
1684 /* make it a primary/extended/logical */
1685 if (partno <= 4) {
1686 mr_strcat(output, "n\np\n%d\n", partno);
1687 } else {
1688 /* MBR needs an extended partition if more than 4 partitions */
1689 if (strcmp(part_table_fmt, "MBR") == 0) {
1690 if (partno == 5) {
1691 if (prev_partno >= 4) {
1692 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1693 mr_free(partition_name);
1694 mr_free(output);
1695 mr_free(part_table_fmt);
1696 return (1);
1697 } else {
1698 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1699 }
1700 }
1701 mr_strcat(output, "n\nl\n");
1702 } else {
1703 /* GPT allows more than 4 primary partitions */
1704 mr_strcat(output, "n\np\n%d\n", partno);
1705 }
1706 }
1707 mr_free(part_table_fmt);
1708
1709 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1710 if (partsize > 0) {
1711 if (!strcmp(format, "7")) {
1712 log_msg(1, "Adding 512K, just in case");
1713 partsize += 512;
1714 }
1715 mr_strcat(output, "+%lldK", (long long) (partsize));
1716 }
1717 mr_strcat(output, "\n");
1718 log_it("PARTSIZE = +%ld",(long)partsize);
1719
1720 log_it("---fdisk command---");
1721 log_it(output);
1722 log_it("---end of fdisk---");
1723
1724 mr_asprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1725 if (pout_to_fdisk) {
1726 log_msg(1, "Doing the new all-in-one fdisk thing");
1727 log_msg(1, "output = '%s'", output);
1728 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1729 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1730 tmp = last_line_of_file(FDISK_LOG);
1731 if (strstr(tmp, " (m ")) {
1732 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1733 } else {
1734 log_msg(1, "last line = %s", tmp);
1735 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1736 }
1737 mr_free(tmp);
1738
1739 if (!retval) {
1740 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1741 retval =
1742 set_partition_type(pout_to_fdisk, drive, partno, format,
1743 partsize);
1744 if (retval) {
1745 log_msg(1, "Failed. Trying again...");
1746 retval =
1747 set_partition_type(pout_to_fdisk, drive, partno,
1748 format, partsize);
1749 }
1750 }
1751 if (retval) {
1752 log_msg(1, "...but failed to set type");
1753 }
1754 } else {
1755 mr_strcat(output, "w\n\n");
1756 if (g_fprep) {
1757 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1758 }
1759 /* write to disk; close fdisk's stream */
1760 if (!(fout = popen(program, "w"))) {
1761 log_OS_error("can't popen-out to program");
1762 } else {
1763 fputs(output, fout);
1764 paranoid_pclose(fout);
1765 }
1766 if (!does_partition_exist(drive, partno) && partsize > 0) {
1767 log_it("Vaccum-packing");
1768 g_current_progress--;
1769 res =
1770 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1771 format, -1);
1772 if (res) {
1773 log_it("Failed to vacuum-pack %s", partition_name);
1774
1775 retval++;
1776 } else {
1777 retval = 0;
1778 }
1779 }
1780 if (does_partition_exist(drive, partno)) {
1781 retval =
1782 set_partition_type(pout_to_fdisk, drive, partno, format,
1783 partsize);
1784 if (retval) {
1785 log_it("Partitioned %s but failed to set its type", partition_name);
1786 } else {
1787 if (partsize > 0) {
1788 log_to_screen("Partition %s created+configured OK", partition_name);
1789 } else {
1790 log_it("Returning from a successful vacuum-pack");
1791 }
1792 }
1793 } else {
1794 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1795 if (partsize > 0) {
1796 log_to_screen(tmp);
1797 } else {
1798 log_it(tmp);
1799 }
1800 mr_free(tmp);
1801 retval++;
1802 }
1803 }
1804 mr_free(program);
1805 mr_free(partition_name);
1806 paranoid_free(output);
1807
1808 g_current_progress++;
1809 log_it("partition_device() --- leaving");
1810 return (retval);
1811}
1812
1813
1814
1815/**
1816 * Create all partitions listed in @p mountlist.
1817 * @param mountlist The mountlist to use to guide the partitioning.
1818 * @return The number of errors encountered (0 for success).
1819 * @note This sets the partition types but doesn't actually do the formatting.
1820 * Use format_everything() for that.
1821 */
1822int partition_everything(struct mountlist_itself *mountlist)
1823{
1824 /** int ************************************************************/
1825 int lino;
1826 int retval = 0;
1827 int i;
1828 int res;
1829
1830 /** buffer *********************************************************/
1831 struct list_of_disks *drivelist;
1832 /* struct mountlist_itself new_mtlist, *mountlist; */
1833
1834 /** end ************************************************************/
1835
1836 drivelist = malloc(sizeof(struct list_of_disks));
1837 assert(mountlist != NULL);
1838
1839 log_it("partition_everything() --- starting");
1840 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1841 /* mountlist=orig_mtlist; */
1842 if (mountlist_contains_raid_devices(mountlist)) {
1843 /* mountlist=&new_mtlist; */
1844 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1845 log_msg(0,
1846 "Mountlist, including the partitions incorporated in RAID devices:-");
1847 for (i = 0; i < mountlist->entries; i++) {
1848 log_it(mountlist->el[i].device);
1849 }
1850 log_msg(0, "End of mountlist.");
1851 }
1852 log_msg(0, "Stopping all LVMs, just in case");
1853 if (!g_text_mode) {
1854 newtSuspend();
1855 }
1856 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1857 if (!g_text_mode) {
1858 newtResume();
1859 }
1860 log_msg(0, "Stopping all software RAID devices, just in case");
1861 stop_all_raid_devices(mountlist);
1862 log_msg(0, "Done.");
1863
1864 open_progress_form("Partitioning devices",
1865 "I am now going to partition all your drives.",
1866 "This should not take more than five minutes.", "",
1867 mountlist->entries);
1868
1869 make_list_of_drives_in_mountlist(mountlist, drivelist);
1870
1871 /* partition each drive */
1872 for (lino = 0; lino < drivelist->entries; lino++) {
1873 res = partition_drive(mountlist, drivelist->el[lino].device);
1874 retval += res;
1875 }
1876 close_progress_form();
1877 if (retval) {
1878 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1879 log_to_screen("Errors occurred during the partitioning of your hard drives.");
1880 } else {
1881 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1882 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1883 }
1884 newtSuspend();
1885 paranoid_system("clear");
1886 newtResume();
1887 paranoid_free(drivelist);
1888 return (retval);
1889}
1890
1891
1892
1893
1894
1895
1896/**
1897 * Set the type of partition number @p partno on @p drive to @p format.
1898 * @param drive The drive to change the type of a partition on.
1899 * @param partno The partition number on @p drive to change the type of.
1900 * @param format The filesystem type this partition will eventually contain.
1901 * @param partsize The size of this partition, in @e bytes (used for vfat
1902 * type calculations).
1903 * @return 0 for success, nonzero for failure.
1904 */
1905int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
1906 const char *format, long long partsize)
1907{
1908 /** buffers *********************************************************/
1909 char *partition = NULL;
1910 char *command = NULL;
1911 char *output = NULL;
1912 char *tmp = NULL;
1913 char *tmp1 = NULL;
1914 char *partcode = NULL;
1915
1916 /** pointers *********************************************************/
1917 char *p;
1918 FILE *fout;
1919
1920 /** int **************************************************************/
1921 int res = 0;
1922
1923 /** end **************************************************************/
1924
1925 assert_string_is_neither_NULL_nor_zerolength(drive);
1926 assert(format != NULL);
1927
1928 partition = build_partition_name(drive, partno);
1929 p = (char *) strrchr(partition, '/');
1930 if (strcmp(format, "swap") == 0) {
1931 mr_asprintf(partcode, "82");
1932 } else if (strcmp(format, "vfat") == 0) {
1933 if (partsize / 1024 > 8192) {
1934 mr_asprintf(partcode, "c");
1935 } else {
1936 mr_asprintf(partcode, "b");
1937 }
1938 } else if (strcmp(format, "ext2") == 0
1939 || strcmp(format, "reiserfs") == 0
1940 || strcmp(format, "ext3") == 0
1941 || strcmp(format, "ext4") == 0
1942 || strcmp(format, "xfs") == 0
1943 || strcmp(format, "jfs") == 0
1944 || strcmp(format, "btrfs") == 0) {
1945 mr_asprintf(partcode, "83");
1946 } else if (strcmp(format, "minix") == 0) {
1947 mr_asprintf(partcode, "81");
1948 } else if (strcmp(format, "vmfs3") == 0) {
1949 mr_asprintf(partcode, "fb");
1950 } else if (strcmp(format, "vmkcore") == 0) {
1951 mr_asprintf(partcode, "fc");
1952 } else if (strcmp(format, "raid") == 0) {
1953 mr_asprintf(partcode, "fd");
1954 } else if (strcmp(format, "ntfs") == 0) {
1955 mr_asprintf(partcode, "7");
1956 } else if ((strcmp(format, "ufs") == 0)
1957 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1958 mr_asprintf(partcode, "a5");
1959 } else if (strcmp(format, "lvm") == 0) {
1960 mr_asprintf(partcode, "8e");
1961 } else if (format[0] == '\0') { /* LVM physical partition */
1962 mr_asprintf(partcode, "");
1963 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
1964 mr_asprintf(partcode, "%s", format);
1965 } else {
1966 /* probably an image */
1967 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1968 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1969 mr_free(tmp);
1970#ifdef __FreeBSD__
1971 mr_asprintf(partcode, "%s", format); // was a5
1972#else
1973 mr_asprintf(partcode, "%s", format); // was 83
1974#endif
1975 }
1976 log_msg(1, tmp, "Setting %s's type to %s (%s)", partition, format, partcode);
1977 mr_free(partition);
1978
1979 if (partcode != NULL && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1980
1981 if (pout_to_fdisk) {
1982 res = 0;
1983 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1984 tmp1 = last_line_of_file(FDISK_LOG);
1985 if (partno > 1 || strstr(tmp1, " (1-4)")) {
1986 log_msg(5, "Specifying partno (%d) - yay", partno);
1987 mr_asprintf(tmp, "%d\n", partno);
1988 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1989 mr_free(tmp);
1990
1991 mr_free(tmp1);
1992 tmp1 = last_line_of_file(FDISK_LOG);
1993 log_msg(5, "A - last line = '%s'", tmp1);
1994 }
1995 mr_free(tmp1);
1996
1997 mr_asprintf(tmp, "%s\n", partcode);
1998 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1999 mr_free(tmp);
2000
2001 tmp1 = last_line_of_file(FDISK_LOG);
2002 log_msg(5, "B - last line = '%s'", tmp1);
2003 mr_free(tmp1);
2004
2005 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2006 tmp1 = last_line_of_file(FDISK_LOG);
2007 log_msg(5, "C - last line = '%s'", tmp1);
2008 mr_free(tmp1);
2009
2010 tmp1 = last_line_of_file(FDISK_LOG);
2011 if (!strstr(tmp1, " (m ")) {
2012 log_msg(1, "last line = '%s'; part type set failed", tmp1);
2013 res++;
2014 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2015 }
2016 mr_free(tmp1);
2017
2018 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2019 } else {
2020 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
2021 mr_asprintf(command, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
2022 log_msg(5, "output = '%s'", output);
2023 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2024 log_msg(5, "command = '%s'", command);
2025 fout = popen(command, "w");
2026 if (!fout) {
2027 log_OS_error(command);
2028 res = 1;
2029 } else {
2030 res = 0;
2031 fprintf(fout, "%s", output);
2032 paranoid_pclose(fout);
2033 }
2034 paranoid_free(output);
2035 mr_free(command);
2036 }
2037 }
2038
2039 mr_free(partcode);
2040 return (res);
2041}
2042
2043
2044int start_raid_device(char *raid_device)
2045{
2046 /** int *************************************************************/
2047 int res;
2048 int retval = 0;
2049
2050 /** buffers *********************************************************/
2051 char *program = NULL;
2052
2053 /** end *************************************************************/
2054
2055 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2056
2057#ifdef __FreeBSD__
2058 if (is_this_device_mounted(raid_device)) {
2059 log_it("Can't start %s when it's mounted!", raid_device);
2060 return 1;
2061 }
2062 mr_asprintf(program, "vinum start -f %s", raid_device);
2063#else
2064 mr_asprintf(program, "raidstart %s", raid_device);
2065#endif
2066 log_msg(1, "program = %s", program);
2067 res = run_program_and_log_output(program, 1);
2068 if (g_fprep) {
2069 fprintf(g_fprep, "%s\n", program);
2070 }
2071 mr_free(program);
2072
2073 if (res) {
2074 log_msg(1, "Warning - failed to start RAID device %s",
2075 raid_device);
2076 }
2077 retval += res;
2078 sleep(1);
2079 return (retval);
2080}
2081
2082
2083
2084/**
2085 * Stop @p raid_device using @p raidstop.
2086 * @param raid_device The software RAID device to stop.
2087 * @return 0 for success, nonzero for failure.
2088 */
2089int stop_raid_device(char *raid_device)
2090{
2091 /** int *************************************************************/
2092 int res;
2093 int retval = 0;
2094
2095 /** buffers *********************************************************/
2096 char *program = NULL;
2097
2098 /** end *************************************************************/
2099
2100 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2101
2102#ifdef __FreeBSD__
2103 if (is_this_device_mounted(raid_device)) {
2104 log_it("Can't stop %s when it's mounted!", raid_device);
2105 return 1;
2106 }
2107 mr_asprintf(program, "vinum stop -f %s", raid_device);
2108#else
2109 // use raidstop if it exists, otherwise use mdadm
2110 if (run_program_and_log_output("which raidstop", FALSE)) {
2111 mr_asprintf(program, "mdadm -S %s", raid_device);
2112 } else {
2113 mr_asprintf(program, "raidstop %s", raid_device);
2114 }
2115#endif
2116 log_msg(1, "program = %s", program);
2117 res = run_program_and_log_output(program, 1);
2118 if (g_fprep) {
2119 fprintf(g_fprep, "%s\n", program);
2120 }
2121 mr_free(program);
2122
2123 if (res) {
2124 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2125 }
2126 retval += res;
2127 return (retval);
2128}
2129
2130
2131int start_all_raid_devices(struct mountlist_itself *mountlist)
2132{
2133 int i;
2134 int retval = 0;
2135 int res;
2136
2137 for (i = 0; i < mountlist->entries; i++) {
2138 if (!strncmp
2139 (mountlist->el[i].device, RAID_DEVICE_STUB,
2140 strlen(RAID_DEVICE_STUB))) {
2141 log_msg(1, "Starting %s", mountlist->el[i].device);
2142 res = start_raid_device(mountlist->el[i].device);
2143 retval += res;
2144 }
2145 }
2146 if (retval) {
2147 log_msg(1, "Started all s/w raid devices OK");
2148 } else {
2149 log_msg(1, "Failed to start some/all s/w raid devices");
2150 }
2151 return (retval);
2152}
2153
2154/**
2155 * Stop all software RAID devices listed in @p mountlist.
2156 * @param mountlist The mountlist to stop the RAID devices in.
2157 * @return The number of errors encountered (0 for success).
2158 * @bug @p mountlist is not used.
2159 */
2160int stop_all_raid_devices(struct mountlist_itself *mountlist)
2161{
2162 /** int *************************************************************/
2163 int retval = 0;
2164
2165 /** char ************************************************************/
2166 char *incoming = NULL;
2167#ifndef __FreeBSD__
2168 char *dev;
2169 char *p;
2170 int res;
2171#endif
2172
2173 /** pointers ********************************************************/
2174 FILE *fin;
2175 char *q;
2176 int i;
2177
2178 /** end ****************************************************************/
2179
2180 assert(mountlist != NULL);
2181
2182 for (i = 0; i < 3; i++) {
2183#ifdef __FreeBSD__
2184 fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r");
2185 if (!fin) {
2186 return (1);
2187 }
2188 for (mr_getline(incoming, fin); !feof(fin); mr_getline(incoming, fin)) {
2189 retval += stop_raid_device(incoming);
2190 mr_free(incoming);
2191 }
2192 mr_free(incoming);
2193#else
2194 fin = fopen("/proc/mdstat", "r");
2195 if (!fin) {
2196 log_OS_error("/proc/mdstat");
2197 return (1);
2198 }
2199 for (mr_getline(incoming, fin); !feof(fin); mr_getline(incoming, fin)) {
2200 for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++);
2201 if (*p != '\0') {
2202 mr_asprintf(dev, "/dev/%s", p);
2203 for (p = dev; *p > 32; p++);
2204 *p = '\0';
2205 retval += stop_raid_device(dev);
2206 mr_free(dev);
2207 }
2208 mr_free(incoming);
2209 }
2210 mr_free(incoming);
2211#endif
2212 }
2213 paranoid_fclose(fin);
2214 if (retval) {
2215 log_msg(1, "Warning - unable to stop some RAID devices");
2216 }
2217 sync();
2218 sync();
2219 sync();
2220 sleep(1);
2221 return (retval);
2222}
2223
2224
2225
2226/**
2227 * Decide which command we need to use to format a device of type @p format.
2228 * @param format The filesystem type we are about to format.
2229 * @param program Where to put the binary name for this format.
2230 * @return 0 for success, nonzero for failure.
2231 */
2232char *which_format_command_do_i_need(char *format)
2233{
2234 /** int *************************************************************/
2235 int res = 0;
2236
2237 /** buffers *********************************************************/
2238 char *program = NULL;
2239
2240 /** end ***************************************************************/
2241
2242 assert_string_is_neither_NULL_nor_zerolength(format);
2243
2244 if (strcmp(format, "swap") == 0) {
2245#ifdef __FreeBSD__
2246 mr_asprintf(program, "true");
2247#else
2248 mr_asprintf(program, "mkswap");
2249#endif
2250 } else if (strcmp(format, "vfat") == 0) {
2251 mr_asprintf(program, "format-and-kludge-vfat");
2252#ifndef __FreeBSD__
2253 } else if (strcmp(format, "reiserfs") == 0) {
2254 mr_asprintf(program, "mkreiserfs -ff");
2255 } else if (strcmp(format, "xfs") == 0) {
2256 mr_asprintf(program, "mkfs.xfs -f -q");
2257 } else if (strcmp(format, "jfs") == 0) {
2258 mr_asprintf(program, "mkfs.jfs");
2259 } else if (strcmp(format, "ext3") == 0) {
2260 mr_asprintf(program, "mkfs -t ext3 -F -q");
2261 } else if (strcmp(format, "ext4") == 0) {
2262 mr_asprintf(program, "mkfs -t ext4 -F -q");
2263 } else if (strcmp(format, "btrfs") == 0) {
2264 strcpy(program, "mkfs.btrfs");
2265 } else if (strcmp(format, "minix") == 0) {
2266 mr_asprintf(program, "mkfs.minix");
2267 } else if (strcmp(format, "vmfs") == 0) {
2268 mr_asprintf(program, "mkfs -t vmfs");
2269 } else if (strcmp(format, "ntfs") == 0) {
2270 /*
2271 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2272 * so the default "mkfs -t %s -c" command structure fails
2273 */
2274 mr_asprintf(program, "mkfs -t ntfs");
2275 } else if (strcmp(format, "ocfs2") == 0) {
2276 /*
2277 * 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.
2278 *
2279 */
2280 mr_asprintf(program, "mkfs -t ocfs2 -F");
2281#endif
2282 } else if (strcmp(format, "ext2") == 0) {
2283 mr_asprintf(program, "mke2fs -F -q");
2284 } else {
2285#ifdef __FreeBSD__
2286 mr_asprintf(program, "newfs_%s", format);
2287#else
2288 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2289#endif
2290 log_it("Unknown format (%s) - assuming '%s' will do", format, program);
2291 res = 0;
2292 }
2293 return (program);
2294}
2295
2296
2297/**
2298 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2299 * There are a few problems with this function:
2300 * - It won't work if there was any unallocated space on the user's hard drive
2301 * when it was backed up.
2302 * - It won't work if the user's hard drive lies about its size (more common
2303 * than you'd think).
2304 *
2305 * @param mountlist The mountlist to use for resizing @p drive_name.
2306 * @param drive_name The drive to resize.
2307 */
2308void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2309 *mountlist,
2310 char *drive_name)
2311{
2312
2313 /** int *************************************************************/
2314 int partno, lastpart;
2315
2316 /** float ***********************************************************/
2317 float factor;
2318 long long new_size;
2319
2320 /** long *************************************************************/
2321 long long newsizL = 0LL;
2322 long long totalsizL = 0LL;
2323 long long current_size_of_drive = 0LL; /* use KB interally for precision */
2324 long long original_size_of_drive = 0LL; /* use KB interally for precision */
2325 struct mountlist_reference *drivemntlist;
2326
2327 /** structures *******************************************************/
2328
2329 /** end **************************************************************/
2330
2331 assert(mountlist != NULL);
2332 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2333
2334 if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2335 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2336 == 0) {
2337 return;
2338 }
2339 }
2340
2341 current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
2342
2343 if (current_size_of_drive <= 0LL) {
2344 log_it("Not resizing to match %s - can't find drive", drive_name);
2345 return;
2346 }
2347 log_to_screen("Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
2348
2349 drivemntlist = malloc(sizeof(struct mountlist_reference));
2350 drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2351
2352 if (!drivemntlist) {
2353 fatal_error("Cannot malloc temporary mountlist\n");
2354 }
2355 create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2356
2357 for (partno = 0; partno < drivemntlist->entries; partno++) {
2358 if (drivemntlist->el[partno]->size > 0LL) {
2359 /* Keep KB here */
2360 original_size_of_drive += drivemntlist->el[partno]->size;
2361 }
2362 }
2363
2364 if (original_size_of_drive <= 0LL) {
2365 log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name);
2366 return;
2367 }
2368 factor = ((float)current_size_of_drive/(float)original_size_of_drive);
2369 mr_asprintf(tmp, "Disk %s was %lld MB; is now %lld MB; Proportionally resizing partitions (factor ~= %.5f)",
2370 drive_name, original_size_of_drive/1024, current_size_of_drive/1024, factor);
2371 log_to_screen(tmp);
2372 mr_free(tmp);
2373
2374 lastpart = drivemntlist->entries - 1;
2375 for (partno = 0; partno < drivemntlist->entries; partno++) {
2376 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2377 if (!atoi(drivemntlist->el[partno]->format)) {
2378 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
2379 } else {
2380 new_size = drivemntlist->el[partno]->size;
2381 }
2382
2383 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2384 log_msg(1, "Skipping %s (%s) because it's an image",
2385 drivemntlist->el[partno]->device,
2386 drivemntlist->el[partno]->mountpoint);
2387 }
2388 newsizL = new_size;
2389
2390 /* Do not apply the factor if partition was of negative size */
2391 if (newsizL < 0LL) {
2392 newsizL = drivemntlist->el[partno]->size;
2393 }
2394 totalsizL += newsizL;
2395
2396 log_to_screen("Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2397 drivemntlist->el[partno]->size = newsizL;
2398 }
2399 // Ensures over-allocation alert and prompt for interactive mode does not happen
2400 if (totalsizL > current_size_of_drive) {
2401 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));
2402 drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive);
2403 } else if (totalsizL < current_size_of_drive) {
2404 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));
2405 drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL);
2406 }
2407 log_to_screen("final_size = %lld MB", current_size_of_drive / 1024);
2408}
2409
2410
2411/**
2412 * Resize all partitions in @p mountlist proportionately (each one
2413 * grows or shrinks by the same percentage) to fit them into the new
2414 * drives (presumably different from the old ones).
2415 * @param mountlist The mountlist to resize the drives in.
2416 */
2417void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2418 *mountlist)
2419{
2420 /** buffers *********************************************************/
2421 struct list_of_disks *drivelist;
2422
2423 /** int *************************************************************/
2424 int driveno;
2425
2426 /** end *************************************************************/
2427
2428 drivelist = malloc(sizeof(struct list_of_disks));
2429 assert(mountlist != NULL);
2430
2431 log_it("Resizing mountlist");
2432 make_list_of_drives_in_mountlist(mountlist, drivelist);
2433 log_it("Back from MLoDiM");
2434 for (driveno = 0; driveno < drivelist->entries; driveno++) {
2435 resize_drive_proportionately_to_suit_new_drives(mountlist,
2436 drivelist->
2437 el[driveno].
2438 device);
2439 }
2440 log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2441 paranoid_free(drivelist);
2442}
2443
2444/**
2445 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2446 * @param mountlist The complete mountlist to get the drive references from.
2447 * @param drive_name The drive to put in @p drivemntlist.
2448 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2449 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2450 * @author Ralph Grewe
2451 */
2452void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2453 char *drive_name,
2454 struct mountlist_reference *drivemntlist)
2455{
2456 int partno;
2457 char *tmp_drive_name, *c;
2458
2459 assert(mountlist != NULL);
2460 assert(drive_name != NULL);
2461 assert(drivemntlist != NULL);
2462
2463 log_msg(1, "Creating list of partitions for drive %s", drive_name);
2464
2465 tmp_drive_name = strdup(drive_name);
2466 if (!tmp_drive_name)
2467 fatal_error("Out of memory");
2468
2469 /* devfs devices? */
2470 c = strrchr(tmp_drive_name, '/');
2471 if (c && strncmp(c, "/disc", 5) == 0) {
2472 /* yup its devfs, change the "disc" to "part" so the existing code works */
2473 strcpy(c + 1, "part");
2474 }
2475 drivemntlist->entries = 0;
2476 for (partno = 0; partno < mountlist->entries; partno++) {
2477 if (strncmp
2478 (mountlist->el[partno].device, tmp_drive_name,
2479 strlen(tmp_drive_name)) == 0) {
2480 drivemntlist->el[drivemntlist->entries] =
2481 &mountlist->el[partno];
2482 drivemntlist->entries++;
2483 }
2484 }
2485 if (tmp_drive_name)
2486 free(tmp_drive_name);
2487}
2488
2489/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.