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

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