source: branches/3.0/mondo/src/mondorestore/mondo-prep.c @ 2990

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