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

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

r4626@localhost: bruno | 2012-03-30 16:24:25 +0200

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