source: MondoRescue/branches/2.2.10/mondo/src/mondorestore/mondo-prep.c@ 2299

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