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

Last change on this file since 3193 was 3193, checked in by Bruno Cornec, 11 years ago
  • Finish with backports from 3.1 for now. Still some work to do, but we will now make that version compile and work again and serve as a base

so the gettext patch can be added

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