source: MondoRescue/branches/3.2/mondo/src/mondorestore/mondo-prep.c@ 3330

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