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

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