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

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

r4625@localhost: bruno | 2012-03-30 10:37:17 +0200

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