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

Last change on this file since 2291 was 2291, checked in by Bruno Cornec, 11 years ago
  • Fix a printing error in mindi for the tar command
  • Fix all mr_asprintf which had no second param as a string

(report bug fix done originaly in 2.2.9)

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