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

Last change on this file since 2933 was 2933, checked in by Bruno Cornec, 12 years ago
  • Fix #578 by improving the regexp used for CD/DVD detection with -scanbus option
  • Adds more verbosity when LVM creation fails.
  • Property svn:keywords set to Id
File size: 77.0 KB
RevLine 
[1]1/***************************************************************************
[2052]2$Id: mondo-prep.c 2933 2012-01-24 18:09:40Z bruno $
[2211]3* Functions for prepping hard drives: partitioning, formatting, etc.
4*/
[1]5
6
[1930]7#include "my-stuff.h"
[2211]8#include "mr_mem.h"
[1]9#include "../common/mondostructures.h"
10#include "mondoprep.h"
11#include "../common/libmondo.h"
[2928]12#include "../common/libmondo-tools-EXT.h"
[1]13#include "mondo-rstr-tools-EXT.h"
14#include <sys/ioctl.h>
15#include <linux/hdreg.h>
16#include <math.h>
17
18
[2192]19#define FDISK_LOG "/var/log/mondofdisk.log"
[1]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
[71]36//static char cvsid[] = "$Id: mondo-prep.c 2933 2012-01-24 18:09:40Z bruno $";
[1]37
38extern char *g_mountlist_fname;
39extern long g_current_progress, g_maximum_progress;
40
41extern bool g_text_mode;
42
[128]43extern void pause_for_N_seconds(int, char *);
[1316]44extern char *MONDO_LOGFILE;
[1]45
[128]46FILE *g_fprep = NULL;
[2928]47extern char *g_mondo_cfg_file; // where m*ndo-restore.cfg (the config file) is stored
[1]48
[128]49int g_partition_table_locked_up = 0;
[1]50
51
52
53void wipe_MBRs_and_reboot_if_necessary(struct mountlist_itself *mountlist)
54{
[128]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;
[1]63// If LVMs are present and a zero-and-reboot wasn't recently undertaken
64// then zero & insist on reboot.
[128]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) {
[1]84// zero & reboot
[128]85 log_to_screen
[541]86 ("I am sorry for the inconvenience but I must ask you to reboot.");
[128]87 log_to_screen
[541]88 ("I need to reset the Master Boot Record; in order to be");
[128]89 log_to_screen
[541]90 ("sure the kernel notices, I must reboot after doing it.");
[128]91 log_to_screen("Please hit 'Enter' to reboot.");
92 for (lino = 0; lino < drivelist->entries; lino++) {
93 for (i = 0; i < blocksize; i++) {
94 buf[i] = 0;
95 }
96 sprintf(buf, "%s\n", MONDO_WAS_HERE);
97 fout = fopen(drivelist->el[lino].device, "w+");
98 if (!fout) {
99 log_msg(1, "Unable to open+wipe %s",
100 drivelist->el[lino].device);
101 } else {
102 if (1 != fwrite(buf, blocksize, 1, fout)) {
103 log_msg(1, "Failed to wipe %s",
104 drivelist->el[lino].device);
105 } else {
106 log_msg(1, "Successfully wiped %s",
107 drivelist->el[lino].device);
108 }
109 fclose(fout);
110 }
111 }
112 system("sync");
113 system("sync");
114 system("sync");
115 popup_and_OK
[541]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.");
[128]117 system("reboot");
118 }
119 }
[1]120// Still here? Cool!
[128]121 paranoid_free(command);
122 paranoid_free(tmp);
123 log_msg(1, "Cool. I didn't have to wipe anything.");
[1]124}
125
126
127
128
129
130
[128]131int fput_string_one_char_at_a_time(FILE * fout, char *str)
[1]132{
[128]133 int i, j;
134 FILE *fq;
[1]135
[128]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);
[1]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
[128]178
179int do_my_funky_lvm_stuff(bool just_erase_existing_volumes,
180 bool vacuum_pack)
[1]181{
182 /** buffers **********************************************/
183 char *tmp;
[1315]184 char *tmp1 = NULL;
[1]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;
[128]194// char *do_this_last;
[1]195
196 /** char **************************************************/
197 char *p;
198 char *q;
199
200 /** int ***************************************************/
201 int retval = 0;
202 int res = 0;
203 int i;
204 int lvmversion = 1;
205 long extents;
206 fpos_t orig_pos;
[128]207
[1]208 /** pointers **********************************************/
209 FILE *fin;
210
211 /** end *****************************************************/
212
213#ifdef __FreeBSD__
214 return (0);
215#endif
216
[2480]217 if (strstr(call_program_and_get_last_line_of_output("cat /proc/cmdline"), "nolvm")) {
218 return(0);
219 }
[1]220 if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) {
221 log_OS_error("/tmp/i-want-my-lvm");
222 return (1);
223 }
224
225 malloc_string(tmp);
226 malloc_string(incoming);
227 malloc_string(lvscan_sz);
228 malloc_string(lvremove_sz);
229 malloc_string(vgscan_sz);
230 malloc_string(pvscan_sz);
231 malloc_string(vgcreate_sz);
232 malloc_string(vgchange_sz);
233 malloc_string(vgremove_sz);
[128]234// malloc_string(do_this_last); // postpone lvcreate call if necessary
[1]235 command = malloc(512);
236
[128]237// do_this_last[0] = '\0';
[2230]238 log_it("STARTING");
[1]239 log_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes...");
[128]240 if (find_home_of_exe("lvm")) // found it :) cool
241 {
242 strcpy(lvscan_sz, "lvm lvscan");
243 strcpy(lvremove_sz, "lvm lvremove");
244 strcpy(vgscan_sz, "lvm vgscan");
245 strcpy(pvscan_sz, "lvm pvscan");
246 strcpy(vgcreate_sz, "lvm vgcreate");
247 strcpy(vgchange_sz, "lvm vgchange");
[2035]248 strcpy(vgremove_sz, "lvm vgremove -f");
[128]249 } else {
250 strcpy(lvscan_sz, "lvscan");
251 strcpy(lvremove_sz, "lvremove");
252 strcpy(vgscan_sz, "vgscan");
253 strcpy(pvscan_sz, "pvscan");
254 strcpy(vgcreate_sz, "vgcreate");
255 strcpy(vgchange_sz, "vgchange");
256 strcpy(vgremove_sz, "vgremove");
257 }
258 sprintf(command,
[1320]259 "for i in `%s | cut -d\"'\" -f2 | sort -r` ; do echo \"Shutting down lv $i\" >> %s ; %s -f $i; done", lvscan_sz, MONDO_LOGFILE, lvremove_sz);
[1]260 run_program_and_log_output(command, 5);
261 sleep(1);
[128]262 sprintf(command,
[1320]263 "for i in `%s | grep -i lvm | cut -d'\"' -f2` ; do %s -a n $i ; %s $i; echo \"Shutting down vg $i\" >> %s ; done", vgscan_sz, vgchange_sz, vgremove_sz, MONDO_LOGFILE);
[1]264 run_program_and_log_output(command, 5);
265 if (just_erase_existing_volumes) {
266 paranoid_fclose(fin);
267 log_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs.");
[128]268 retval = 0;
[1]269 goto end_of_i_want_my_lvm;
270 }
271
272 log_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff...");
273 rewind(fin);
[2179]274 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin); fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]275 fgetpos(fin, &orig_pos);
276 if (incoming[0] != '#') {
277 continue;
278 }
[128]279 if (res && strstr(command, "create") && vacuum_pack) {
280 sleep(2);
281 system("sync");
282 system("sync");
283 system("sync");
284 }
285 if ((p = strstr(incoming, "vgcreate"))) {
[1]286// include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm)
[2179]287 for (fgets(tmp, MAX_STR_LEN - 1, fin); !feof(fin); fgets(tmp, MAX_STR_LEN - 1, fin)) {
[128]288 if (tmp[0] == '#') {
289 fsetpos(fin, &orig_pos);
290 break;
291 } else {
292 fgetpos(fin, &orig_pos);
293 strcat(incoming, tmp);
294 }
[1]295 }
[128]296 for (q = incoming; *q != '\0'; q++) {
297 if (*q < 32) {
298 *q = ' ';
299 }
300 }
301 strcpy(tmp, p + strlen("vgcreate") + 1);
302 for (q = tmp; *q > 32; q++);
303 *q = '\0';
304 log_msg(1, "Deleting old entries at /dev/%s", tmp);
305// sprintf(command, "%s -f %s", vgremove_sz, tmp);
306// run_program_and_log_output(command, 1);
307 sprintf(command, "rm -Rf /dev/%s", tmp);
308 run_program_and_log_output(command, 1);
309 run_program_and_log_output(vgscan_sz, 1);
310 run_program_and_log_output(pvscan_sz, 1);
311 log_msg(3,
312 "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'",
313 incoming);
314 }
[1]315 for (p = incoming + 1; *p == ' '; p++);
316 strcpy(command, p);
317 for (p = command; *p != '\0'; p++);
318 for (; *(p - 1) < 32; p--);
319 *p = '\0';
320 res = run_program_and_log_output(command, 5);
[128]321 if (res > 0 && (p = strstr(command, "lvm "))) {
[2933]322 log_msg(0, "%s --> %d failed so removing lvm just in case", command, res);
[128]323 *p = *(p + 1) = *(p + 2) = ' ';
324 res = run_program_and_log_output(command, 5);
325 }
[1]326 log_msg(0, "%s --> %d", command, res);
[128]327 if (res > 0) {
328 res = 1;
[1]329 }
[128]330 if (res && strstr(command, "lvcreate") && vacuum_pack) {
331 res = 0;
332 if (strstr(command, "lvm lvcreate"))
333 lvmversion = 2;
334 log_it("%s... so I'll get creative.", tmp);
335 if (lvmversion == 2) {
[2211]336 mr_asprintf(&tmp1, "tail -n5 %s | grep Insufficient | tail -n1", MONDO_LOGFILE);
[1315]337 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
338 free(tmp1);
[128]339 } else {
[2211]340 mr_asprintf(&tmp1, "tail -n5 %s | grep lvcreate | tail -n1", MONDO_LOGFILE);
[1315]341 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
342 free(tmp1);
[128]343 }
344 for (p = tmp; *p != '\0' && !isdigit(*p); p++);
345 extents = atol(p);
346 log_msg(5, "p='%s' --> extents=%ld", p, extents);
347 p = strstr(command, "-L");
348 if (!p) {
349 log_msg(0, "Fiddlesticks. '%s' returned %d", command, res);
350 } else {
351 if (lvmversion == 2) {
352 *p++ = '-';
353 *p++ = 'l';
354 *p++ = ' ';
355 for (q = p; *q != ' '; q++) {
356 *q = ' ';
357 }
358 sprintf(p, "%ld", extents);
359 i = strlen(p);
360 *(p + i) = ' ';
361 } else {
362 p++;
363 p++;
364 p++;
365 for (q = p; *q != ' '; q++) {
366 *(q - 1) = ' ';
367 }
368 sprintf(p, "%ld%c", extents, 'm');
369 i = strlen(p);
370 *(p + i) = ' ';
371 }
372 log_msg(5, "Retrying with '%s'", command);
373 res = run_program_and_log_output(command, 5);
374 if (res > 0) {
375 res = 1;
376 }
377 if (g_fprep) {
378 fprintf(g_fprep, "%s\n", command);
379 }
380 log_msg(0, "%s --> %d", command, res);
381 if (!res) {
382 log_msg(5, "YAY! This time, it succeeded.");
383 }
384 }
385 }
386 if (strstr(command, "vgcreate")) {
387 log_msg(0, "In case you're interested...");
388 run_program_and_log_output(vgscan_sz, 1);
389 run_program_and_log_output(pvscan_sz, 1);
390 }
391 if (res != 0 && !strstr(command, "insmod")) {
392 retval++;
393 }
[1]394 sprintf(tmp, "echo \"%s\" >> /tmp/out.sh", command);
395 system(tmp);
396 sleep(1);
397 }
398 paranoid_fclose(fin);
399 log_msg(1, "Closed i-want-my-lvm. Finished doing funky stuff.");
[128]400 end_of_i_want_my_lvm:
[1]401 paranoid_free(tmp);
402 paranoid_free(incoming);
403 paranoid_free(command);
404 paranoid_free(lvscan_sz);
405 paranoid_free(lvremove_sz);
406 paranoid_free(vgscan_sz);
407 paranoid_free(pvscan_sz);
408 paranoid_free(vgcreate_sz);
409 paranoid_free(vgchange_sz);
410 paranoid_free(vgremove_sz);
[128]411// paranoid_free(do_this_last);
412 system("sync");
413 system("sync");
414 system("sync");
[1]415 sleep(1);
[2230]416 log_it("ENDING");
[128]417 if (retval > 2) {
418 log_msg(1, "%d errors. I'm reporting this.", retval);
419 return (retval);
420 } else {
421 log_msg(1, "Not many errors. Returning 0.");
422 return (0);
423 }
[1]424}
425
426
427/**
428 * Add RAID partitions while copying @p old_mountlist to @p new_mountlist.
429 * We go through @p old_mountlist and check if any RAID device (/dev/md? on Linux)
430 * is in it; if it is, then we put the disks contained within that RAID device
431 * into the mountlist as well.
432 * @param old_mountlist The mountlist to read.
433 * @param new_mountlist The mountlist to write, with the RAID partitions added.
434 * @return 0 for success, nonzero for failure.
435 */
[128]436int extrapolate_mountlist_to_include_raid_partitions(struct mountlist_itself
437 *new_mountlist, struct mountlist_itself
438 *old_mountlist)
[1]439{
440 /** pointers *********************************************************/
441 FILE *fin;
442
443 /** int **************************************************************/
444 int lino;
445 int j;
446
447 /** buffers **********************************************************/
448 char *incoming;
449 char *tmp;
450
451 /** pointers *********************************************************/
452 char *p;
453
454 /** init *************************************************************/
455 new_mountlist->entries = 0;
456
457 /** end **************************************************************/
458
459 malloc_string(incoming);
460 malloc_string(tmp);
461 assert(new_mountlist != NULL);
462 assert(old_mountlist != NULL);
463
464#ifdef __FreeBSD__
[128]465 log_to_screen
[541]466 ("I don't know how to extrapolate the mountlist on FreeBSD. Sorry.");
[128]467 return (1);
[1]468#endif
469
470 for (lino = 0; lino < old_mountlist->entries; lino++) {
471 if (strstr(old_mountlist->el[lino].device, RAID_DEVICE_STUB)) // raid
472 {
473 if (!does_file_exist("/etc/raidtab")) {
[128]474 log_to_screen
[541]475 ("Cannot find /etc/raidtab - cannot extrapolate the fdisk entries");
[1]476 finish(1);
477 }
478 if (!(fin = fopen("/etc/raidtab", "r"))) {
479 log_OS_error("Cannot open /etc/raidtab");
480 finish(1);
481 }
482 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin)
[128]483 && !strstr(incoming, old_mountlist->el[lino].device);
484 fgets(incoming, MAX_STR_LEN - 1, fin));
[1]485 if (!feof(fin)) {
[128]486 sprintf(tmp, "Investigating %s",
487 old_mountlist->el[lino].device);
[1]488 log_it(tmp);
489 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin)
[128]490 && !strstr(incoming, "raiddev");
491 fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]492 if (strstr(incoming, OSSWAP("device", "drive"))
[128]493 && !strchr(incoming, '#')) {
494 for (p = incoming + strlen(incoming);
495 *(p - 1) <= 32; p--);
[1]496 *p = '\0';
497 for (p--; p > incoming && *(p - 1) > 32; p--);
498 sprintf(tmp, "Extrapolating %s", p);
499 log_it(tmp);
[128]500 for (j = 0;
501 j < new_mountlist->entries
502 && strcmp(new_mountlist->el[j].device, p);
503 j++);
[1]504 if (j >= new_mountlist->entries) {
[128]505 strcpy(new_mountlist->
506 el[new_mountlist->entries].device, p);
507 strcpy(new_mountlist->
508 el[new_mountlist->entries].mountpoint,
509 "raid");
510 strcpy(new_mountlist->
511 el[new_mountlist->entries].format,
512 "raid");
513 new_mountlist->el[new_mountlist->entries].
514 size = old_mountlist->el[lino].size;
[1]515 new_mountlist->entries++;
516 } else {
[128]517 sprintf(tmp,
518 "Not adding %s to mountlist: it's already there",
519 p);
[1]520 log_it(tmp);
521 }
522 }
523 }
524 }
525 paranoid_fclose(fin);
526 } else {
[128]527 strcpy(new_mountlist->el[new_mountlist->entries].device,
528 old_mountlist->el[lino].device);
529 strcpy(new_mountlist->el[new_mountlist->entries].mountpoint,
530 old_mountlist->el[lino].mountpoint);
531 strcpy(new_mountlist->el[new_mountlist->entries].format,
532 old_mountlist->el[lino].format);
533 new_mountlist->el[new_mountlist->entries].size =
534 old_mountlist->el[lino].size;
[1]535 new_mountlist->entries++;
536 }
537 }
538 paranoid_free(incoming);
539 paranoid_free(tmp);
540
541 return (0);
542}
543
544
545/**
[558]546 * Create @p RAID device using information from @p structure.
547 * This will create the specified RAID devive using information provided in
548 * raidlist by means of the mdadm tool.
549 * @param raidlist The structure containing all RAID information
550 * @param device The RAID device to create.
551 * @return 0 for success, nonzero for failure.
552 */
553int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device)
554{
555 /** int **************************************************************/
556 int i = 0;
557 int j = 0;
558 int res = 0;
559
560 /** buffers ***********************************************************/
561 char *devices = NULL;
562 char *strtmp = NULL;
563 char *level = NULL;
564 char *program = NULL;
[2928]565 char *tmp = NULL;
566 char *oldmd = NULL;
567 char *bootdevice;
568 char *name;
569
570 malloc_string(bootdevice);
571 malloc_string(name);
[558]572
573 // leave straight away if raidlist is initial or has no entries
574 if (!raidlist || raidlist->entries == 0) {
575 log_msg(1, "No RAID arrays found.");
576 return 1;
577 } else {
578 log_msg(1, "%d RAID arrays found.", raidlist->entries);
579 }
580 // find raidlist entry for requested device
581 for (i = 0; i < raidlist->entries; i++) {
582 if (!strcmp(raidlist->el[i].raid_device, device)) break;
583 }
584 // check whether RAID device was found in raidlist
585 if (i == raidlist->entries) {
586 log_msg(1, "RAID device %s not found in list.", device);
587 return 1;
588 }
589 // create device list from normal disks followed by spare ones
[2211]590 mr_asprintf(&devices, "%s", raidlist->el[i].data_disks.el[0].device);
[558]591 for (j = 1; j < raidlist->el[i].data_disks.entries; j++) {
[2211]592 mr_asprintf(&strtmp, "%s", devices);
[558]593 paranoid_free(devices);
[2211]594 mr_asprintf(&devices, "%s %s", strtmp,
[558]595 raidlist->el[i].data_disks.el[j].device);
596 paranoid_free(strtmp);
597 }
598 for (j = 0; j < raidlist->el[i].spare_disks.entries; j++) {
[2211]599 mr_asprintf(&strtmp, "%s", devices);
[558]600 paranoid_free(devices);
[2211]601 mr_asprintf(&devices, "%s %s", strtmp,
[558]602 raidlist->el[i].spare_disks.el[j].device);
603 paranoid_free(strtmp);
604 }
605 // translate RAID level
606 if (raidlist->el[i].raid_level == -2) {
[2211]607 mr_asprintf(&level, "multipath");
[558]608 } else if (raidlist->el[i].raid_level == -1) {
[2211]609 mr_asprintf(&level, "linear");
[558]610 } else {
[2211]611 mr_asprintf(&level, "raid%d", raidlist->el[i].raid_level);
[558]612 }
613 // create RAID device:
614 // - RAID device, number of devices and devices mandatory
615 // - parity algorithm, chunk size and spare devices optional
616 // - faulty devices ignored
617 // - persistent superblock always used as this is recommended
[2928]618 // As per bug #473, the parameter "-e 0.90" is used only when:
619 // 1) It detects that system boots from Raid-1
620 // 2) grub bootloader < v1 is used.
621 // Otherwise it won't boot which is bad.
622 read_cfg_var(g_mondo_cfg_file, "bootloader.device", bootdevice);
623 read_cfg_var(g_mondo_cfg_file, "bootloader.name", name);
624 if (strcmp(name,"GRUB") == 0) {
625 mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output("grub --version"));
626 if ((strstr(tmp, "GRUB 0.9") != NULL) && (strcmp(raidlist->el[i].raid_device,device) == 0)) {
627 mr_free(oldmd);
628 mr_asprintf(&oldmd, "-e 0.90");
629 log_it("Forcing old metadata 0.90 for md on %s for old GRUB", device);
630 }
631 } else if ((strcmp(name,"LILO") == 0) && (strcmp(raidlist->el[i].raid_device,device) == 0)) {
632 mr_free(oldmd);
633 mr_asprintf(&oldmd, "-e 0.90");
634 log_it("Forcing old metadata 0.90 for md on %s for LILO", device);
635 } else {
636 mr_asprintf(&oldmd, "");
637 }
638 mr_free(device);
639 mr_free(name);
640
641 mr_asprintf(&program, "mdadm --create --force --run --auto=yes %s --level=%s --raid-devices=%d %s", raidlist->el[i].raid_device, level, raidlist->el[i].data_disks.entries, oldmd);
642 mr_free(oldmd);
[558]643 if (raidlist->el[i].parity != -1) {
[2211]644 mr_asprintf(&strtmp, "%s", program);
[558]645 paranoid_free(program);
646 switch(raidlist->el[i].parity) {
647 case 0:
[2211]648 mr_asprintf(&program, "%s --parity=%s", strtmp, "la");
[558]649 break;
650 case 1:
[2211]651 mr_asprintf(&program, "%s --parity=%s", strtmp, "ra");
[558]652 break;
653 case 2:
[2211]654 mr_asprintf(&program, "%s --parity=%s", strtmp, "ls");
[558]655 break;
656 case 3:
[2211]657 mr_asprintf(&program, "%s --parity=%s", strtmp, "rs");
[558]658 break;
659 default:
660 fatal_error("Unknown RAID parity algorithm.");
661 break;
662 }
663 paranoid_free(strtmp);
664 }
665 if (raidlist->el[i].chunk_size != -1) {
[2211]666 mr_asprintf(&strtmp, "%s", program);
[558]667 paranoid_free(program);
[2211]668 mr_asprintf(&program, "%s --chunk=%d", strtmp, raidlist->el[i].chunk_size);
[558]669 paranoid_free(strtmp);
670 }
671 if (raidlist->el[i].spare_disks.entries > 0) {
[2211]672 mr_asprintf(&strtmp, "%s", program);
[558]673 paranoid_free(program);
[2211]674 mr_asprintf(&program, "%s --spare-devices=%d", strtmp,
[558]675 raidlist->el[i].spare_disks.entries);
676 paranoid_free(strtmp);
677 }
[2211]678 mr_asprintf(&strtmp, "%s", program);
[558]679 paranoid_free(program);
[2211]680 mr_asprintf(&program, "%s %s", strtmp, devices);
[558]681 paranoid_free(strtmp);
682 res = run_program_and_log_output(program, 1);
683 // free memory
684 paranoid_free(devices);
685 paranoid_free(level);
686 paranoid_free(program);
687 // return to calling instance
688 return res;
689}
690
691
692/**
[1]693 * Format @p device as a @p format filesystem.
694 * This will use the format command returned by which_format_command_do_i_need().
695 * If @p device is an LVM PV, it will not be formatted, and LVM will be started
696 * (if not already done). If it's an imagedev, software RAID component, or
697 * (under BSD) swap partition, no format will be done.
698 * @param device The device to format.
699 * @param format The filesystem type to format it as.
700 * @return 0 for success, nonzero for failure.
701 */
[558]702int format_device(char *device, char *format, struct raidlist_itself *raidlist)
[1]703{
704 /** int **************************************************************/
705#ifdef __FreeBSD__
706 static bool vinum_started_yet = FALSE;
707#endif
708
709 /** buffers ***********************************************************/
710 char *program;
[2211]711 char *tmp = NULL;
712 int res = 0;
713 int retval = 0;
[1]714
715 /** end ****************************************************************/
716
717 malloc_string(program);
718 assert_string_is_neither_NULL_nor_zerolength(device);
719 assert(format != NULL);
720
721 if (strstr(format, "raid")) { // do not form RAID disks; do it to /dev/md* instead
[2211]722 mr_asprintf(&tmp, "Not formatting %s (it is a RAID disk)", device);
[1]723 log_it(tmp);
[2211]724 paranoid_free(tmp);
[128]725 paranoid_free(program);
[1]726 return (0);
727 }
728#ifdef __FreeBSD__
729 if (strcmp(format, "swap") == 0) {
730 log_it("Not formatting %s - it's swap", device);
[128]731 paranoid_free(program);
732 paranoid_free(tmp);
[1]733 return (0);
734 }
735#endif
736 if (strlen(format) <= 2) {
[2290]737 mr_asprintf(&tmp, "%s has a really small format type ('%s') - this is probably a hexadecimal string, which would suggest the partition is an image --- I shouldn't format it", device, format);
[1]738 log_it(tmp);
[2211]739 paranoid_free(tmp);
[128]740 paranoid_free(program);
[1]741 return (0);
742 }
743 if (is_this_device_mounted(device)) {
[2211]744 mr_asprintf(&tmp, "%s is mounted - cannot format it ", device);
[1]745 log_to_screen(tmp);
[2211]746 paranoid_free(tmp);
[128]747 paranoid_free(program);
[1]748 return (1);
749 }
750 if (strstr(device, RAID_DEVICE_STUB)) {
751 newtSuspend();
752#ifdef __FreeBSD__
753 if (!vinum_started_yet) {
754 if (!does_file_exist("/tmp/raidconf.txt")) {
[128]755 log_to_screen
[541]756 ("/tmp/raidconf.txt does not exist. I therefore cannot start Vinum.");
[1]757 } else {
758 int res;
[128]759 res =
760 run_program_and_log_output
761 ("vinum create /tmp/raidconf.txt", TRUE);
[1]762 if (res) {
763 log_to_screen
[541]764 ("`vinum create /tmp/raidconf.txt' returned errors. Please fix them and re-run mondorestore.");
[1]765 finish(1);
766 }
767 vinum_started_yet = TRUE;
768 }
769 }
770
771 if (vinum_started_yet) {
772 FILE *fin;
773 char line[MAX_STR_LEN];
[2211]774
775 mr_asprintf(&tmp, "Initializing Vinum device %s (this may take a *long* time)", device);
[1]776 log_to_screen(tmp);
[2211]777 paranoid_free(tmp);
778
[1]779 /* format raid partition */
780 // sprintf (program, "mkraid --really-force %s", device); --- disabled -- BB, 02/12/2003
781 sprintf(program,
[128]782 "for plex in `vinum lv -r %s | grep '^P' | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f2`; do echo $plex; done > /tmp/plexes",
783 basename(device));
[1]784 system(program);
[128]785 if (g_fprep) {
786 fprintf(g_fprep, "%s\n", program);
787 }
[1]788 fin = fopen("/tmp/plexes", "r");
789 while (fgets(line, MAX_STR_LEN - 1, fin)) {
790 if (strchr(line, '\n'))
791 *(strchr(line, '\n')) = '\0'; // get rid of the \n on the end
792
[2211]793 mr_asprintf(&tmp, "Initializing plex: %s", line);
[1]794 open_evalcall_form(tmp);
[2211]795 paranoid_free(tmp);
796
797 mr_asprintf(&tmp, "vinum init %s", line);
[1]798 system(tmp);
[2211]799 paranoid_free(tmp);
800
[1]801 while (1) {
[2290]802 mr_asprintf(&tmp, "vinum lp -r %s | grep '^S' | head -1 | tr -s ' ' | cut -d: -f2 | cut -f1 | sed 's/^ //' | sed 's/I //' | sed 's/%%//'", line);
[1]803 FILE *pin = popen(tmp, "r");
[2211]804 paranoid_free(tmp);
805
[1]806 char status[MAX_STR_LEN / 4];
807 fgets(status, MAX_STR_LEN / 4 - 1, pin);
808 pclose(pin);
809
810 if (!strcmp(status, "up")) {
811 break; /* it's done */
812 }
813 update_evalcall_form(atoi(status));
814 usleep(250000);
815 }
816 close_evalcall_form();
817 }
818 fclose(fin);
819 unlink("/tmp/plexes");
820 }
821#else
[2211]822 mr_asprintf(&tmp, "Initializing RAID device %s", device);
[1]823 log_to_screen(tmp);
[2211]824 paranoid_free(tmp);
[1]825
826// Shouldn't be necessary.
[541]827 log_to_screen("Stopping %s", device);
[1]828 stop_raid_device(device);
[128]829 system("sync");
830 sleep(1);
831 if (g_fprep) {
832 fprintf(g_fprep, "%s\n", program);
833 }
[1]834
835 log_msg(1, "Making %s", device);
[558]836 // use mkraid if it exists, otherwise use mdadm
837 if (run_program_and_log_output("which mkraid", FALSE)) {
838 res = create_raid_device_via_mdadm(raidlist, device);
839 log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
840 } else {
841 sprintf(program, "mkraid --really-force %s", device);
842 res = run_program_and_log_output(program, 1);
843 log_msg(1, "%s returned %d", program, res);
844 system("sync");
845 sleep(3);
846 start_raid_device(device);
847 if (g_fprep) {
848 fprintf(g_fprep, "%s\n", program);
849 }
[128]850 }
851 system("sync");
852 sleep(2);
853// log_to_screen("Starting %s", device);
854// sprintf(program, "raidstart %s", device);
855// res = run_program_and_log_output(program, 1);
856// log_msg(1, "%s returned %d", program, res);
857// system("sync"); sleep(1);
[1]858#endif
[128]859 system("sync");
860 sleep(1);
[1]861 newtResume();
862 }
863//#ifndef __FreeBSD__
864//#endif
865
[128]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 }
[1]872 res = which_format_command_do_i_need(format, program);
[2211]873 mr_asprintf(&tmp, "%s %s", program, device);
[1]874 if (strstr(program, "kludge")) {
[2211]875 mr_strcat(tmp, " /");
[1]876 }
877 sprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
[2211]878 paranoid_free(tmp);
879
880 mr_asprintf(&tmp, "Formatting %s as %s", device, format);
[1]881 update_progress_form(tmp);
[2211]882 paranoid_free(tmp);
883
[1]884 res = run_program_and_log_output(program, FALSE);
[2297]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
[1]893 if (res && strstr(program, "kludge")) {
[2298]894 mr_asprintf(&tmp, "Kludge failed; using regular mkfs.%s to format %s",
[128]895 format, device);
[1]896#ifdef __FreeBSD__
897 sprintf(program, "newfs_msdos -F 32 %s", device);
898#else
[85]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
[1]904 sprintf(program, "mkfs -t %s -F 32 %s", format, device);
905#endif
[85]906#endif
[1]907 res = run_program_and_log_output(program, FALSE);
[128]908 if (g_fprep) {
909 fprintf(g_fprep, "%s\n", program);
910 }
[2297]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
[1]920 }
921 retval += res;
[128]922 paranoid_free(program);
923 system("sync");
924 sleep(1);
[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 */
[558]938int format_everything(struct mountlist_itself *mountlist, bool interactively,
939 struct raidlist_itself *raidlist)
[1]940{
941 /** int **************************************************************/
942 int retval = 0;
943 int lino;
944 int res;
[128]945// int i;
946// struct list_of_disks *drivelist;
[1]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
[128]961 assert(mountlist != NULL);
[1]962 malloc_string(tmp);
[128]963 sprintf(tmp, "format_everything (mountlist, interactively = %s",
964 (interactively) ? "true" : "false");
[1]965 log_it(tmp);
[541]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.", "",
[128]970 mountlist->entries + 1);
[1]971
[128]972 progress_step =
973 (mountlist->entries >
974 0) ? g_maximum_progress / mountlist->entries : 1;
[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);
[128]979 system("sync");
980 system("sync");
981 system("sync");
[1]982 sleep(2);
[128]983 log_msg(1, "Prepare soft-RAIDs"); // prep and format too
[1]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
[128]990 sprintf(tmp, "Shall I format %s (%s) ?", me->device,
991 me->mountpoint);
[1]992 do_it = ask_me_yes_or_no(tmp);
993 } else {
994 do_it = TRUE;
995 }
996 if (do_it) {
[128]997 // NB: format_device() also stops/starts RAID device if necessary
[558]998 retval += format_device(me->device, me->format, raidlist);
[1]999 }
1000 g_current_progress += progress_step;
1001 }
1002 }
[128]1003 system("sync");
1004 system("sync");
1005 system("sync");
[1]1006 sleep(2);
1007// This last step is probably necessary
[128]1008// log_to_screen("Re-starting software RAIDs...");
1009// start_all_raid_devices(mountlist);
1010// system("sync"); system("sync"); system("sync");
1011// sleep(5);
[1]1012// do LVMs now
1013 log_msg(1, "Creating LVMs");
1014 if (does_file_exist("/tmp/i-want-my-lvm")) {
[558]1015 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
[541]1016 log_to_screen("Configuring LVM");
[128]1017 if (!g_text_mode) {
1018 newtSuspend();
1019 }
[1]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*/
[128]1032 res = do_my_funky_lvm_stuff(FALSE, TRUE);
[1]1033/*
1034 }
1035*/
[128]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 }
[1]1044 // retval += res;
1045 if (res) {
[128]1046 retval++;
[1]1047 }
[128]1048 sleep(3);
[1]1049 }
1050// do regulars at last
[128]1051 sleep(2); // woo!
1052 log_msg(1, "Formatting regulars");
[1]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")) {
[128]1059 sprintf(tmp, "Not formatting %s - it's a raid-let",
1060 me->device);
[1]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)) {
[128]1068 sprintf(tmp, "Already formatted %s - it's a soft-RAID dev",
1069 me->device);
[1]1070 log_it(tmp);
1071 continue;
1072 } else if (!does_file_exist(me->device)
[128]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);
[1]1078 log_it(tmp);
1079 continue;
1080 } else {
1081 if (interactively) {
1082 // ask user if we should format the current device
[128]1083 sprintf(tmp, "Shall I format %s (%s) ?", me->device,
1084 me->mountpoint);
[1]1085 do_it = ask_me_yes_or_no(tmp);
1086 } else {
1087 do_it = TRUE;
1088 }
1089
1090 if (do_it)
[558]1091 retval += format_device(me->device, me->format, raidlist);
[1]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) {
[541]1107 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
[128]1108 log_to_screen
[541]1109 ("Errors occurred during the formatting of your hard drives.");
[1]1110 } else {
[541]1111 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
[1]1112 }
1113
[128]1114 sprintf(tmp, "format_everything () - %s",
1115 (retval) ? "failed!" : "finished successfully");
[1]1116 log_it(tmp);
1117
[128]1118 if (g_partition_table_locked_up > 0) {
1119 if (retval > 0 && !interactively) {
[1]1120//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
[128]1121 log_to_screen
[541]1122 ("Partition table locked up %d times. At least one 'mkfs' (format) command",
[128]1123 g_partition_table_locked_up);
1124 log_to_screen
[541]1125 ("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
[128]1126 log_to_screen
[541]1127 ("to refresh its copy of the partition table causes the kernel to lock the ");
[128]1128 log_to_screen
[541]1129 ("partition table. I believe this has just happened.");
[128]1130 if (ask_me_yes_or_no
[541]1131 ("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue."))
[128]1132 {
1133 system("sync");
1134 system("sync");
1135 system("sync");
1136 system("reboot");
1137 }
1138 } else {
1139 log_to_screen
[541]1140 ("Partition table locked up %d time%c. However, disk formatting succeeded.",
[128]1141 g_partition_table_locked_up,
1142 (g_partition_table_locked_up == 1) ? '.' : 's');
1143 }
1144 }
1145 newtSuspend();
[1]1146 system("clear");
1147 newtResume();
1148 paranoid_free(tmp);
1149 return (retval);
1150}
1151
1152
1153/**
1154 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
1155 * Each partition created is 32k in size.
1156 * @param drivename The drive to create the dummy partitions on.
1157 * @param devno_we_must_allow_for The lowest-numbered real partition; create
1158 * dummies up to (this - 1).
1159 * @return The number of errors encountered (0 for success).
1160 */
[128]1161int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename,
1162 int devno_we_must_allow_for)
[1]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) {
[1303]1179 sprintf(tmp, "Making dummy primary 1 on %s", drivename);
[1]1180 log_it(tmp);
1181 g_maximum_progress++;
[128]1182 res =
1183 partition_device(pout_to_fdisk, drivename, 1, 0, "ext2",
1184 32000);
[1]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++) {
[1303]1193 sprintf(tmp, "Creating dummy partition %d on %s", current_devno, drivename);
[1]1194 log_it(tmp);
1195 g_maximum_progress++;
[128]1196 res =
1197 partition_device(pout_to_fdisk, drivename, current_devno,
1198 previous_devno, OSSWAP("ext2", "ufs"), 32000);
[1]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);
[128]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);
[1]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);
[128]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);
[1]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);
[128]1281 fprintf(f,
1282 "# size offset fstype [fsize bsize bps/cpg]\n");
[1]1283 pp = lp->d_partitions;
1284 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1285 if (pp->p_size) {
[128]1286 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size,
1287 (u_long) pp->p_offset);
[1]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 */
[128]1295 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1296 (u_long) (pp->p_fsize * pp->p_frag), "");
[1]1297 break;
1298
1299 case FS_BSDFFS:
[128]1300 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize,
1301 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
[1]1302 break;
1303
1304 case FS_BSDLFS:
[128]1305 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize,
1306 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
[1]1307 break;
1308
1309 default:
1310 fprintf(f, "%20.20s", "");
1311 break;
1312 }
[128]1313 fprintf(f, "\t# (Cyl. %4lu",
1314 (u_long) (pp->p_offset / lp->d_secpercyl));
[1]1315 if (pp->p_offset % lp->d_secpercyl)
1316 putc('*', f);
1317 else
1318 putc(' ', f);
[128]1319 fprintf(f, "- %lu",
1320 (u_long) ((pp->p_offset + pp->p_size +
1321 lp->d_secpercyl - 1) / lp->d_secpercyl -
1322 1));
[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)
[128]1348 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
[1]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}
[128]1392
[1]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 */
[128]1412int label_drive_or_slice(struct mountlist_itself *mountlist,
1413 char *drivename, struct disklabel *ret)
[1]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")
[128]1437 || !strcmp(mountlist->el[idx].format, "ffs")
1438 || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
[1]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")
[128]1444 || !strcasecmp(mountlist->el[idx].format, "vinum")) {
[1]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)
[128]1465 && (lastone != RAW_PART))
[1]1466 break;
1467 }
[128]1468 lp->d_partitions[i].p_offset =
1469 lp->d_partitions[lastone].p_offset +
1470 lp->d_partitions[lastone].p_size;
[1]1471 }
[128]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;
[1]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);
[128]1483 sprintf(command, "disklabel -R %s /tmp/disklabel",
1484 canonical_name(drivename));
[1]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;
[128]1507 FILE *pout_to_fdisk = NULL;
1508
[1]1509#ifdef __FreeBSD__
1510 bool fbsd_part = FALSE;
1511 char subdev_str[MAX_STR_LEN];
1512#endif
1513
1514 /** long long *******************************************************/
1515 long long partsize;
1516
1517 /** buffers *********************************************************/
1518 char *device_str;
1519 char *format;
1520 char *tmp;
1521
1522 /** end *************************************************************/
1523
1524 assert(mountlist != NULL);
1525 assert_string_is_neither_NULL_nor_zerolength(drivename);
1526
1527 malloc_string(device_str);
1528 malloc_string(format);
1529 malloc_string(tmp);
[128]1530
[1]1531 sprintf(tmp, "Partitioning drive %s", drivename);
1532 log_it(tmp);
1533
[128]1534#if __FreeBSD__
1535 log_it("(Not opening fdisk now; that's the Linux guy's job)");
[1]1536 pout_to_fdisk = NULL;
1537#else
1538 make_hole_for_file(FDISK_LOG);
[196]1539 sprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
[1]1540 pout_to_fdisk = popen(tmp, "w");
[128]1541 if (!pout_to_fdisk) {
[541]1542 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
[1]1543 paranoid_free(device_str);
1544 paranoid_free(format);
1545 paranoid_free(tmp);
[128]1546 return (1);
[1]1547 }
1548#endif
1549 for (current_devno = 1; current_devno < 99; current_devno++) {
1550 build_partition_name(device_str, drivename, current_devno);
1551 lino = find_device_in_mountlist(mountlist, device_str);
1552
1553 if (lino < 0) {
1554 // device not found in mountlist
1555#if __FreeBSD__
1556 // If this is the first partition (just as a sentinel value),
1557 // then see if the user has picked 'dangerously-dedicated' mode.
1558 // If so, then we just call label_drive_or_slice() and return.
1559 char c;
1560 if (current_devno == 1) {
1561 // try DangerouslyDedicated mode
1562 for (c = 'a'; c <= 'z'; c++) {
1563 sprintf(subdev_str, "%s%c", drivename, c);
[128]1564 if (find_device_in_mountlist(mountlist, subdev_str) >
1565 0) {
[1]1566 fbsd_part = TRUE;
1567 }
1568 }
1569 if (fbsd_part) {
1570 int r = label_drive_or_slice(mountlist,
[128]1571 drivename,
1572 0);
[1]1573 char command[MAX_STR_LEN];
[128]1574 sprintf(command, "disklabel -B %s",
1575 basename(drivename));
[1]1576 if (system(command)) {
[128]1577 log_to_screen
[541]1578 ("Warning! Unable to make the drive bootable.");
[1]1579 }
1580 paranoid_free(device_str);
1581 paranoid_free(format);
1582 paranoid_free(tmp);
1583 return r;
1584 }
1585 }
1586 for (c = 'a'; c <= 'z'; c++) {
1587 sprintf(subdev_str, "%s%c", device_str, c);
1588 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1589 fbsd_part = TRUE;
1590 }
1591 }
1592 // Now we check the subpartitions of the current partition.
1593 if (fbsd_part) {
1594 int i, line;
1595
1596 strcpy(format, "ufs");
1597 partsize = 0;
1598 for (i = 'a'; i < 'z'; ++i) {
1599 sprintf(subdev_str, "%s%c", device_str, i);
1600 line = find_device_in_mountlist(mountlist, subdev_str);
1601 if (line > 0) {
1602 // We found one! Add its size to the total size.
1603 partsize += mountlist->el[line].size;
1604 }
1605 }
1606 } else {
1607 continue;
1608 }
1609#else
1610 continue;
1611#endif
1612 }
1613
1614 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1615 /* For FreeBSD, that is /dev/adXsY */
1616
1617 log_it("Found partition %s in mountlist", device_str);
1618 if (!previous_devno) {
1619
1620 log_it("Wiping %s's partition table", drivename);
1621#if __FreeBSD__
1622 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
[128]1623// sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1624// if (run_program_and_log_output(tmp, TRUE)) {
[1]1625 file = open(drivename, O_WRONLY);
[2205]1626 if (file != -1) {
[128]1627 sprintf(tmp,
[541]1628 "Warning - unable to open %s for wiping it's partition table",
[128]1629 drivename);
[1]1630 log_to_screen(tmp);
1631 }
1632
[128]1633 for (i = 0; i < 512; i++) {
1634 if (!write(file, "\0", 1)) {
[541]1635 sprintf(tmp, "Warning - unable to write to %s",
[128]1636 drivename);
[1]1637 log_to_screen(tmp);
1638 }
1639 }
1640 system("sync");
1641#else
[2230]1642 log_it("New, kernel-friendly partition remover");
[128]1643 for (i = 20; i > 0; i--) {
1644 fprintf(pout_to_fdisk, "d\n%d\n", i);
1645 fflush(pout_to_fdisk);
1646 }
1647// sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1648// run_program_and_log_output(tmp, 1);
1649#endif
[1]1650 if (current_devno > 1) {
[128]1651 previous_devno =
1652 make_dummy_partitions(pout_to_fdisk, drivename,
1653 current_devno);
[1]1654 }
1655 }
1656#ifdef __FreeBSD__
1657 if (!fbsd_part) {
1658#endif
1659
[128]1660 strcpy(format, mountlist->el[lino].format);
1661 partsize = mountlist->el[lino].size;
[1]1662
1663#ifdef __FreeBSD__
1664 }
1665#endif
1666
[71]1667#ifndef __IA64__
[1]1668 if (current_devno == 5 && previous_devno == 4) {
[128]1669 log_to_screen
[541]1670 ("You must leave at least one partition spare as the Extended partition.");
[1]1671 paranoid_free(device_str);
1672 paranoid_free(format);
1673 paranoid_free(tmp);
1674 return (1);
1675 }
[71]1676#endif
[1]1677
[128]1678 retval +=
1679 partition_device(pout_to_fdisk, drivename, current_devno,
1680 previous_devno, format, partsize);
[1]1681
1682#ifdef __FreeBSD__
1683 if ((current_devno <= 4) && fbsd_part) {
1684 sprintf(tmp, "disklabel -B %s", basename(device_str));
1685 retval += label_drive_or_slice(mountlist, device_str, 0);
1686 if (system(tmp)) {
[128]1687 log_to_screen
[541]1688 ("Warning! Unable to make the slice bootable.");
[1]1689 }
1690 }
1691#endif
1692
1693 previous_devno = current_devno;
1694 }
1695
[128]1696 if (pout_to_fdisk) {
[1]1697// mark relevant partition as bootable
[128]1698 sprintf(tmp, "a\n%s\n",
1699 call_program_and_get_last_line_of_output
1700 ("make-me-bootable /tmp/mountlist.txt dummy"));
[1]1701 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1702// close fdisk
1703 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1704 system("sync");
[128]1705 paranoid_pclose(pout_to_fdisk);
1706 log_msg(0,
1707 "------------------- fdisk.log looks like this ------------------");
[1]1708 sprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1709 system(tmp);
[128]1710 log_msg(0,
1711 "------------------- end of fdisk.log... word! ------------------");
[681]1712 sprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
[128]1713 if (!run_program_and_log_output(tmp, 5)) {
1714 g_partition_table_locked_up++;
[2222]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) {
[128]1721 log_to_screen
[2222]1722 ("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
[128]1723 }
[1]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 */
[128]1740int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1741 int prev_partno, const char *format,
1742 long long partsize)
[1]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;
[2211]1753 char *output = NULL;
[1]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);
[128]1766
[1]1767 assert_string_is_neither_NULL_nor_zerolength(drive);
1768 assert(format != NULL);
1769
[128]1770 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1771 drive, partno, prev_partno, format, partsize);
[1]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 {
[128]1786 sprintf(tmp, "Partitioning device %s (%lld MB)", partition_name,
1787 (long long) partsize / 1024);
[1]1788 }
1789 update_progress_form(tmp);
1790 log_it(tmp);
1791
1792 if (is_this_device_mounted(partition_name)) {
[541]1793 sprintf(tmp, "%s is mounted, and should not be partitioned",
[128]1794 partition_name);
[1]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);
[128]1814 sprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE,
1815 MONDO_LOGFILE);
[1]1816
[2154]1817 /* BERLIOS: should not be called each time */
[88]1818 part_table_fmt = which_partition_format(drive);
[2211]1819 mr_asprintf(&output, "");
[1]1820 /* make it a primary/extended/logical */
1821 if (partno <= 4) {
[2211]1822 mr_strcat(output, "n\np\n%d\n", partno);
[1]1823 } else {
[88]1824 /* MBR needs an extended partition if more than 4 partitions */
[128]1825 if (strcmp(part_table_fmt, "MBR") == 0) {
[88]1826 if (partno == 5) {
1827 if (prev_partno >= 4) {
[128]1828 log_to_screen
[541]1829 ("You need to leave at least one partition free, for 'extended/logical'");
[88]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 {
[2211]1837 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
[88]1838 }
1839 }
[2211]1840 mr_strcat(output, "n\nl\n");
[88]1841 } else {
[1]1842 /* GPT allows more than 4 primary partitions */
[2211]1843 mr_strcat(output, "n\np\n%d\n", partno);
[1]1844 }
1845 }
[2211]1846 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
[1]1847 if (partsize > 0) {
[128]1848 if (!strcmp(format, "7")) {
1849 log_msg(1, "Adding 512K, just in case");
1850 partsize += 512;
1851 }
[2211]1852 mr_strcat(output, "+%lldK", (long long) (partsize));
[1]1853 }
[2211]1854 mr_strcat(output, "\n");
[1]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
[128]1868 if (pout_to_fdisk) {
[1]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));
[128]1874 if (strstr(tmp, " (m ")) {
[1303]1875 log_msg(1, "Successfully created partition %d on %s", partno, drive);
[128]1876 } else {
[1]1877 log_msg(1, "last line = %s", tmp);
[1303]1878 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
[1]1879 }
[128]1880 if (!retval) {
[1303]1881 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
[128]1882 retval =
1883 set_partition_type(pout_to_fdisk, drive, partno, format,
1884 partsize);
1885 if (retval) {
[1]1886 log_msg(1, "Failed. Trying again...");
[128]1887 retval =
1888 set_partition_type(pout_to_fdisk, drive, partno,
1889 format, partsize);
[1]1890 }
[128]1891 }
1892 if (retval) {
1893 log_msg(1, "...but failed to set type");
1894 }
1895 } else {
[2211]1896 mr_strcat(output, "w\n\n");
[128]1897 if (g_fprep) {
1898 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1899 }
[1]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--;
[128]1910 res =
1911 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1912 format, -1);
[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)) {
[128]1922 retval =
1923 set_partition_type(pout_to_fdisk, drive, partno, format,
1924 partsize);
[1]1925 if (retval) {
[128]1926 sprintf(tmp, "Partitioned %s but failed to set its type",
1927 partition_name);
[1]1928 log_it(tmp);
1929 } else {
1930 if (partsize > 0) {
[128]1931 sprintf(tmp, "Partition %s created+configured OK",
1932 partition_name);
[1]1933 log_to_screen(tmp);
1934 } else {
1935 log_it("Returning from a successful vacuum-pack");
1936 }
1937 }
[128]1938 } else {
[1]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 }
[2211]1948 paranoid_free(output);
1949
[1]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); */
[128]1991 log_msg(0,
1992 "Mountlist, including the partitions incorporated in RAID devices:-");
[1]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");
[128]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 }
[1]2006 log_msg(0, "Stopping all software RAID devices, just in case");
2007 stop_all_raid_devices(mountlist);
2008 log_msg(0, "Done.");
[128]2009
[1]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
[541]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.", "",
[128]2020 mountlist->entries);
[1]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) {
[541]2031 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
[128]2032 log_to_screen
[541]2033 ("Errors occurred during the partitioning of your hard drives.");
[1]2034 } else {
[541]2035 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
[1]2036 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
2037 }
2038 newtSuspend();
2039 system("clear");
2040 newtResume();
2041 paranoid_free(drivelist);
2042 return (retval);
2043}
2044
2045
2046
2047
2048
2049
2050/**
2051 * Set the type of partition number @p partno on @p drive to @p format.
2052 * @param drive The drive to change the type of a partition on.
2053 * @param partno The partition number on @p drive to change the type of.
2054 * @param format The filesystem type this partition will eventually contain.
2055 * @param partsize The size of this partition, in @e bytes (used for vfat
2056 * type calculations).
2057 * @return 0 for success, nonzero for failure.
2058 */
[128]2059int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
2060 const char *format, long long partsize)
[1]2061{
2062 /** buffers *********************************************************/
[128]2063 char *partition;
2064 char *command;
[2211]2065 char *output = NULL;
[128]2066 char *tmp;
2067 char *partcode;
2068 char *logfile;
[1]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
[128]2082 malloc_string(partition);
2083 malloc_string(command);
2084 malloc_string(tmp);
2085 malloc_string(partcode);
2086 malloc_string(logfile);
[1]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 }
[128]2099 } else if (strcmp(format, "ext2") == 0
2100 || strcmp(format, "reiserfs") == 0
[1303]2101 || strcmp(format, "ext3") == 0
[2087]2102 || strcmp(format, "ext4") == 0
[1303]2103 || strcmp(format, "xfs") == 0
[128]2104 || strcmp(format, "jfs") == 0) {
[1]2105 strcpy(partcode, "83");
2106 } else if (strcmp(format, "minix") == 0) {
2107 strcpy(partcode, "81");
[1824]2108 } else if (strcmp(format, "vmfs3") == 0) {
[1497]2109 strcpy(partcode, "fb");
[1824]2110 } else if (strcmp(format, "vmkcore") == 0) {
2111 strcpy(partcode, "fc");
[1]2112 } else if (strcmp(format, "raid") == 0) {
2113 strcpy(partcode, "fd");
[2141]2114 } else if (strcmp(format, "ntfs") == 0) {
2115 strcpy(partcode, "7");
[1]2116 } else if ((strcmp(format, "ufs") == 0)
[128]2117 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
[1]2118 strcpy(partcode, "a5");
2119 } else if (strcmp(format, "lvm") == 0) {
2120 strcpy(partcode, "8e");
2121 } else if (format[0] == '\0') { /* LVM physical partition */
2122 partcode[0] = '\0';
2123 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
2124 strcpy(partcode, format);
2125 } else {
2126 /* probably an image */
[128]2127 sprintf(tmp,
2128 "Unknown format ('%s') - using supplied string anyway",
2129 format);
[1]2130 mvaddstr_and_log_it(g_currentY++, 0, tmp);
2131#ifdef __FreeBSD__
[128]2132 strcpy(partcode, format); // was a5
[1]2133#else
[128]2134 strcpy(partcode, format); // was 83
[1]2135#endif
2136 }
[128]2137 sprintf(tmp, "Setting %s's type to %s (%s)", partition, format,
2138 partcode);
[1]2139 log_msg(1, tmp);
2140 if (partcode[0] != '\0' && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
[128]2141
2142 if (pout_to_fdisk) {
[1]2143 res = 0;
2144 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
[128]2145 if (partno > 1
2146 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
[1]2147 log_msg(5, "Specifying partno (%d) - yay", partno);
2148 sprintf(tmp, "%d\n", partno);
2149 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
[128]2150 log_msg(5, "A - last line = '%s'",
2151 last_line_of_file(FDISK_LOG));
[1]2152 }
[128]2153
[1]2154 sprintf(tmp, "%s\n", partcode);
2155 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
[128]2156 log_msg(5, "B - last line = '%s'",
2157 last_line_of_file(FDISK_LOG));
[1]2158 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
[128]2159 log_msg(5, "C - last line = '%s'",
2160 last_line_of_file(FDISK_LOG));
2161
[1]2162 strcpy(tmp, last_line_of_file(FDISK_LOG));
[128]2163 if (!strstr(tmp, " (m ")) {
2164 log_msg(1, "last line = '%s'; part type set failed", tmp);
2165 res++;
2166 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2167 }
2168 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2169 } else {
[2211]2170 mr_asprintf(&output, "t\n%d\n%s\nw\n", partno, partcode);
[128]2171 sprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2172 MONDO_LOGFILE, MONDO_LOGFILE);
[1]2173 log_msg(5, "output = '%s'", output);
2174 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2175 log_msg(5, "command = '%s'", command);
2176 fout = popen(command, "w");
2177 if (!fout) {
2178 log_OS_error(command);
2179 res = 1;
2180 } else {
2181 res = 0;
[2190]2182 fprintf(fout, "%s", output);
[1]2183 paranoid_pclose(fout);
2184 }
[2211]2185 paranoid_free(output);
[1]2186 }
[128]2187 if (res) {
2188 log_OS_error(command);
2189 }
[1]2190 }
2191
[128]2192 paranoid_free(partition);
2193 paranoid_free(command);
2194 paranoid_free(tmp);
2195 paranoid_free(partcode);
2196 paranoid_free(logfile);
[1]2197
[128]2198 return (res);
[1]2199}
2200
2201
2202int start_raid_device(char *raid_device)
2203{
2204 /** int *************************************************************/
2205 int res;
2206 int retval = 0;
2207
2208 /** buffers *********************************************************/
2209 char *program;
2210
2211 /** end *************************************************************/
2212
2213 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2214 malloc_string(program);
[128]2215
[1]2216#ifdef __FreeBSD__
2217 if (is_this_device_mounted(raid_device)) {
2218 log_it("Can't start %s when it's mounted!", raid_device);
2219 return 1;
2220 }
2221 sprintf(program, "vinum start -f %s", raid_device);
2222#else
2223 sprintf(program, "raidstart %s", raid_device);
2224#endif
2225 log_msg(1, "program = %s", program);
2226 res = run_program_and_log_output(program, 1);
[128]2227 if (g_fprep) {
2228 fprintf(g_fprep, "%s\n", program);
2229 }
2230 if (res) {
2231 log_msg(1, "Warning - failed to start RAID device %s",
2232 raid_device);
2233 }
[1]2234 retval += res;
2235 sleep(1);
2236 return (retval);
2237}
2238
2239
2240
2241/**
2242 * Stop @p raid_device using @p raidstop.
2243 * @param raid_device The software RAID device to stop.
2244 * @return 0 for success, nonzero for failure.
2245 */
2246int stop_raid_device(char *raid_device)
2247{
2248 /** int *************************************************************/
2249 int res;
2250 int retval = 0;
2251
2252 /** buffers *********************************************************/
2253 char *program;
2254
2255 /** end *************************************************************/
2256
2257 assert_string_is_neither_NULL_nor_zerolength(raid_device);
2258 malloc_string(program);
[128]2259
[1]2260#ifdef __FreeBSD__
2261 if (is_this_device_mounted(raid_device)) {
2262 log_it("Can't stop %s when it's mounted!", raid_device);
2263 return 1;
2264 }
2265 sprintf(program, "vinum stop -f %s", raid_device);
2266#else
[558]2267 // use raidstop if it exists, otherwise use mdadm
2268 if (run_program_and_log_output("which raidstop", FALSE)) {
2269 sprintf(program, "mdadm -S %s", raid_device);
2270 } else {
2271 sprintf(program, "raidstop %s", raid_device);
2272 }
[1]2273#endif
2274 log_msg(1, "program = %s", program);
2275 res = run_program_and_log_output(program, 1);
[128]2276 if (g_fprep) {
2277 fprintf(g_fprep, "%s\n", program);
2278 }
2279 if (res) {
2280 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2281 }
[1]2282 retval += res;
2283 return (retval);
2284}
2285
2286
2287int start_all_raid_devices(struct mountlist_itself *mountlist)
2288{
2289 int i;
[128]2290 int retval = 0;
[1]2291 int res;
[128]2292
2293 for (i = 0; i < mountlist->entries; i++) {
2294 if (!strncmp
2295 (mountlist->el[i].device, RAID_DEVICE_STUB,
2296 strlen(RAID_DEVICE_STUB))) {
2297 log_msg(1, "Starting %s", mountlist->el[i].device);
2298 res = start_raid_device(mountlist->el[i].device);
2299 retval += res;
2300 }
2301 }
2302 if (retval) {
2303 log_msg(1, "Started all s/w raid devices OK");
2304 } else {
2305 log_msg(1, "Failed to start some/all s/w raid devices");
2306 }
2307 return (retval);
[1]2308}
2309
2310/**
2311 * Stop all software RAID devices listed in @p mountlist.
2312 * @param mountlist The mountlist to stop the RAID devices in.
2313 * @return The number of errors encountered (0 for success).
2314 * @bug @p mountlist is not used.
2315 */
2316int stop_all_raid_devices(struct mountlist_itself *mountlist)
2317{
2318 /** int *************************************************************/
2319 int retval = 0;
2320#ifndef __FreeBSD__
2321 int res;
2322#endif
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 int i;
2335
2336 /** end ****************************************************************/
2337
2338 malloc_string(dev);
2339 malloc_string(incoming);
2340 assert(mountlist != NULL);
2341
2342 for (i = 0; i < 3; i++) {
2343#ifdef __FreeBSD__
[128]2344 fin =
2345 popen
2346 ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2347 "r");
[1]2348 if (!fin) {
2349 paranoid_free(dev);
2350 paranoid_free(incoming);
2351 return (1);
2352 }
[128]2353 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2354 fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]2355 retval += stop_raid_device(incoming);
2356 }
2357#else
2358 fin = fopen("/proc/mdstat", "r");
2359 if (!fin) {
2360 log_OS_error("/proc/mdstat");
2361 paranoid_free(dev);
2362 paranoid_free(incoming);
2363 return (1);
2364 }
[128]2365 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2366 fgets(incoming, MAX_STR_LEN - 1, fin)) {
2367 for (p = incoming;
2368 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2369 || !isdigit(*(p + 2))); p++);
[1]2370 if (*p != '\0') {
2371 sprintf(dev, "/dev/%s", p);
2372 for (p = dev; *p > 32; p++);
2373 *p = '\0';
2374 res = stop_raid_device(dev);
2375 }
2376 }
2377#endif
2378 }
2379 paranoid_fclose(fin);
[128]2380 if (retval) {
2381 log_msg(1, "Warning - unable to stop some RAID devices");
2382 }
[1]2383 paranoid_free(dev);
2384 paranoid_free(incoming);
[128]2385 system("sync");
2386 system("sync");
2387 system("sync");
[1]2388 sleep(1);
2389 return (retval);
2390}
2391
2392
2393
2394/**
2395 * Decide which command we need to use to format a device of type @p format.
2396 * @param format The filesystem type we are about to format.
2397 * @param program Where to put the binary name for this format.
2398 * @return 0 for success, nonzero for failure.
2399 */
2400int which_format_command_do_i_need(char *format, char *program)
2401{
2402 /** int *************************************************************/
2403 int res = 0;
2404
2405 /** buffers *********************************************************/
2406 char *tmp;
2407
2408 /** end ***************************************************************/
2409
2410 malloc_string(tmp);
2411 assert_string_is_neither_NULL_nor_zerolength(format);
2412 assert(program != NULL);
2413
2414 if (strcmp(format, "swap") == 0) {
2415#ifdef __FreeBSD__
2416 strcpy(program, "true");
2417#else
2418 strcpy(program, "mkswap");
2419#endif
2420 } else if (strcmp(format, "vfat") == 0) {
2421 strcpy(program, "format-and-kludge-vfat");
2422#ifndef __FreeBSD__
2423 } else if (strcmp(format, "reiserfs") == 0) {
2424 strcpy(program, "mkreiserfs -ff");
2425 } else if (strcmp(format, "xfs") == 0) {
2426 strcpy(program, "mkfs.xfs -f -q");
2427 } else if (strcmp(format, "jfs") == 0) {
2428 strcpy(program, "mkfs.jfs");
2429 } else if (strcmp(format, "ext3") == 0) {
[1741]2430 strcpy(program, "mkfs -t ext3 -F -q");
[2087]2431 } else if (strcmp(format, "ext4") == 0) {
2432 strcpy(program, "mkfs -t ext4 -F -q");
[1]2433 } else if (strcmp(format, "minix") == 0) {
2434 strcpy(program, "mkfs.minix");
[1497]2435 } else if (strcmp(format, "vmfs") == 0) {
2436 strcpy(program, "mkfs -t vmfs");
[2147]2437 } else if (strcmp(format, "ntfs") == 0) {
2438 /*
2439 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2440 * so the default "mkfs -t %s -c" command structure fails
2441 */
2442 strcpy(program, "mkfs -t ntfs");
[2017]2443 } else if (strcmp(format, "ocfs2") == 0) {
2444 /*
2445 * 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.
2446 *
2447 */
2448 strcpy(program, "mkfs -t ocfs2 -F");
[1]2449#endif
2450 } else if (strcmp(format, "ext2") == 0) {
2451 strcpy(program, "mke2fs -F -q");
2452 } else {
2453#ifdef __FreeBSD__
2454 sprintf(program, "newfs_%s", format);
2455#else
2456 sprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
2457#endif
[128]2458 sprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format,
2459 program);
[1]2460 log_it(tmp);
2461 res = 0;
2462 }
2463 paranoid_free(tmp);
2464 return (res);
2465}
2466
2467
2468/**
2469 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2470 * There are a few problems with this function:
2471 * - It won't work if there was any unallocated space on the user's hard drive
2472 * when it was backed up.
2473 * - It won't work if the user's hard drive lies about its size (more common
2474 * than you'd think).
2475 *
2476 * @param mountlist The mountlist to use for resizing @p drive_name.
2477 * @param drive_name The drive to resize.
2478 */
2479void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
[128]2480 *mountlist,
2481 char *drive_name)
[1]2482{
2483 /**buffers **********************************************************/
2484 char *tmp;
2485
2486 /** int *************************************************************/
2487 int partno, lastpart;
[128]2488 /** remove driveno, noof_drives stan benoit apr 2002**/
[1]2489
2490 /** float ***********************************************************/
[2932]2491 float factor;
[2764]2492 long long new_size;
[1]2493
2494 /** long *************************************************************/
[2764]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 */
[1]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)) {
[128]2509 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2510 == 0) {
[1]2511 return;
2512 }
2513 }
2514
[2764]2515 current_size_of_drive = (long long) get_phys_size_of_drive(drive_name) * 1024LL;
[128]2516
[2764]2517 if (current_size_of_drive <= 0LL) {
[1]2518 log_it("Not resizing to match %s - can't find drive", drive_name);
2519 return;
2520 }
[2764]2521 mr_asprintf(&tmp, "Expanding entries to suit drive %s (%lld MB)", drive_name, current_size_of_drive / 1024);
[1]2522 log_to_screen(tmp);
[2764]2523 mr_free(tmp);
[1]2524
[128]2525 drivemntlist = malloc(sizeof(struct mountlist_reference));
[2932]2526 drivemntlist->el = malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
[1]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++) {
[2764]2534 if (drivemntlist->el[partno]->size > 0LL) {
2535 /* Keep KB here */
2536 original_size_of_drive += drivemntlist->el[partno]->size;
[2125]2537 }
[1]2538 }
2539
[2932]2540 if (original_size_of_drive <= 0LL) {
[2764]2541 mr_asprintf(&tmp, "Cannot resize %s's entries. Drive not found.", drive_name);
[1]2542 log_to_screen(tmp);
[2764]2543 mr_free(tmp);
[1]2544 return;
2545 }
[2932]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)",
[2764]2548 drive_name, original_size_of_drive/1024, current_size_of_drive/1024, factor);
[1]2549 log_to_screen(tmp);
[2764]2550 mr_free(tmp);
[1]2551
[128]2552 lastpart = drivemntlist->entries - 1;
[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 */
[128]2555 if (!atoi(drivemntlist->el[partno]->format)) {
[2932]2556 new_size = (long long)((drivemntlist->el[partno]->size) * factor);
[1]2557 } else {
2558 new_size = drivemntlist->el[partno]->size;
2559 }
[128]2560
[1]2561 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2562 log_msg(1, "Skipping %s (%s) because it's an image",
[128]2563 drivemntlist->el[partno]->device,
2564 drivemntlist->el[partno]->mountpoint);
[1]2565 }
[2764]2566 newsizL = new_size;
[2125]2567
2568 /* Do not apply the factor if partition was of negative size */
[2764]2569 if (newsizL < 0LL) {
[2125]2570 newsizL = drivemntlist->el[partno]->size;
2571 }
[2764]2572 totalsizL += newsizL;
[2125]2573
[2764]2574 mr_asprintf(&tmp, "Changing %s from %lld KB to %lld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
[1]2575 log_to_screen(tmp);
[2764]2576 mr_free(tmp);
[1]2577 drivemntlist->el[partno]->size = newsizL;
2578 }
[2764]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 }
[2125]2587 log_to_screen(tmp);
[2764]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);
[1]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
[128]2602 *mountlist)
[1]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') {
[128]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");
[1]2620 }
[2230]2621 log_it("Resizing mountlist");
[1]2622 make_list_of_drives_in_mountlist(mountlist, drivelist);
[2230]2623 log_it("Back from MLoDiM");
[1]2624 for (driveno = 0; driveno < drivelist->entries; driveno++) {
[128]2625 resize_drive_proportionately_to_suit_new_drives(mountlist,
2626 drivelist->
2627 el[driveno].
2628 device);
[1]2629 }
[541]2630 log_to_screen("Mountlist adjusted to suit current hard drive(s)");
[1]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 */
[128]2642void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2643 char *drive_name,
2644 struct mountlist_reference *drivemntlist)
2645{
[1]2646 int partno;
2647 char *tmp_drive_name, *c;
2648
2649 assert(mountlist != NULL);
2650 assert(drive_name != NULL);
2651 assert(drivemntlist != NULL);
2652
[128]2653 log_msg(1, "Creating list of partitions for drive %s", drive_name);
[1]2654
[128]2655 tmp_drive_name = strdup(drive_name);
2656 if (!tmp_drive_name)
2657 fatal_error("Out of memory");
2658
[1]2659 /* devfs devices? */
[128]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");
[1]2664 }
[128]2665 drivemntlist->entries = 0;
[1]2666 for (partno = 0; partno < mountlist->entries; partno++) {
[128]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];
[1]2672 drivemntlist->entries++;
2673 }
2674 }
2675 if (tmp_drive_name)
[128]2676 free(tmp_drive_name);
[1]2677}
2678
2679/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.