source: branches/2.2.6/mondo/src/mondorestore/mondo-prep.c @ 1930

Last change on this file since 1930 was 1930, checked in by Bruno Cornec, 12 years ago

Renaming of files to be in conformity with stable and ease aplication of patches between branches.

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