source: trunk/mondo/src/mondorestore/mondo-prep.c @ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 14 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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