source: MondoRescue/branches/2.2.10/mondo/src/mondorestore/mondo-prep.c@ 2323

Last change on this file since 2323 was 2323, checked in by Bruno Cornec, 15 years ago

r3334@localhost: bruno | 2009-08-08 12:17:37 +0200

  • Change mr_asprintf interface to pass only the char * (makes bkpinfo usage more easy)
  • Property svn:keywords set to Id
File size: 72.9 KB
RevLine 
[1]1/***************************************************************************
[2052]2$Id: mondo-prep.c 2323 2009-08-18 13:05:43Z 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"
12#include "mondo-rstr-tools-EXT.h"
13#include <sys/ioctl.h>
14#include <linux/hdreg.h>
15#include <math.h>
16
17
[2192]18#define FDISK_LOG "/var/log/mondofdisk.log"
[1]19
20#ifdef __FreeBSD__
21#define DKTYPENAMES
22#define FSTYPENAMES
23#include <sys/disklabel.h>
24#include <sys/disk.h>
25#include <err.h>
26#include <libgen.h>
27#define OSSWAP(x,y) y
28#else
29#define OSSWAP(x,y) x
30#endif
31
32#define ARCHIVES_PATH MNT_CDROM"/archives"
33#define MONDO_WAS_HERE "MONDOWOZEREMONDOWOZEREMONDOWOZEREhahahaMOJOJOJO"
34
[71]35//static char cvsid[] = "$Id: mondo-prep.c 2323 2009-08-18 13:05:43Z bruno $";
[1]36
37extern char *g_mountlist_fname;
38extern long g_current_progress, g_maximum_progress;
39
40extern bool g_text_mode;
41
[128]42extern void pause_for_N_seconds(int, char *);
[1316]43extern char *MONDO_LOGFILE;
[1]44
[128]45FILE *g_fprep = NULL;
[1]46
47
48
[128]49int g_partition_table_locked_up = 0;
[1]50
51
52
53
54
55
56
57
58
59
60void wipe_MBRs_and_reboot_if_necessary(struct mountlist_itself *mountlist)
61{
[2281]62 char *command = NULL;
[128]63 char *tmp;
64 int lino;
65 int i;
[2281]66 int res = 0;
[128]67 FILE *fout;
68 char *buf;
69 const int blocksize = 512;
70 struct list_of_disks *drivelist = NULL;
[2281]71
[1]72// If LVMs are present and a zero-and-reboot wasn't recently undertaken
73// then zero & insist on reboot.
[128]74 malloc_string(tmp);
75 buf = malloc(blocksize);
76 if (does_file_exist("/tmp/i-want-my-lvm")) // FIXME - cheating :)
77 {
78 drivelist = malloc(sizeof(struct list_of_disks));
79 make_list_of_drives_in_mountlist(mountlist, drivelist);
80 for (lino = 0; lino < drivelist->entries; lino++) {
[2323]81 mr_asprintf(command, "dd if=%s bs=512 count=1 2> /dev/null | grep \"%s\"", drivelist->el[lino].device, MONDO_WAS_HERE);
[2281]82 res = run_program_and_log_output(command, 1);
83 mr_free(command);
84 if (!res) {
[128]85 log_msg(1, "Found MONDO_WAS_HERE marker on drive#%d (%s)",
86 lino, drivelist->el[lino].device);
87 break;
88 }
89 }
90
91 if (lino == drivelist->entries) {
[1]92// zero & reboot
[128]93 log_to_screen
[541]94 ("I am sorry for the inconvenience but I must ask you to reboot.");
[128]95 log_to_screen
[541]96 ("I need to reset the Master Boot Record; in order to be");
[128]97 log_to_screen
[541]98 ("sure the kernel notices, I must reboot after doing it.");
[128]99 log_to_screen("Please hit 'Enter' to reboot.");
100 for (lino = 0; lino < drivelist->entries; lino++) {
101 for (i = 0; i < blocksize; i++) {
102 buf[i] = 0;
103 }
104 sprintf(buf, "%s\n", MONDO_WAS_HERE);
105 fout = fopen(drivelist->el[lino].device, "w+");
106 if (!fout) {
107 log_msg(1, "Unable to open+wipe %s",
108 drivelist->el[lino].device);
109 } else {
110 if (1 != fwrite(buf, blocksize, 1, fout)) {
111 log_msg(1, "Failed to wipe %s",
112 drivelist->el[lino].device);
113 } else {
114 log_msg(1, "Successfully wiped %s",
115 drivelist->el[lino].device);
116 }
117 fclose(fout);
118 }
119 }
120 system("sync");
121 system("sync");
122 system("sync");
123 popup_and_OK
[541]124 ("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]125 system("reboot");
126 }
127 }
[1]128// Still here? Cool!
[128]129 paranoid_free(tmp);
130 log_msg(1, "Cool. I didn't have to wipe anything.");
[1]131}
132
133
134
135
136
137
[128]138int fput_string_one_char_at_a_time(FILE * fout, char *str)
[1]139{
[128]140 int i, j;
141 FILE *fq;
[1]142
[128]143 if (ferror(fout)) {
144 return (-1);
145 }
146 log_msg(5, "Writing string '%s', one char at a time", str);
147 j = strlen(str);
148 for (i = 0; i < j; i++) {
149 log_msg(6, "Writing %d ('%c')", str[i], str[i]);
150 if ((fq = fopen(FDISK_LOG, "a+"))) {
151 fputc(str[i], fq);
152 fclose(fq);
153 }
154 fputc(str[i], fout);
155 fflush(fout);
156 usleep(1000L * 100L);
157 if (str[i] < 32) {
158 usleep(1000L * 10L);
159 }
160 }
161 log_msg(5, "Returning");
162
163 return (i);
[1]164}
165
166
167
168
169
170
171
172
173
174
175/**
176 * @addtogroup prepGroup
177 * @{
178 */
179/**
180 * Execute the commands in /tmp/i-want-my-lvm.
181 * These should probably be commands to set up LVM.
182 * @return The number of errors encountered (0 for success).
183 */
184
[128]185
186int do_my_funky_lvm_stuff(bool just_erase_existing_volumes,
187 bool vacuum_pack)
[1]188{
189 /** buffers **********************************************/
190 char *tmp;
[1315]191 char *tmp1 = NULL;
[1]192 char *incoming;
193 char *command;
194 char *lvscan_sz;
195 char *lvremove_sz;
196 char *pvscan_sz;
197 char *vgscan_sz;
198 char *vgcreate_sz;
199 char *vgchange_sz;
200 char *vgremove_sz;
[128]201// char *do_this_last;
[1]202
203 /** char **************************************************/
204 char *p;
205 char *q;
206
207 /** int ***************************************************/
208 int retval = 0;
209 int res = 0;
210 int i;
211 int lvmversion = 1;
212 long extents;
213 fpos_t orig_pos;
[128]214
[1]215 /** pointers **********************************************/
216 FILE *fin;
217
218 /** end *****************************************************/
219
220#ifdef __FreeBSD__
221 return (0);
222#endif
223
224 if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) {
225 log_OS_error("/tmp/i-want-my-lvm");
226 return (1);
227 }
228
229 malloc_string(tmp);
230 malloc_string(incoming);
231 malloc_string(lvscan_sz);
232 malloc_string(lvremove_sz);
233 malloc_string(vgscan_sz);
234 malloc_string(pvscan_sz);
235 malloc_string(vgcreate_sz);
236 malloc_string(vgchange_sz);
237 malloc_string(vgremove_sz);
238 command = malloc(512);
239
[2230]240 log_it("STARTING");
[1]241 log_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes...");
[128]242 if (find_home_of_exe("lvm")) // found it :) cool
243 {
244 strcpy(lvscan_sz, "lvm lvscan");
245 strcpy(lvremove_sz, "lvm lvremove");
246 strcpy(vgscan_sz, "lvm vgscan");
247 strcpy(pvscan_sz, "lvm pvscan");
248 strcpy(vgcreate_sz, "lvm vgcreate");
249 strcpy(vgchange_sz, "lvm vgchange");
[2035]250 strcpy(vgremove_sz, "lvm vgremove -f");
[128]251 } else {
252 strcpy(lvscan_sz, "lvscan");
253 strcpy(lvremove_sz, "lvremove");
254 strcpy(vgscan_sz, "vgscan");
255 strcpy(pvscan_sz, "pvscan");
256 strcpy(vgcreate_sz, "vgcreate");
257 strcpy(vgchange_sz, "vgchange");
258 strcpy(vgremove_sz, "vgremove");
259 }
[2323]260 mr_asprintf(tmp1, "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);
[2281]261 run_program_and_log_output(tmp1, 5);
262 mr_free(tmp1);
263
[1]264 sleep(1);
[128]265 sprintf(command,
[1320]266 "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]267 run_program_and_log_output(command, 5);
268 if (just_erase_existing_volumes) {
269 paranoid_fclose(fin);
270 log_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs.");
[128]271 retval = 0;
[2281]272 } else {
[1]273
274 log_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff...");
275 rewind(fin);
[2179]276 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin); fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]277 fgetpos(fin, &orig_pos);
278 if (incoming[0] != '#') {
279 continue;
280 }
[128]281 if (res && strstr(command, "create") && vacuum_pack) {
282 sleep(2);
283 system("sync");
284 system("sync");
285 system("sync");
286 }
287 if ((p = strstr(incoming, "vgcreate"))) {
[2281]288 // include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm)
[2179]289 for (fgets(tmp, MAX_STR_LEN - 1, fin); !feof(fin); fgets(tmp, MAX_STR_LEN - 1, fin)) {
[128]290 if (tmp[0] == '#') {
291 fsetpos(fin, &orig_pos);
292 break;
293 } else {
294 fgetpos(fin, &orig_pos);
295 strcat(incoming, tmp);
296 }
[1]297 }
[128]298 for (q = incoming; *q != '\0'; q++) {
299 if (*q < 32) {
300 *q = ' ';
301 }
302 }
303 strcpy(tmp, p + strlen("vgcreate") + 1);
304 for (q = tmp; *q > 32; q++);
305 *q = '\0';
306 log_msg(1, "Deleting old entries at /dev/%s", tmp);
[2323]307 mr_asprintf(tmp1, "rm -Rf /dev/%s", tmp);
[2281]308 run_program_and_log_output(tmp1, 1);
309 mr_free(tmp1);
310
[128]311 run_program_and_log_output(vgscan_sz, 1);
312 run_program_and_log_output(pvscan_sz, 1);
313 log_msg(3,
314 "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'",
315 incoming);
316 }
[1]317 for (p = incoming + 1; *p == ' '; p++);
318 strcpy(command, p);
319 for (p = command; *p != '\0'; p++);
320 for (; *(p - 1) < 32; p--);
321 *p = '\0';
322 res = run_program_and_log_output(command, 5);
[128]323 if (res > 0 && (p = strstr(command, "lvm "))) {
324 *p = *(p + 1) = *(p + 2) = ' ';
325 res = run_program_and_log_output(command, 5);
326 }
[1]327 log_msg(0, "%s --> %d", command, res);
[128]328 if (res > 0) {
329 res = 1;
[1]330 }
[128]331 if (res && strstr(command, "lvcreate") && vacuum_pack) {
332 res = 0;
333 if (strstr(command, "lvm lvcreate"))
334 lvmversion = 2;
335 log_it("%s... so I'll get creative.", tmp);
336 if (lvmversion == 2) {
[2323]337 mr_asprintf(tmp1, "tail -n5 %s | grep Insufficient | tail -n1", MONDO_LOGFILE);
[1315]338 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
[2281]339 mr_free(tmp1);
[128]340 } else {
[2323]341 mr_asprintf(tmp1, "tail -n5 %s | grep lvcreate | tail -n1", MONDO_LOGFILE);
[1315]342 strcpy(tmp, call_program_and_get_last_line_of_output(tmp1));
[2281]343 mr_free(tmp1);
[128]344 }
345 for (p = tmp; *p != '\0' && !isdigit(*p); p++);
346 extents = atol(p);
347 log_msg(5, "p='%s' --> extents=%ld", p, extents);
348 p = strstr(command, "-L");
349 if (!p) {
350 log_msg(0, "Fiddlesticks. '%s' returned %d", command, res);
351 } else {
352 if (lvmversion == 2) {
353 *p++ = '-';
354 *p++ = 'l';
355 *p++ = ' ';
356 for (q = p; *q != ' '; q++) {
357 *q = ' ';
358 }
359 sprintf(p, "%ld", extents);
360 i = strlen(p);
361 *(p + i) = ' ';
362 } else {
363 p++;
364 p++;
365 p++;
366 for (q = p; *q != ' '; q++) {
367 *(q - 1) = ' ';
368 }
369 sprintf(p, "%ld%c", extents, 'm');
370 i = strlen(p);
371 *(p + i) = ' ';
372 }
373 log_msg(5, "Retrying with '%s'", command);
374 res = run_program_and_log_output(command, 5);
375 if (res > 0) {
376 res = 1;
377 }
378 if (g_fprep) {
379 fprintf(g_fprep, "%s\n", command);
380 }
381 log_msg(0, "%s --> %d", command, res);
382 if (!res) {
383 log_msg(5, "YAY! This time, it succeeded.");
384 }
385 }
386 }
387 if (strstr(command, "vgcreate")) {
388 log_msg(0, "In case you're interested...");
389 run_program_and_log_output(vgscan_sz, 1);
390 run_program_and_log_output(pvscan_sz, 1);
391 }
392 if (res != 0 && !strstr(command, "insmod")) {
393 retval++;
394 }
[2323]395 mr_asprintf(tmp1, "echo \"%s\" >> /tmp/out.sh", command);
[2281]396 system(tmp1);
397 mr_free(tmp1);
[1]398 sleep(1);
399 }
400 paranoid_fclose(fin);
401 log_msg(1, "Closed i-want-my-lvm. Finished doing funky stuff.");
[2281]402 }
[1]403 paranoid_free(tmp);
404 paranoid_free(incoming);
405 paranoid_free(command);
406 paranoid_free(lvscan_sz);
407 paranoid_free(lvremove_sz);
408 paranoid_free(vgscan_sz);
409 paranoid_free(pvscan_sz);
410 paranoid_free(vgcreate_sz);
411 paranoid_free(vgchange_sz);
412 paranoid_free(vgremove_sz);
[128]413 system("sync");
414 system("sync");
415 system("sync");
[1]416 sleep(1);
[2230]417 log_it("ENDING");
[128]418 if (retval > 2) {
419 log_msg(1, "%d errors. I'm reporting this.", retval);
420 return (retval);
421 } else {
422 log_msg(1, "Not many errors. Returning 0.");
423 return (0);
424 }
[1]425}
426
427
428/**
429 * Add RAID partitions while copying @p old_mountlist to @p new_mountlist.
430 * We go through @p old_mountlist and check if any RAID device (/dev/md? on Linux)
431 * is in it; if it is, then we put the disks contained within that RAID device
432 * into the mountlist as well.
433 * @param old_mountlist The mountlist to read.
434 * @param new_mountlist The mountlist to write, with the RAID partitions added.
435 * @return 0 for success, nonzero for failure.
436 */
[128]437int extrapolate_mountlist_to_include_raid_partitions(struct mountlist_itself
438 *new_mountlist, struct mountlist_itself
439 *old_mountlist)
[1]440{
441 /** pointers *********************************************************/
442 FILE *fin;
443
444 /** int **************************************************************/
445 int lino;
446 int j;
447
448 /** buffers **********************************************************/
449 char *incoming;
[2281]450 char *tmp = NULL;
[1]451
452 /** pointers *********************************************************/
453 char *p;
454
455 /** init *************************************************************/
456 new_mountlist->entries = 0;
457
458 /** end **************************************************************/
459
460 malloc_string(incoming);
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)) {
[2323]486 mr_asprintf(tmp, "Investigating %s", old_mountlist->el[lino].device);
[1]487 log_it(tmp);
[2281]488 mr_free(tmp);
489
[1]490 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin)
[128]491 && !strstr(incoming, "raiddev");
492 fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]493 if (strstr(incoming, OSSWAP("device", "drive"))
[128]494 && !strchr(incoming, '#')) {
495 for (p = incoming + strlen(incoming);
496 *(p - 1) <= 32; p--);
[1]497 *p = '\0';
498 for (p--; p > incoming && *(p - 1) > 32; p--);
[2323]499 mr_asprintf(tmp, "Extrapolating %s", p);
[1]500 log_it(tmp);
[2281]501 mr_free(tmp);
502
[128]503 for (j = 0;
504 j < new_mountlist->entries
505 && strcmp(new_mountlist->el[j].device, p);
506 j++);
[1]507 if (j >= new_mountlist->entries) {
[128]508 strcpy(new_mountlist->
509 el[new_mountlist->entries].device, p);
510 strcpy(new_mountlist->
511 el[new_mountlist->entries].mountpoint,
512 "raid");
513 strcpy(new_mountlist->
514 el[new_mountlist->entries].format,
515 "raid");
516 new_mountlist->el[new_mountlist->entries].
517 size = old_mountlist->el[lino].size;
[1]518 new_mountlist->entries++;
519 } else {
[2323]520 mr_asprintf(tmp, "Not adding %s to mountlist: it's already there", p);
[1]521 log_it(tmp);
[2281]522 mr_free(tmp);
[1]523 }
524 }
525 }
526 }
527 paranoid_fclose(fin);
528 } else {
[128]529 strcpy(new_mountlist->el[new_mountlist->entries].device,
530 old_mountlist->el[lino].device);
531 strcpy(new_mountlist->el[new_mountlist->entries].mountpoint,
532 old_mountlist->el[lino].mountpoint);
533 strcpy(new_mountlist->el[new_mountlist->entries].format,
534 old_mountlist->el[lino].format);
535 new_mountlist->el[new_mountlist->entries].size =
536 old_mountlist->el[lino].size;
[1]537 new_mountlist->entries++;
538 }
539 }
540 paranoid_free(incoming);
541
542 return (0);
543}
544
545
546/**
[558]547 * Create @p RAID device using information from @p structure.
548 * This will create the specified RAID devive using information provided in
549 * raidlist by means of the mdadm tool.
550 * @param raidlist The structure containing all RAID information
551 * @param device The RAID device to create.
552 * @return 0 for success, nonzero for failure.
553 */
554int create_raid_device_via_mdadm(struct raidlist_itself *raidlist, char *device)
555{
556 /** int **************************************************************/
557 int i = 0;
558 int j = 0;
559 int res = 0;
560
561 /** buffers ***********************************************************/
562 char *devices = NULL;
563 char *strtmp = NULL;
564 char *level = NULL;
565 char *program = NULL;
566
567 // leave straight away if raidlist is initial or has no entries
568 if (!raidlist || raidlist->entries == 0) {
569 log_msg(1, "No RAID arrays found.");
570 return 1;
571 } else {
572 log_msg(1, "%d RAID arrays found.", raidlist->entries);
573 }
574 // find raidlist entry for requested device
575 for (i = 0; i < raidlist->entries; i++) {
576 if (!strcmp(raidlist->el[i].raid_device, device)) break;
577 }
578 // check whether RAID device was found in raidlist
579 if (i == raidlist->entries) {
580 log_msg(1, "RAID device %s not found in list.", device);
581 return 1;
582 }
583 // create device list from normal disks followed by spare ones
[2323]584 mr_asprintf(devices, "%s", raidlist->el[i].data_disks.el[0].device);
[558]585 for (j = 1; j < raidlist->el[i].data_disks.entries; j++) {
[2323]586 mr_asprintf(strtmp, "%s", devices);
[558]587 paranoid_free(devices);
[2323]588 mr_asprintf(devices, "%s %s", strtmp,
[558]589 raidlist->el[i].data_disks.el[j].device);
590 paranoid_free(strtmp);
591 }
592 for (j = 0; j < raidlist->el[i].spare_disks.entries; j++) {
[2323]593 mr_asprintf(strtmp, "%s", devices);
[558]594 paranoid_free(devices);
[2323]595 mr_asprintf(devices, "%s %s", strtmp,
[558]596 raidlist->el[i].spare_disks.el[j].device);
597 paranoid_free(strtmp);
598 }
599 // translate RAID level
600 if (raidlist->el[i].raid_level == -2) {
[2323]601 mr_asprintf(level, "multipath");
[558]602 } else if (raidlist->el[i].raid_level == -1) {
[2323]603 mr_asprintf(level, "linear");
[558]604 } else {
[2323]605 mr_asprintf(level, "raid%d", raidlist->el[i].raid_level);
[558]606 }
607 // create RAID device:
608 // - RAID device, number of devices and devices mandatory
609 // - parity algorithm, chunk size and spare devices optional
610 // - faulty devices ignored
611 // - persistent superblock always used as this is recommended
[2323]612 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);
[558]613 if (raidlist->el[i].parity != -1) {
[2323]614 mr_asprintf(strtmp, "%s", program);
[558]615 paranoid_free(program);
616 switch(raidlist->el[i].parity) {
617 case 0:
[2323]618 mr_asprintf(program, "%s --parity=%s", strtmp, "la");
[558]619 break;
620 case 1:
[2323]621 mr_asprintf(program, "%s --parity=%s", strtmp, "ra");
[558]622 break;
623 case 2:
[2323]624 mr_asprintf(program, "%s --parity=%s", strtmp, "ls");
[558]625 break;
626 case 3:
[2323]627 mr_asprintf(program, "%s --parity=%s", strtmp, "rs");
[558]628 break;
629 default:
630 fatal_error("Unknown RAID parity algorithm.");
631 break;
632 }
633 paranoid_free(strtmp);
634 }
635 if (raidlist->el[i].chunk_size != -1) {
[2323]636 mr_asprintf(strtmp, "%s", program);
[558]637 paranoid_free(program);
[2323]638 mr_asprintf(program, "%s --chunk=%d", strtmp, raidlist->el[i].chunk_size);
[558]639 paranoid_free(strtmp);
640 }
641 if (raidlist->el[i].spare_disks.entries > 0) {
[2323]642 mr_asprintf(strtmp, "%s", program);
[558]643 paranoid_free(program);
[2323]644 mr_asprintf(program, "%s --spare-devices=%d", strtmp, raidlist->el[i].spare_disks.entries);
[558]645 paranoid_free(strtmp);
646 }
[2323]647 mr_asprintf(strtmp, "%s", program);
[558]648 paranoid_free(program);
[2323]649 mr_asprintf(program, "%s %s", strtmp, devices);
[558]650 paranoid_free(strtmp);
651 res = run_program_and_log_output(program, 1);
652 // free memory
653 paranoid_free(devices);
654 paranoid_free(level);
655 paranoid_free(program);
656 // return to calling instance
657 return res;
658}
659
660
661/**
[1]662 * Format @p device as a @p format filesystem.
663 * This will use the format command returned by which_format_command_do_i_need().
664 * If @p device is an LVM PV, it will not be formatted, and LVM will be started
665 * (if not already done). If it's an imagedev, software RAID component, or
666 * (under BSD) swap partition, no format will be done.
667 * @param device The device to format.
668 * @param format The filesystem type to format it as.
669 * @return 0 for success, nonzero for failure.
670 */
[558]671int format_device(char *device, char *format, struct raidlist_itself *raidlist)
[1]672{
673 /** int **************************************************************/
674#ifdef __FreeBSD__
675 static bool vinum_started_yet = FALSE;
676#endif
677
678 /** buffers ***********************************************************/
[2281]679 char *program = NULL;
[2211]680 char *tmp = NULL;
681 int res = 0;
682 int retval = 0;
[1]683
684 /** end ****************************************************************/
685
686 assert_string_is_neither_NULL_nor_zerolength(device);
687 assert(format != NULL);
688
689 if (strstr(format, "raid")) { // do not form RAID disks; do it to /dev/md* instead
[2323]690 mr_asprintf(tmp, "Not formatting %s (it is a RAID disk)", device);
[1]691 log_it(tmp);
[2299]692 mr_free(tmp);
[1]693 return (0);
694 }
695#ifdef __FreeBSD__
696 if (strcmp(format, "swap") == 0) {
697 log_it("Not formatting %s - it's swap", device);
698 return (0);
699 }
700#endif
701 if (strlen(format) <= 2) {
[2323]702 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]703 log_it(tmp);
[2299]704 mr_free(tmp);
[1]705 return (0);
706 }
707 if (is_this_device_mounted(device)) {
[2323]708 mr_asprintf(tmp, "%s is mounted - cannot format it ", device);
[1]709 log_to_screen(tmp);
[2299]710 mr_free(tmp);
[1]711 return (1);
712 }
713 if (strstr(device, RAID_DEVICE_STUB)) {
714 newtSuspend();
715#ifdef __FreeBSD__
716 if (!vinum_started_yet) {
717 if (!does_file_exist("/tmp/raidconf.txt")) {
[128]718 log_to_screen
[541]719 ("/tmp/raidconf.txt does not exist. I therefore cannot start Vinum.");
[1]720 } else {
721 int res;
[128]722 res =
723 run_program_and_log_output
724 ("vinum create /tmp/raidconf.txt", TRUE);
[1]725 if (res) {
726 log_to_screen
[541]727 ("`vinum create /tmp/raidconf.txt' returned errors. Please fix them and re-run mondorestore.");
[1]728 finish(1);
729 }
730 vinum_started_yet = TRUE;
731 }
732 }
733
734 if (vinum_started_yet) {
735 FILE *fin;
736 char line[MAX_STR_LEN];
[2211]737
[2323]738 mr_asprintf(tmp, "Initializing Vinum device %s (this may take a *long* time)", device);
[1]739 log_to_screen(tmp);
[2299]740 mr_free(tmp);
[2211]741
[1]742 /* format raid partition */
[2323]743 mr_asprintf(program, "for plex in `vinum lv -r %s | grep '^P' | tr '\t' ' ' | tr -s ' ' | cut -d' ' -f2`; do echo $plex; done > /tmp/plexes", basename(device));
[1]744 system(program);
[128]745 if (g_fprep) {
746 fprintf(g_fprep, "%s\n", program);
747 }
[2281]748 mr_free(program);
749
[1]750 fin = fopen("/tmp/plexes", "r");
751 while (fgets(line, MAX_STR_LEN - 1, fin)) {
752 if (strchr(line, '\n'))
753 *(strchr(line, '\n')) = '\0'; // get rid of the \n on the end
754
[2323]755 mr_asprintf(tmp, "Initializing plex: %s", line);
[1]756 open_evalcall_form(tmp);
[2299]757 mr_free(tmp);
[2211]758
[2323]759 mr_asprintf(tmp, "vinum init %s", line);
[1]760 system(tmp);
[2299]761 mr_free(tmp);
[2211]762
[1]763 while (1) {
[2323]764 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]765 FILE *pin = popen(tmp, "r");
[2299]766 mr_free(tmp);
[2211]767
[1]768 char status[MAX_STR_LEN / 4];
769 fgets(status, MAX_STR_LEN / 4 - 1, pin);
770 pclose(pin);
771
772 if (!strcmp(status, "up")) {
773 break; /* it's done */
774 }
775 update_evalcall_form(atoi(status));
776 usleep(250000);
777 }
778 close_evalcall_form();
779 }
780 fclose(fin);
781 unlink("/tmp/plexes");
782 }
783#else
[2323]784 mr_asprintf(tmp, "Initializing RAID device %s", device);
[1]785 log_to_screen(tmp);
[2299]786 mr_free(tmp);
[1]787
788// Shouldn't be necessary.
[541]789 log_to_screen("Stopping %s", device);
[1]790 stop_raid_device(device);
[128]791 system("sync");
792 sleep(1);
[1]793
794 log_msg(1, "Making %s", device);
[558]795 // use mkraid if it exists, otherwise use mdadm
796 if (run_program_and_log_output("which mkraid", FALSE)) {
797 res = create_raid_device_via_mdadm(raidlist, device);
798 log_msg(1, "Creating RAID device %s via mdadm returned %d", device, res);
799 } else {
[2323]800 mr_asprintf(program, "mkraid --really-force %s", device);
[558]801 res = run_program_and_log_output(program, 1);
802 log_msg(1, "%s returned %d", program, res);
803 system("sync");
804 sleep(3);
805 start_raid_device(device);
806 if (g_fprep) {
807 fprintf(g_fprep, "%s\n", program);
808 }
[2281]809 mr_free(program);
[128]810 }
811 system("sync");
812 sleep(2);
[1]813#endif
[128]814 system("sync");
815 sleep(1);
[1]816 newtResume();
817 }
818
[128]819 if (!strcmp(format, "lvm")) {
820 log_msg(1, "Don't format %s - it's part of an lvm volume", device);
821 return (0);
822 }
[2281]823 program = which_format_command_do_i_need(format);
[2323]824 mr_asprintf(tmp, "%s %s", program, device);
[1]825 if (strstr(program, "kludge")) {
[2211]826 mr_strcat(tmp, " /");
[1]827 }
[2281]828 mr_free(program);
829
[2323]830 mr_asprintf(program, "sh -c 'echo -en \"y\\ny\\ny\\n\" | %s'", tmp);
[2299]831 mr_free(tmp);
[2211]832
[2323]833 mr_asprintf(tmp, "Formatting %s as %s", device, format);
[1]834 update_progress_form(tmp);
[2299]835 mr_free(tmp);
[2211]836
[1]837 res = run_program_and_log_output(program, FALSE);
[2299]838 if (res) {
839 mr_strcat(tmp, "...failed");
840 } else {
841 mr_strcat(tmp, "...OK");
842 }
843 log_to_screen(tmp);
844 mr_free(tmp);
845
[1]846 if (res && strstr(program, "kludge")) {
[2299]847 mr_asprintf(&tmp, "Kludge failed; using regular mkfs.%s to format %s", format, device);
[2281]848 mr_free(program);
[1]849#ifdef __FreeBSD__
[2323]850 mr_asprintf(program, "newfs_msdos -F 32 %s", device);
[1]851#else
[85]852#ifdef __IA64__
853 /* For EFI partitions take fat16
854 * as we want to make small ones */
[2323]855 mr_asprintf(program, "mkfs -t %s -F 16 %s", format, device);
[85]856#else
[2323]857 mr_asprintf(program, "mkfs -t %s -F 32 %s", format, device);
[1]858#endif
[85]859#endif
[1]860 res = run_program_and_log_output(program, FALSE);
[128]861 if (g_fprep) {
862 fprintf(g_fprep, "%s\n", program);
863 }
[2299]864 if (retval) {
865 mr_strcat(tmp, "...failed");
866 } else {
867 mr_strcat(tmp, "...OK");
868 }
869
870 log_to_screen(tmp);
871 mr_free(tmp);
872
[1]873 }
[2281]874 mr_free(program);
[1]875 retval += res;
[128]876 system("sync");
877 sleep(1);
[1]878 return (retval);
879}
880
881
882
883
884
885/**
886 * Format all drives (except those excluded by format_device()) in @p mountlist.
887 * @param mountlist The mountlist containing partitions to be formatted.
888 * @param interactively If TRUE, then prompt the user before each partition.
889 * @return The number of errors encountered (0 for success).
890 */
[558]891int format_everything(struct mountlist_itself *mountlist, bool interactively,
892 struct raidlist_itself *raidlist)
[1]893{
894 /** int **************************************************************/
895 int retval = 0;
896 int lino;
897 int res;
898
899 /** long *************************************************************/
900 long progress_step;
901
902 /** bools ************************************************************/
903 bool do_it;
904
905 /** buffers **********************************************************/
[2281]906 char *tmp = NULL;
[1]907
908 /** pointers *********************************************************/
909 struct mountlist_line *me; // mountlist entry
910 /** end **************************************************************/
911
[128]912 assert(mountlist != NULL);
[2323]913 mr_asprintf(tmp, "format_everything (mountlist, interactively = %s", (interactively) ? "true" : "false");
[1]914 log_it(tmp);
[2281]915 mr_free(tmp);
916
[541]917 mvaddstr_and_log_it(g_currentY, 0, "Formatting partitions ");
918 open_progress_form("Formatting partitions",
919 "I am now formatting your hard disk partitions.",
920 "This may take up to five minutes.", "",
[128]921 mountlist->entries + 1);
[1]922
[128]923 progress_step =
924 (mountlist->entries >
925 0) ? g_maximum_progress / mountlist->entries : 1;
[2281]926 // start soft-raids now (because LVM might depend on them)
927 // ...and for simplicity's sake, let's format them at the same time :)
[1]928 log_msg(1, "Stopping all RAID devices");
929 stop_all_raid_devices(mountlist);
[128]930 system("sync");
931 system("sync");
932 system("sync");
[1]933 sleep(2);
[128]934 log_msg(1, "Prepare soft-RAIDs"); // prep and format too
[1]935 for (lino = 0; lino < mountlist->entries; lino++) {
936 me = &mountlist->el[lino]; // the current mountlist entry
937 log_msg(2, "Examining %s", me->device);
938 if (!strncmp(me->device, "/dev/md", 7)) {
939 if (interactively) {
940 // ask user if we should format the current device
[2323]941 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
[1]942 do_it = ask_me_yes_or_no(tmp);
[2281]943 mr_free(tmp);
[1]944 } else {
945 do_it = TRUE;
946 }
947 if (do_it) {
[128]948 // NB: format_device() also stops/starts RAID device if necessary
[558]949 retval += format_device(me->device, me->format, raidlist);
[1]950 }
951 g_current_progress += progress_step;
952 }
953 }
[128]954 system("sync");
955 system("sync");
956 system("sync");
[1]957 sleep(2);
958// This last step is probably necessary
[128]959// log_to_screen("Re-starting software RAIDs...");
960// start_all_raid_devices(mountlist);
961// system("sync"); system("sync"); system("sync");
962// sleep(5);
[1]963// do LVMs now
964 log_msg(1, "Creating LVMs");
965 if (does_file_exist("/tmp/i-want-my-lvm")) {
[558]966 wait_until_software_raids_are_prepped("/proc/mdstat", 100);
[541]967 log_to_screen("Configuring LVM");
[128]968 if (!g_text_mode) {
969 newtSuspend();
970 }
971 res = do_my_funky_lvm_stuff(FALSE, TRUE);
972 if (!g_text_mode) {
973 newtResume();
974 }
975 if (!res) {
976 log_to_screen("LVM initialized OK");
977 } else {
978 log_to_screen("Failed to initialize LVM");
979 }
[1]980 if (res) {
[128]981 retval++;
[1]982 }
[128]983 sleep(3);
[1]984 }
[2281]985 // do regulars at last
[128]986 sleep(2); // woo!
987 log_msg(1, "Formatting regulars");
[1]988 for (lino = 0; lino < mountlist->entries; lino++) {
989 me = &mountlist->el[lino]; // the current mountlist entry
990 if (!strcmp(me->mountpoint, "image")) {
[2323]991 mr_asprintf(tmp, "Not formatting %s - it's an image", me->device);
[1]992 log_it(tmp);
[2281]993 mr_free(tmp);
[1]994 } else if (!strcmp(me->format, "raid")) {
[2323]995 mr_asprintf(tmp, "Not formatting %s - it's a raid-let", me->device);
[1]996 log_it(tmp);
[2281]997 mr_free(tmp);
[1]998 continue;
999 } else if (!strcmp(me->format, "lvm")) {
[2323]1000 mr_asprintf(tmp, "Not formatting %s - it's an LVM", me->device);
[1]1001 log_it(tmp);
[2281]1002 mr_free(tmp);
[1]1003 continue;
1004 } else if (!strncmp(me->device, "/dev/md", 7)) {
[2323]1005 mr_asprintf(tmp, "Already formatted %s - it's a soft-RAID dev", me->device);
[1]1006 log_it(tmp);
[2281]1007 mr_free(tmp);
[1]1008 continue;
1009 } else if (!does_file_exist(me->device)
[128]1010 && strncmp(me->device, "/dev/hd", 7)
1011 && strncmp(me->device, "/dev/sd", 7)) {
[2323]1012 mr_asprintf(tmp, "Not formatting %s yet - doesn't exist - probably an LVM", me->device);
[1]1013 log_it(tmp);
[2281]1014 mr_free(tmp);
[1]1015 continue;
1016 } else {
1017 if (interactively) {
1018 // ask user if we should format the current device
[2323]1019 mr_asprintf(tmp, "Shall I format %s (%s) ?", me->device, me->mountpoint);
[1]1020 do_it = ask_me_yes_or_no(tmp);
[2281]1021 mr_free(tmp);
[1]1022 } else {
1023 do_it = TRUE;
1024 }
1025
1026 if (do_it)
[558]1027 retval += format_device(me->device, me->format, raidlist);
[1]1028 }
1029
1030 // update progress bar
1031 g_current_progress += progress_step;
1032 }
1033
1034
1035 // update progress bar to 100% to compensate for
1036 // rounding errors of the progress_step calculation
1037 if (lino >= mountlist->entries)
1038 g_current_progress = g_maximum_progress;
1039
1040 close_progress_form();
1041
1042 if (retval) {
[541]1043 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
[128]1044 log_to_screen
[541]1045 ("Errors occurred during the formatting of your hard drives.");
[1]1046 } else {
[541]1047 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
[1]1048 }
1049
[2323]1050 mr_asprintf(tmp, "format_everything () - %s", (retval) ? "failed!" : "finished successfully");
[1]1051 log_it(tmp);
[2281]1052 mr_free(tmp);
[1]1053
[128]1054 if (g_partition_table_locked_up > 0) {
1055 if (retval > 0 && !interactively) {
[1]1056//123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
[128]1057 log_to_screen
[541]1058 ("Partition table locked up %d times. At least one 'mkfs' (format) command",
[128]1059 g_partition_table_locked_up);
1060 log_to_screen
[541]1061 ("failed. I think these two events are related. Sometimes, fdisk's ioctl() call");
[128]1062 log_to_screen
[541]1063 ("to refresh its copy of the partition table causes the kernel to lock the ");
[128]1064 log_to_screen
[541]1065 ("partition table. I believe this has just happened.");
[128]1066 if (ask_me_yes_or_no
[541]1067 ("Please choose 'yes' to reboot and try again; or 'no' to ignore this warning and continue."))
[128]1068 {
1069 system("sync");
1070 system("sync");
1071 system("sync");
1072 system("reboot");
1073 }
1074 } else {
1075 log_to_screen
[541]1076 ("Partition table locked up %d time%c. However, disk formatting succeeded.",
[128]1077 g_partition_table_locked_up,
1078 (g_partition_table_locked_up == 1) ? '.' : 's');
1079 }
1080 }
1081 newtSuspend();
[1]1082 system("clear");
1083 newtResume();
1084 return (retval);
1085}
1086
1087
1088/**
1089 * Create small dummy partitions to fill in the gaps in partition numbering for @p drivename.
1090 * Each partition created is 32k in size.
1091 * @param drivename The drive to create the dummy partitions on.
1092 * @param devno_we_must_allow_for The lowest-numbered real partition; create
1093 * dummies up to (this - 1).
1094 * @return The number of errors encountered (0 for success).
1095 */
[128]1096int make_dummy_partitions(FILE * pout_to_fdisk, char *drivename,
1097 int devno_we_must_allow_for)
[1]1098{
1099 /** int **************************************************************/
1100 int current_devno;
1101 int previous_devno;
1102 int retval = 0;
1103 int res;
1104
1105 /** buffers **********************************************************/
[2281]1106 char *tmp = NULL;
[1]1107
1108 /** end **************************************************************/
1109
1110 assert_string_is_neither_NULL_nor_zerolength(drivename);
1111
1112 if (devno_we_must_allow_for >= 5) {
[2323]1113 mr_asprintf(tmp, "Making dummy primary 1 on %s", drivename);
[1]1114 log_it(tmp);
[2281]1115 mr_free(tmp);
1116
[1]1117 g_maximum_progress++;
[128]1118 res =
1119 partition_device(pout_to_fdisk, drivename, 1, 0, "ext2",
1120 32000);
[1]1121 retval += res;
1122 previous_devno = 1;
1123 current_devno = 5;
1124 } else {
1125 previous_devno = 0;
1126 current_devno = 1;
1127 }
1128 for (; current_devno < devno_we_must_allow_for; current_devno++) {
[2323]1129 mr_asprintf(tmp, "Creating dummy partition %d on %s", current_devno, drivename);
[1]1130 log_it(tmp);
[2281]1131 mr_free(tmp);
[1]1132 g_maximum_progress++;
[128]1133 res =
1134 partition_device(pout_to_fdisk, drivename, current_devno,
1135 previous_devno, OSSWAP("ext2", "ufs"), 32000);
[1]1136 retval += res;
1137 previous_devno = current_devno;
1138 }
1139 return (previous_devno);
1140}
1141
1142
1143/**
1144 * Decide whether @p mountlist contains any RAID devices.
1145 * @param mountlist The mountlist to examine.
1146 * @return TRUE if it does, FALSE if it doesn't.
1147 */
1148bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist)
1149{
1150 /** int *************************************************************/
1151 int i;
1152 int matching = 0;
1153
1154 /** end **************************************************************/
1155
1156 assert(mountlist != NULL);
1157
1158 for (i = 0; i < mountlist->entries; i++) {
1159 if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1160 matching++;
1161 }
1162 }
1163 if (matching) {
1164 return (TRUE);
1165 } else {
1166 return (FALSE);
1167 }
1168}
1169
1170/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1171#ifdef __FreeBSD__
1172static void display_disklabel(FILE * f, const struct disklabel *lp)
1173{
1174 int i, j;
1175 const struct partition *pp;
1176
1177 fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1178 if (lp->d_type < DKMAXTYPES)
1179 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1180 else
1181 fprintf(f, "type: %u\n", lp->d_type);
[128]1182 fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename),
1183 lp->d_typename);
1184 fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname),
1185 lp->d_packname);
[1]1186 fprintf(f, "flags:");
1187 if (lp->d_flags & D_REMOVABLE)
1188 fprintf(f, " removeable");
1189 if (lp->d_flags & D_ECC)
1190 fprintf(f, " ecc");
1191 if (lp->d_flags & D_BADSECT)
1192 fprintf(f, " badsect");
1193 fprintf(f, "\n");
1194 fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1195 fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1196 fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1197 fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1198 fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1199 fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1200 fprintf(f, "rpm: %u\n", lp->d_rpm);
1201 fprintf(f, "interleave: %u\n", lp->d_interleave);
1202 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1203 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
[128]1204 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
1205 (u_long) lp->d_headswitch);
1206 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
1207 (u_long) lp->d_trkseek);
[1]1208 fprintf(f, "drivedata: ");
1209 for (i = NDDATA - 1; i >= 0; i--)
1210 if (lp->d_drivedata[i])
1211 break;
1212 if (i < 0)
1213 i = 0;
1214 for (j = 0; j <= i; j++)
1215 fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1216 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
[128]1217 fprintf(f,
1218 "# size offset fstype [fsize bsize bps/cpg]\n");
[1]1219 pp = lp->d_partitions;
1220 for (i = 0; i < lp->d_npartitions; i++, pp++) {
1221 if (pp->p_size) {
[128]1222 fprintf(f, " %c: %8lu %8lu ", 'a' + i, (u_long) pp->p_size,
1223 (u_long) pp->p_offset);
[1]1224 if (pp->p_fstype < FSMAXTYPES)
1225 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1226 else
1227 fprintf(f, "%8d", pp->p_fstype);
1228 switch (pp->p_fstype) {
1229
1230 case FS_UNUSED: /* XXX */
[128]1231 fprintf(f, " %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1232 (u_long) (pp->p_fsize * pp->p_frag), "");
[1]1233 break;
1234
1235 case FS_BSDFFS:
[128]1236 fprintf(f, " %5lu %5lu %5u ", (u_long) pp->p_fsize,
1237 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
[1]1238 break;
1239
1240 case FS_BSDLFS:
[128]1241 fprintf(f, " %5lu %5lu %5d", (u_long) pp->p_fsize,
1242 (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
[1]1243 break;
1244
1245 default:
1246 fprintf(f, "%20.20s", "");
1247 break;
1248 }
[128]1249 fprintf(f, "\t# (Cyl. %4lu",
1250 (u_long) (pp->p_offset / lp->d_secpercyl));
[1]1251 if (pp->p_offset % lp->d_secpercyl)
1252 putc('*', f);
1253 else
1254 putc(' ', f);
[128]1255 fprintf(f, "- %lu",
1256 (u_long) ((pp->p_offset + pp->p_size +
1257 lp->d_secpercyl - 1) / lp->d_secpercyl -
1258 1));
[1]1259 if (pp->p_size % lp->d_secpercyl)
1260 putc('*', f);
1261 fprintf(f, ")\n");
1262 }
1263 }
1264 fflush(f);
1265}
1266
1267static struct disklabel *get_virgin_disklabel(char *dkname)
1268{
1269 static struct disklabel loclab;
1270 struct partition *dp;
1271 char lnamebuf[BBSIZE];
1272 int f;
1273 u_int secsize, u;
1274 off_t mediasize;
1275
1276 (void) snprintf(lnamebuf, BBSIZE, "%s", dkname);
1277 if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1278 warn("cannot open %s", lnamebuf);
1279 return (NULL);
1280 }
1281
1282 /* New world order */
1283 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
[128]1284 || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
[1]1285 close(f);
1286 return (NULL);
1287 }
1288 memset(&loclab, 0, sizeof loclab);
1289 loclab.d_magic = DISKMAGIC;
1290 loclab.d_magic2 = DISKMAGIC;
1291 loclab.d_secsize = secsize;
1292 loclab.d_secperunit = mediasize / secsize;
1293
1294 /*
1295 * Nobody in these enligthened days uses the CHS geometry for
1296 * anything, but nontheless try to get it right. If we fail
1297 * to get any good ideas from the device, construct something
1298 * which is IBM-PC friendly.
1299 */
1300 if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1301 loclab.d_nsectors = u;
1302 else
1303 loclab.d_nsectors = 63;
1304 if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1305 loclab.d_ntracks = u;
1306 else if (loclab.d_secperunit <= 63 * 1 * 1024)
1307 loclab.d_ntracks = 1;
1308 else if (loclab.d_secperunit <= 63 * 16 * 1024)
1309 loclab.d_ntracks = 16;
1310 else
1311 loclab.d_ntracks = 255;
1312 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1313 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1314 loclab.d_npartitions = MAXPARTITIONS;
1315
1316 /* Various (unneeded) compat stuff */
1317 loclab.d_rpm = 3600;
1318 loclab.d_bbsize = BBSIZE;
1319 loclab.d_interleave = 1;;
1320 strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1321
1322 dp = &loclab.d_partitions[RAW_PART];
1323 dp->p_size = loclab.d_secperunit;
1324 loclab.d_checksum = dkcksum(&loclab);
1325 close(f);
1326 return (&loclab);
1327}
[128]1328
[1]1329/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1330
1331char *canonical_name(char *drivename)
1332{
1333 if (drivename) {
1334 if (strncmp(drivename, "/dev/", 5) == 0) {
1335 return drivename + 5;
1336 }
1337 }
1338 return drivename;
1339}
1340
1341/**
1342 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1343 * @param mountlist The mountlist to get the subpartition information from.
1344 * @param drivename The drive or slice to create a disklabel on.
1345 * @param ret If non-NULL, store the created disklabel here.
1346 * @return The number of errors encountered (0 for success).
1347 */
[128]1348int label_drive_or_slice(struct mountlist_itself *mountlist,
1349 char *drivename, struct disklabel *ret)
[1]1350{
[2281]1351 char *subdev_str = NULL
1352 char *command = NULL;
[1]1353 struct disklabel *lp;
1354 int i, lo = 0;
1355 int retval = 0;
1356 char c;
1357 FILE *ftmp;
1358
1359 lp = get_virgin_disklabel(drivename);
1360 for (c = 'a'; c <= 'z'; ++c) {
1361 int idx;
[2323]1362 mr_asprintf(subdev_str, "%s%c", drivename, c);
[1]1363 if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1364 lp->d_partitions[c - 'a'].p_size = 0;
1365 lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1366 } else {
1367 lo = c - 'a';
1368 lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1369 lp->d_partitions[c - 'a'].p_fsize = 0;
1370 lp->d_partitions[c - 'a'].p_frag = 0;
1371 lp->d_partitions[c - 'a'].p_cpg = 0;
1372 if (!strcmp(mountlist->el[idx].format, "ufs")
[128]1373 || !strcmp(mountlist->el[idx].format, "ffs")
1374 || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
[1]1375 lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1376 lp->d_partitions[c - 'a'].p_fsize = 2048;
1377 lp->d_partitions[c - 'a'].p_frag = 8;
1378 lp->d_partitions[c - 'a'].p_cpg = 64;
1379 } else if (!strcasecmp(mountlist->el[idx].format, "raid")
[128]1380 || !strcasecmp(mountlist->el[idx].format, "vinum")) {
[1]1381 lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1382 } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1383 lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1384 } else
1385 lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1386 }
[2281]1387 mr_free(subdev_str);
[1]1388 }
1389
1390 // fix up the offsets
1391 lp->d_partitions[0].p_offset = 0;
1392 lp->d_partitions[RAW_PART].p_offset = 0;
1393 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1394 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1395
1396 for (i = 1; i < lp->d_npartitions; ++i) {
1397 int lastone;
1398 if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1399 continue;
1400 for (lastone = i - 1; lastone >= 0; lastone--) {
1401 if ((lp->d_partitions[lastone].p_size)
[128]1402 && (lastone != RAW_PART))
[1]1403 break;
1404 }
[128]1405 lp->d_partitions[i].p_offset =
1406 lp->d_partitions[lastone].p_offset +
1407 lp->d_partitions[lastone].p_size;
[1]1408 }
[128]1409 if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size >
1410 lp->d_secperunit) {
1411 lp->d_partitions[lo].p_size =
1412 lp->d_secperunit - lp->d_partitions[lo].p_offset;
[1]1413 }
1414
1415 ftmp = fopen("/tmp/disklabel", "w");
1416 display_disklabel(ftmp, lp);
1417 fclose(ftmp);
[2323]1418 mr_asprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
[1]1419 retval += run_program_and_log_output(command, TRUE);
[2281]1420 mr_free(command);
1421
[2323]1422 mr_asprintf(command, "disklabel -R %s /tmp/disklabel", canonical_name(drivename));
[1]1423 retval += run_program_and_log_output(command, TRUE);
[2281]1424 mr_free(command);
[1]1425 if (ret)
1426 *ret = *lp;
1427 return retval;
1428}
1429#endif
1430
1431
1432/**
1433 * Partition @p drivename based on @p mountlist.
1434 * @param mountlist The mountlist to use to guide the partitioning.
1435 * @param drivename The drive to partition.
1436 * @return 0 for success, nonzero for failure.
1437 */
1438int partition_drive(struct mountlist_itself *mountlist, char *drivename)
1439{
1440 /** int *************************************************************/
1441 int current_devno;
1442 int previous_devno = 0;
1443 int lino;
1444 int retval = 0;
1445 int i;
[128]1446 FILE *pout_to_fdisk = NULL;
1447
[1]1448#ifdef __FreeBSD__
1449 bool fbsd_part = FALSE;
[2281]1450 char *subdev_str = NULL;
1451 char *command = NULL;
1452 int r = 0;
[1]1453#endif
1454
1455 /** long long *******************************************************/
1456 long long partsize;
1457
1458 /** buffers *********************************************************/
[2316]1459 char *device_str = NULL;
[1]1460 char *format;
[2281]1461 char *tmp = NULL;
[1]1462
1463 /** end *************************************************************/
1464
1465 assert(mountlist != NULL);
1466 assert_string_is_neither_NULL_nor_zerolength(drivename);
1467
1468 malloc_string(format);
[128]1469
[2323]1470 mr_asprintf(tmp, "Partitioning drive %s", drivename);
[1]1471 log_it(tmp);
[2281]1472 mr_free(tmp);
[1]1473
[128]1474#if __FreeBSD__
1475 log_it("(Not opening fdisk now; that's the Linux guy's job)");
[1]1476 pout_to_fdisk = NULL;
1477#else
1478 make_hole_for_file(FDISK_LOG);
[2323]1479 mr_asprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
[1]1480 pout_to_fdisk = popen(tmp, "w");
[2281]1481 mr_free(tmp);
[128]1482 if (!pout_to_fdisk) {
[541]1483 log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
[1]1484 paranoid_free(format);
[128]1485 return (1);
[1]1486 }
1487#endif
1488 for (current_devno = 1; current_devno < 99; current_devno++) {
[2316]1489 device_str = build_partition_name(drivename, current_devno);
[1]1490 lino = find_device_in_mountlist(mountlist, device_str);
1491
1492 if (lino < 0) {
1493 // device not found in mountlist
1494#if __FreeBSD__
1495 // If this is the first partition (just as a sentinel value),
1496 // then see if the user has picked 'dangerously-dedicated' mode.
1497 // If so, then we just call label_drive_or_slice() and return.
1498 char c;
1499 if (current_devno == 1) {
1500 // try DangerouslyDedicated mode
1501 for (c = 'a'; c <= 'z'; c++) {
[2323]1502 mr_asprintf(subdev_str, "%s%c", drivename, c);
[2281]1503 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
[1]1504 fbsd_part = TRUE;
1505 }
[2281]1506 mr_free(subdev_str);
[1]1507 }
1508 if (fbsd_part) {
[2281]1509 r = label_drive_or_slice(mountlist,
[128]1510 drivename,
1511 0);
[2323]1512 mr_asprintf(command, "disklabel -B %s", basename(drivename));
[1]1513 if (system(command)) {
[128]1514 log_to_screen
[541]1515 ("Warning! Unable to make the drive bootable.");
[1]1516 }
[2281]1517 mr_free(command);
[2316]1518 mr_free(device_str);
[1]1519 paranoid_free(format);
1520 return r;
1521 }
1522 }
1523 for (c = 'a'; c <= 'z'; c++) {
[2323]1524 mr_asprintf(subdev_str, "%s%c", device_str, c);
[1]1525 if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1526 fbsd_part = TRUE;
1527 }
[2281]1528 mr_free(subdev_str);
[1]1529 }
1530 // Now we check the subpartitions of the current partition.
1531 if (fbsd_part) {
1532 int i, line;
1533
1534 strcpy(format, "ufs");
1535 partsize = 0;
1536 for (i = 'a'; i < 'z'; ++i) {
[2323]1537 mr_asprintf(subdev_str, "%s%c", device_str, i);
[1]1538 line = find_device_in_mountlist(mountlist, subdev_str);
[2281]1539 mr_free(subdev_str);
1540
[1]1541 if (line > 0) {
1542 // We found one! Add its size to the total size.
1543 partsize += mountlist->el[line].size;
1544 }
1545 }
1546 } else {
[2316]1547 mr_free(device_str);
[1]1548 continue;
1549 }
1550#else
[2316]1551 mr_free(device_str);
[1]1552 continue;
1553#endif
1554 }
1555
1556 /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1557 /* For FreeBSD, that is /dev/adXsY */
1558
1559 log_it("Found partition %s in mountlist", device_str);
1560 if (!previous_devno) {
1561
1562 log_it("Wiping %s's partition table", drivename);
1563#if __FreeBSD__
1564 // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1565 file = open(drivename, O_WRONLY);
[2205]1566 if (file != -1) {
[2323]1567 mr_asprintf(tmp, "Warning - unable to open %s for wiping it's partition table", drivename);
[1]1568 log_to_screen(tmp);
[2281]1569 mr_free(tmp);
[1]1570 }
1571
[128]1572 for (i = 0; i < 512; i++) {
1573 if (!write(file, "\0", 1)) {
[2323]1574 mr_asprintf(tmp, "Warning - unable to write to %s", drivename);
[1]1575 log_to_screen(tmp);
[2281]1576 mr_free(tmp);
[1]1577 }
1578 }
1579 system("sync");
1580#else
[2230]1581 log_it("New, kernel-friendly partition remover");
[128]1582 for (i = 20; i > 0; i--) {
1583 fprintf(pout_to_fdisk, "d\n%d\n", i);
1584 fflush(pout_to_fdisk);
1585 }
1586#endif
[1]1587 if (current_devno > 1) {
[128]1588 previous_devno =
1589 make_dummy_partitions(pout_to_fdisk, drivename,
1590 current_devno);
[1]1591 }
1592 }
1593#ifdef __FreeBSD__
1594 if (!fbsd_part) {
1595#endif
1596
[128]1597 strcpy(format, mountlist->el[lino].format);
1598 partsize = mountlist->el[lino].size;
[1]1599
1600#ifdef __FreeBSD__
1601 }
1602#endif
1603
[71]1604#ifndef __IA64__
[1]1605 if (current_devno == 5 && previous_devno == 4) {
[128]1606 log_to_screen
[541]1607 ("You must leave at least one partition spare as the Extended partition.");
[2316]1608 mr_free(device_str);
[1]1609 paranoid_free(format);
1610 return (1);
1611 }
[71]1612#endif
[1]1613
[128]1614 retval +=
1615 partition_device(pout_to_fdisk, drivename, current_devno,
1616 previous_devno, format, partsize);
[1]1617
1618#ifdef __FreeBSD__
1619 if ((current_devno <= 4) && fbsd_part) {
[2323]1620 mr_asprintf(tmp, "disklabel -B %s", basename(device_str));
[1]1621 retval += label_drive_or_slice(mountlist, device_str, 0);
1622 if (system(tmp)) {
[128]1623 log_to_screen
[541]1624 ("Warning! Unable to make the slice bootable.");
[1]1625 }
[2281]1626 mr_free(tmp);
[1]1627 }
1628#endif
[2316]1629 mr_free(device_str);
[1]1630
1631 previous_devno = current_devno;
1632 }
1633
[128]1634 if (pout_to_fdisk) {
[1]1635// mark relevant partition as bootable
[2323]1636 mr_asprintf(tmp, "a\n%s\n", call_program_and_get_last_line_of_output ("make-me-bootable /tmp/mountlist.txt dummy"));
[1]1637 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
[2281]1638 mr_free(tmp);
1639
[1]1640// close fdisk
1641 fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1642 system("sync");
[128]1643 paranoid_pclose(pout_to_fdisk);
1644 log_msg(0,
1645 "------------------- fdisk.log looks like this ------------------");
[2323]1646 mr_asprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
[1]1647 system(tmp);
[2281]1648 mr_free(tmp);
1649
[128]1650 log_msg(0,
1651 "------------------- end of fdisk.log... word! ------------------");
[2323]1652 mr_asprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
[128]1653 if (!run_program_and_log_output(tmp, 5)) {
1654 g_partition_table_locked_up++;
[2222]1655 }
[2281]1656 mr_free(tmp);
1657
[2323]1658 mr_asprintf(tmp, "partprobe %s", drivename);
[2222]1659 if (!run_program_and_log_output(tmp, 5)) {
1660 g_partition_table_locked_up--;
1661 }
[2281]1662 mr_free(tmp);
1663
[2222]1664 if (g_partition_table_locked_up > 0) {
[128]1665 log_to_screen
[2222]1666 ("A flaw in the Linux kernel has locked the partition table. Even calling partprobe did not suceed :-(");
[128]1667 }
[1]1668 }
1669 paranoid_free(format);
1670 return (retval);
1671}
1672
1673/**
1674 * Create partition number @p partno on @p drive with @p fdisk.
1675 * @param drive The drive to create the partition on.
1676// * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1677 * @param prev_partno The partition number of the most recently prepped partition.
1678 * @param format The filesystem type of this partition (used to set the type).
1679 * @param partsize The size of the partition in @e bytes.
1680 * @return 0 for success, nonzero for failure.
1681 */
[128]1682int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1683 int prev_partno, const char *format,
1684 long long partsize)
[1]1685{
1686 /** int **************************************************************/
1687 int retval = 0;
1688 int res = 0;
1689
1690 /** buffers **********************************************************/
[2281]1691 char *program = NULL;
[2316]1692 char *partition_name = NULL;
[2281]1693 char *tmp = NULL;
[2211]1694 char *output = NULL;
[1]1695
1696 /** pointers **********************************************************/
1697 char *p;
1698 char *part_table_fmt;
1699 FILE *fout;
1700
1701 /** end ***************************************************************/
1702
1703 assert_string_is_neither_NULL_nor_zerolength(drive);
1704 assert(format != NULL);
1705
[128]1706 log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1707 drive, partno, prev_partno, format, partsize);
[1]1708
1709 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
[2323]1710 mr_asprintf(tmp, "Not partitioning %s - it is a virtual drive", drive);
[1]1711 log_it(tmp);
[2281]1712 mr_free(tmp);
1713
[1]1714 return (0);
1715 }
[2316]1716 partition_name = build_partition_name(drive, partno);
[1]1717 if (partsize <= 0) {
[2323]1718 mr_asprintf(tmp, "Partitioning device %s (max size)", partition_name);
[1]1719 } else {
[2323]1720 mr_asprintf(tmp, "Partitioning device %s (%lld MB)", partition_name, (long long) partsize / 1024);
[1]1721 }
1722 update_progress_form(tmp);
1723 log_it(tmp);
[2281]1724 mr_free(tmp);
[1]1725
1726 if (is_this_device_mounted(partition_name)) {
[2323]1727 mr_asprintf(tmp, "%s is mounted, and should not be partitioned", partition_name);
[1]1728 log_to_screen(tmp);
[2281]1729 mr_free(tmp);
[2316]1730 mr_free(partition_name);
[1]1731 return (1);
1732 }
1733
1734
1735 p = (char *) strrchr(partition_name, '/');
1736
[2154]1737 /* BERLIOS: should not be called each time */
[88]1738 part_table_fmt = which_partition_format(drive);
[2323]1739 mr_asprintf(output, "");
[1]1740 /* make it a primary/extended/logical */
1741 if (partno <= 4) {
[2211]1742 mr_strcat(output, "n\np\n%d\n", partno);
[1]1743 } else {
[88]1744 /* MBR needs an extended partition if more than 4 partitions */
[128]1745 if (strcmp(part_table_fmt, "MBR") == 0) {
[88]1746 if (partno == 5) {
1747 if (prev_partno >= 4) {
[2316]1748 log_to_screen("You need to leave at least one partition free, for 'extended/logical'");
1749 mr_free(partition_name);
[88]1750 paranoid_free(output);
1751 return (1);
1752 } else {
[2211]1753 mr_strcat(output, "n\ne\n%d\n\n\n", prev_partno + 1);
[88]1754 }
1755 }
[2211]1756 mr_strcat(output, "n\nl\n");
[88]1757 } else {
[1]1758 /* GPT allows more than 4 primary partitions */
[2211]1759 mr_strcat(output, "n\np\n%d\n", partno);
[1]1760 }
1761 }
[2211]1762 mr_strcat(output, "\n"); /*start block (ENTER for next free blk */
[1]1763 if (partsize > 0) {
[128]1764 if (!strcmp(format, "7")) {
1765 log_msg(1, "Adding 512K, just in case");
1766 partsize += 512;
1767 }
[2211]1768 mr_strcat(output, "+%lldK", (long long) (partsize));
[1]1769 }
[2211]1770 mr_strcat(output, "\n");
[2323]1771 mr_asprintf(tmp,"PARTSIZE = +%ld",(long)partsize);
[1]1772 log_it(tmp);
[2281]1773 mr_free(tmp);
[2316]1774
[1]1775 log_it("---fdisk command---");
1776 log_it(output);
1777 log_it("---end of fdisk---");
1778
[2323]1779 mr_asprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE, MONDO_LOGFILE);
[128]1780 if (pout_to_fdisk) {
[1]1781 log_msg(1, "Doing the new all-in-one fdisk thing");
1782 log_msg(1, "output = '%s'", output);
1783 fput_string_one_char_at_a_time(pout_to_fdisk, output);
1784 fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
[2323]1785 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
[128]1786 if (strstr(tmp, " (m ")) {
[1303]1787 log_msg(1, "Successfully created partition %d on %s", partno, drive);
[128]1788 } else {
[1]1789 log_msg(1, "last line = %s", tmp);
[1303]1790 log_msg(1, "Failed to create partition %d on %s; sending 'Enter'...", partno, drive);
[1]1791 }
[2281]1792 mr_free(tmp);
1793
[128]1794 if (!retval) {
[1303]1795 log_msg(1, "Trying to set partition %d type now on %s", partno, drive);
[128]1796 retval =
1797 set_partition_type(pout_to_fdisk, drive, partno, format,
1798 partsize);
1799 if (retval) {
[1]1800 log_msg(1, "Failed. Trying again...");
[128]1801 retval =
1802 set_partition_type(pout_to_fdisk, drive, partno,
1803 format, partsize);
[1]1804 }
[128]1805 }
1806 if (retval) {
1807 log_msg(1, "...but failed to set type");
1808 }
1809 } else {
[2211]1810 mr_strcat(output, "w\n\n");
[128]1811 if (g_fprep) {
1812 fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
1813 }
[1]1814 /* write to disk; close fdisk's stream */
1815 if (!(fout = popen(program, "w"))) {
1816 log_OS_error("can't popen-out to program");
1817 } else {
1818 fputs(output, fout);
1819 paranoid_pclose(fout);
1820 }
1821 if (!does_partition_exist(drive, partno) && partsize > 0) {
1822 log_it("Vaccum-packing");
1823 g_current_progress--;
[128]1824 res =
1825 partition_device(pout_to_fdisk, drive, partno, prev_partno,
1826 format, -1);
[1]1827 if (res) {
[2323]1828 mr_asprintf(tmp, "Failed to vacuum-pack %s", partition_name);
[1]1829 log_it(tmp);
[2281]1830 mr_free(tmp);
1831
[1]1832 retval++;
1833 } else {
1834 retval = 0;
1835 }
1836 }
1837 if (does_partition_exist(drive, partno)) {
[128]1838 retval =
1839 set_partition_type(pout_to_fdisk, drive, partno, format,
1840 partsize);
[1]1841 if (retval) {
[2323]1842 mr_asprintf(tmp, "Partitioned %s but failed to set its type", partition_name);
[1]1843 log_it(tmp);
[2281]1844 mr_free(tmp);
[1]1845 } else {
1846 if (partsize > 0) {
[2323]1847 mr_asprintf(tmp, "Partition %s created+configured OK", partition_name);
[1]1848 log_to_screen(tmp);
[2281]1849 mr_free(tmp);
[1]1850 } else {
1851 log_it("Returning from a successful vacuum-pack");
1852 }
1853 }
[128]1854 } else {
[2323]1855 mr_asprintf(tmp, "Failed to partition %s", partition_name);
[1]1856 if (partsize > 0) {
1857 log_to_screen(tmp);
1858 } else {
1859 log_it(tmp);
1860 }
[2281]1861 mr_free(tmp);
[1]1862 retval++;
1863 }
1864 }
[2281]1865 mr_free(program);
[2316]1866 mr_free(partition_name);
[2211]1867 paranoid_free(output);
1868
[1]1869 g_current_progress++;
1870 log_it("partition_device() --- leaving");
1871 return (retval);
1872}
1873
1874
1875
1876/**
1877 * Create all partitions listed in @p mountlist.
1878 * @param mountlist The mountlist to use to guide the partitioning.
1879 * @return The number of errors encountered (0 for success).
1880 * @note This sets the partition types but doesn't actually do the formatting.
1881 * Use format_everything() for that.
1882 */
1883int partition_everything(struct mountlist_itself *mountlist)
1884{
1885 /** int ************************************************************/
1886 int lino;
1887 int retval = 0;
1888 int i;
1889 int res;
1890
1891 /** buffer *********************************************************/
1892 struct list_of_disks *drivelist;
1893 /* struct mountlist_itself new_mtlist, *mountlist; */
1894
1895 /** end ************************************************************/
1896
1897 drivelist = malloc(sizeof(struct list_of_disks));
1898 assert(mountlist != NULL);
1899
1900 log_it("partition_everything() --- starting");
1901 mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives ");
1902 /* mountlist=orig_mtlist; */
1903 if (mountlist_contains_raid_devices(mountlist)) {
1904 /* mountlist=&new_mtlist; */
1905 /* extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
[128]1906 log_msg(0,
1907 "Mountlist, including the partitions incorporated in RAID devices:-");
[1]1908 for (i = 0; i < mountlist->entries; i++) {
1909 log_it(mountlist->el[i].device);
1910 }
1911 log_msg(0, "End of mountlist.");
1912 }
1913 log_msg(0, "Stopping all LVMs, just in case");
[128]1914 if (!g_text_mode) {
1915 newtSuspend();
1916 }
1917 do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
1918 if (!g_text_mode) {
1919 newtResume();
1920 }
[1]1921 log_msg(0, "Stopping all software RAID devices, just in case");
1922 stop_all_raid_devices(mountlist);
1923 log_msg(0, "Done.");
[128]1924
[1]1925/*
1926 if (does_file_exist("/tmp/i-want-my-lvm"))
1927 {
1928 wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
1929 }
1930*/
1931
[541]1932 open_progress_form("Partitioning devices",
1933 "I am now going to partition all your drives.",
1934 "This should not take more than five minutes.", "",
[128]1935 mountlist->entries);
[1]1936
1937 make_list_of_drives_in_mountlist(mountlist, drivelist);
1938
1939 /* partition each drive */
1940 for (lino = 0; lino < drivelist->entries; lino++) {
1941 res = partition_drive(mountlist, drivelist->el[lino].device);
1942 retval += res;
1943 }
1944 close_progress_form();
1945 if (retval) {
[541]1946 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
[128]1947 log_to_screen
[541]1948 ("Errors occurred during the partitioning of your hard drives.");
[1]1949 } else {
[541]1950 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
[1]1951 paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
1952 }
1953 newtSuspend();
1954 system("clear");
1955 newtResume();
1956 paranoid_free(drivelist);
1957 return (retval);
1958}
1959
1960
1961
1962
1963
1964
1965/**
1966 * Set the type of partition number @p partno on @p drive to @p format.
1967 * @param drive The drive to change the type of a partition on.
1968 * @param partno The partition number on @p drive to change the type of.
1969 * @param format The filesystem type this partition will eventually contain.
1970 * @param partsize The size of this partition, in @e bytes (used for vfat
1971 * type calculations).
1972 * @return 0 for success, nonzero for failure.
1973 */
[128]1974int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
1975 const char *format, long long partsize)
[1]1976{
1977 /** buffers *********************************************************/
[2316]1978 char *partition = NULL;
[2281]1979 char *command = NULL;
[2211]1980 char *output = NULL;
[2281]1981 char *tmp = NULL;
[2316]1982 char *partcode = NULL;
[1]1983
1984 /** pointers *********************************************************/
1985 char *p;
1986 FILE *fout;
1987
1988 /** int **************************************************************/
1989 int res = 0;
1990
1991 /** end **************************************************************/
1992
1993 assert_string_is_neither_NULL_nor_zerolength(drive);
1994 assert(format != NULL);
1995
[2316]1996 partition = build_partition_name(drive, partno);
[1]1997 p = (char *) strrchr(partition, '/');
1998 if (strcmp(format, "swap") == 0) {
[2323]1999 mr_asprintf(partcode, "82");
[1]2000 } else if (strcmp(format, "vfat") == 0) {
2001 if (partsize / 1024 > 8192) {
[2323]2002 mr_asprintf(partcode, "c");
[1]2003 } else {
[2323]2004 mr_asprintf(partcode, "b");
[1]2005 }
[128]2006 } else if (strcmp(format, "ext2") == 0
2007 || strcmp(format, "reiserfs") == 0
[1303]2008 || strcmp(format, "ext3") == 0
[2087]2009 || strcmp(format, "ext4") == 0
[1303]2010 || strcmp(format, "xfs") == 0
[128]2011 || strcmp(format, "jfs") == 0) {
[2323]2012 mr_asprintf(partcode, "83");
[1]2013 } else if (strcmp(format, "minix") == 0) {
[2323]2014 mr_asprintf(partcode, "81");
[1824]2015 } else if (strcmp(format, "vmfs3") == 0) {
[2323]2016 mr_asprintf(partcode, "fb");
[1824]2017 } else if (strcmp(format, "vmkcore") == 0) {
[2323]2018 mr_asprintf(partcode, "fc");
[1]2019 } else if (strcmp(format, "raid") == 0) {
[2323]2020 mr_asprintf(partcode, "fd");
[2141]2021 } else if (strcmp(format, "ntfs") == 0) {
[2323]2022 mr_asprintf(partcode, "7");
[1]2023 } else if ((strcmp(format, "ufs") == 0)
[128]2024 || (strcmp(format, "ffs") == 0)) { /* raid autodetect */
[2323]2025 mr_asprintf(partcode, "a5");
[1]2026 } else if (strcmp(format, "lvm") == 0) {
[2323]2027 mr_asprintf(partcode, "8e");
[1]2028 } else if (format[0] == '\0') { /* LVM physical partition */
[2323]2029 mr_asprintf(partcode, "");
[1]2030 } else if (strlen(format) >= 1 && strlen(format) <= 2) {
[2323]2031 mr_asprintf(partcode, format);
[1]2032 } else {
2033 /* probably an image */
[2323]2034 mr_asprintf(tmp, "Unknown format ('%s') - using supplied string anyway", format);
[1]2035 mvaddstr_and_log_it(g_currentY++, 0, tmp);
[2281]2036 mr_free(tmp);
[1]2037#ifdef __FreeBSD__
[2323]2038 mr_asprintf(partcode, format); // was a5
[1]2039#else
[2323]2040 mr_asprintf(partcode, format); // was 83
[1]2041#endif
2042 }
[2281]2043 log_msg(1, tmp, "Setting %s's type to %s (%s)", partition, format, partcode);
[2316]2044 mr_free(partition);
[128]2045
[2316]2046 if (partcode != NULL && strcmp(partcode, "83")) { /* no need to set type if 83: 83 is default */
2047
[128]2048 if (pout_to_fdisk) {
[1]2049 res = 0;
2050 fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
[128]2051 if (partno > 1
2052 || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
[1]2053 log_msg(5, "Specifying partno (%d) - yay", partno);
[2323]2054 mr_asprintf(tmp, "%d\n", partno);
[1]2055 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
[2281]2056 mr_free(tmp);
2057
[128]2058 log_msg(5, "A - last line = '%s'",
2059 last_line_of_file(FDISK_LOG));
[1]2060 }
[128]2061
[2323]2062 mr_asprintf(tmp, "%s\n", partcode);
[1]2063 fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
[2281]2064 mr_free(tmp);
2065
[128]2066 log_msg(5, "B - last line = '%s'",
2067 last_line_of_file(FDISK_LOG));
[1]2068 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
[128]2069 log_msg(5, "C - last line = '%s'",
2070 last_line_of_file(FDISK_LOG));
2071
[2323]2072 mr_asprintf(tmp, "%s", last_line_of_file(FDISK_LOG));
[128]2073 if (!strstr(tmp, " (m ")) {
2074 log_msg(1, "last line = '%s'; part type set failed", tmp);
2075 res++;
2076 fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2077 }
[2281]2078 mr_free(tmp);
2079
[128]2080 fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2081 } else {
[2323]2082 mr_asprintf(output, "t\n%d\n%s\nw\n", partno, partcode);
2083 mr_asprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
[128]2084 MONDO_LOGFILE, MONDO_LOGFILE);
[1]2085 log_msg(5, "output = '%s'", output);
2086 log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2087 log_msg(5, "command = '%s'", command);
2088 fout = popen(command, "w");
2089 if (!fout) {
2090 log_OS_error(command);
2091 res = 1;
2092 } else {
2093 res = 0;
[2190]2094 fprintf(fout, "%s", output);
[1]2095 paranoid_pclose(fout);
2096 }
[2211]2097 paranoid_free(output);
[2281]2098 mr_free(command);
[1]2099 }
2100 }
2101
[2316]2102 mr_free(partcode);
[128]2103 return (res);
[1]2104}
2105
2106
2107int start_raid_device(char *raid_device)
2108{
2109 /** int *************************************************************/
2110 int res;
2111 int retval = 0;
2112
2113 /** buffers *********************************************************/
[2281]2114 char *program = NULL;
[1]2115
2116 /** end *************************************************************/
2117
2118 assert_string_is_neither_NULL_nor_zerolength(raid_device);
[128]2119
[1]2120#ifdef __FreeBSD__
2121 if (is_this_device_mounted(raid_device)) {
2122 log_it("Can't start %s when it's mounted!", raid_device);
2123 return 1;
2124 }
[2323]2125 mr_asprintf(program, "vinum start -f %s", raid_device);
[1]2126#else
[2323]2127 mr_asprintf(program, "raidstart %s", raid_device);
[1]2128#endif
2129 log_msg(1, "program = %s", program);
2130 res = run_program_and_log_output(program, 1);
[128]2131 if (g_fprep) {
2132 fprintf(g_fprep, "%s\n", program);
2133 }
[2281]2134 mr_free(program);
2135
[128]2136 if (res) {
2137 log_msg(1, "Warning - failed to start RAID device %s",
2138 raid_device);
2139 }
[1]2140 retval += res;
2141 sleep(1);
2142 return (retval);
2143}
2144
2145
2146
2147/**
2148 * Stop @p raid_device using @p raidstop.
2149 * @param raid_device The software RAID device to stop.
2150 * @return 0 for success, nonzero for failure.
2151 */
2152int stop_raid_device(char *raid_device)
2153{
2154 /** int *************************************************************/
2155 int res;
2156 int retval = 0;
2157
2158 /** buffers *********************************************************/
[2281]2159 char *program = NULL;
[1]2160
2161 /** end *************************************************************/
2162
2163 assert_string_is_neither_NULL_nor_zerolength(raid_device);
[128]2164
[1]2165#ifdef __FreeBSD__
2166 if (is_this_device_mounted(raid_device)) {
2167 log_it("Can't stop %s when it's mounted!", raid_device);
2168 return 1;
2169 }
[2323]2170 mr_asprintf(program, "vinum stop -f %s", raid_device);
[1]2171#else
[558]2172 // use raidstop if it exists, otherwise use mdadm
2173 if (run_program_and_log_output("which raidstop", FALSE)) {
[2323]2174 mr_asprintf(program, "mdadm -S %s", raid_device);
[558]2175 } else {
[2323]2176 mr_asprintf(program, "raidstop %s", raid_device);
[558]2177 }
[1]2178#endif
2179 log_msg(1, "program = %s", program);
2180 res = run_program_and_log_output(program, 1);
[128]2181 if (g_fprep) {
2182 fprintf(g_fprep, "%s\n", program);
2183 }
[2281]2184 mr_free(program);
2185
[128]2186 if (res) {
2187 log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2188 }
[1]2189 retval += res;
2190 return (retval);
2191}
2192
2193
2194int start_all_raid_devices(struct mountlist_itself *mountlist)
2195{
2196 int i;
[128]2197 int retval = 0;
[1]2198 int res;
[128]2199
2200 for (i = 0; i < mountlist->entries; i++) {
2201 if (!strncmp
2202 (mountlist->el[i].device, RAID_DEVICE_STUB,
2203 strlen(RAID_DEVICE_STUB))) {
2204 log_msg(1, "Starting %s", mountlist->el[i].device);
2205 res = start_raid_device(mountlist->el[i].device);
2206 retval += res;
2207 }
2208 }
2209 if (retval) {
2210 log_msg(1, "Started all s/w raid devices OK");
2211 } else {
2212 log_msg(1, "Failed to start some/all s/w raid devices");
2213 }
2214 return (retval);
[1]2215}
2216
2217/**
2218 * Stop all software RAID devices listed in @p mountlist.
2219 * @param mountlist The mountlist to stop the RAID devices in.
2220 * @return The number of errors encountered (0 for success).
2221 * @bug @p mountlist is not used.
2222 */
2223int stop_all_raid_devices(struct mountlist_itself *mountlist)
2224{
2225 /** int *************************************************************/
2226 int retval = 0;
2227#ifndef __FreeBSD__
2228 int res;
2229#endif
2230
2231 /** char ************************************************************/
2232 char *incoming;
2233#ifndef __FreeBSD__
2234 char *dev;
2235#endif
2236 /** pointers ********************************************************/
2237#ifndef __FreeBSD__
2238 char *p;
2239#endif
2240 FILE *fin;
2241 int i;
2242
2243 /** end ****************************************************************/
2244
2245 malloc_string(dev);
2246 malloc_string(incoming);
2247 assert(mountlist != NULL);
2248
2249 for (i = 0; i < 3; i++) {
2250#ifdef __FreeBSD__
[128]2251 fin =
2252 popen
2253 ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2254 "r");
[1]2255 if (!fin) {
2256 paranoid_free(dev);
2257 paranoid_free(incoming);
2258 return (1);
2259 }
[128]2260 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2261 fgets(incoming, MAX_STR_LEN - 1, fin)) {
[1]2262 retval += stop_raid_device(incoming);
2263 }
2264#else
2265 fin = fopen("/proc/mdstat", "r");
2266 if (!fin) {
2267 log_OS_error("/proc/mdstat");
2268 paranoid_free(dev);
2269 paranoid_free(incoming);
2270 return (1);
2271 }
[128]2272 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2273 fgets(incoming, MAX_STR_LEN - 1, fin)) {
2274 for (p = incoming;
2275 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2276 || !isdigit(*(p + 2))); p++);
[1]2277 if (*p != '\0') {
2278 sprintf(dev, "/dev/%s", p);
2279 for (p = dev; *p > 32; p++);
2280 *p = '\0';
2281 res = stop_raid_device(dev);
2282 }
2283 }
2284#endif
2285 }
2286 paranoid_fclose(fin);
[128]2287 if (retval) {
2288 log_msg(1, "Warning - unable to stop some RAID devices");
2289 }
[1]2290 paranoid_free(dev);
2291 paranoid_free(incoming);
[128]2292 system("sync");
2293 system("sync");
2294 system("sync");
[1]2295 sleep(1);
2296 return (retval);
2297}
2298
2299
2300
2301/**
2302 * Decide which command we need to use to format a device of type @p format.
2303 * @param format The filesystem type we are about to format.
2304 * @param program Where to put the binary name for this format.
2305 * @return 0 for success, nonzero for failure.
2306 */
[2281]2307char *which_format_command_do_i_need(char *format)
[1]2308{
2309 /** int *************************************************************/
2310 int res = 0;
2311
2312 /** buffers *********************************************************/
[2281]2313 char *tmp = NULL;
2314 char *program = NULL;
[1]2315
2316 /** end ***************************************************************/
2317
2318 assert_string_is_neither_NULL_nor_zerolength(format);
2319
2320 if (strcmp(format, "swap") == 0) {
2321#ifdef __FreeBSD__
[2323]2322 mr_asprintf(program, "true");
[1]2323#else
[2323]2324 mr_asprintf(program, "mkswap");
[1]2325#endif
2326 } else if (strcmp(format, "vfat") == 0) {
[2323]2327 mr_asprintf(program, "format-and-kludge-vfat");
[1]2328#ifndef __FreeBSD__
2329 } else if (strcmp(format, "reiserfs") == 0) {
[2323]2330 mr_asprintf(program, "mkreiserfs -ff");
[1]2331 } else if (strcmp(format, "xfs") == 0) {
[2323]2332 mr_asprintf(program, "mkfs.xfs -f -q");
[1]2333 } else if (strcmp(format, "jfs") == 0) {
[2323]2334 mr_asprintf(program, "mkfs.jfs");
[1]2335 } else if (strcmp(format, "ext3") == 0) {
[2323]2336 mr_asprintf(program, "mkfs -t ext3 -F -q");
[2087]2337 } else if (strcmp(format, "ext4") == 0) {
[2323]2338 mr_asprintf(program, "mkfs -t ext4 -F -q");
[1]2339 } else if (strcmp(format, "minix") == 0) {
[2323]2340 mr_asprintf(program, "mkfs.minix");
[1497]2341 } else if (strcmp(format, "vmfs") == 0) {
[2323]2342 mr_asprintf(program, "mkfs -t vmfs");
[2147]2343 } else if (strcmp(format, "ntfs") == 0) {
2344 /*
2345 * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2346 * so the default "mkfs -t %s -c" command structure fails
2347 */
[2323]2348 mr_asprintf(program, "mkfs -t ntfs");
[2017]2349 } else if (strcmp(format, "ocfs2") == 0) {
2350 /*
2351 * 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.
2352 *
2353 */
[2323]2354 mr_asprintf(program, "mkfs -t ocfs2 -F");
[1]2355#endif
2356 } else if (strcmp(format, "ext2") == 0) {
[2323]2357 mr_asprintf(program, "mke2fs -F -q");
[1]2358 } else {
2359#ifdef __FreeBSD__
[2323]2360 mr_asprintf(program, "newfs_%s", format);
[1]2361#else
[2323]2362 mr_asprintf(program, "mkfs -t %s -c", format); // -c checks for bad blocks
[1]2363#endif
[2323]2364 mr_asprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format, program);
[1]2365 log_it(tmp);
[2281]2366 mr_free(tmp);
[1]2367 res = 0;
2368 }
[2281]2369 return (program);
[1]2370}
2371
2372
2373/**
2374 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2375 * There are a few problems with this function:
2376 * - It won't work if there was any unallocated space on the user's hard drive
2377 * when it was backed up.
2378 * - It won't work if the user's hard drive lies about its size (more common
2379 * than you'd think).
2380 *
2381 * @param mountlist The mountlist to use for resizing @p drive_name.
2382 * @param drive_name The drive to resize.
2383 */
2384void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
[128]2385 *mountlist,
2386 char *drive_name)
[1]2387{
2388 /**buffers **********************************************************/
[2281]2389 char *tmp = NULL;
[1]2390
2391 /** int *************************************************************/
2392 int partno, lastpart;
[128]2393 /** remove driveno, noof_drives stan benoit apr 2002**/
[1]2394
2395 /** float ***********************************************************/
2396 float factor;
2397 float new_size;
[128]2398// float newcylinderno;
[1]2399
2400 /** long *************************************************************/
[2125]2401 long newsizL = 0L;
[2037]2402 long current_size_of_drive = 0L;
2403 long original_size_of_drive = 0L;
[2125]2404 long final_size = 0L; /* all in Megabytes */
[1]2405 struct mountlist_reference *drivemntlist;
2406
2407 /** structures *******************************************************/
2408
2409 /** end **************************************************************/
2410
2411 assert(mountlist != NULL);
2412 assert_string_is_neither_NULL_nor_zerolength(drive_name);
2413
2414 if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
[128]2415 if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2416 == 0) {
[1]2417 return;
2418 }
2419 }
2420
2421 current_size_of_drive = get_phys_size_of_drive(drive_name);
[128]2422
[1]2423 if (current_size_of_drive <= 0) {
2424 log_it("Not resizing to match %s - can't find drive", drive_name);
2425 return;
2426 }
[2323]2427 mr_asprintf(tmp, "Expanding entries to suit drive %s (%ld MB)", drive_name, current_size_of_drive);
[1]2428 log_to_screen(tmp);
[2281]2429 mr_free(tmp);
[1]2430
[128]2431 drivemntlist = malloc(sizeof(struct mountlist_reference));
2432 drivemntlist->el =
[2188]2433 malloc(sizeof(struct mountlist_line *) * MAX_MOUNTLIST_ENTRIES);
[1]2434
2435 if (!drivemntlist) {
2436 fatal_error("Cannot malloc temporary mountlist\n");
2437 }
2438 create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2439
2440 for (partno = 0; partno < drivemntlist->entries; partno++) {
[2125]2441 if (drivemntlist->el[partno]->size > 0) {
2442 original_size_of_drive += (drivemntlist->el[partno]->size / 1024L);
2443 }
[1]2444 }
2445
2446 if (original_size_of_drive <= 0) {
[2323]2447 mr_asprintf(tmp, "Cannot resize %s's entries. Drive not found.", drive_name);
[1]2448 log_to_screen(tmp);
[2281]2449 mr_free(tmp);
[1]2450 return;
2451 }
[2281]2452 factor = (float) (current_size_of_drive) / (float) (original_size_of_drive);
[2323]2453 mr_asprintf(tmp, "Disk %s was %ld MB; is now %ld MB; factor = %f", drive_name, original_size_of_drive, current_size_of_drive, factor);
[1]2454 log_to_screen(tmp);
[2281]2455 mr_free(tmp);
[1]2456
[128]2457 lastpart = drivemntlist->entries - 1;
[1]2458 for (partno = 0; partno < drivemntlist->entries; partno++) {
2459 /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
[128]2460 if (!atoi(drivemntlist->el[partno]->format)) {
[1]2461 new_size = (float) (drivemntlist->el[partno]->size) * factor;
2462 } else {
2463 new_size = drivemntlist->el[partno]->size;
2464 }
[128]2465
[1]2466 if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2467 log_msg(1, "Skipping %s (%s) because it's an image",
[128]2468 drivemntlist->el[partno]->device,
2469 drivemntlist->el[partno]->mountpoint);
2470 newsizL = (long) new_size; // It looks wrong but it's not
[1]2471 } else {
2472 newsizL = (long) new_size;
2473 }
[2125]2474
2475 /* Do not apply the factor if partition was of negative size */
2476 if (newsizL < 0) {
2477 newsizL = drivemntlist->el[partno]->size;
2478 }
2479
[2323]2480 mr_asprintf(tmp, "Changing %s from %lld KB to %ld KB", drivemntlist->el[partno]->device, drivemntlist->el[partno]->size, newsizL);
[1]2481 log_to_screen(tmp);
[2281]2482 mr_free(tmp);
[1]2483 drivemntlist->el[partno]->size = newsizL;
2484 }
2485 final_size = get_phys_size_of_drive(drive_name);
[2323]2486 mr_asprintf(tmp, "final_size = %ld MB", final_size);
[2125]2487 log_to_screen(tmp);
[2281]2488 mr_free(tmp);
[1]2489}
2490
2491
2492/**
2493 * Resize all partitions in @p mountlist proportionately (each one
2494 * grows or shrinks by the same percentage) to fit them into the new
2495 * drives (presumably different from the old ones).
2496 * @param mountlist The mountlist to resize the drives in.
2497 */
2498void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
[128]2499 *mountlist)
[1]2500{
2501 /** buffers *********************************************************/
2502 struct list_of_disks *drivelist;
2503
2504 /** int *************************************************************/
2505 int driveno;
2506
2507 /** end *************************************************************/
2508
2509 drivelist = malloc(sizeof(struct list_of_disks));
2510 assert(mountlist != NULL);
2511
2512 if (g_mountlist_fname[0] == '\0') {
[128]2513 log_it
2514 ("resize_mountlist_prop...() - warning - mountlist fname is blank");
2515 log_it("That does NOT affect the functioning of this subroutine.");
2516 log_it("--- Hugo, 2002/11/20");
[1]2517 }
[2230]2518 log_it("Resizing mountlist");
[1]2519 make_list_of_drives_in_mountlist(mountlist, drivelist);
[2230]2520 log_it("Back from MLoDiM");
[1]2521 for (driveno = 0; driveno < drivelist->entries; driveno++) {
[128]2522 resize_drive_proportionately_to_suit_new_drives(mountlist,
2523 drivelist->
2524 el[driveno].
2525 device);
[1]2526 }
[541]2527 log_to_screen("Mountlist adjusted to suit current hard drive(s)");
[1]2528 paranoid_free(drivelist);
2529}
2530
2531/**
2532 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2533 * @param mountlist The complete mountlist to get the drive references from.
2534 * @param drive_name The drive to put in @p drivemntlist.
2535 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2536 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2537 * @author Ralph Grewe
2538 */
[128]2539void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2540 char *drive_name,
2541 struct mountlist_reference *drivemntlist)
2542{
[1]2543 int partno;
2544 char *tmp_drive_name, *c;
2545
2546 assert(mountlist != NULL);
2547 assert(drive_name != NULL);
2548 assert(drivemntlist != NULL);
2549
[128]2550 log_msg(1, "Creating list of partitions for drive %s", drive_name);
[1]2551
[128]2552 tmp_drive_name = strdup(drive_name);
2553 if (!tmp_drive_name)
2554 fatal_error("Out of memory");
2555
[1]2556 /* devfs devices? */
[128]2557 c = strrchr(tmp_drive_name, '/');
2558 if (c && strncmp(c, "/disc", 5) == 0) {
2559 /* yup its devfs, change the "disc" to "part" so the existing code works */
2560 strcpy(c + 1, "part");
[1]2561 }
[128]2562 drivemntlist->entries = 0;
[1]2563 for (partno = 0; partno < mountlist->entries; partno++) {
[128]2564 if (strncmp
2565 (mountlist->el[partno].device, tmp_drive_name,
2566 strlen(tmp_drive_name)) == 0) {
2567 drivemntlist->el[drivemntlist->entries] =
2568 &mountlist->el[partno];
[1]2569 drivemntlist->entries++;
2570 }
2571 }
2572 if (tmp_drive_name)
[128]2573 free(tmp_drive_name);
[1]2574}
2575
2576/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.