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

Last change on this file was 3185, checked in by Bruno Cornec, 11 years ago

Simplify the interface of mr_getline and mr_asprintf. With 3.1 compatibility now will allow backports from this branch into 3.0

  • Property svn:keywords set to Id
File size: 77.9 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 3185 2013-09-20 12:29:57Z 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 3185 2013-09-20 12:29:57Z 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 paranoid_system("sync");
113 paranoid_system("sync");
114 paranoid_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 paranoid_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 char *r;
200
201 /** int ***************************************************/
202 int retval = 0;
203 int res = 0;
204 int i;
205 int lvmversion = 1;
206 long extents;
207 fpos_t orig_pos;
208
209 /** pointers **********************************************/
210 FILE *fin;
211
212 /** end *****************************************************/
213
214#ifdef __FreeBSD__
215 return (0);
216#endif
217
218 if (strstr(call_program_and_get_last_line_of_output("cat /proc/cmdline"), "nolvm")) {
219 return(0);
220 }
221 if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) {
222 log_OS_error("/tmp/i-want-my-lvm");
223 return (1);
224 }
225
226 malloc_string(tmp);
227 malloc_string(incoming);
228 malloc_string(lvscan_sz);
229 malloc_string(lvremove_sz);
230 malloc_string(vgscan_sz);
231 malloc_string(pvscan_sz);
232 malloc_string(vgcreate_sz);
233 malloc_string(vgchange_sz);
234 malloc_string(vgremove_sz);
235// malloc_string(do_this_last); // postpone lvcreate call if necessary
236 command = malloc(512);
237
238// do_this_last[0] = '\0';
239 log_it("STARTING");
240 log_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes...");
241 if (find_home_of_exe("lvm")) // found it :) cool
242 {
243 strcpy(lvscan_sz, "lvm lvscan");
244 strcpy(lvremove_sz, "lvm lvremove");
245 strcpy(vgscan_sz, "lvm vgscan");
246 strcpy(pvscan_sz, "lvm pvscan");
247 strcpy(vgcreate_sz, "lvm vgcreate");
248 strcpy(vgchange_sz, "lvm vgchange");
249 strcpy(vgremove_sz, "lvm vgremove -f");
250 } else {
251 strcpy(lvscan_sz, "lvscan");
252 strcpy(lvremove_sz, "lvremove");
253 strcpy(vgscan_sz, "vgscan");
254 strcpy(pvscan_sz, "pvscan");
255 strcpy(vgcreate_sz, "vgcreate");
256 strcpy(vgchange_sz, "vgchange");
257 strcpy(vgremove_sz, "vgremove");
258 }
259 sprintf(command,
260 "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);
261 run_program_and_log_output(command, 5);
262 sleep(1);
263 sprintf(command,
264 "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);
265 run_program_and_log_output(command, 5);
266 if (just_erase_existing_volumes) {
267 paranoid_fclose(fin);
268 log_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs.");
269 retval = 0;
270 goto end_of_i_want_my_lvm;
271 }
272
273 log_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff...");
274 rewind(fin);
275 for (r = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (r != NULL); r = fgets(incoming, MAX_STR_LEN - 1, fin)) {
276 fgetpos(fin, &orig_pos);
277 if (incoming[0] != '#') {
278 continue;
279 }
280 if (res && strstr(command, "create") && vacuum_pack) {
281 sleep(2);
282 paranoid_system("sync");
283 paranoid_system("sync");
284 paranoid_system("sync");
285 }
286 if ((p = strstr(incoming, "vgcreate"))) {
287// include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm)
288 for (q = fgets(tmp, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL); q = fgets(tmp, MAX_STR_LEN - 1, fin)) {
289 if (tmp[0] == '#') {
290 fsetpos(fin, &orig_pos);
291 break;
292 } else {
293 fgetpos(fin, &orig_pos);
294 strcat(incoming, tmp);
295 }
296 }
297 for (q = incoming; *q != '\0'; q++) {
298 if (*q < 32) {
299 *q = ' ';
300 }
301 }
302 strcpy(tmp, p + strlen("vgcreate") + 1);
303 for (q = tmp; *q > 32; q++);
304 *q = '\0';
305 log_msg(1, "Deleting old entries at /dev/%s", tmp);
306// sprintf(command, "%s -f %s", vgremove_sz, tmp);
307// run_program_and_log_output(command, 1);
308 sprintf(command, "rm -Rf /dev/%s", tmp);
309 run_program_and_log_output(command, 1);
310 run_program_and_log_output(vgscan_sz, 1);
311 run_program_and_log_output(pvscan_sz, 1);
312 log_msg(3,
313 "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'",
314 incoming);
315 }
316 for (p = incoming + 1; *p == ' '; p++);
317 strcpy(command, p);
318 for (p = command; *p != '\0'; p++);
319 for (; *(p - 1) < 32; p--);
320 *p = '\0';
321 res = run_program_and_log_output(command, 5);
322 if (res > 0 && (p = strstr(command, "lvm "))) {
323 log_msg(0, "%s --> %d failed so removing lvm just in case", command, res);
324 *p = *(p + 1) = *(p + 2) = ' ';
325 res = run_program_and_log_output(command, 5);
326 }
327 log_msg(0, "%s --> %d", command, res);
328 if (res > 0) {
329 res = 1;
330 }
331 if (res && strstr(command, "lvcreate") && vacuum_pack) {
332 res = 0;
333 if (strstr(command, "lvm lvcreate"))
334 lvmversion = 2;
335 log_it("%s... so I'll get creative.", tmp);
336 if (lvmversion == 2) {
337 mr_asprintf(tmp1, "tail -n5 %s | grep Insufficient | tail -n1", MONDO_LOGFILE);
338 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
339 free(tmp1);
340 } else {
341 mr_asprintf(tmp1, "tail -n5 %s | grep lvcreate | tail -n1", MONDO_LOGFILE);
342 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
343 free(tmp1);
344 }
345 for (p = tmp; *p != '\0' && !isdigit(*p); p++);
346 extents = atol(p);
347 log_msg(5, "p='%s' --> extents=%ld", p, extents);
348 p = strstr(command, "-L");
349 if (!p) {
350 log_msg(0, "Fiddlesticks. '%s' returned %d", command, res);
351 } else {
352 if (lvmversion == 2) {
353 *p++ = '-';
354 *p++ = 'l';
355 *p++ = ' ';
356 for (q = p; *q != ' '; q++) {
357 *q = ' ';
358 }
359 sprintf(p, "%ld", extents);
360 i = strlen(p);
361 *(p + i) = ' ';
362 } else {
363 p++;
364 p++;
365 p++;
366 for (q = p; *q != ' '; q++) {
367 *(q - 1) = ' ';
368 }
369 sprintf(p, "%ld%c", extents, 'm');
370 i = strlen(p);
371 *(p + i) = ' ';
372 }
373 log_msg(5, "Retrying with '%s'", command);
374 res = run_program_and_log_output(command, 5);
375 if (res > 0) {
376 res = 1;
377 }
378 if (g_fprep) {
379 fprintf(g_fprep, "%s\n", command);
380 }
381 log_msg(0, "%s --> %d", command, res);
382 if (!res) {
383 log_msg(5, "YAY! This time, it succeeded.");
384 }
385 }
386 }
387 if (strstr(command, "vgcreate")) {
388 log_msg(0, "In case you're interested...");
389 run_program_and_log_output(vgscan_sz, 1);
390 run_program_and_log_output(pvscan_sz, 1);
391 }
392 if (res != 0 && !strstr(command, "insmod")) {
393 retval++;
394 }
395 sprintf(tmp, "echo \"%s\" >> /tmp/out.sh", command);
396 paranoid_system(tmp);
397 sleep(1);
398 }
399 paranoid_fclose(fin);
400 log_msg(1, "Closed i-want-my-lvm. Finished doing funky stuff.");
401 end_of_i_want_my_lvm:
402 paranoid_free(tmp);
403 paranoid_free(incoming);
404 paranoid_free(command);
405 paranoid_free(lvscan_sz);
406 paranoid_free(lvremove_sz);
407 paranoid_free(vgscan_sz);
408 paranoid_free(pvscan_sz);
409 paranoid_free(vgcreate_sz);
410 paranoid_free(vgchange_sz);
411 paranoid_free(vgremove_sz);
412// paranoid_free(do_this_last);
413 paranoid_system("sync");
414 paranoid_system("sync");
415 paranoid_system("sync");
416 sleep(1);
417 log_it("ENDING");
418 if (retval > 2) {
419 log_msg(1, "%d errors. I'm reporting this.", retval);
420 return (retval);
421 } else {
422 log_msg(1, "Not many errors. Returning 0.");
423 return (0);
424 }
425}
426
427
428/**
429 * Add RAID partitions while copying @p old_mountlist to @p new_mountlist.
430 * We go through @p old_mountlist and check if any RAID device (/dev/md? on Linux)
431 * is in it; if it is, then we put the disks contained within that RAID device
432 * into the mountlist as well.
433 * @param old_mountlist The mountlist to read.
434 * @param new_mountlist The mountlist to write, with the RAID partitions added.
435 * @return 0 for success, nonzero for failure.
436 */
437int extrapolate_mountlist_to_include_raid_partitions(struct mountlist_itself
438 *new_mountlist, struct mountlist_itself
439 *old_mountlist)
440{
441 /** pointers *********************************************************/
442 FILE *fin;
443
444 /** int **************************************************************/
445 int lino;
446 int j;
447
448 /** buffers **********************************************************/
449 char *incoming;
450 char *tmp;
451
452 /** pointers *********************************************************/
453 char *p;
454 char *q;
455
456 /** init *************************************************************/
457 new_mountlist->entries = 0;
458
459 /** end **************************************************************/
460
461 malloc_string(incoming);
462 malloc_string(tmp);
463 assert(new_mountlist != NULL);
464 assert(old_mountlist != NULL);
465
466#ifdef __FreeBSD__
467 log_to_screen
468 ("I don't know how to extrapolate the mountlist on FreeBSD. Sorry.");
469 return (1);
470#endif
471
472 for (lino = 0; lino < old_mountlist->entries; lino++) {
473 if (strstr(old_mountlist->el[lino].device, RAID_DEVICE_STUB)) // raid
474 {
475 if (!does_file_exist("/etc/raidtab")) {
476 log_to_screen
477 ("Cannot find /etc/raidtab - cannot extrapolate the fdisk entries");
478 finish(1);
479 }
480 if (!(fin = fopen("/etc/raidtab", "r"))) {
481 log_OS_error("Cannot open /etc/raidtab");
482 finish(1);
483 }
484 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL)
485 && !strstr(incoming, old_mountlist->el[lino].device);
486 q = fgets(incoming, MAX_STR_LEN - 1, fin));
487 if (!feof(fin)) {
488 sprintf(tmp, "Investigating %s",
489 old_mountlist->el[lino].device);
490 log_it(tmp);
491 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL)
492 && !strstr(incoming, "raiddev");
493 q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
494 if (strstr(incoming, OSSWAP("device", "drive"))
495 && !strchr(incoming, '#')) {
496 for (p = incoming + strlen(incoming);
497 *(p - 1) <= 32; p--);
498 *p = '\0';
499 for (p--; p > incoming && *(p - 1) > 32; p--);
500 sprintf(tmp, "Extrapolating %s", p);
501 log_it(tmp);
502 for (j = 0;
503 j < new_mountlist->entries
504 && strcmp(new_mountlist->el[j].device, p);
505 j++);
506 if (j >= new_mountlist->entries) {
507 strcpy(new_mountlist->
508 el[new_mountlist->entries].device, p);
509 strcpy(new_mountlist->
510 el[new_mountlist->entries].mountpoint,
511 "raid");
512 strcpy(new_mountlist->
513 el[new_mountlist->entries].format,
514 "raid");
515 new_mountlist->el[new_mountlist->entries].
516 size = old_mountlist->el[lino].size;
517 new_mountlist->entries++;
518 } else {
519 sprintf(tmp,
520 "Not adding %s to mountlist: it's already there",
521 p);
522 log_it(tmp);
523 }
524 }
525 }
526 }
527 paranoid_fclose(fin);
528 } else {
529 strcpy(new_mountlist->el[new_mountlist->entries].device,
530 old_mountlist->el[lino].device);
531 strcpy(new_mountlist->el[new_mountlist->entries].mountpoint,
532 old_mountlist->el[lino].mountpoint);
533 strcpy(new_mountlist->el[new_mountlist->entries].format,
534 old_mountlist->el[lino].format);
535 new_mountlist->el[new_mountlist->entries].size =
536 old_mountlist->el[lino].size;
537 new_mountlist->entries++;
538 }
539 }
540 paranoid_free(incoming);
541 paranoid_free(tmp);
542
543 return (0);
544}
545
546
547/**
548 * Create @p RAID device using information from @p structure.
549 * This will create the specified RAID devive using information provided in
550 * raidlist by means of the mdadm tool.
551 * @param raidlist The structure containing all RAID information
552 * @param device The RAID device to create.
553 * @return 0 for success, nonzero for failure.
554 */
555int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device, bool test) {
556 /** int **************************************************************/
557 int i = 0;
558 int j = 0;
559 int v = 0;
560 int res = 0;
561
562 /** buffers ***********************************************************/
563 char *devices = NULL;
564 char *level = NULL;
565 char *program = 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 paranoid_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 paranoid_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 if (fgets(status, MAX_STR_LEN / 4 - 1, pin)) {
806 // FIXME
807 }
808 pclose(pin);
809
810 if (!strcmp(status, "up")) {
811 break; /* it's done */
812 }
813 update_evalcall_form(atoi(status));
814 usleep(250000);
815 }
816 close_evalcall_form();
817 }
818 fclose(fin);
819 unlink("/tmp/plexes");
820 }
821#else
822 mr_asprintf(tmp, "Initializing RAID device %s", device);
823 log_to_screen(tmp);
824 paranoid_free(tmp);
825
826 // Shouldn't be necessary.
827 log_to_screen("Stopping %s", device);
828 stop_raid_device(device);
829 paranoid_system("sync");
830 sleep(1);
831 if (g_fprep) {
832 fprintf(g_fprep, "%s\n", program);
833 }
834
835 log_msg(1, "Making %s", device);
836 // use mkraid if it exists, otherwise use mdadm
837 if (run_program_and_log_output("which mkraid", FALSE)) {
838 res = create_raid_device_via_mdadm(raidlist, device, TRUE);
839 log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
840 } else {
841 sprintf(program, "mkraid --really-force %s", device);
842 res = run_program_and_log_output(program, 1);
843 log_msg(1, "%s returned %d", program, res);
844 paranoid_system("sync");
845 sleep(3);
846 start_raid_device(device);
847 if (g_fprep) {
848 fprintf(g_fprep, "%s\n", program);
849 }
850 }
851 paranoid_system("sync");
852 sleep(2);
853// log_to_screen("Starting %s", device);
854// sprintf(program, "raidstart %s", device);
855// res = run_program_and_log_output(program, 1);
856// log_msg(1, "%s returned %d", program, res);
857// paranoid_system("sync"); sleep(1);
858#endif
859 paranoid_system("sync");
860 sleep(1);
861 newtResume();
862 }
863//#ifndef __FreeBSD__
864//#endif
865
866 if (!strcmp(format, "lvm")) {
867 log_msg(1, "Don't format %s - it's part of an lvm volume", device);
868 paranoid_free(program);
869 paranoid_free(tmp);
870 return (0);
871 }
872 res = which_format_command_do_i_need(format, program);
873 mr_asprintf(tmp, "%s %s", program, device);
874 if (strstr(program, "kludge")) {
875 mr_strcat(tmp, " /");
876 }
877 sprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
878 paranoid_free(tmp);
879
880 mr_asprintf(tmp, "Formatting %s as %s", device, format);
881 update_progress_form(tmp);
882 paranoid_free(tmp);
883
884 res = run_program_and_log_output(program, FALSE);
885 if (res) {
886 mr_strcat(tmp, "...failed");
887 } else {
888 mr_strcat(tmp, "...OK");
889 }
890 log_to_screen(tmp);
891 paranoid_free(tmp);
892
893 if (res && strstr(program, "kludge")) {
894 mr_asprintf(tmp, "Kludge failed; using regular mkfs.%s to format %s",
895 format, device);
896#ifdef __FreeBSD__
897 sprintf(program, "newfs_msdos -F 32 %s", device);
898#else
899#ifdef __IA64__
900 /* For EFI partitions take fat16
901 * as we want to make small ones */
902 sprintf(program, "mkfs -t %s -F 16 %s", format, device);
903#else
904 sprintf(program, "mkfs -t %s -F 32 %s", format, device);
905#endif
906#endif
907 res = run_program_and_log_output(program, FALSE);
908 if (g_fprep) {
909 fprintf(g_fprep, "%s\n", program);
910 }
911 if (retval) {
912 mr_strcat(tmp, "...failed");
913 } else {
914 mr_strcat(tmp, "...OK");
915 }
916
917 log_to_screen(tmp);
918 paranoid_free(tmp);
919
920 }
921 retval += res;
922 paranoid_free(program);
923 paranoid_system("sync");
924 sleep(1);
925 return (retval);
926}
927
928
929
930
931
932/**
933 * Format all drives (except those excluded by format_device()) in @p mountlist.
934 * @param mountlist The mountlist containing partitions to be formatted.
935 * @param interactively If TRUE, then prompt the user before each partition.
936 * @return The number of errors encountered (0 for success).
937 */
938int format_everything(struct mountlist_itself *mountlist, bool interactively,
939 struct raidlist_itself *raidlist)
940{
941 /** int **************************************************************/
942 int retval = 0;
943 int lino;
944 int res;
945// int i;
946// struct list_of_disks *drivelist;
947
948 /** long *************************************************************/
949 long progress_step;
950
951 /** bools ************************************************************/
952 bool do_it;
953
954 /** buffers **********************************************************/
955 char *tmp;
956
957 /** pointers *********************************************************/
958 struct mountlist_line *me; // mountlist entry
959 /** end **************************************************************/
960
961 assert(mountlist != NULL);
962 malloc_string(tmp);
963 sprintf(tmp, "format_everything (mountlist, interactively = %s",
964 (interactively) ? "true" : "false");
965 log_it(tmp);
966 mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
967 open_progress_form("Formatting partitions",
968 "I am now formatting your hard disk partitions.",
969 "This may take up to five minutes.", "",
970 mountlist->entries + 1);
971
972 progress_step =
973 (mountlist->entries >
974 0) ? g_maximum_progress / mountlist->entries : 1;
975// start soft-raids now (because LVM might depend on them)
976// ...and for simplicity's sake, let's format them at the same time :)
977 log_msg(1, "Stopping all RAID devices");
978 stop_all_raid_devices(mountlist);
979 paranoid_system("sync");
980 paranoid_system("sync");
981 paranoid_system("sync");
982 sleep(2);
983 log_msg(1, "Prepare soft-RAIDs"); // prep and format too
984 for (lino = 0; lino < mountlist->entries; lino++) {
985 me = &mountlist->el[lino]; // the current mountlist entry
986 log_msg(2, "Examining %s", me->device);
987 if (!strncmp(me->device, "/dev/md", 7)) {
988 if (interactively) {
989 // ask user if we should format the current device
990 sprintf(tmp, "Shall I format %s (%s) ?", me->device,
991 me->mountpoint);
992 do_it = ask_me_yes_or_no(tmp);
993 } else {
994 do_it = TRUE;
995 }
996 if (do_it) {
997 // NB: format_device() also stops/starts RAID device if necessary
998 retval += format_device(me->device, me->format, raidlist);
999 }
1000 g_current_progress += progress_step;
1001 }
1002 }
1003 paranoid_system("sync");
1004 paranoid_system("sync");
1005 paranoid_system("sync");
1006 sleep(2);
1007// This last step is probably necessary
1008// log_to_screen("Re-starting software RAIDs...");
1009// start_all_raid_devices(mountlist);
1010// paranoid_system("sync"); paranoid_system("sync"); paranoid_system("sync");
1011// sleep(5);
1012// do LVMs now
1013 log_msg(1, "Creating LVMs");
1014 if (does_file_exist("/tmp/i-want-my-lvm")) {
1015 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
1016 log_to_screen("Configuring LVM");
1017 if (!g_text_mode) {
1018 newtSuspend();
1019 }
1020/*
1021 for(i=0; i<3; i++)
1022 {
1023 res = do_my_funky_lvm_stuff(FALSE, FALSE);
1024 if (!res) { break; }
1025 sleep(3);
1026 res = do_my_funky_lvm_stuff(TRUE, FALSE);
1027 sleep(3);
1028 }
1029 if (res) {
1030 log_msg(1, "Vacuum-packing...");
1031*/
1032 res = do_my_funky_lvm_stuff(FALSE, TRUE);
1033/*
1034 }
1035*/
1036 if (!g_text_mode) {
1037 newtResume();
1038 }
1039 if (!res) {
1040 log_to_screen("LVM initialized OK");
1041 } else {
1042 log_to_screen("Failed to initialize LVM");
1043 }
1044 // retval += res;
1045 if (res) {
1046 retval++;
1047 }
1048 sleep(3);
1049 }
1050// do regulars at last
1051 sleep(2); // woo!
1052 log_msg(1, "Formatting regulars");
1053 for (lino = 0; lino < mountlist->entries; lino++) {
1054 me = &mountlist->el[lino]; // the current mountlist entry
1055 if (!strcmp(me->mountpoint, "image")) {
1056 sprintf(tmp, "Not formatting %s - it's an image", me->device);
1057 log_it(tmp);
1058 } else if (!strcmp(me->format, "raid")) {
1059 sprintf(tmp, "Not formatting %s - it's a raid-let",
1060 me->device);
1061 log_it(tmp);
1062 continue;
1063 } else if (!strcmp(me->format, "lvm")) {
1064 sprintf(tmp, "Not formatting %s - it's an LVM", me->device);
1065 log_it(tmp);
1066 continue;
1067 } else if (!strncmp(me->device, "/dev/md", 7)) {
1068 sprintf(tmp, "Already formatted %s - it's a soft-RAID dev",
1069 me->device);
1070 log_it(tmp);
1071 continue;
1072 } else if (!does_file_exist(me->device)
1073 && strncmp(me->device, "/dev/hd", 7)
1074 && strncmp(me->device, "/dev/sd", 7)) {
1075 sprintf(tmp,
1076 "Not formatting %s yet - doesn't exist - probably an LVM",
1077 me->device);
1078 log_it(tmp);
1079 continue;
1080 } else {
1081 if (interactively) {
1082 // ask user if we should format the current device
1083 sprintf(tmp, "Shall I format %s (%s) ?", me->device,
1084 me->mountpoint);
1085 do_it = ask_me_yes_or_no(tmp);
1086 } else {
1087 do_it = TRUE;
1088 }
1089
1090 if (do_it)
1091 retval += format_device(me->device, me->format, raidlist);
1092 }
1093
1094 // update progress bar
1095 g_current_progress += progress_step;
1096 }
1097
1098
1099 // update progress bar to 100% to compensate for
1100 // rounding errors of the progress_step calculation
1101 if (lino >= mountlist->entries)
1102 g_current_progress = g_maximum_progress;
1103
1104 close_progress_form();
1105
1106 if (retval) {
1107 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1108 log_to_screen
1109 ("Errors occurred during the formatting of your hard drives.");
1110 } else {
1111 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1112 }
1113
1114 sprintf(tmp, "format_everything () - %s",
1115 (retval) ? "failed!" : "finished successfully");
1116 log_it(tmp);
1117
1118 if (g_partition_table_locked_up > 0) {
1119 if (retval > 0 && !interactively) {
1120//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
1121 log_to_screen
1122 ("Partition table locked up %d times. At least one 'mkfs' (format) command",
1123 g_partition_table_locked_up);
1124 log_to_screen
1125 ("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
1126 log_to_screen
1127 ("to refresh its copy of the partition table causes the kernel to lock the ");
1128 log_to_screen
1129 ("partition table. I believe this has just happened.");
1130 if (ask_me_yes_or_no
1131 ("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue."))
1132 {
1133 paranoid_system("sync");
1134 paranoid_system("sync");
1135 paranoid_system("sync");
1136 paranoid_system("reboot");
1137 }
1138 } else {
1139 log_to_screen
1140 ("Partition table locked up %d time%c. However, disk formatting succeeded.",
1141 g_partition_table_locked_up,
1142 (g_partition_table_locked_up == 1) ? '.' : 's');
1143 }
1144 }
1145 newtSuspend();
1146 paranoid_system("clear");
1147 newtResume();
1148 paranoid_free(tmp);
1149 return (retval);
1150}
1151
1152
1153/**
1154 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
1155 * Each partition created is 32k in size.
1156 * @param drivename The drive to create the dummy partitions on.
1157 * @param devno_we_must_allow_for The lowest-numbered real partition; create
1158 * dummies up to (this - 1).
1159 * @return The number of errors encountered (0 for success).
1160 */
1161int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename,
1162 int devno_we_must_allow_for)
1163{
1164 /** int **************************************************************/
1165 int current_devno;
1166 int previous_devno;
1167 int retval = 0;
1168 int res;
1169
1170 /** buffers **********************************************************/
1171 char *tmp;
1172
1173 /** end **************************************************************/
1174
1175 malloc_string(tmp);
1176 assert_string_is_neither_NULL_nor_zerolength(drivename);
1177
1178 if (devno_we_must_allow_for >= 5) {
1179 sprintf(tmp, "Making dummy primary 1 on %s", drivename);
1180 log_it(tmp);
1181 g_maximum_progress++;
1182 res =
1183 partition_device(pout_to_fdisk, drivename, 1, 0, "ext2",
1184 32000);
1185 retval += res;
1186 previous_devno = 1;
1187 current_devno = 5;
1188 } else {
1189 previous_devno = 0;
1190 current_devno = 1;
1191 }
1192 for (; current_devno < devno_we_must_allow_for; current_devno++) {
1193 sprintf(tmp, "Creating dummy partition %d on %s", current_devno, drivename);
1194 log_it(tmp);
1195 g_maximum_progress++;
1196 res =
1197 partition_device(pout_to_fdisk, drivename, current_devno,
1198 previous_devno, OSSWAP("ext2", "ufs"), 32000);
1199 retval += res;
1200 previous_devno = current_devno;
1201 }
1202 paranoid_free(tmp);
1203 return (previous_devno);
1204}
1205
1206
1207/**
1208 * Decide whether @p mountlist contains any RAID devices.
1209 * @param mountlist The mountlist to examine.
1210 * @return TRUE if it does, FALSE if it doesn't.
1211 */
1212bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist)
1213{
1214 /** int *************************************************************/
1215 int i;
1216 int matching = 0;
1217
1218 /** end **************************************************************/
1219
1220 assert(mountlist != NULL);
1221
1222 for (i = 0; i < mountlist->entries; i++) {
1223 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1224 matching++;
1225 }
1226 }
1227 if (matching) {
1228 return (TRUE);
1229 } else {
1230 return (FALSE);
1231 }
1232}
1233
1234/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1235#ifdef __FreeBSD__
1236static void display_disklabel(FILE * f, const struct disklabel *lp)
1237{
1238 int i, j;
1239 const struct partition *pp;
1240
1241 fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1242 if (lp->d_type < DKMAXTYPES)
1243 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1244 else
1245 fprintf(f, "type: %u\n", lp->d_type);
1246 fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename),
1247 lp->d_typename);
1248 fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname),
1249 lp->d_packname);
1250 fprintf(f, "flags:");
1251 if (lp->d_flags & D_REMOVABLE)
1252 fprintf(f, " removeable");
1253 if (lp->d_flags & D_ECC)
1254 fprintf(f, " ecc");
1255 if (lp->d_flags & D_BADSECT)
1256 fprintf(f, " badsect");
1257 fprintf(f, "\n");
1258 fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1259 fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1260 fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1261 fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1262 fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1263 fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1264 fprintf(f, "rpm: %u\n", lp->d_rpm);
1265 fprintf(f, "interleave: %u\n", lp->d_interleave);
1266 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1267 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1268 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
1269 (u_long) lp->d_headswitch);
1270 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
1271 (u_long) lp->d_trkseek);
1272 fprintf(f, "drivedata: ");
1273 for (i = NDDATA - 1; i >= 0; i--)
1274 if (lp->d_drivedata[i])
1275 break;
1276 if (i < 0)
1277 i = 0;
1278 for (j = 0; j <= i; j++)
1279 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1280 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1281 fprintf(f,
1282 "# size offset fstype [fsize bsize bps/cpg]\n");
1283 pp = lp->d_partitions;
1284 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1285 if (pp->p_size) {
1286 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size,
1287 (u_long) pp->p_offset);
1288 if (pp->p_fstype < FSMAXTYPES)
1289 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1290 else
1291 fprintf(f, "%8d", pp->p_fstype);
1292 switch (pp->p_fstype) {
1293
1294 case FS_UNUSED: /* XXX */
1295 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1296 (u_long) (pp->p_fsize * pp->p_frag), "");
1297 break;
1298
1299 case FS_BSDFFS:
1300 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize,
1301 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1302 break;
1303
1304 case FS_BSDLFS:
1305 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize,
1306 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1307 break;
1308
1309 default:
1310 fprintf(f, "%20.20s", "");
1311 break;
1312 }
1313 fprintf(f, "\t# (Cyl. %4lu",
1314 (u_long) (pp->p_offset / lp->d_secpercyl));
1315 if (pp->p_offset % lp->d_secpercyl)
1316 putc('*', f);
1317 else
1318 putc(' ', f);
1319 fprintf(f, "- %lu",
1320 (u_long) ((pp->p_offset + pp->p_size +
1321 lp->d_secpercyl - 1) / lp->d_secpercyl -
1322 1));
1323 if (pp->p_size % lp->d_secpercyl)
1324 putc('*', f);
1325 fprintf(f, ")\n");
1326 }
1327 }
1328 fflush(f);
1329}
1330
1331static struct disklabel *get_virgin_disklabel(char *dkname)
1332{
1333 static struct disklabel loclab;
1334 struct partition *dp;
1335 char lnamebuf[BBSIZE];
1336 int f;
1337 u_int secsize, u;
1338 off_t mediasize;
1339
1340 (void) snprintf(lnamebuf, BBSIZE, "%s", dkname);
1341 if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1342 warn("cannot open %s", lnamebuf);
1343 return (NULL);
1344 }
1345
1346 /* New world order */
1347 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1348 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1349 close(f);
1350 return (NULL);
1351 }
1352 memset(&loclab, 0, sizeof loclab);
1353 loclab.d_magic = DISKMAGIC;
1354 loclab.d_magic2 = DISKMAGIC;
1355 loclab.d_secsize = secsize;
1356 loclab.d_secperunit = mediasize / secsize;
1357
1358 /*
1359 * Nobody in these enligthened days uses the CHS geometry for
1360 * anything, but nontheless try to get it right. If we fail
1361 * to get any good ideas from the device, construct something
1362 * which is IBM-PC friendly.
1363 */
1364 if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1365 loclab.d_nsectors = u;
1366 else
1367 loclab.d_nsectors = 63;
1368 if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1369 loclab.d_ntracks = u;
1370 else if (loclab.d_secperunit <= 63 * 1 * 1024)
1371 loclab.d_ntracks = 1;
1372 else if (loclab.d_secperunit <= 63 * 16 * 1024)
1373 loclab.d_ntracks = 16;
1374 else
1375 loclab.d_ntracks = 255;
1376 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1377 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1378 loclab.d_npartitions = MAXPARTITIONS;
1379
1380 /* Various (unneeded) compat stuff */
1381 loclab.d_rpm = 3600;
1382 loclab.d_bbsize = BBSIZE;
1383 loclab.d_interleave = 1;;
1384 strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1385
1386 dp = &loclab.d_partitions[RAW_PART];
1387 dp->p_size = loclab.d_secperunit;
1388 loclab.d_checksum = dkcksum(&loclab);
1389 close(f);
1390 return (&loclab);
1391}
1392
1393/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1394
1395char *canonical_name(char *drivename)
1396{
1397 if (drivename) {
1398 if (strncmp(drivename, "/dev/", 5) == 0) {
1399 return drivename + 5;
1400 }
1401 }
1402 return drivename;
1403}
1404
1405/**
1406 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1407 * @param mountlist The mountlist to get the subpartition information from.
1408 * @param drivename The drive or slice to create a disklabel on.
1409 * @param ret If non-NULL, store the created disklabel here.
1410 * @return The number of errors encountered (0 for success).
1411 */
1412int label_drive_or_slice(struct mountlist_itself *mountlist,
1413 char *drivename, struct disklabel *ret)
1414{
1415 char subdev_str[MAX_STR_LEN];
1416 char command[MAX_STR_LEN];
1417 struct disklabel *lp;
1418 int i, lo = 0;
1419 int retval = 0;
1420 char c;
1421 FILE *ftmp;
1422
1423 lp = get_virgin_disklabel(drivename);
1424 for (c = 'a'; c <= 'z'; ++c) {
1425 int idx;
1426 sprintf(subdev_str, "%s%c", drivename, c);
1427 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1428 lp->d_partitions[c - 'a'].p_size = 0;
1429 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1430 } else {
1431 lo = c - 'a';
1432 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1433 lp->d_partitions[c - 'a'].p_fsize = 0;
1434 lp->d_partitions[c - 'a'].p_frag = 0;
1435 lp->d_partitions[c - 'a'].p_cpg = 0;
1436 if (!strcmp(mountlist->el[idx].format, "ufs")
1437 || !strcmp(mountlist->el[idx].format, "ffs")
1438 || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1439 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1440 lp->d_partitions[c - 'a'].p_fsize = 2048;
1441 lp->d_partitions[c - 'a'].p_frag = 8;
1442 lp->d_partitions[c - 'a'].p_cpg = 64;
1443 } else if (!strcasecmp(mountlist->el[idx].format, "raid")
1444 || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1445 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1446 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1447 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1448 } else
1449 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1450 }
1451 }
1452
1453 // fix up the offsets
1454 lp->d_partitions[0].p_offset = 0;
1455 lp->d_partitions[RAW_PART].p_offset = 0;
1456 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1457 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1458
1459 for (i = 1; i < lp->d_npartitions; ++i) {
1460 int lastone;
1461 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1462 continue;
1463 for (lastone = i - 1; lastone >= 0; lastone--) {
1464 if ((lp->d_partitions[lastone].p_size)
1465 && (lastone != RAW_PART))
1466 break;
1467 }
1468 lp->d_partitions[i].p_offset =
1469 lp->d_partitions[lastone].p_offset +
1470 lp->d_partitions[lastone].p_size;
1471 }
1472 if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size >
1473 lp->d_secperunit) {
1474 lp->d_partitions[lo].p_size =
1475 lp->d_secperunit - lp->d_partitions[lo].p_offset;
1476 }
1477
1478 ftmp = fopen("/tmp/disklabel", "w");
1479 display_disklabel(ftmp, lp);
1480 fclose(ftmp);
1481 sprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1482 retval += run_program_and_log_output(command, TRUE);
1483 sprintf(command, "disklabel -R %s /tmp/disklabel",
1484 canonical_name(drivename));
1485 retval += run_program_and_log_output(command, TRUE);
1486 if (ret)
1487 *ret = *lp;
1488 return retval;
1489}
1490#endif
1491
1492
1493/**
1494 * Partition @p drivename based on @p mountlist.
1495 * @param mountlist The mountlist to use to guide the partitioning.
1496 * @param drivename The drive to partition.
1497 * @return 0 for success, nonzero for failure.
1498 */
1499int partition_drive(struct mountlist_itself *mountlist, char *drivename)
1500{
1501 /** int *************************************************************/
1502 int current_devno;
1503 int previous_devno = 0;
1504 int lino;
1505 int retval = 0;
1506 int i;
1507 FILE *pout_to_fdisk = NULL;
1508
1509#ifdef __FreeBSD__
1510 bool fbsd_part = FALSE;
1511 char subdev_str[MAX_STR_LEN];
1512#endif
1513
1514 /** long long *******************************************************/
1515 long long partsize;
1516
1517 /** buffers *********************************************************/
1518 char *device_str;
1519 char *format;
1520 char *tmp;
1521 char *tmp1 = NULL;
1522
1523 /** end *************************************************************/
1524
1525 assert(mountlist != NULL);
1526 assert_string_is_neither_NULL_nor_zerolength(drivename);
1527
1528 malloc_string(device_str);
1529 malloc_string(format);
1530 malloc_string(tmp);
1531
1532 sprintf(tmp, "Partitioning drive %s", drivename);
1533 log_it(tmp);
1534
1535#if __FreeBSD__
1536 log_it("(Not opening fdisk now; that's the Linux guy's job)");
1537 pout_to_fdisk = NULL;
1538#else
1539 make_hole_for_file(FDISK_LOG);
1540 sprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1541 pout_to_fdisk = popen(tmp, "w");
1542 if (!pout_to_fdisk) {
1543 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
1544 paranoid_free(device_str);
1545 paranoid_free(format);
1546 paranoid_free(tmp);
1547 return (1);
1548 }
1549#endif
1550 for (current_devno = 1; current_devno < 99; current_devno++) {
1551 build_partition_name(device_str, drivename, current_devno);
1552 lino = find_device_in_mountlist(mountlist, device_str);
1553
1554 if (lino < 0) {
1555 // device not found in mountlist
1556#if __FreeBSD__
1557 // If this is the first partition (just as a sentinel value),
1558 // then see if the user has picked 'dangerously-dedicated' mode.
1559 // If so, then we just call label_drive_or_slice() and return.
1560 char c;
1561 if (current_devno == 1) {
1562 // try DangerouslyDedicated mode
1563 for (c = 'a'; c <= 'z'; c++) {
1564 sprintf(subdev_str, "%s%c", drivename, c);
1565 if (find_device_in_mountlist(mountlist, subdev_str) >
1566 0) {
1567 fbsd_part = TRUE;
1568 }
1569 }
1570 if (fbsd_part) {
1571 int r = label_drive_or_slice(mountlist,
1572 drivename,
1573 0);
1574 char command[MAX_STR_LEN];
1575 sprintf(command, "disklabel -B %s",
1576 basename(drivename));
1577 if (system(command)) {
1578 log_to_screen
1579 ("Warning! Unable to make the drive bootable.");
1580 }
1581 paranoid_free(device_str);
1582 paranoid_free(format);
1583 paranoid_free(tmp);
1584 return r;
1585 }
1586 }
1587 for (c = 'a'; c <= 'z'; c++) {
1588 sprintf(subdev_str, "%s%c", device_str, c);
1589 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1590 fbsd_part = TRUE;
1591 }
1592 }
1593 // Now we check the subpartitions of the current partition.
1594 if (fbsd_part) {
1595 int i, line;
1596
1597 strcpy(format, "ufs");
1598 partsize = 0;
1599 for (i = 'a'; i < 'z'; ++i) {
1600 sprintf(subdev_str, "%s%c", device_str, i);
1601 line = find_device_in_mountlist(mountlist, subdev_str);
1602 if (line > 0) {
1603 // We found one! Add its size to the total size.
1604 partsize += mountlist->el[line].size;
1605 }
1606 }
1607 } else {
1608 continue;
1609 }
1610#else
1611 continue;
1612#endif
1613 }
1614
1615 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1616 /* For FreeBSD, that is /dev/adXsY */
1617
1618 log_it("Found partition %s in mountlist", device_str);
1619 if (!previous_devno) {
1620
1621 log_it("Wiping %s's partition table", drivename);
1622#if __FreeBSD__
1623 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1624// sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1625// if (run_program_and_log_output(tmp, TRUE)) {
1626 file = open(drivename, O_WRONLY);
1627 if (file != -1) {
1628 sprintf(tmp,
1629 "Warning - unable to open %s for wiping it's partition table",
1630 drivename);
1631 log_to_screen(tmp);
1632 }
1633
1634 for (i = 0; i < 512; i++) {
1635 if (!write(file, "\0", 1)) {
1636 sprintf(tmp, "Warning - unable to write to %s",
1637 drivename);
1638 log_to_screen(tmp);
1639 }
1640 }
1641 paranoid_system("sync");
1642#else
1643 log_it("New, kernel-friendly partition remover");
1644 for (i = 20; i > 0; i--) {
1645 fprintf(pout_to_fdisk, "d\n%d\n", i);
1646 fflush(pout_to_fdisk);
1647 }
1648// sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1649// run_program_and_log_output(tmp, 1);
1650#endif
1651 if (current_devno > 1) {
1652 previous_devno =
1653 make_dummy_partitions(pout_to_fdisk, drivename,
1654 current_devno);
1655 }
1656 }
1657#ifdef __FreeBSD__
1658 if (!fbsd_part) {
1659#endif
1660
1661 strcpy(format, mountlist->el[lino].format);
1662 partsize = mountlist->el[lino].size;
1663
1664#ifdef __FreeBSD__
1665 }
1666#endif
1667
1668#ifndef __IA64__
1669 if (current_devno == 5 && previous_devno == 4) {
1670 log_to_screen
1671 ("You must leave at least one partition spare as the Extended partition.");
1672 paranoid_free(device_str);
1673 paranoid_free(format);
1674 paranoid_free(tmp);
1675 return (1);
1676 }
1677#endif
1678
1679 retval +=
1680 partition_device(pout_to_fdisk, drivename, current_devno,
1681 previous_devno, format, partsize);
1682
1683#ifdef __FreeBSD__
1684 if ((current_devno <= 4) && fbsd_part) {
1685 sprintf(tmp, "disklabel -B %s", basename(device_str));
1686 retval += label_drive_or_slice(mountlist, device_str, 0);
1687 if (system(tmp)) {
1688 log_to_screen
1689 ("Warning! Unable to make the slice bootable.");
1690 }
1691 }
1692#endif
1693
1694 previous_devno = current_devno;
1695 }
1696
1697 if (pout_to_fdisk) {
1698 // close fdisk
1699 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
1700 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1701 paranoid_pclose(pout_to_fdisk);
1702 paranoid_system("sync");
1703 log_msg(0,"------------------- fdisk.log looks like this ------------------");
1704 sprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1705 paranoid_system(tmp);
1706 // mark relevant partition as bootable
1707 mr_asprintf(tmp1,"make-me-bootable /tmp/mountlist.txt %s",drivename);
1708 call_program_and_get_last_line_of_output(tmp1);
1709 mr_free(tmp1);
1710 log_msg(0,"------------------- end of fdisk.log... ------------------");
1711 paranoid_system("sync");
1712 sprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1713 if (!run_program_and_log_output(tmp, 5)) {
1714 g_partition_table_locked_up++;
1715 }
1716 sprintf(tmp, "partprobe %s", drivename);
1717 if (!run_program_and_log_output(tmp, 5)) {
1718 g_partition_table_locked_up--;
1719 }
1720 if (g_partition_table_locked_up > 0) {
1721 log_to_screen
1722 ("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
1723 }
1724 }
1725 paranoid_free(device_str);
1726 paranoid_free(format);
1727 paranoid_free(tmp);
1728 return (retval);
1729}
1730
1731/**
1732 * Create partition number @p partno on @p drive with @p fdisk.
1733 * @param drive The drive to create the partition on.
1734// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1735 * @param prev_partno The partition number of the most recently prepped partition.
1736 * @param format The filesystem type of this partition (used to set the type).
1737 * @param partsize The size of the partition in @e bytes.
1738 * @return 0 for success, nonzero for failure.
1739 */
1740int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1741 int prev_partno, const char *format,
1742 long long partsize)
1743{
1744 /** int **************************************************************/
1745 int retval = 0;
1746 int res = 0;
1747
1748 /** buffers **********************************************************/
1749 char *program;
1750 char *partition_name;
1751 char *tmp;
1752 char *logfile;
1753 char *output = NULL;
1754
1755 /** pointers **********************************************************/
1756 char *p;
1757 char *part_table_fmt;
1758 FILE *fout;
1759
1760 /** end ***************************************************************/
1761
1762 malloc_string(program);
1763 malloc_string(partition_name);
1764 malloc_string(tmp);
1765 malloc_string(logfile);
1766
1767 assert_string_is_neither_NULL_nor_zerolength(drive);
1768 assert(format != NULL);
1769
1770 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1771 drive, partno, prev_partno, format, partsize);
1772
1773 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1774 sprintf(tmp, "Not partitioning %s - it is a virtual drive", drive);
1775 log_it(tmp);
1776 paranoid_free(program);
1777 paranoid_free(partition_name);
1778 paranoid_free(tmp);
1779 paranoid_free(logfile);
1780 return (0);
1781 }
1782 build_partition_name(partition_name, drive, partno);
1783 if (partsize <= 0) {
1784 sprintf(tmp, "Partitioning device %s (max size)", partition_name);
1785 } else {
1786 sprintf(tmp, "Partitioning device %s (%lld MB)", partition_name,
1787 (long long) partsize / 1024);
1788 }
1789 update_progress_form(tmp);
1790 log_it(tmp);
1791
1792 if (is_this_device_mounted(partition_name)) {
1793 sprintf(tmp, "%s is mounted, and should not be partitioned",
1794 partition_name);
1795 log_to_screen(tmp);
1796 paranoid_free(program);
1797 paranoid_free(partition_name);
1798 paranoid_free(tmp);
1799 paranoid_free(logfile);
1800 return (1);
1801/*
1802 } else if (does_partition_exist(drive, partno)) {
1803 sprintf(tmp, "%s already has a partition", partition_name);
1804 log_to_screen(tmp);
1805 return (1);
1806*/
1807 }
1808
1809
1810 /* sprintf(tmp,"Partitioning %s ",partition_name); */
1811 /* mvaddstr_and_log_it(g_currentY+1,30,tmp); */
1812 p = (char *) strrchr(partition_name, '/');
1813 sprintf(logfile, "/tmp/fdisk.log.%s", ++p);
1814 sprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE,
1815 MONDO_LOGFILE);
1816
1817 /* BERLIOS: should not be called each time */
1818 part_table_fmt = which_partition_format(drive);
1819 mr_asprintf(output, "");
1820 /* make it a primary/extended/logical */
1821 if (partno <= 4) {
1822 mr_strcat(output, "n\np\n%d\n", partno);
1823 } else {
1824 /* MBR needs an extended partition if more than 4 partitions */
1825 if (strcmp(part_table_fmt, "MBR") == 0) {
1826 if (partno == 5) {
1827 if (prev_partno >= 4) {
1828 log_to_screen
1829 ("You need to leave at least one partition free, for 'extended/logical'");
1830 paranoid_free(program);
1831 paranoid_free(partition_name);
1832 paranoid_free(tmp);
1833 paranoid_free(logfile);
1834 paranoid_free(output);
1835 return (1);
1836 } else {
1837 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
1838 }
1839 }
1840 mr_strcat(output, "n\nl\n");
1841 } else {
1842 /* GPT allows more than 4 primary partitions */
1843 mr_strcat(output, "n\np\n%d\n", partno);
1844 }
1845 }
1846 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1847 if (partsize > 0) {
1848 if (!strcmp(format, "7")) {
1849 log_msg(1, "Adding 512K, just in case");
1850 partsize += 512;
1851 }
1852 mr_strcat(output, "+%lldK", (long long) (partsize));
1853 }
1854 mr_strcat(output, "\n");
1855#if 0
1856/*
1857#endif
1858 sprintf(tmp,"PARTSIZE = +%ld",(long)partsize);
1859 log_it(tmp);
1860 log_it("---fdisk command---");
1861 log_it(output);
1862 log_it("---end of fdisk---");
1863#if 0
1864*/
1865#endif
1866
1867
1868 if (pout_to_fdisk) {
1869 log_msg(1, "Doing the new all-in-one fdisk thing");
1870 log_msg(1, "output = '%s'", output);
1871 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1872 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1873 strcpy(tmp, last_line_of_file(FDISK_LOG));
1874 if (strstr(tmp, " (m ")) {
1875 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1876 } else {
1877 log_msg(1, "last line = %s", tmp);
1878 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1879 }
1880 if (!retval) {
1881 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1882 retval =
1883 set_partition_type(pout_to_fdisk, drive, partno, format,
1884 partsize);
1885 if (retval) {
1886 log_msg(1, "Failed. Trying again...");
1887 retval =
1888 set_partition_type(pout_to_fdisk, drive, partno,
1889 format, partsize);
1890 }
1891 }
1892 if (retval) {
1893 log_msg(1, "...but failed to set type");
1894 }
1895 } else {
1896 mr_strcat(output, "w\n\n");
1897 if (g_fprep) {
1898 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1899 }
1900 /* write to disk; close fdisk's stream */
1901 if (!(fout = popen(program, "w"))) {
1902 log_OS_error("can't popen-out to program");
1903 } else {
1904 fputs(output, fout);
1905 paranoid_pclose(fout);
1906 }
1907 if (!does_partition_exist(drive, partno) && partsize > 0) {
1908 log_it("Vaccum-packing");
1909 g_current_progress--;
1910 res =
1911 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1912 format, -1);
1913 if (res) {
1914 sprintf(tmp, "Failed to vacuum-pack %s", partition_name);
1915 log_it(tmp);
1916 retval++;
1917 } else {
1918 retval = 0;
1919 }
1920 }
1921 if (does_partition_exist(drive, partno)) {
1922 retval =
1923 set_partition_type(pout_to_fdisk, drive, partno, format,
1924 partsize);
1925 if (retval) {
1926 sprintf(tmp, "Partitioned %s but failed to set its type",
1927 partition_name);
1928 log_it(tmp);
1929 } else {
1930 if (partsize > 0) {
1931 sprintf(tmp, "Partition %s created+configured OK",
1932 partition_name);
1933 log_to_screen(tmp);
1934 } else {
1935 log_it("Returning from a successful vacuum-pack");
1936 }
1937 }
1938 } else {
1939 sprintf(tmp, "Failed to partition %s", partition_name);
1940 if (partsize > 0) {
1941 log_to_screen(tmp);
1942 } else {
1943 log_it(tmp);
1944 }
1945 retval++;
1946 }
1947 }
1948 paranoid_free(output);
1949
1950 g_current_progress++;
1951 log_it("partition_device() --- leaving");
1952 paranoid_free(program);
1953 paranoid_free(partition_name);
1954 paranoid_free(tmp);
1955 paranoid_free(logfile);
1956 return (retval);
1957}
1958
1959
1960
1961/**
1962 * Create all partitions listed in @p mountlist.
1963 * @param mountlist The mountlist to use to guide the partitioning.
1964 * @return The number of errors encountered (0 for success).
1965 * @note This sets the partition types but doesn't actually do the formatting.
1966 * Use format_everything() for that.
1967 */
1968int partition_everything(struct mountlist_itself *mountlist)
1969{
1970 /** int ************************************************************/
1971 int lino;
1972 int retval = 0;
1973 int i;
1974 int res;
1975
1976 /** buffer *********************************************************/
1977 struct list_of_disks *drivelist;
1978 /* struct mountlist_itself new_mtlist, *mountlist; */
1979
1980 /** end ************************************************************/
1981
1982 drivelist = malloc(sizeof(struct list_of_disks));
1983 assert(mountlist != NULL);
1984
1985 log_it("partition_everything() --- starting");
1986 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1987 /* mountlist=orig_mtlist; */
1988 if (mountlist_contains_raid_devices(mountlist)) {
1989 /* mountlist=&new_mtlist; */
1990 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1991 log_msg(0,
1992 "Mountlist, including the partitions incorporated in RAID devices:-");
1993 for (i = 0; i < mountlist->entries; i++) {
1994 log_it(mountlist->el[i].device);
1995 }
1996 log_msg(0, "End of mountlist.");
1997 }
1998 log_msg(0, "Stopping all LVMs, just in case");
1999 if (!g_text_mode) {
2000 newtSuspend();
2001 }
2002 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
2003 if (!g_text_mode) {
2004 newtResume();
2005 }
2006 log_msg(0, "Stopping all software RAID devices, just in case");
2007 stop_all_raid_devices(mountlist);
2008 log_msg(0, "Done.");
2009
2010/*
2011 if (does_file_exist("/tmp/i-want-my-lvm"))
2012 {
2013 wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
2014 }
2015*/
2016
2017 open_progress_form("Partitioning devices",
2018 "I am now going to partition all your drives.",
2019 "This should not take more than five minutes.", "",
2020 mountlist->entries);
2021
2022 make_list_of_drives_in_mountlist(mountlist, drivelist);
2023
2024 /* partition each drive */
2025 for (lino = 0; lino < drivelist->entries; lino++) {
2026 res = partition_drive(mountlist, drivelist->el[lino].device);
2027 retval += res;
2028 }
2029 close_progress_form();
2030 if (retval) {
2031 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
2032 log_to_screen
2033 ("Errors occurred during the partitioning of your hard drives.");
2034 } else {
2035 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2036 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
2037 }
2038 newtSuspend();
2039 paranoid_system("clear");
2040 newtResume();
2041 paranoid_free(drivelist);
2042 return (retval);
2043}
2044
2045
2046
2047
2048
2049
2050/**
2051 * Set the type of partition number @p partno on @p drive to @p format.
2052 * @param drive The drive to change the type of a partition on.
2053 * @param partno The partition number on @p drive to change the type of.
2054 * @param format The filesystem type this partition will eventually contain.
2055 * @param partsize The size of this partition, in @e bytes (used for vfat
2056 * type calculations).
2057 * @return 0 for success, nonzero for failure.
2058 */
2059int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
2060 const char *format, long long partsize)
2061{
2062 /** buffers *********************************************************/
2063 char *partition;
2064 char *command;
2065 char *output = NULL;
2066 char *tmp;
2067 char *partcode;
2068 char *logfile;
2069
2070 /** pointers *********************************************************/
2071 char *p;
2072 FILE *fout;
2073
2074 /** int **************************************************************/
2075 int res = 0;
2076
2077 /** end **************************************************************/
2078
2079 assert_string_is_neither_NULL_nor_zerolength(drive);
2080 assert(format != NULL);
2081
2082 malloc_string(partition);
2083 malloc_string(command);
2084 malloc_string(tmp);
2085 malloc_string(partcode);
2086 malloc_string(logfile);
2087
2088 build_partition_name(partition, drive, partno);
2089 p = (char *) strrchr(partition, '/');
2090 sprintf(logfile, "/tmp/fdisk-set-type.%s.log", ++p);
2091 if (strcmp(format, "swap") == 0) {
2092 strcpy(partcode, "82");
2093 } else if (strcmp(format, "vfat") == 0) {
2094 if (partsize / 1024 > 8192) {
2095 strcpy(partcode, "c");
2096 } else {
2097 strcpy(partcode, "b");
2098 }
2099 } else if (strcmp(format, "ext2") == 0
2100 || strcmp(format, "reiserfs") == 0
2101 || strcmp(format, "ext3") == 0
2102 || strcmp(format, "ext4") == 0
2103 || strcmp(format, "xfs") == 0
2104 || strcmp(format, "jfs") == 0
2105 || strcmp(format, "btrfs") == 0) {
2106 strcpy(partcode, "83");
2107 } else if (strcmp(format, "minix") == 0) {
2108 strcpy(partcode, "81");
2109 } else if (strcmp(format, "vmfs3") == 0) {
2110 strcpy(partcode, "fb");
2111 } else if (strcmp(format, "vmkcore") == 0) {
2112 strcpy(partcode, "fc");
2113 } else if (strcmp(format, "raid") == 0) {
2114 strcpy(partcode, "fd");
2115 } else if (strcmp(format, "ntfs") == 0) {
2116 strcpy(partcode, "7");
2117 } else if ((strcmp(format, "ufs") == 0)
2118 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
2119 strcpy(partcode, "a5");
2120 } else if (strcmp(format, "lvm") == 0) {
2121 strcpy(partcode, "8e");
2122 } else if (format[0] == '\0') { /* LVM physical partition */
2123 partcode[0] = '\0';
2124 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
2125 strcpy(partcode, format);
2126 } else {
2127 /* probably an image */
2128 sprintf(tmp,
2129 "Unknown format ('%s') - using supplied string anyway",
2130 format);
2131 mvaddstr_and_log_it(g_currentY++, 0, tmp);
2132#ifdef __FreeBSD__
2133 strcpy(partcode, format); // was a5
2134#else
2135 strcpy(partcode, format); // was 83
2136#endif
2137 }
2138 sprintf(tmp, "Setting %s's type to %s (%s)", partition, format,
2139 partcode);
2140 log_msg(1, tmp);
2141 if (partcode[0] != '\0' && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
2142
2143 if (pout_to_fdisk) {
2144 res = 0;
2145 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
2146 if (partno > 1
2147 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
2148 log_msg(5, "Specifying partno (%d) - yay", partno);
2149 sprintf(tmp, "%d\n", partno);
2150 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2151 log_msg(5, "A - last line = '%s'",
2152 last_line_of_file(FDISK_LOG));
2153 }
2154
2155 sprintf(tmp, "%s\n", partcode);
2156 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2157 log_msg(5, "B - last line = '%s'",
2158 last_line_of_file(FDISK_LOG));
2159 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2160 log_msg(5, "C - last line = '%s'",
2161 last_line_of_file(FDISK_LOG));
2162
2163 strcpy(tmp, last_line_of_file(FDISK_LOG));
2164 if (!strstr(tmp, " (m ")) {
2165 log_msg(1, "last line = '%s'; part type set failed", tmp);
2166 res++;
2167 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2168 }
2169 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2170 } else {
2171 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
2172 sprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2173 MONDO_LOGFILE, MONDO_LOGFILE);
2174 log_msg(5, "output = '%s'", output);
2175 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2176 log_msg(5, "command = '%s'", command);
2177 fout = popen(command, "w");
2178 if (!fout) {
2179 log_OS_error(command);
2180 res = 1;
2181 } else {
2182 res = 0;
2183 fprintf(fout, "%s", output);
2184 paranoid_pclose(fout);
2185 }
2186 paranoid_free(output);
2187 }
2188 if (res) {
2189 log_OS_error(command);
2190 }
2191 }
2192
2193 paranoid_free(partition);
2194 paranoid_free(command);
2195 paranoid_free(tmp);
2196 paranoid_free(partcode);
2197 paranoid_free(logfile);
2198
2199 return (res);
2200}
2201
2202
2203int start_raid_device(char *raid_device)
2204{
2205 /** int *************************************************************/
2206 int res;
2207 int retval = 0;
2208
2209 /** buffers *********************************************************/
2210 char *program;
2211
2212 /** end *************************************************************/
2213
2214 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2215 malloc_string(program);
2216
2217#ifdef __FreeBSD__
2218 if (is_this_device_mounted(raid_device)) {
2219 log_it("Can't start %s when it's mounted!", raid_device);
2220 return 1;
2221 }
2222 sprintf(program, "vinum start -f %s", raid_device);
2223#else
2224 sprintf(program, "raidstart %s", raid_device);
2225#endif
2226 log_msg(1, "program = %s", program);
2227 res = run_program_and_log_output(program, 1);
2228 if (g_fprep) {
2229 fprintf(g_fprep, "%s\n", program);
2230 }
2231 if (res) {
2232 log_msg(1, "Warning - failed to start RAID device %s",
2233 raid_device);
2234 }
2235 retval += res;
2236 sleep(1);
2237 return (retval);
2238}
2239
2240
2241
2242/**
2243 * Stop @p raid_device using @p raidstop.
2244 * @param raid_device The software RAID device to stop.
2245 * @return 0 for success, nonzero for failure.
2246 */
2247int stop_raid_device(char *raid_device)
2248{
2249 /** int *************************************************************/
2250 int res;
2251 int retval = 0;
2252
2253 /** buffers *********************************************************/
2254 char *program;
2255
2256 /** end *************************************************************/
2257
2258 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2259 malloc_string(program);
2260
2261#ifdef __FreeBSD__
2262 if (is_this_device_mounted(raid_device)) {
2263 log_it("Can't stop %s when it's mounted!", raid_device);
2264 return 1;
2265 }
2266 sprintf(program, "vinum stop -f %s", raid_device);
2267#else
2268 // use raidstop if it exists, otherwise use mdadm
2269 if (run_program_and_log_output("which raidstop", FALSE)) {
2270 sprintf(program, "mdadm -S %s", raid_device);
2271 } else {
2272 sprintf(program, "raidstop %s", raid_device);
2273 }
2274#endif
2275 log_msg(1, "program = %s", program);
2276 res = run_program_and_log_output(program, 1);
2277 if (g_fprep) {
2278 fprintf(g_fprep, "%s\n", program);
2279 }
2280 if (res) {
2281 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2282 }
2283 retval += res;
2284 return (retval);
2285}
2286
2287
2288int start_all_raid_devices(struct mountlist_itself *mountlist)
2289{
2290 int i;
2291 int retval = 0;
2292 int res;
2293
2294 for (i = 0; i < mountlist->entries; i++) {
2295 if (!strncmp
2296 (mountlist->el[i].device, RAID_DEVICE_STUB,
2297 strlen(RAID_DEVICE_STUB))) {
2298 log_msg(1, "Starting %s", mountlist->el[i].device);
2299 res = start_raid_device(mountlist->el[i].device);
2300 retval += res;
2301 }
2302 }
2303 if (retval) {
2304 log_msg(1, "Started all s/w raid devices OK");
2305 } else {
2306 log_msg(1, "Failed to start some/all s/w raid devices");
2307 }
2308 return (retval);
2309}
2310
2311/**
2312 * Stop all software RAID devices listed in @p mountlist.
2313 * @param mountlist The mountlist to stop the RAID devices in.
2314 * @return The number of errors encountered (0 for success).
2315 * @bug @p mountlist is not used.
2316 */
2317int stop_all_raid_devices(struct mountlist_itself *mountlist)
2318{
2319 /** int *************************************************************/
2320 int retval = 0;
2321
2322 /** char ************************************************************/
2323 char *incoming;
2324#ifndef __FreeBSD__
2325 char *dev;
2326#endif
2327 /** pointers ********************************************************/
2328#ifndef __FreeBSD__
2329 char *p;
2330#endif
2331 FILE *fin;
2332 char *q;
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 (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL);
2353 q = 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 (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL);
2365 q = 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 retval += 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 paranoid_system("sync");
2385 paranoid_system("sync");
2386 paranoid_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.