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

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