source: MondoRescue/branches/3.0/mondo/src/mondorestore/mondo-prep.c@ 2985

Last change on this file since 2985 was 2985, checked in by Bruno Cornec, 12 years ago

r4608@localhost: bruno | 2012-03-29 20:28:19 +0200

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