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

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

r4625@localhost: bruno | 2012-03-30 10:37:17 +0200

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