source: branches/2.2.10/mondo/src/mondorestore/mondo-prep.c @ 2383

Last change on this file since 2383 was 2383, checked in by bruno, 10 years ago

call_program_and_get_last_line_of_output is now allocating memory and returning that string

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