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

Last change on this file since 2282 was 2282, checked in by Bruno Cornec, 11 years ago

r3279@localhost: bruno | 2009-07-20 00:29:15 +0200
Fix mondo compilation and link

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