source: branches/3.1/mondo/src/mondorestore/mondo-prep.c @ 2937

Last change on this file since 2937 was 2937, checked in by Bruno Cornec, 9 years ago

svn merge -r 2849:2935 ../3.0

  • Adds 3 binaries called potentially by udev o support USB key mount at restore time (Victor Gattegno)
  • mindi only sets the boot flag of a USB device if none is present already (should avoid flip/flop situation)
  • Fix a compatibility bug in analyze-my-lvm whete exclude lists with '|' was incorrectly analyzed (' ' still expected)
  • Precise that -J is not supported by mondorestore yet.
  • Fix a compatibility bug in mindi where exclude lists with '|' was incorrectly analyzed (' ' still expected)
  • Install an MBR on USB devices when possible
  • Improve error message in case mondorestore isn't found
  • Adds support for more virtio devices for KVM restore
  • Improve mbr.bin handling
  • Fix an issue in test of FindKernel? for Xen and non Xen cases
    • Fix #492 by removing an extra useless fi
    • Move fvat nd fat modules to CDROM_MODS in order to have them in the initrd to support saving logs to a USB device e.g.
    • Fix an error when dmidecode reports comments before system name
    • Fix previous broken patch on comment management for bkphw
    • Improve msgs printed during kbd analysis
    • Fix a small remaining pb with new comment support
    • Try to again improve the mount/umount stuff in mondo -Adds mention to OEL, CentOS, ScientifLinux? as RHEL clones
  • Fix a panadoid_free done on the wrong variable (solve a memory leak)
  • Solve #495 by skipping the potential (auto-read-only) when analyzin /proc/mdstat result
  • Fix some markup in man pages
  • adds the post-nuke script sample for Debian (Guillaume Pernot/Andrée? Leidenfrost)
  • Avoid a useless umount when changing of afio set, let insist_on_cd check and perform if needed
  • Copy everything under .ssh of root account to allow for sshfs mount without passwd at restore time.
  • Adds support for bnx2i driver
  • Try to fix #496 by supporting the protocol in the output of the mount command (sshfs#...)
  • Uses the -d option of the mount command to avoid leaving loop devices in use. Probably provoked by the usage of a more recent busybox, but anyway that option doesn't hurt, and does nothing for non-loop devices. Should fix the problems reported on the ML with NFS and more than 8 ISO images (8 being the default number of loop devices available)
  • Attempt to fix #436 by adding some newtDrawForm where appropriate.
  • Fix bugs in the kernel detection routine of mindi (some echo were done without capturing their output, confusing the return). This should also help the Xen detection issue
  • Change the logging function to be nearer from 2.2.10, and start using some
  • Initialize some global fields with an empty string, now that newt Draws more regularly progress forms
  • Mindi progression still not good, but showing now 3% when calling mindi. Would need a specific handling for the progress bar to evolve more afterwards
  • Add compatibility with the latest SSSTK + PSP content for HP ProLiant? + branding homogeneous now. We only take conrep out of the SSSTK pending a package availability. Using hpacuscripting now. Review of parameters called following test made.
  • Fix #501 by pushing BOOT_SIZE to 36864 for certain Ubuntu cases
  • Fix some remaining inconsistencis in the ProLiant? HW backup. ready for usage.
  • Fix an issue on udevadm call (needs an intermediate variable)
  • Fix a remaining ProLiant? tool call
  • Remove again some wrong variable initialization for Net in order to not have strange messages now we call Draw more often
  • Adds support for hwaddr (MAC addresses) at restore time, and map to the correct NIC if it's found at restore time (based on code from Stefan Heijmans)
  • Try to Fix #499 by changing init in order to never exit, and rebooting using sysrq in /proc (not portable). Maybe should move to using a real init, and a separated rcS script.
  • Fixes the shell msg error by using setsid as per Busybox FAQ
  • Fix #491 by correctly checking Xen kernel used for a dom0 env (apollo13)
  • Improves logging in Die()
  • Improve again ProLiant? HW support, by adding references to the yet to come SSSTK rpm so that conrep is called at its future right place.
  • Improve mindi support for kernel 3.x
  • Fix #499 for good, by using a real init from busybox and moving our init script to etc/init.d/rcS. We also now call the reboot from busybox to exit, which indeed reset the system correctly (in a VM at least which wasn't the case before). Reauires a new mindi-busybox as well.
  • Attempt to solve #503 by handling /lib64 separately for udev and only if not a link (to /lib) for Ubuntu 64
  • Improve again previous tests for bug #503
  • Improve -d option description for NFS
  • Allow http download for ftp content
  • New italian mirror
  • Fix #505 by documenting environment variables
    • Fix a bug where on OBDR mode compression was turned off to create the OBDR content but not back on (report from the mailing list)
  • solve http://trac.mondorescue.org/ticket/520 by Victor Gattegno
  • Fix #524 as option -U needs a size also
  • Removes useless gendf option
  • Fix #511 now stabgrub is called also after conf file modifications
  • Adds support for SUID binaries
  • remove a useless xenkernelname variable from mindi
  • Should fix #512 by clearing old scratchdir before changing to a new
  • Simplify the function engaging SCSI for Smart Array controllers, and support as many controller as we have
  • Add some binaries used on SLES 10 by udev
  • Fix a syntax issue in newt-specific.c
  • Fix a memory free bug where a used variable was freed to early
  • Fix a memory free bug where a used variable was misused in asprintf/free
  • Fix #498 by using an external program (hpsa_obdr_mode) which can set the mode of the tape to CD-ROM or Sequential at will.

That program will have to be downloaded from http://cciss.sf.net

  • Adds support for the route command in mindi-busybox
  • Force block size back to 32768 in OBDR mode after skipping the 2 tape marks, to read the additional rootfs data corerctly - Fix #498 for good it seems
  • Adds support for a new pata_atiixp driver
  • Fix #525 and improve printing when no /etc/raidtab, but still md devices
  • Exclude /run similarly to /sys and /proc
  • Fix a bug in mindi when having multiple swap partiions with same starting string (/dev/dm-1 and /dev/dm-16). We now add a space in the grep to avoid mischoice.
  • Fix grub installation if we had to go in the hack part which wasn't using the correct variables to make decisions !
  • Remove all mention of mondorescue.com from code
  • Fix some website typo on the download page and precise that we now develop on Mageia
  • Exclude sysfs devpts and tmpfs partitions found in RHEL 6.2 from analyze by mindi (made error messages)
  • Force activation of first partition which should not be optional as everything is destroyed before
  • Fix a bug in analyze-my-lvm where LVs were created in random order (the one of lvscan) instead of using the dm-xxx order, which creates issues at restore time between the mapping created then and the one we had at backup time which could be inconssistent

-mondoarchive now exists if the mt command is missing when needed

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