source: MondoRescue/branches/3.2/mondo/src/mondorestore/mondo-prep.c@ 3263

Last change on this file since 3263 was 3263, checked in by Bruno Cornec, 10 years ago
  • Fix a bug due to lack of memory allocation for a tmp var to display
  • Fix another bug in the call to labeling which used a bad variable
  • Property svn:keywords set to Id
File size: 77.9 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 3263 2014-04-22 09:06:38Z 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 3263 2014-04-22 09:06:38Z 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 = NULL;
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_free(part_table_fmt);
1847
1848 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
1849 if (partsize > 0) {
1850 if (!strcmp(format, "7")) {
1851 log_msg(1, "Adding 512K, just in case");
1852 partsize += 512;
1853 }
1854 mr_strcat(output, "+%lldK", (long long) (partsize));
1855 }
1856 mr_strcat(output, "\n");
1857#if 0
1858/*
1859#endif
1860 sprintf(tmp,"PARTSIZE = +%ld",(long)partsize);
1861 log_it(tmp);
1862 log_it("---fdisk command---");
1863 log_it(output);
1864 log_it("---end of fdisk---");
1865#if 0
1866*/
1867#endif
1868
1869
1870 if (pout_to_fdisk) {
1871 log_msg(1, "Doing the new all-in-one fdisk thing");
1872 log_msg(1, "output = '%s'", output);
1873 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1874 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1875 strcpy(tmp, last_line_of_file(FDISK_LOG));
1876 if (strstr(tmp, " (m ")) {
1877 log_msg(1, "Successfully created partition %d on %s", partno, drive);
1878 } else {
1879 log_msg(1, "last line = %s", tmp);
1880 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
1881 }
1882 if (!retval) {
1883 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
1884 retval =
1885 set_partition_type(pout_to_fdisk, drive, partno, format,
1886 partsize);
1887 if (retval) {
1888 log_msg(1, "Failed. Trying again...");
1889 retval =
1890 set_partition_type(pout_to_fdisk, drive, partno,
1891 format, partsize);
1892 }
1893 }
1894 if (retval) {
1895 log_msg(1, "...but failed to set type");
1896 }
1897 } else {
1898 mr_strcat(output, "w\n\n");
1899 if (g_fprep) {
1900 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1901 }
1902 /* write to disk; close fdisk's stream */
1903 if (!(fout = popen(program, "w"))) {
1904 log_OS_error("can't popen-out to program");
1905 } else {
1906 fputs(output, fout);
1907 paranoid_pclose(fout);
1908 }
1909 if (!does_partition_exist(drive, partno) && partsize > 0) {
1910 log_it("Vaccum-packing");
1911 g_current_progress--;
1912 res =
1913 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1914 format, -1);
1915 if (res) {
1916 sprintf(tmp, "Failed to vacuum-pack %s", partition_name);
1917 log_it(tmp);
1918 retval++;
1919 } else {
1920 retval = 0;
1921 }
1922 }
1923 if (does_partition_exist(drive, partno)) {
1924 retval =
1925 set_partition_type(pout_to_fdisk, drive, partno, format,
1926 partsize);
1927 if (retval) {
1928 sprintf(tmp, "Partitioned %s but failed to set its type",
1929 partition_name);
1930 log_it(tmp);
1931 } else {
1932 if (partsize > 0) {
1933 sprintf(tmp, "Partition %s created+configured OK",
1934 partition_name);
1935 log_to_screen(tmp);
1936 } else {
1937 log_it("Returning from a successful vacuum-pack");
1938 }
1939 }
1940 } else {
1941 sprintf(tmp, "Failed to partition %s", partition_name);
1942 if (partsize > 0) {
1943 log_to_screen(tmp);
1944 } else {
1945 log_it(tmp);
1946 }
1947 retval++;
1948 }
1949 }
1950 paranoid_free(output);
1951
1952 g_current_progress++;
1953 log_it("partition_device() --- leaving");
1954 paranoid_free(program);
1955 paranoid_free(partition_name);
1956 paranoid_free(tmp);
1957 paranoid_free(logfile);
1958 return (retval);
1959}
1960
1961
1962
1963/**
1964 * Create all partitions listed in @p mountlist.
1965 * @param mountlist The mountlist to use to guide the partitioning.
1966 * @return The number of errors encountered (0 for success).
1967 * @note This sets the partition types but doesn't actually do the formatting.
1968 * Use format_everything() for that.
1969 */
1970int partition_everything(struct mountlist_itself *mountlist)
1971{
1972 /** int ************************************************************/
1973 int lino;
1974 int retval = 0;
1975 int i;
1976 int res;
1977
1978 /** buffer *********************************************************/
1979 struct list_of_disks *drivelist;
1980 /* struct mountlist_itself new_mtlist, *mountlist; */
1981
1982 /** end ************************************************************/
1983
1984 drivelist = malloc(sizeof(struct list_of_disks));
1985 assert(mountlist != NULL);
1986
1987 log_it("partition_everything() --- starting");
1988 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1989 /* mountlist=orig_mtlist; */
1990 if (mountlist_contains_raid_devices(mountlist)) {
1991 /* mountlist=&new_mtlist; */
1992 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
1993 log_msg(0,
1994 "Mountlist, including the partitions incorporated in RAID devices:-");
1995 for (i = 0; i < mountlist->entries; i++) {
1996 log_it(mountlist->el[i].device);
1997 }
1998 log_msg(0, "End of mountlist.");
1999 }
2000 log_msg(0, "Stopping all LVMs, just in case");
2001 if (!g_text_mode) {
2002 newtSuspend();
2003 }
2004 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
2005 if (!g_text_mode) {
2006 newtResume();
2007 }
2008 log_msg(0, "Stopping all software RAID devices, just in case");
2009 stop_all_raid_devices(mountlist);
2010 log_msg(0, "Done.");
2011
2012/*
2013 if (does_file_exist("/tmp/i-want-my-lvm"))
2014 {
2015 wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
2016 }
2017*/
2018
2019 open_progress_form("Partitioning devices",
2020 "I am now going to partition all your drives.",
2021 "This should not take more than five minutes.", "",
2022 mountlist->entries);
2023
2024 make_list_of_drives_in_mountlist(mountlist, drivelist);
2025
2026 /* partition each drive */
2027 for (lino = 0; lino < drivelist->entries; lino++) {
2028 res = partition_drive(mountlist, drivelist->el[lino].device);
2029 retval += res;
2030 }
2031 close_progress_form();
2032 if (retval) {
2033 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
2034 log_to_screen
2035 ("Errors occurred during the partitioning of your hard drives.");
2036 } else {
2037 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2038 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
2039 }
2040 newtSuspend();
2041 paranoid_system("clear");
2042 newtResume();
2043 paranoid_free(drivelist);
2044 return (retval);
2045}
2046
2047
2048
2049
2050
2051
2052/**
2053 * Set the type of partition number @p partno on @p drive to @p format.
2054 * @param drive The drive to change the type of a partition on.
2055 * @param partno The partition number on @p drive to change the type of.
2056 * @param format The filesystem type this partition will eventually contain.
2057 * @param partsize The size of this partition, in @e bytes (used for vfat
2058 * type calculations).
2059 * @return 0 for success, nonzero for failure.
2060 */
2061int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
2062 const char *format, long long partsize)
2063{
2064 /** buffers *********************************************************/
2065 char *partition;
2066 char *command;
2067 char *output = NULL;
2068 char *tmp;
2069 char *partcode;
2070 char *logfile;
2071
2072 /** pointers *********************************************************/
2073 char *p;
2074 FILE *fout;
2075
2076 /** int **************************************************************/
2077 int res = 0;
2078
2079 /** end **************************************************************/
2080
2081 assert_string_is_neither_NULL_nor_zerolength(drive);
2082 assert(format != NULL);
2083
2084 malloc_string(partition);
2085 malloc_string(command);
2086 malloc_string(tmp);
2087 malloc_string(partcode);
2088 malloc_string(logfile);
2089
2090 build_partition_name(partition, drive, partno);
2091 p = (char *) strrchr(partition, '/');
2092 sprintf(logfile, "/tmp/fdisk-set-type.%s.log", ++p);
2093 if (strcmp(format, "swap") == 0) {
2094 strcpy(partcode, "82");
2095 } else if (strcmp(format, "vfat") == 0) {
2096 if (partsize / 1024 > 8192) {
2097 strcpy(partcode, "c");
2098 } else {
2099 strcpy(partcode, "b");
2100 }
2101 } else if (strcmp(format, "ext2") == 0
2102 || strcmp(format, "reiserfs") == 0
2103 || strcmp(format, "ext3") == 0
2104 || strcmp(format, "ext4") == 0
2105 || strcmp(format, "xfs") == 0
2106 || strcmp(format, "jfs") == 0
2107 || strcmp(format, "btrfs") == 0) {
2108 strcpy(partcode, "83");
2109 } else if (strcmp(format, "minix") == 0) {
2110 strcpy(partcode, "81");
2111 } else if (strcmp(format, "vmfs3") == 0) {
2112 strcpy(partcode, "fb");
2113 } else if (strcmp(format, "vmkcore") == 0) {
2114 strcpy(partcode, "fc");
2115 } else if (strcmp(format, "raid") == 0) {
2116 strcpy(partcode, "fd");
2117 } else if (strcmp(format, "ntfs") == 0) {
2118 strcpy(partcode, "7");
2119 } else if ((strcmp(format, "ufs") == 0)
2120 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
2121 strcpy(partcode, "a5");
2122 } else if (strcmp(format, "lvm") == 0) {
2123 strcpy(partcode, "8e");
2124 } else if (format[0] == '\0') { /* LVM physical partition */
2125 partcode[0] = '\0';
2126 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
2127 strcpy(partcode, format);
2128 } else {
2129 /* probably an image */
2130 sprintf(tmp,
2131 "Unknown format ('%s') - using supplied string anyway",
2132 format);
2133 mvaddstr_and_log_it(g_currentY++, 0, tmp);
2134#ifdef __FreeBSD__
2135 strcpy(partcode, format); // was a5
2136#else
2137 strcpy(partcode, format); // was 83
2138#endif
2139 }
2140 sprintf(tmp, "Setting %s's type to %s (%s)", partition, format,
2141 partcode);
2142 log_msg(1, tmp);
2143 if (partcode[0] != '\0' && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
2144
2145 if (pout_to_fdisk) {
2146 res = 0;
2147 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
2148 if (partno > 1
2149 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
2150 log_msg(5, "Specifying partno (%d) - yay", partno);
2151 sprintf(tmp, "%d\n", partno);
2152 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2153 log_msg(5, "A - last line = '%s'",
2154 last_line_of_file(FDISK_LOG));
2155 }
2156
2157 sprintf(tmp, "%s\n", partcode);
2158 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2159 log_msg(5, "B - last line = '%s'",
2160 last_line_of_file(FDISK_LOG));
2161 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2162 log_msg(5, "C - last line = '%s'",
2163 last_line_of_file(FDISK_LOG));
2164
2165 strcpy(tmp, last_line_of_file(FDISK_LOG));
2166 if (!strstr(tmp, " (m ")) {
2167 log_msg(1, "last line = '%s'; part type set failed", tmp);
2168 res++;
2169 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2170 }
2171 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2172 } else {
2173 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
2174 sprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2175 MONDO_LOGFILE, MONDO_LOGFILE);
2176 log_msg(5, "output = '%s'", output);
2177 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2178 log_msg(5, "command = '%s'", command);
2179 fout = popen(command, "w");
2180 if (!fout) {
2181 log_OS_error(command);
2182 res = 1;
2183 } else {
2184 res = 0;
2185 fprintf(fout, "%s", output);
2186 paranoid_pclose(fout);
2187 }
2188 paranoid_free(output);
2189 }
2190 if (res) {
2191 log_OS_error(command);
2192 }
2193 }
2194
2195 paranoid_free(partition);
2196 paranoid_free(command);
2197 paranoid_free(tmp);
2198 paranoid_free(partcode);
2199 paranoid_free(logfile);
2200
2201 return (res);
2202}
2203
2204
2205int start_raid_device(char *raid_device)
2206{
2207 /** int *************************************************************/
2208 int res;
2209 int retval = 0;
2210
2211 /** buffers *********************************************************/
2212 char *program;
2213
2214 /** end *************************************************************/
2215
2216 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2217 malloc_string(program);
2218
2219#ifdef __FreeBSD__
2220 if (is_this_device_mounted(raid_device)) {
2221 log_it("Can't start %s when it's mounted!", raid_device);
2222 return 1;
2223 }
2224 sprintf(program, "vinum start -f %s", raid_device);
2225#else
2226 sprintf(program, "raidstart %s", raid_device);
2227#endif
2228 log_msg(1, "program = %s", program);
2229 res = run_program_and_log_output(program, 1);
2230 if (g_fprep) {
2231 fprintf(g_fprep, "%s\n", program);
2232 }
2233 if (res) {
2234 log_msg(1, "Warning - failed to start RAID device %s",
2235 raid_device);
2236 }
2237 retval += res;
2238 sleep(1);
2239 return (retval);
2240}
2241
2242
2243
2244/**
2245 * Stop @p raid_device using @p raidstop.
2246 * @param raid_device The software RAID device to stop.
2247 * @return 0 for success, nonzero for failure.
2248 */
2249int stop_raid_device(char *raid_device)
2250{
2251 /** int *************************************************************/
2252 int res;
2253 int retval = 0;
2254
2255 /** buffers *********************************************************/
2256 char *program;
2257
2258 /** end *************************************************************/
2259
2260 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2261 malloc_string(program);
2262
2263#ifdef __FreeBSD__
2264 if (is_this_device_mounted(raid_device)) {
2265 log_it("Can't stop %s when it's mounted!", raid_device);
2266 return 1;
2267 }
2268 sprintf(program, "vinum stop -f %s", raid_device);
2269#else
2270 // use raidstop if it exists, otherwise use mdadm
2271 if (run_program_and_log_output("which raidstop", FALSE)) {
2272 sprintf(program, "mdadm -S %s", raid_device);
2273 } else {
2274 sprintf(program, "raidstop %s", raid_device);
2275 }
2276#endif
2277 log_msg(1, "program = %s", program);
2278 res = run_program_and_log_output(program, 1);
2279 if (g_fprep) {
2280 fprintf(g_fprep, "%s\n", program);
2281 }
2282 if (res) {
2283 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2284 }
2285 retval += res;
2286 return (retval);
2287}
2288
2289
2290int start_all_raid_devices(struct mountlist_itself *mountlist)
2291{
2292 int i;
2293 int retval = 0;
2294 int res;
2295
2296 for (i = 0; i < mountlist->entries; i++) {
2297 if (!strncmp
2298 (mountlist->el[i].device, RAID_DEVICE_STUB,
2299 strlen(RAID_DEVICE_STUB))) {
2300 log_msg(1, "Starting %s", mountlist->el[i].device);
2301 res = start_raid_device(mountlist->el[i].device);
2302 retval += res;
2303 }
2304 }
2305 if (retval) {
2306 log_msg(1, "Started all s/w raid devices OK");
2307 } else {
2308 log_msg(1, "Failed to start some/all s/w raid devices");
2309 }
2310 return (retval);
2311}
2312
2313/**
2314 * Stop all software RAID devices listed in @p mountlist.
2315 * @param mountlist The mountlist to stop the RAID devices in.
2316 * @return The number of errors encountered (0 for success).
2317 * @bug @p mountlist is not used.
2318 */
2319int stop_all_raid_devices(struct mountlist_itself *mountlist)
2320{
2321 /** int *************************************************************/
2322 int retval = 0;
2323
2324 /** char ************************************************************/
2325 char *incoming;
2326#ifndef __FreeBSD__
2327 char *dev;
2328#endif
2329 /** pointers ********************************************************/
2330#ifndef __FreeBSD__
2331 char *p;
2332#endif
2333 FILE *fin;
2334 char *q;
2335 int i;
2336
2337 /** end ****************************************************************/
2338
2339 malloc_string(dev);
2340 malloc_string(incoming);
2341 assert(mountlist != NULL);
2342
2343 for (i = 0; i < 3; i++) {
2344#ifdef __FreeBSD__
2345 fin =
2346 popen
2347 ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2348 "r");
2349 if (!fin) {
2350 paranoid_free(dev);
2351 paranoid_free(incoming);
2352 return (1);
2353 }
2354 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL);
2355 q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2356 retval += stop_raid_device(incoming);
2357 }
2358#else
2359 fin = fopen("/proc/mdstat", "r");
2360 if (!fin) {
2361 log_OS_error("/proc/mdstat");
2362 paranoid_free(dev);
2363 paranoid_free(incoming);
2364 return (1);
2365 }
2366 for (q = fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin) && (q != NULL);
2367 q = fgets(incoming, MAX_STR_LEN - 1, fin)) {
2368 for (p = incoming;
2369 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2370 || !isdigit(*(p + 2))); p++);
2371 if (*p != '\0') {
2372 sprintf(dev, "/dev/%s", p);
2373 for (p = dev; *p > 32; p++);
2374 *p = '\0';
2375 retval += stop_raid_device(dev);
2376 }
2377 }
2378#endif
2379 }
2380 paranoid_fclose(fin);
2381 if (retval) {
2382 log_msg(1, "Warning - unable to stop some RAID devices");
2383 }
2384 paranoid_free(dev);
2385 paranoid_free(incoming);
2386 paranoid_system("sync");
2387 paranoid_system("sync");
2388 paranoid_system("sync");
2389 sleep(1);
2390 return (retval);
2391}
2392
2393
2394
2395/**
2396 * Decide which command we need to use to format a device of type @p format.
2397 * @param format The filesystem type we are about to format.
2398 * @param program Where to put the binary name for this format.
2399 * @return 0 for success, nonzero for failure.
2400 */
2401int which_format_command_do_i_need(char *format, char *program)
2402{
2403 /** int *************************************************************/
2404 int res = 0;
2405
2406 /** buffers *********************************************************/
2407 char *tmp;
2408
2409 /** end ***************************************************************/
2410
2411 malloc_string(tmp);
2412 assert_string_is_neither_NULL_nor_zerolength(format);
2413 assert(program != NULL);
2414
2415 if (strcmp(format, "swap") == 0) {
2416#ifdef __FreeBSD__
2417 strcpy(program, "true");
2418#else
2419 strcpy(program, "mkswap");
2420#endif
2421 } else if (strcmp(format, "vfat") == 0) {
2422 strcpy(program, "format-and-kludge-vfat");
2423#ifndef __FreeBSD__
2424 } else if (strcmp(format, "reiserfs") == 0) {
2425 strcpy(program, "mkreiserfs -ff");
2426 } else if (strcmp(format, "xfs") == 0) {
2427 strcpy(program, "mkfs.xfs -f -q");
2428 } else if (strcmp(format, "jfs") == 0) {
2429 strcpy(program, "mkfs.jfs");
2430 } else if (strcmp(format, "ext3") == 0) {
2431 strcpy(program, "mkfs -t ext3 -F -q");
2432 } else if (strcmp(format, "ext4") == 0) {
2433 strcpy(program, "mkfs -t ext4 -F -q");
2434 } else if (strcmp(format, "btrfs") == 0) {
2435 strcpy(program, "mkfs.btrfs");
2436 } else if (strcmp(format, "minix") == 0) {
2437 strcpy(program, "mkfs.minix");
2438 } else if (strcmp(format, "vmfs") == 0) {
2439 strcpy(program, "mkfs -t vmfs");
2440 } else if (strcmp(format, "ntfs") == 0) {
2441 /*
2442 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2443 * so the default "mkfs -t %s -c" command structure fails
2444 */
2445 strcpy(program, "mkfs -t ntfs");
2446 } else if (strcmp(format, "ocfs2") == 0) {
2447 /*
2448 * For existing OCFS2 volumes, mkfs.ocfs2 ensures the volume is not mounted on any node in the cluster before formatting. For that to work, mkfs.ocfs2 expects the O2CB cluster service to be running. Specify this option to disable this check.
2449 *
2450 */
2451 strcpy(program, "mkfs -t ocfs2 -F");
2452#endif
2453 } else if (strcmp(format, "ext2") == 0) {
2454 strcpy(program, "mke2fs -F -q");
2455 } else {
2456#ifdef __FreeBSD__
2457 sprintf(program, "newfs_%s", format);
2458#else
2459 sprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2460#endif
2461 sprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format,
2462 program);
2463 log_it(tmp);
2464 res = 0;
2465 }
2466 paranoid_free(tmp);
2467 return (res);
2468}
2469
2470
2471/**
2472 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2473 * There are a few problems with this function:
2474 * - It won't work if there was any unallocated space on the user's hard drive
2475 * when it was backed up.
2476 * - It won't work if the user's hard drive lies about its size (more common
2477 * than you'd think).
2478 *
2479 * @param mountlist The mountlist to use for resizing @p drive_name.
2480 * @param drive_name The drive to resize.
2481 */
2482void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2483 *mountlist,
2484 char *drive_name)
2485{
2486 /**buffers **********************************************************/
2487 char *tmp;
2488
2489 /** int *************************************************************/
2490 int partno, lastpart;
2491
2492 /** float ***********************************************************/
2493 float factor;
2494 long long new_size;
2495
2496 /** long *************************************************************/
2497 long long newsizL = 0LL;
2498 long long totalsizL = 0LL;
2499 long long current_size_of_drive = 0LL; /* use KB interally for precision */
2500 long long original_size_of_drive = 0LL; /* use KB interally for precision */
2501 struct mountlist_reference *drivemntlist;
2502
2503 /** structures *******************************************************/
2504
2505 /** end **************************************************************/
2506
2507 assert(mountlist != NULL);
2508 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2509
2510 if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2511 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2512 == 0) {
2513 return;
2514 }
2515 }
2516
2517 current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
2518
2519 if (current_size_of_drive <= 0LL) {
2520 log_it("Not resizing to match %s - can't find drive", drive_name);
2521 return;
2522 }
2523 mr_asprintf(tmp, "Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
2524 log_to_screen(tmp);
2525 mr_free(tmp);
2526
2527 drivemntlist = malloc(sizeof(struct mountlist_reference));
2528 drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
2529
2530 if (!drivemntlist) {
2531 fatal_error("Cannot malloc temporary mountlist\n");
2532 }
2533 create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2534
2535 for (partno = 0; partno < drivemntlist->entries; partno++) {
2536 if (drivemntlist->el[partno]->size > 0LL) {
2537 /* Keep KB here */
2538 original_size_of_drive += drivemntlist->el[partno]->size;
2539 }
2540 }
2541
2542 if (original_size_of_drive <= 0LL) {
2543 mr_asprintf(tmp, "Cannot resize %s's entries. Drive not found.", drive_name);
2544 log_to_screen(tmp);
2545 mr_free(tmp);
2546 return;
2547 }
2548 factor = ((float)current_size_of_drive/(float)original_size_of_drive);
2549 mr_asprintf(tmp, "Disk %s was %lld MB; is now %lld MB; Proportionally resizing partitions (factor ~= %.5f)",
2550 drive_name, original_size_of_drive/1024, current_size_of_drive/1024, factor);
2551 log_to_screen(tmp);
2552 mr_free(tmp);
2553
2554 lastpart = drivemntlist->entries - 1;
2555 for (partno = 0; partno < drivemntlist->entries; partno++) {
2556 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2557 if (!atoi(drivemntlist->el[partno]->format)) {
2558 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
2559 } else {
2560 new_size = drivemntlist->el[partno]->size;
2561 }
2562
2563 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2564 log_msg(1, "Skipping %s (%s) because it's an image",
2565 drivemntlist->el[partno]->device,
2566 drivemntlist->el[partno]->mountpoint);
2567 }
2568 newsizL = new_size;
2569
2570 /* Do not apply the factor if partition was of negative size */
2571 if (newsizL < 0LL) {
2572 newsizL = drivemntlist->el[partno]->size;
2573 }
2574 totalsizL += newsizL;
2575
2576 mr_asprintf(tmp, "Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
2577 log_to_screen(tmp);
2578 mr_free(tmp);
2579 drivemntlist->el[partno]->size = newsizL;
2580 }
2581 // Ensures over-allocation alert and prompt for interactive mode does not happen
2582 if (totalsizL > current_size_of_drive) {
2583 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));
2584 drivemntlist->el[drivemntlist->entries-1]->size -= (totalsizL - current_size_of_drive);
2585 } else if (totalsizL < current_size_of_drive) {
2586 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));
2587 drivemntlist->el[drivemntlist->entries-1]->size += (current_size_of_drive - totalsizL);
2588 }
2589 log_to_screen(tmp);
2590 mr_free(tmp);
2591 mr_asprintf(tmp, "final_size = %lld MB", current_size_of_drive / 1024);
2592 log_to_screen(tmp);
2593 mr_free(tmp);
2594}
2595
2596
2597/**
2598 * Resize all partitions in @p mountlist proportionately (each one
2599 * grows or shrinks by the same percentage) to fit them into the new
2600 * drives (presumably different from the old ones).
2601 * @param mountlist The mountlist to resize the drives in.
2602 */
2603void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2604 *mountlist)
2605{
2606 /** buffers *********************************************************/
2607 struct list_of_disks *drivelist;
2608
2609 /** int *************************************************************/
2610 int driveno;
2611
2612 /** end *************************************************************/
2613
2614 drivelist = malloc(sizeof(struct list_of_disks));
2615 assert(mountlist != NULL);
2616
2617 if (g_mountlist_fname[0] == '\0') {
2618 log_it("resize_mountlist_prop...() - warning - mountlist fname is blank");
2619 log_it("That does NOT affect the functioning of this subroutine.");
2620 log_it("--- Hugo, 2002/11/20");
2621 }
2622 log_it("Resizing mountlist");
2623 make_list_of_drives_in_mountlist(mountlist, drivelist);
2624 log_it("Back from MLoDiM");
2625 for (driveno = 0; driveno < drivelist->entries; driveno++) {
2626 resize_drive_proportionately_to_suit_new_drives(mountlist, drivelist->el[driveno].device);
2627 }
2628 log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2629 paranoid_free(drivelist);
2630}
2631
2632/**
2633 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2634 * @param mountlist The complete mountlist to get the drive references from.
2635 * @param drive_name The drive to put in @p drivemntlist.
2636 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2637 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2638 * @author Ralph Grewe
2639 */
2640void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2641 char *drive_name,
2642 struct mountlist_reference *drivemntlist)
2643{
2644 int partno;
2645 char *tmp_drive_name, *c;
2646
2647 assert(mountlist != NULL);
2648 assert(drive_name != NULL);
2649 assert(drivemntlist != NULL);
2650
2651 log_msg(1, "Creating list of partitions for drive %s", drive_name);
2652
2653 tmp_drive_name = strdup(drive_name);
2654 if (!tmp_drive_name)
2655 fatal_error("Out of memory");
2656
2657 /* devfs devices? */
2658 c = strrchr(tmp_drive_name, '/');
2659 if (c && strncmp(c, "/disc", 5) == 0) {
2660 /* yup its devfs, change the "disc" to "part" so the existing code works */
2661 strcpy(c + 1, "part");
2662 }
2663 drivemntlist->entries = 0;
2664 for (partno = 0; partno < mountlist->entries; partno++) {
2665 if (strncmp
2666 (mountlist->el[partno].device, tmp_drive_name,
2667 strlen(tmp_drive_name)) == 0) {
2668 drivemntlist->el[drivemntlist->entries] =
2669 &mountlist->el[partno];
2670 drivemntlist->entries++;
2671 }
2672 }
2673 if (tmp_drive_name)
2674 free(tmp_drive_name);
2675}
2676
2677/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.