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

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