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

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