source: branches/3.2/mondo/src/mondorestore/mondo-prep.c @ 3292

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