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

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