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

Last change on this file since 3435 was 3435, checked in by Bruno Cornec, 9 years ago
  • Fix calling format-and-kludge-vfat with only one param now
  • Property svn:keywords set to Id
File size: 71.0 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 3435 2015-08-28 13:31:31Z 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 3435 2015-08-28 13:31:31Z 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", 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);
773mr_free(program);
774
775mr_asprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
776mr_free(tmp);
777
778mr_asprintf(tmp, "Formatting %s as %s", device, format);
779update_progress_form(tmp);
780
781res = run_program_and_log_output(program, FALSE);
782if (res) {
783 mr_strcat(tmp, "...failed");
784} else {
785 mr_strcat(tmp, "...OK");
786}
787log_to_screen(tmp);
788mr_free(tmp);
789
790if (res && strstr(program, "kludge")) {
791 mr_asprintf(tmp, "Kludge failed; using regular mkfs.%s to format %s", format, device);
792 mr_free(program);
793#ifdef __FreeBSD__
794 mr_asprintf(program, "newfs_msdos -F 32 %s", device);
795#else
796#ifdef __IA64__
797 /* For EFI or UEFI partitions take fat16
798 * as we want to make small ones */
799 mr_asprintf(program, "mkfs -t %s -F 16 %s", format, device);
800#else
801 mr_asprintf(program, "mkfs -t %s -F 32 %s", format, device);
802#endif
803#endif
804 res = run_program_and_log_output(program, FALSE);
805 if (g_fprep) {
806 fprintf(g_fprep, "%s\n", program);
807 }
808 mr_free(program);
809
810 if (retval) {
811 mr_strcat(tmp, "...failed");
812 } else {
813 mr_strcat(tmp, "...OK");
814 }
815
816 log_to_screen(tmp);
817 mr_free(tmp);
818
819}
820retval += res;
821paranoid_system("sync");
822sleep(1);
823return (retval);
824}
825
826
827/**
828 * Format all drives (except those excluded by format_device()) in @p mountlist.
829 * @param mountlist The mountlist containing partitions to be formatted.
830 * @param interactively If TRUE, then prompt the user before each partition.
831 * @return The number of errors encountered (0 for success).
832 */
833int format_everything(struct mountlist_itself *mountlist, bool interactively, struct raidlist_itself *raidlist) {
834
835/** int **************************************************************/
836int retval = 0;
837int lino;
838int res;
839
840/** long *************************************************************/
841long progress_step;
842
843/** bools ************************************************************/
844bool do_it;
845
846/** buffers **********************************************************/
847char *tmp = NULL;
848
849/** pointers *********************************************************/
850struct mountlist_line *me; // mountlist entry
851/** end **************************************************************/
852
853assert(mountlist != NULL);
854log_it("format_everything (mountlist, interactively = %s", (interactively) ? "true" : "false");
855mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
856open_progress_form("Formatting partitions", "I am now formatting your hard disk partitions.", "This may take up to five minutes.", "", mountlist->entries + 1);
857
858progress_step = (mountlist->entries > 0) ? g_maximum_progress / mountlist->entries : 1;
859// start soft-raids now (because LVM might depend on them)
860// ...and for simplicity's sake, let's format them at the same time :)
861log_msg(1, "Stopping all RAID devices");
862stop_all_raid_devices(mountlist);
863paranoid_system("sync");
864paranoid_system("sync");
865paranoid_system("sync");
866sleep(2);
867log_msg(1, "Prepare soft-RAIDs"); // prep and format too
868for (lino = 0; lino < mountlist->entries; lino++) {
869 me = &mountlist->el[lino]; // the current mountlist entry
870 log_msg(2, "Examining %s", me->device);
871 if (!strncmp(me->device, "/dev/md", 7)) {
872 if (interactively) {
873 // ask user if we should format the current device
874 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
875 do_it = ask_me_yes_or_no(tmp);
876 mr_free(tmp);
877 } else {
878 do_it = TRUE;
879 }
880 if (do_it) {
881 // NB: format_device() also stops/starts RAID device if necessary
882 retval += format_device(me->device, me->format, raidlist);
883 }
884 g_current_progress += progress_step;
885 }
886}
887paranoid_system("sync");
888paranoid_system("sync");
889paranoid_system("sync");
890sleep(2);
891// do LVMs now
892log_msg(1, "Creating LVMs");
893if (does_file_exist("/tmp/i-want-my-lvm")) {
894 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
895 log_to_screen("Configuring LVM");
896 if (!g_text_mode) {
897 newtSuspend();
898 }
899 res = do_my_funky_lvm_stuff(FALSE, TRUE);
900 if (!g_text_mode) {
901 newtResume();
902 }
903 if (!res) {
904 log_to_screen("LVM initialized OK");
905 } else {
906 log_to_screen("Failed to initialize LVM");
907 }
908 // retval += res;
909 if (res) {
910 retval++;
911 }
912 sleep(3);
913}
914// do regulars at last
915sleep(2); // woo!
916log_msg(1, "Formatting regulars");
917for (lino = 0; lino < mountlist->entries; lino++) {
918 me = &mountlist->el[lino]; // the current mountlist entry
919 if (!strcmp(me->mountpoint, "image")) {
920 log_it("Not formatting %s - it's an image", me->device);
921 } else if (!strcmp(me->format, "raid")) {
922 log_it("Not formatting %s - it's a raid-let", me->device);
923 continue;
924 } else if (!strcmp(me->format, "lvm")) {
925 log_it("Not formatting %s - it's an LVM", me->device);
926 continue;
927 } else if (!strncmp(me->device, "/dev/md", 7)) {
928 log_it("Already formatted %s - it's a soft-RAID dev", me->device);
929 continue;
930 } else if (!does_file_exist(me->device) && strncmp(me->device, "/dev/hd", 7) && strncmp(me->device, "/dev/sd", 7)) {
931 log_it("Not formatting %s yet - doesn't exist - probably an LVM", me->device);
932 continue;
933 } else {
934 if (interactively) {
935 // ask user if we should format the current device
936 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
937 do_it = ask_me_yes_or_no(tmp);
938 mr_free(tmp);
939 } else {
940 do_it = TRUE;
941 }
942
943 if (do_it)
944 retval += format_device(me->device, me->format, raidlist);
945 }
946
947 // update progress bar
948 g_current_progress += progress_step;
949}
950
951
952// update progress bar to 100% to compensate for
953// rounding errors of the progress_step calculation
954if (lino >= mountlist->entries)
955 g_current_progress = g_maximum_progress;
956
957close_progress_form();
958
959if (retval) {
960 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
961 log_to_screen("Errors may have occurred during the formatting of your hard drives.");
962} else {
963 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
964}
965
966log_it("format_everything () - %s", (retval) ? "failed!" : "finished successfully");
967
968if (g_partition_table_locked_up > 0) {
969 if (retval > 0 && !interactively) {
970//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
971 log_to_screen("Partition table locked up %d times. At least one 'mkfs' (format) command", g_partition_table_locked_up);
972 log_to_screen("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
973 log_to_screen("to refresh its copy of the partition table causes the kernel to lock the ");
974 log_to_screen("partition table. I believe this has just happened.");
975 if (ask_me_yes_or_no("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue.")) {
976 paranoid_system("sync");
977 paranoid_system("sync");
978 paranoid_system("sync");
979 paranoid_system("reboot");
980 }
981 } else {
982 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');
983 }
984}
985newtSuspend();
986paranoid_system("clear");
987newtResume();
988return (retval);
989}
990
991
992/**
993 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
994 * Each partition created is 32k in size.
995 * @param drivename The drive to create the dummy partitions on.
996 * @param devno_we_must_allow_for The lowest-numbered real partition; create
997 * dummies up to (this - 1).
998 * @return The number of errors encountered (0 for success).
999 */
1000int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename, int devno_we_must_allow_for) {
1001
1002/** int **************************************************************/
1003int current_devno;
1004int previous_devno;
1005int retval = 0;
1006int res;
1007
1008assert_string_is_neither_NULL_nor_zerolength(drivename);
1009
1010if (devno_we_must_allow_for >= 5) {
1011 log_it("Making dummy primary 1 on %s", drivename);
1012 g_maximum_progress++;
1013 res = partition_device(pout_to_fdisk, drivename, 1, 0, "ext2", 32000);
1014 retval += res;
1015 previous_devno = 1;
1016 current_devno = 5;
1017} else {
1018 previous_devno = 0;
1019 current_devno = 1;
1020}
1021for (; current_devno < devno_we_must_allow_for; current_devno++) {
1022 log_it("Creating dummy partition %d on %s", current_devno, drivename);
1023 g_maximum_progress++;
1024 res = partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, OSSWAP("ext2", "ufs"), 32000);
1025 retval += res;
1026 previous_devno = current_devno;
1027}
1028return (previous_devno);
1029}
1030
1031
1032/**
1033 * Decide whether @p mountlist contains any RAID devices.
1034 * @param mountlist The mountlist to examine.
1035 * @return TRUE if it does, FALSE if it doesn't.
1036 */
1037bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist) {
1038
1039/** int *************************************************************/
1040int i;
1041int matching = 0;
1042
1043/** end **************************************************************/
1044
1045assert(mountlist != NULL);
1046
1047for (i = 0; i < mountlist->entries; i++) {
1048 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1049 matching++;
1050 }
1051}
1052if (matching) {
1053 return (TRUE);
1054} else {
1055 return (FALSE);
1056}
1057}
1058
1059/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1060#ifdef __FreeBSD__
1061static void display_disklabel(FILE * f, const struct disklabel *lp) {
1062
1063int i, j;
1064const struct partition *pp;
1065
1066fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1067if (lp->d_type < DKMAXTYPES)
1068 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1069else
1070 fprintf(f, "type: %u\n", lp->d_type);
1071fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename);
1072fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname);
1073fprintf(f, "flags:");
1074if (lp->d_flags & D_REMOVABLE)
1075 fprintf(f, " removeable");
1076if (lp->d_flags & D_ECC)
1077 fprintf(f, " ecc");
1078if (lp->d_flags & D_BADSECT)
1079 fprintf(f, " badsect");
1080fprintf(f, "\n");
1081fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1082fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1083fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1084fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1085fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1086fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1087fprintf(f, "rpm: %u\n", lp->d_rpm);
1088fprintf(f, "interleave: %u\n", lp->d_interleave);
1089fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1090fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1091fprintf(f, "headswitch: %lu\t\t# milliseconds\n", (u_long) lp->d_headswitch);
1092fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (u_long) lp->d_trkseek);
1093fprintf(f, "drivedata: ");
1094for (i = NDDATA - 1; i >= 0; i--)
1095 if (lp->d_drivedata[i])
1096 break;
1097if (i < 0)
1098 i = 0;
1099for (j = 0; j <= i; j++)
1100 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1101fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1102fprintf(f, "# size offset fstype [fsize bsize bps/cpg]\n");
1103pp = lp->d_partitions;
1104for (i = 0; i < lp->d_npartitions; i++, pp++) {
1105 if (pp->p_size) {
1106 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size, (u_long) pp->p_offset);
1107 if (pp->p_fstype < FSMAXTYPES)
1108 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1109 else
1110 fprintf(f, "%8d", pp->p_fstype);
1111 switch (pp->p_fstype) {
1112
1113 case FS_UNUSED: /* XXX */
1114 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), "");
1115 break;
1116
1117 case FS_BSDFFS:
1118 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1119 break;
1120
1121 case FS_BSDLFS:
1122 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize, (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1123 break;
1124
1125 default:
1126 fprintf(f, "%20.20s", "");
1127 break;
1128 }
1129 fprintf(f, "\t# (Cyl. %4lu", (u_long) (pp->p_offset / lp->d_secpercyl));
1130 if (pp->p_offset % lp->d_secpercyl)
1131 putc('*', f);
1132 else
1133 putc(' ', f);
1134 fprintf(f, "- %lu", (u_long) ((pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl - 1));
1135 if (pp->p_size % lp->d_secpercyl)
1136 putc('*', f);
1137 fprintf(f, ")\n");
1138 }
1139}
1140fflush(f);
1141}
1142
1143static struct disklabel *get_virgin_disklabel(char *dkname) {
1144
1145static struct disklabel loclab;
1146struct partition *dp;
1147char *lnamebuf = NULL;
1148int f;
1149u_int secsize, u;
1150off_t mediasize;
1151
1152mr_asprintf(lnamebuf, "%s", dkname);
1153if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1154 warn("cannot open %s", lnamebuf);
1155 mr_free(lnamebuf);
1156 return (NULL);
1157}
1158mr_free(lnamebuf);
1159
1160/* New world order */
1161if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1162 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1163 close(f);
1164 return (NULL);
1165}
1166memset(&loclab, 0, sizeof loclab);
1167loclab.d_magic = DISKMAGIC;
1168loclab.d_magic2 = DISKMAGIC;
1169loclab.d_secsize = secsize;
1170loclab.d_secperunit = mediasize / secsize;
1171
1172/*
1173 * Nobody in these enligthened days uses the CHS geometry for
1174 * anything, but nontheless try to get it right. If we fail
1175 * to get any good ideas from the device, construct something
1176 * which is IBM-PC friendly.
1177 */
1178if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1179 loclab.d_nsectors = u;
1180else
1181 loclab.d_nsectors = 63;
1182
1183if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1184 loclab.d_ntracks = u;
1185else if (loclab.d_secperunit <= 63 * 1 * 1024)
1186 loclab.d_ntracks = 1;
1187else if (loclab.d_secperunit <= 63 * 16 * 1024)
1188 loclab.d_ntracks = 16;
1189else
1190 loclab.d_ntracks = 255;
1191loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1192loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1193loclab.d_npartitions = MAXPARTITIONS;
1194
1195/* Various (unneeded) compat stuff */
1196loclab.d_rpm = 3600;
1197loclab.d_bbsize = BBSIZE;
1198loclab.d_interleave = 1;;
1199strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1200
1201 dp = &loclab.d_partitions[RAW_PART];
1202dp->p_size = loclab.d_secperunit;
1203loclab.d_checksum = dkcksum(&loclab);
1204close(f);
1205return (&loclab);
1206}
1207
1208/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1209
1210char *canonical_name(char *drivename) {
1211
1212if (drivename) {
1213 if (strncmp(drivename, "/dev/", 5) == 0) {
1214 return drivename + 5;
1215 }
1216}
1217return drivename;
1218}
1219
1220/**
1221 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1222 * @param mountlist The mountlist to get the subpartition information from.
1223 * @param drivename The drive or slice to create a disklabel on.
1224 * @param ret If non-NULL, store the created disklabel here.
1225 * @return The number of errors encountered (0 for success).
1226 */
1227int label_drive_or_slice(struct mountlist_itself *mountlist, char *drivename, struct disklabel *ret) {
1228
1229char *subdev_str = NULL;
1230char *command = NULL;
1231struct disklabel *lp;
1232int i, lo = 0;
1233int retval = 0;
1234char c;
1235FILE *ftmp;
1236
1237lp = get_virgin_disklabel(drivename);
1238for (c = 'a'; c <= 'z'; ++c) {
1239 int idx;
1240 mr_asprintf(subdev_str, "%s%c", drivename, c);
1241 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1242 lp->d_partitions[c - 'a'].p_size = 0;
1243 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1244 } else {
1245 lo = c - 'a';
1246 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1247 lp->d_partitions[c - 'a'].p_fsize = 0;
1248 lp->d_partitions[c - 'a'].p_frag = 0;
1249 lp->d_partitions[c - 'a'].p_cpg = 0;
1250 if (!strcmp(mountlist->el[idx].format, "ufs") || !strcmp(mountlist->el[idx].format, "ffs") || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1251 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1252 lp->d_partitions[c - 'a'].p_fsize = 2048;
1253 lp->d_partitions[c - 'a'].p_frag = 8;
1254 lp->d_partitions[c - 'a'].p_cpg = 64;
1255 } else if (!strcasecmp(mountlist->el[idx].format, "raid") || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1256 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1257 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1258 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1259 } else
1260 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1261 }
1262 mr_free(subdev_str);
1263}
1264
1265// fix up the offsets
1266lp->d_partitions[0].p_offset = 0;
1267lp->d_partitions[RAW_PART].p_offset = 0;
1268lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1269lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1270
1271for (i = 1; i < lp->d_npartitions; ++i) {
1272 int lastone;
1273 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1274 continue;
1275 for (lastone = i - 1; lastone >= 0; lastone--) {
1276 if ((lp->d_partitions[lastone].p_size) && (lastone != RAW_PART))
1277 break;
1278 }
1279 lp->d_partitions[i].p_offset = lp->d_partitions[lastone].p_offset + lp->d_partitions[lastone].p_size;
1280}
1281if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size > lp->d_secperunit) {
1282 lp->d_partitions[lo].p_size = lp->d_secperunit - lp->d_partitions[lo].p_offset;
1283}
1284
1285ftmp = fopen("/tmp/disklabel", "w");
1286display_disklabel(ftmp, lp);
1287fclose(ftmp);
1288mr_asprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1289retval += run_program_and_log_output(command, TRUE);
1290mr_free(command);
1291
1292mr_asprintf(command, "disklabel -R %s /tmp/disklabel", canonical_name(drivename));
1293retval += run_program_and_log_output(command, TRUE);
1294mr_free(command);
1295
1296if (ret)
1297 *ret = *lp;
1298return retval;
1299}
1300#endif
1301
1302
1303/**
1304 * Partition @p drivename based on @p mountlist.
1305 * @param mountlist The mountlist to use to guide the partitioning.
1306 * @param drivename The drive to partition.
1307 * @return 0 for success, nonzero for failure.
1308 */
1309int partition_drive(struct mountlist_itself *mountlist, char *drivename) {
1310
1311/** int *************************************************************/
1312int current_devno;
1313int previous_devno = 0;
1314int lino;
1315int retval = 0;
1316int i;
1317FILE *pout_to_fdisk = NULL;
1318
1319#ifdef __FreeBSD__
1320bool fbsd_part = FALSE;
1321char *subdev_str = NULL;
1322#endif
1323
1324/** long long *******************************************************/
1325long long partsize;
1326
1327/** buffers *********************************************************/
1328char *device_str;
1329char *format = NULL;
1330char *tmp = NULL;
1331char *tmp1 = NULL;
1332
1333/** end *************************************************************/
1334
1335assert(mountlist != NULL);
1336assert_string_is_neither_NULL_nor_zerolength(drivename);
1337
1338
1339log_it("Partitioning drive %s", drivename);
1340
1341#if __FreeBSD__
1342 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1343 pout_to_fdisk = NULL;
1344#else
1345make_hole_for_file(FDISK_LOG);
1346mr_asprintf(tmp, "mr-parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1347pout_to_fdisk = popen(tmp, "w");
1348if (!pout_to_fdisk) {
1349 log_to_screen("Cannot call mr-parted2fdisk to configure %s", drivename);
1350 mr_free(tmp);
1351 return (1);
1352}
1353mr_free(tmp);
1354#endif
1355
1356malloc_string(device_str);
1357
1358for (current_devno = 1; current_devno < 99; current_devno++) {
1359 build_partition_name(device_str, drivename, current_devno);
1360 lino = find_device_in_mountlist(mountlist, device_str);
1361
1362 if (lino < 0) {
1363 // device not found in mountlist
1364#if __FreeBSD__
1365 // If this is the first partition (just as a sentinel value),
1366 // then see if the user has picked 'dangerously-dedicated' mode.
1367 // If so, then we just call label_drive_or_slice() and return.
1368 char c;
1369 if (current_devno == 1) {
1370 // try DangerouslyDedicated mode
1371 for (c = 'a'; c <= 'z'; c++) {
1372 mr_asprintf(subdev_str, "%s%c", drivename, c);
1373 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1374 fbsd_part = TRUE;
1375 }
1376 mr_free(subdev_str);
1377 }
1378 if (fbsd_part) {
1379 int r = label_drive_or_slice(mountlist,
1380 drivename,
1381 0);
1382 char command[MAX_STR_LEN];
1383 sprintf(command, "disklabel -B %s",
1384 basename(drivename));
1385 if (system(command)) {
1386 log_to_screen
1387 ("Warning! Unable to make the drive bootable.");
1388 }
1389 paranoid_free(device_str);
1390 return r;
1391 }
1392 }
1393 for (c = 'a'; c <= 'z'; c++) {
1394 mr_assprintf(subdev_str, "%s%c", device_str, c);
1395 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1396 fbsd_part = TRUE;
1397 }
1398 mr_free(subdev_str);
1399 }
1400 // Now we check the subpartitions of the current partition.
1401 if (fbsd_part) {
1402 int i, line;
1403
1404 mr_asprintf(format, "ufs");
1405 partsize = 0;
1406 for (i = 'a'; i < 'z'; ++i) {
1407 mr_asprintf(subdev_str, "%s%c", device_str, i);
1408 line = find_device_in_mountlist(mountlist, subdev_str);
1409 mr_free(subdev_str);
1410
1411 if (line > 0) {
1412 // We found one! Add its size to the total size.
1413 partsize += mountlist->el[line].size;
1414 }
1415 }
1416 } else {
1417 continue;
1418 }
1419#else
1420 continue;
1421#endif
1422 }
1423
1424 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1425 /* For FreeBSD, that is /dev/adXsY */
1426
1427 log_it("Found partition %s in mountlist", device_str);
1428 if (!previous_devno) {
1429
1430 log_it("Wiping %s's partition table", drivename);
1431#if __FreeBSD__
1432 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1433 file = open(drivename, O_WRONLY);
1434 if (file != -1) {
1435 log_to_screnn("Warning - unable to open %s for wiping it's partition table", drivename);
1436 }
1437
1438 for (i = 0; i < 512; i++) {
1439 if (!write(file, "\0", 1)) {
1440 log_to_screen("Warning - unable to write to %s", drivename);
1441 }
1442 }
1443 paranoid_system("sync");
1444#else
1445 log_it("New, kernel-friendly partition remover");
1446 for (i = 20; i > 0; i--) {
1447 fprintf(pout_to_fdisk, "d\n%d\n", i);
1448 fflush(pout_to_fdisk);
1449 }
1450#endif
1451 if (current_devno > 1) {
1452 previous_devno = make_dummy_partitions(pout_to_fdisk, drivename, current_devno);
1453 }
1454 }
1455#ifdef __FreeBSD__
1456 if (!fbsd_part) {
1457 mr_free(format);
1458#endif
1459
1460 mr_asprintf(format, "%s", mountlist->el[lino].format);
1461 partsize = mountlist->el[lino].size;
1462
1463#ifdef __FreeBSD__
1464 }
1465#endif
1466
1467#ifndef __IA64__
1468 if (current_devno == 5 && previous_devno == 4) {
1469 log_to_screen("You must leave at least one partition spare as the Extended partition.");
1470 paranoid_free(device_str);
1471 mr_free(format);
1472 return (1);
1473 }
1474#endif
1475
1476 retval += partition_device(pout_to_fdisk, drivename, current_devno, previous_devno, format, partsize);
1477 mr_free(format);
1478
1479#ifdef __FreeBSD__
1480 if ((current_devno <= 4) && fbsd_part) {
1481 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
1482 retval += label_drive_or_slice(mountlist, device_str, 0);
1483 if (system(tmp)) {
1484 log_to_screen("Warning! Unable to make the slice bootable.");
1485 }
1486 mr_free(tmp);
1487 }
1488#endif
1489
1490 previous_devno = current_devno;
1491}
1492
1493if (pout_to_fdisk) {
1494 // close fdisk
1495 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1496 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1497 paranoid_pclose(pout_to_fdisk);
1498 paranoid_system("sync");
1499 log_msg(0,"------------------- fdisk.log looks like this ------------------");
1500 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1501 paranoid_system(tmp);
1502 mr_free(tmp);
1503
1504 // mark relevant partition as bootable
1505 mr_asprintf(tmp1,"make-me-bootable /tmp/mountlist.txt %s",drivename);
1506 call_program_and_get_last_line_of_output(tmp1);
1507 mr_free(tmp1);
1508
1509 log_msg(0,"------------------- end of fdisk.log... ------------------");
1510 paranoid_system("sync");
1511 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1512 if (!run_program_and_log_output(tmp, 5)) {
1513 g_partition_table_locked_up++;
1514 }
1515 mr_free(tmp);
1516
1517 mr_asprintf(tmp, "partprobe %s", drivename);
1518 if (!run_program_and_log_output(tmp, 5)) {
1519 g_partition_table_locked_up--;
1520 }
1521 mr_free(tmp);
1522
1523 if (g_partition_table_locked_up > 0) {
1524 log_to_screen("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1525 }
1526}
1527paranoid_free(device_str);
1528return (retval);
1529}
1530
1531/**
1532 * Create partition number @p partno on @p drive with @p fdisk.
1533 * @param drive The drive to create the partition on.
1534// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1535 * @param prev_partno The partition number of the most recently prepped partition.
1536 * @param format The filesystem type of this partition (used to set the type).
1537 * @param partsize The size of the partition in @e bytes.
1538 * @return 0 for success, nonzero for failure.
1539 */
1540int partition_device(FILE * pout_to_fdisk, const char *drive, int partno, int prev_partno, const char *format, long long partsize) {
1541
1542/** int **************************************************************/
1543int retval = 0;
1544int res = 0;
1545
1546/** buffers **********************************************************/
1547char *program = NULL;
1548char *partition_name;
1549char *tmp = NULL;
1550char *output = NULL;
1551
1552/** pointers **********************************************************/
1553char *part_table_fmt = NULL;
1554FILE *fout;
1555
1556/** end ***************************************************************/
1557
1558assert_string_is_neither_NULL_nor_zerolength(drive);
1559assert(format != NULL);
1560
1561log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting", drive, partno, prev_partno, format, partsize);
1562
1563if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1564 log_it("Not partitioning %s - it is a virtual drive", drive);
1565 return (0);
1566}
1567
1568malloc_string(partition_name);
1569build_partition_name(partition_name, drive, partno);
1570if (partsize <= 0) {
1571 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
1572} else {
1573 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
1574}
1575update_progress_form(tmp);
1576log_it(tmp);
1577mr_free(tmp);
1578
1579if (is_this_device_mounted(partition_name)) {
1580 log_to_screen("%s is mounted, and should not be partitioned", partition_name);
1581 paranoid_free(partition_name);
1582 return (1);
1583}
1584
1585
1586mr_asprintf(program, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1587
1588/* TODO: should not be called each time */
1589part_table_fmt = which_partition_format(drive);
1590mr_asprintf(output, "");
1591
1592/* make it a primary/extended/logical */
1593if (partno <= 4) {
1594 mr_strcat(output, "n\np\n%d\n", partno);
1595} else {
1596 /* MBR needs an extended partition if more than 4 partitions */
1597 if (strcmp(part_table_fmt, "MBR") == 0) {
1598 if (partno == 5) {
1599 if (prev_partno >= 4) {
1600 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1601 paranoid_free(partition_name);
1602 paranoid_free(output);
1603 return (1);
1604 } else {
1605 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1606 }
1607 }
1608 mr_strcat(output, "n\nl\n");
1609 } else {
1610 /* GPT allows more than 4 primary partitions */
1611 mr_strcat(output, "n\np\n%d\n", partno);
1612 }
1613}
1614mr_free(part_table_fmt);
1615
1616mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1617if (partsize > 0) {
1618 if (!strcmp(format, "7")) {
1619 log_msg(1, "Adding 512K, just in case");
1620 partsize += 512;
1621 }
1622 mr_strcat(output, "+%lldK", (long long) (partsize));
1623}
1624mr_strcat(output, "\n");
1625#if 0
1626/*
1627#endif
1628log_it("PARTSIZE = +%ld",(long)partsize);
1629log_it("---fdisk command---");
1630log_it(output);
1631log_it("---end of fdisk---");
1632#if 0
1633*/
1634#endif
1635
1636
1637if (pout_to_fdisk) {
1638 log_msg(1, "Doing the new all-in-one fdisk thing");
1639 log_msg(1, "output = '%s'", output);
1640 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1641 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1642 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1643 if (strstr(tmp, " (m ")) {
1644 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1645 } else {
1646 log_msg(1, "last line = %s", tmp);
1647 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1648 }
1649 mr_free(tmp);
1650
1651 if (!retval) {
1652 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1653 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1654 if (retval) {
1655 log_msg(1, "Failed. Trying again...");
1656 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1657 }
1658 }
1659 if (retval) {
1660 log_msg(1, "...but failed to set type");
1661 }
1662} else {
1663 mr_strcat(output, "w\n\n");
1664 if (g_fprep) {
1665 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1666 }
1667 /* write to disk; close fdisk's stream */
1668 if (!(fout = popen(program, "w"))) {
1669 log_OS_error("can't popen-out to program");
1670 } else {
1671 fputs(output, fout);
1672 paranoid_pclose(fout);
1673 }
1674
1675 if (!does_partition_exist(drive, partno) && partsize > 0) {
1676 log_it("Vaccum-packing");
1677 g_current_progress--;
1678 res = partition_device(pout_to_fdisk, drive, partno, prev_partno, format, -1);
1679 if (res) {
1680 log_it("Failed to vacuum-pack %s", partition_name);
1681 retval++;
1682 } else {
1683 retval = 0;
1684 }
1685 }
1686 if (does_partition_exist(drive, partno)) {
1687 retval = set_partition_type(pout_to_fdisk, drive, partno, format, partsize);
1688 if (retval) {
1689 log_it("Partitioned %s but failed to set its type", partition_name);
1690 } else {
1691 if (partsize > 0) {
1692 log_to_screen("Partition %s created+configured OK", partition_name);
1693 } else {
1694 log_it("Returning from a successful vacuum-pack");
1695 }
1696 }
1697 } else {
1698 mr_asprintf(tmp, "Failed to partition %s", partition_name);
1699 if (partsize > 0) {
1700 log_to_screen(tmp);
1701 } else {
1702 log_it(tmp);
1703 }
1704 mr_free(tmp);
1705 retval++;
1706 }
1707}
1708mr_free(program);
1709paranoid_free(output);
1710
1711g_current_progress++;
1712log_it("partition_device() --- leaving");
1713paranoid_free(partition_name);
1714return (retval);
1715}
1716
1717
1718
1719/**
1720 * Create all partitions listed in @p mountlist.
1721 * @param mountlist The mountlist to use to guide the partitioning.
1722 * @return The number of errors encountered (0 for success).
1723 * @note This sets the partition types but doesn't actually do the formatting.
1724 * Use format_everything() for that.
1725 */
1726int partition_everything(struct mountlist_itself *mountlist) {
1727
1728/** int ************************************************************/
1729int lino;
1730int retval = 0;
1731int i;
1732int res;
1733
1734/** buffer *********************************************************/
1735struct list_of_disks *drivelist;
1736
1737/** end ************************************************************/
1738
1739drivelist = malloc(sizeof(struct list_of_disks));
1740assert(mountlist != NULL);
1741
1742log_it("partition_everything() --- starting");
1743mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1744
1745if (mountlist_contains_raid_devices(mountlist)) {
1746 log_msg(0, "Mountlist, including the partitions incorporated in RAID devices:-");
1747 for (i = 0; i < mountlist->entries; i++) {
1748 log_it(mountlist->el[i].device);
1749 }
1750 log_msg(0, "End of mountlist.");
1751}
1752log_msg(0, "Stopping all LVMs, just in case");
1753if (!g_text_mode) {
1754 newtSuspend();
1755}
1756do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1757if (!g_text_mode) {
1758 newtResume();
1759}
1760log_msg(0, "Stopping all software RAID devices, just in case");
1761stop_all_raid_devices(mountlist);
1762log_msg(0, "Done.");
1763
1764open_progress_form("Partitioning devices", "I am now going to partition all your drives.", "This should not take more than five minutes.", "", mountlist->entries);
1765
1766make_list_of_drives_in_mountlist(mountlist, drivelist);
1767
1768/* partition each drive */
1769for (lino = 0; lino < drivelist->entries; lino++) {
1770 res = partition_drive(mountlist, drivelist->el[lino].device);
1771 retval += res;
1772}
1773close_progress_form();
1774if (retval) {
1775 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1776 log_to_screen("Errors may have occurred during the partitioning of your hard drives.");
1777} else {
1778 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1779 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1780}
1781newtSuspend();
1782paranoid_system("clear");
1783newtResume();
1784paranoid_free(drivelist);
1785return (retval);
1786}
1787
1788
1789
1790/**
1791 * Set the type of partition number @p partno on @p drive to @p format.
1792 * @param drive The drive to change the type of a partition on.
1793 * @param partno The partition number on @p drive to change the type of.
1794 * @param format The filesystem type this partition will eventually contain.
1795 * @param partsize The size of this partition, in @e bytes (used for vfat
1796 * type calculations).
1797 * @return 0 for success, nonzero for failure.
1798 */
1799int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno, const char *format, long long partsize) {
1800
1801/** buffers *********************************************************/
1802char *partition;
1803char *command = NULL;
1804char *output = NULL;
1805char *tmp = NULL;
1806char *partcode = NULL;
1807
1808/** pointers *********************************************************/
1809FILE *fout;
1810
1811/** int **************************************************************/
1812int res = 0;
1813
1814/** end **************************************************************/
1815
1816assert_string_is_neither_NULL_nor_zerolength(drive);
1817assert(format != NULL);
1818
1819malloc_string(partition);
1820
1821build_partition_name(partition, drive, partno);
1822if (strcmp(format, "swap") == 0) {
1823 mr_asprintf(partcode, "82");
1824} else if (strcmp(format, "vfat") == 0) {
1825 if (partsize / 1024 > 8192) {
1826 mr_asprintf(partcode, "c");
1827 } else {
1828 mr_asprintf(partcode, "b");
1829 }
1830} else if (strcmp(format, "ext2") == 0
1831 || strcmp(format, "reiserfs") == 0
1832 || strcmp(format, "ext3") == 0
1833 || strcmp(format, "ext4") == 0
1834 || strcmp(format, "xfs") == 0
1835 || strcmp(format, "jfs") == 0
1836 || strcmp(format, "btrfs") == 0) {
1837 mr_asprintf(partcode, "83");
1838} else if (strcmp(format, "minix") == 0) {
1839 mr_asprintf(partcode, "81");
1840} else if (strcmp(format, "vmfs3") == 0) {
1841 mr_asprintf(partcode, "fb");
1842} else if (strcmp(format, "vmkcore") == 0) {
1843 mr_asprintf(partcode, "fc");
1844} else if (strcmp(format, "raid") == 0) {
1845 mr_asprintf(partcode, "fd");
1846} else if (strcmp(format, "ntfs") == 0) {
1847 mr_asprintf(partcode, "7");
1848} else if ((strcmp(format, "ufs") == 0)
1849 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
1850 mr_asprintf(partcode, "a5");
1851} else if (strcmp(format, "lvm") == 0) {
1852 mr_asprintf(partcode, "8e");
1853} else if (format[0] == '\0') { /* LVM physical partition */
1854 mr_asprintf(partcode, "");
1855} else if (strlen(format) >= 1 && strlen(format) <= 2) {
1856 mr_asprintf(partcode, format);
1857} else {
1858 /* probably an image */
1859 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
1860 mvaddstr_and_log_it(g_currentY++, 0, tmp);
1861 mr_free(tmp);
1862
1863#ifdef __FreeBSD__
1864 mr_asprintf(partcode, format); // was a5
1865#else
1866 mr_asprintf(partcode, format); // was 83
1867#endif
1868}
1869log_msg(1, "Setting %s's type to %s (%s)", partition, format, partcode);
1870if ((strcmp(partcode,"") != 0) && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
1871
1872 if (pout_to_fdisk) {
1873 res = 0;
1874 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
1875 if (partno > 1
1876 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
1877 log_msg(5, "Specifying partno (%d) - yay", partno);
1878 mr_asprintf(tmp, "%d\n", partno);
1879 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1880 log_msg(5, "A - last line = '%s'", last_line_of_file(FDISK_LOG));
1881 mr_free(tmp);
1882 }
1883
1884 mr_asprintf(tmp, "%s\n", partcode);
1885 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1886 mr_free(tmp);
1887
1888 log_msg(5, "B - last line = '%s'",
1889 last_line_of_file(FDISK_LOG));
1890 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1891 log_msg(5, "C - last line = '%s'",
1892 last_line_of_file(FDISK_LOG));
1893
1894 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
1895 if (!strstr(tmp, " (m ")) {
1896 log_msg(1, "last line = '%s'; part type set failed", tmp);
1897 res++;
1898 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
1899 }
1900 mr_free(tmp);
1901
1902 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1903 } else {
1904 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
1905 mr_asprintf(command, "mr-parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
1906 log_msg(5, "output = '%s'", output);
1907 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
1908 log_msg(5, "command = '%s'", command);
1909 fout = popen(command, "w");
1910 if (!fout) {
1911 log_OS_error(command);
1912 res = 1;
1913 } else {
1914 res = 0;
1915 fprintf(fout, "%s", output);
1916 paranoid_pclose(fout);
1917 }
1918 mr_free(command);
1919 paranoid_free(output);
1920 }
1921}
1922mr_free(partcode);
1923
1924paranoid_free(partition);
1925
1926return (res);
1927}
1928
1929
1930int start_raid_device(char *raid_device) {
1931
1932/** int *************************************************************/
1933int res;
1934int retval = 0;
1935
1936/** buffers *********************************************************/
1937char *program = NULL;
1938
1939/** end *************************************************************/
1940
1941assert_string_is_neither_NULL_nor_zerolength(raid_device);
1942
1943#ifdef __FreeBSD__
1944if (is_this_device_mounted(raid_device)) {
1945 log_it("Can't start %s when it's mounted!", raid_device);
1946 return 1;
1947}
1948mr_asprintf(program, "vinum start -f %s", raid_device);
1949#else
1950mr_asprintf(program, "raidstart %s", raid_device);
1951#endif
1952log_msg(1, "program = %s", program);
1953res = run_program_and_log_output(program, 1);
1954if (g_fprep) {
1955 fprintf(g_fprep, "%s\n", program);
1956}
1957mr_free(program);
1958
1959if (res) {
1960 log_msg(1, "Warning - failed to start RAID device %s", raid_device);
1961}
1962retval += res;
1963sleep(1);
1964return (retval);
1965}
1966
1967
1968
1969/**
1970 * Stop @p raid_device using @p raidstop.
1971 * @param raid_device The software RAID device to stop.
1972 * @return 0 for success, nonzero for failure.
1973 */
1974int stop_raid_device(char *raid_device) {
1975
1976/** int *************************************************************/
1977int res;
1978int retval = 0;
1979
1980/** buffers *********************************************************/
1981char *program = NULL;
1982
1983/** end *************************************************************/
1984
1985assert_string_is_neither_NULL_nor_zerolength(raid_device);
1986
1987#ifdef __FreeBSD__
1988if (is_this_device_mounted(raid_device)) {
1989 log_it("Can't stop %s when it's mounted!", raid_device);
1990 return 1;
1991}
1992mr_asprintf(program, "vinum stop -f %s", raid_device);
1993#else
1994// use raidstop if it exists, otherwise use mdadm
1995if (run_program_and_log_output("which raidstop", FALSE)) {
1996 mr_asprintf(program, "mdadm -S %s", raid_device);
1997} else {
1998 mr_asprintf(program, "raidstop %s", raid_device);
1999}
2000#endif
2001log_msg(1, "program = %s", program);
2002res = run_program_and_log_output(program, 1);
2003if (g_fprep) {
2004 fprintf(g_fprep, "%s\n", program);
2005}
2006mr_free(program);
2007
2008if (res) {
2009 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2010}
2011retval += res;
2012return (retval);
2013}
2014
2015
2016int start_all_raid_devices(struct mountlist_itself *mountlist) {
2017
2018int i;
2019int retval = 0;
2020int res;
2021
2022for (i = 0; i < mountlist->entries; i++) {
2023 if (!strncmp(mountlist->el[i].device, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
2024 log_msg(1, "Starting %s", mountlist->el[i].device);
2025 res = start_raid_device(mountlist->el[i].device);
2026 retval += res;
2027 }
2028}
2029if (retval) {
2030 log_msg(1, "Started all s/w raid devices OK");
2031} else {
2032 log_msg(1, "Failed to start some/all s/w raid devices");
2033}
2034return (retval);
2035}
2036
2037/**
2038 * Stop all software RAID devices listed in @p mountlist.
2039 * @param mountlist The mountlist to stop the RAID devices in.
2040 * @return The number of errors encountered (0 for success).
2041 * @bug @p mountlist is not used.
2042 */
2043int stop_all_raid_devices(struct mountlist_itself *mountlist) {
2044
2045/** int *************************************************************/
2046int retval = 0;
2047
2048/** char ************************************************************/
2049char *incoming;
2050#ifndef __FreeBSD__
2051char *dev;
2052#endif
2053/** pointers ********************************************************/
2054#ifndef __FreeBSD__
2055char *p;
2056#endif
2057FILE *fin;
2058char *q;
2059int i;
2060
2061/** end ****************************************************************/
2062
2063malloc_string(incoming);
2064assert(mountlist != NULL);
2065
2066for (i = 0; i < 3; i++) {
2067#ifdef __FreeBSD__
2068 fin = popen("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2", "r");
2069 if (!fin) {
2070 paranoid_free(incoming);
2071 return (1);
2072 }
2073 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2074 retval += stop_raid_device(incoming);
2075 }
2076#else
2077 fin = fopen("/proc/mdstat", "r");
2078 if (!fin) {
2079 log_OS_error("/proc/mdstat");
2080 paranoid_free(incoming);
2081 return (1);
2082 }
2083 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2084 for (p = incoming; *p != '\0' && (*p != 'm' || *(p + 1) != 'd' || !isdigit(*(p + 2))); p++);
2085 if (*p != '\0') {
2086 malloc_string(dev);
2087 sprintf(dev, "/dev/%s", p);
2088 for (p = dev; *p > 32; p++);
2089 *p = '\0';
2090 retval += stop_raid_device(dev);
2091 paranoid_free(dev);
2092 }
2093 }
2094#endif
2095}
2096paranoid_fclose(fin);
2097if (retval) {
2098 log_msg(1, "Warning - unable to stop some RAID devices");
2099}
2100paranoid_free(incoming);
2101paranoid_system("sync");
2102paranoid_system("sync");
2103paranoid_system("sync");
2104sleep(1);
2105return (retval);
2106}
2107
2108
2109
2110/**
2111 * Decide which command we need to use to format a device of type @p format.
2112 * @param format The filesystem type we are about to format.
2113 * @param program Where to put the binary name for this format.
2114 * @return 0 for success, nonzero for failure.
2115 */
2116char *which_format_command_do_i_need(char *format) {
2117
2118char *program = NULL;
2119
2120assert_string_is_neither_NULL_nor_zerolength(format);
2121
2122if (strcmp(format, "swap") == 0) {
2123#ifdef __FreeBSD__
2124 mr_asprintf(program, "true");
2125#else
2126 mr_asprintf(program, "mkswap");
2127#endif
2128} else if (strcmp(format, "vfat") == 0) {
2129 mr_asprintf(program, "format-and-kludge-vfat");
2130#ifndef __FreeBSD__
2131} else if (strcmp(format, "reiserfs") == 0) {
2132 mr_asprintf(program, "mkreiserfs -ff");
2133} else if (strcmp(format, "xfs") == 0) {
2134 mr_asprintf(program, "mkfs.xfs -f -q");
2135} else if (strcmp(format, "jfs") == 0) {
2136 mr_asprintf(program, "mkfs.jfs");
2137} else if (strcmp(format, "ext3") == 0) {
2138 mr_asprintf(program, "mkfs -t ext3 -F -q");
2139} else if (strcmp(format, "ext4") == 0) {
2140 mr_asprintf(program, "mkfs -t ext4 -F -q");
2141} else if (strcmp(format, "btrfs") == 0) {
2142 mr_asprintf(program, "mkfs.btrfs");
2143} else if (strcmp(format, "minix") == 0) {
2144 mr_asprintf(program, "mkfs.minix");
2145} else if (strcmp(format, "vmfs") == 0) {
2146 mr_asprintf(program, "mkfs -t vmfs");
2147} else if (strcmp(format, "ntfs") == 0) {
2148 /*
2149 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2150 * so the default "mkfs -t %s -c" command structure fails
2151 */
2152 mr_asprintf(program, "mkfs -t ntfs");
2153} else if (strcmp(format, "ocfs2") == 0) {
2154 /*
2155 * 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.
2156 *
2157 */
2158 mr_asprintf(program, "mkfs -t ocfs2 -F");
2159#endif
2160} else if (strcmp(format, "ext2") == 0) {
2161 mr_asprintf(program, "mke2fs -F -q");
2162} else {
2163#ifdef __FreeBSD__
2164 mr_asprintf(program, "newfs_%s", format);
2165#else
2166 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2167#endif
2168 log_it("Unknown format (%s) - assuming '%s' will do", format, program);
2169}
2170return(program);
2171}
2172
2173
2174/**
2175 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2176 * There are a few problems with this function:
2177 * - It won't work if there was any unallocated space on the user's hard drive
2178 * when it was backed up.
2179 * - It won't work if the user's hard drive lies about its size (more common
2180 * than you'd think).
2181 *
2182 * @param mountlist The mountlist to use for resizing @p drive_name.
2183 * @param drive_name The drive to resize.
2184 */
2185void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist, char *drive_name) {
2186
2187/**buffers **********************************************************/
2188char *tmp = NULL;
2189
2190/** int *************************************************************/
2191int partno, lastpart;
2192
2193/** float ***********************************************************/
2194float factor;
2195long long new_size;
2196
2197/** long *************************************************************/
2198long long newsizL = 0LL;
2199long long totalsizL = 0LL;
2200long long current_size_of_drive = 0LL; /* use KB interally for precision */
2201long long original_size_of_drive = 0LL; /* use KB interally for precision */
2202struct mountlist_reference *drivemntlist;
2203
2204/** structures *******************************************************/
2205
2206/** end **************************************************************/
2207
2208assert(mountlist != NULL);
2209assert_string_is_neither_NULL_nor_zerolength(drive_name);
2210
2211if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2212 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2213 == 0) {
2214 return;
2215 }
2216}
2217
2218current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
2219
2220if (current_size_of_drive <= 0LL) {
2221 log_it("Not resizing to match %s - can't find drive", drive_name);
2222 return;
2223}
2224log_to_screen("Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
2225
2226drivemntlist = malloc(sizeof(struct mountlist_reference));
2227drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2228
2229if (!drivemntlist) {
2230 fatal_error("Cannot malloc temporary mountlist\n");
2231}
2232create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2233
2234for (partno = 0; partno < drivemntlist->entries; partno++) {
2235 if (drivemntlist->el[partno]->size > 0LL) {
2236 /* Keep KB here */
2237 original_size_of_drive += drivemntlist->el[partno]->size;
2238 }
2239}
2240
2241if (original_size_of_drive <= 0LL) {
2242 log_to_screen("Cannot resize %s's entries. Drive not found.", drive_name);
2243 return;
2244}
2245factor = ((float)current_size_of_drive/(float)original_size_of_drive);
2246log_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);
2247
2248lastpart = drivemntlist->entries - 1;
2249for (partno = 0; partno < drivemntlist->entries; partno++) {
2250 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2251 if (!atoi(drivemntlist->el[partno]->format)) {
2252 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
2253 } else {
2254 new_size = drivemntlist->el[partno]->size;
2255 }
2256
2257 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2258 log_msg(1, "Skipping %s (%s) because it's an image",
2259 drivemntlist->el[partno]->device,
2260 drivemntlist->el[partno]->mountpoint);
2261 }
2262 newsizL = new_size;
2263
2264 /* Do not apply the factor if partition was of negative size */
2265 if (newsizL < 0LL) {
2266 newsizL = drivemntlist->el[partno]->size;
2267 }
2268 totalsizL += newsizL;
2269
2270 log_to_screen("Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2271 drivemntlist->el[partno]->size = newsizL;
2272}
2273// Ensures over-allocation alert and prompt for interactive mode does not happen
2274if (totalsizL > current_size_of_drive) {
2275 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));
2276 drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive);
2277} else if (totalsizL < current_size_of_drive) {
2278 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));
2279 drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL);
2280}
2281log_to_screen(tmp);
2282mr_free(tmp);
2283log_to_screen("final_size = %lld MB", current_size_of_drive / 1024);
2284}
2285
2286
2287/**
2288 * Resize all partitions in @p mountlist proportionately (each one
2289 * grows or shrinks by the same percentage) to fit them into the new
2290 * drives (presumably different from the old ones).
2291 * @param mountlist The mountlist to resize the drives in.
2292 */
2293void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself *mountlist) {
2294
2295/** buffers *********************************************************/
2296struct list_of_disks *drivelist;
2297
2298/** int *************************************************************/
2299int driveno;
2300
2301/** end *************************************************************/
2302
2303drivelist = malloc(sizeof(struct list_of_disks));
2304assert(mountlist != NULL);
2305
2306if (g_mountlist_fname[0] == '\0') {
2307 log_it("resize_mountlist_prop...() - warning - mountlist fname is blank");
2308 log_it("That does NOT affect the functioning of this subroutine.");
2309 log_it("--- Hugo, 2002/11/20");
2310}
2311log_it("Resizing mountlist");
2312make_list_of_drives_in_mountlist(mountlist, drivelist);
2313log_it("Back from MLoDiM");
2314for (driveno = 0; driveno < drivelist->entries; driveno++) {
2315 resize_drive_proportionately_to_suit_new_drives(mountlist, drivelist->el[driveno].device);
2316}
2317log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2318paranoid_free(drivelist);
2319}
2320
2321/**
2322 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2323 * @param mountlist The complete mountlist to get the drive references from.
2324 * @param drive_name The drive to put in @p drivemntlist.
2325 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2326 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2327 * @author Ralph Grewe
2328 */
2329void create_mountlist_for_drive(struct mountlist_itself *mountlist, char *drive_name, struct mountlist_reference *drivemntlist) {
2330
2331int partno;
2332char *tmp_drive_name, *c;
2333
2334assert(mountlist != NULL);
2335assert(drive_name != NULL);
2336assert(drivemntlist != NULL);
2337
2338log_msg(1, "Creating list of partitions for drive %s", drive_name);
2339
2340tmp_drive_name = strdup(drive_name);
2341if (!tmp_drive_name)
2342 fatal_error("Out of memory");
2343
2344/* devfs devices? */
2345c = strrchr(tmp_drive_name, '/');
2346if (c && strncmp(c, "/disc", 5) == 0) {
2347 /* yup its devfs, change the "disc" to "part" so the existing code works */
2348 strcpy(c + 1, "part");
2349}
2350drivemntlist->entries = 0;
2351for (partno = 0; partno < mountlist->entries; partno++) {
2352 if (strncmp(mountlist->el[partno].device, tmp_drive_name, strlen(tmp_drive_name)) == 0) {
2353 drivemntlist->el[drivemntlist->entries] = &mountlist->el[partno];
2354 drivemntlist->entries++;
2355 }
2356}
2357if (tmp_drive_name)
2358 free(tmp_drive_name);
2359}
2360
2361/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.