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

Last change on this file since 900 was 900, checked in by bruno, 13 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.