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

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