source: MondoRescue/trunk/mondo/mondo/mondorestore/mondo-prep.c @ 689

Last change on this file since 689 was 689, checked in by bcornec, 14 years ago

Still other memory management improvements ( I hope :-)

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