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

Last change on this file since 2989 was 2989, checked in by bruno, 7 years ago

r4626@localhost: bruno | 2012-03-30 16:24:25 +0200

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