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

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

r4607@localhost: bruno | 2012-03-29 16:54:35 +0200

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