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

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