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

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

r3279@localhost: bruno | 2009-07-20 00:29:15 +0200
Fix mondo compilation and link

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