source: branches/stable/mondo/mondo/mondorestore/mondo-prep.c @ 681

Last change on this file since 681 was 681, checked in by andree, 13 years ago

Replaced all occurrences of egrep with 'grep -E' and of fgrep with
'grep -F' in mondo.
egrep and fgrep are usually just script wrappers around grep these
days which means additional overhead compared to calling grep with the
relevant option. Also, it appears that egrep and fgrep have been
deprecated by POSIX some time ago.

  • Property svn:keywords set to Id
File size: 79.6 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 681 2006-06-25 02:41:57Z andree $
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 "../common/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 681 2006-06-25 02:41:57Z andree $";
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 *);
191
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 *incoming;
340    char *command;
341    char *lvscan_sz;
342    char *lvremove_sz;
343    char *pvscan_sz;
344    char *vgscan_sz;
345    char *vgcreate_sz;
346    char *vgchange_sz;
347    char *vgremove_sz;
348//  char *do_this_last;
349
350    /** char **************************************************/
351    char *p;
352    char *q;
353
354    /** int ***************************************************/
355    int retval = 0;
356    int res = 0;
357    int i;
358    int lvmversion = 1;
359    long extents;
360    fpos_t orig_pos;
361
362    /** pointers **********************************************/
363    FILE *fin;
364
365    /** end *****************************************************/
366
367#ifdef __FreeBSD__
368    return (0);
369#endif
370
371    if (!(fin = fopen("/tmp/i-want-my-lvm", "r"))) {
372        log_OS_error("/tmp/i-want-my-lvm");
373        return (1);
374    }
375
376    malloc_string(tmp);
377    malloc_string(incoming);
378    malloc_string(lvscan_sz);
379    malloc_string(lvremove_sz);
380    malloc_string(vgscan_sz);
381    malloc_string(pvscan_sz);
382    malloc_string(vgcreate_sz);
383    malloc_string(vgchange_sz);
384    malloc_string(vgremove_sz);
385//  malloc_string(do_this_last); // postpone lvcreate call if necessary
386    command = malloc(512);
387
388//  do_this_last[0] = '\0';
389    iamhere("STARTING");
390    log_msg(1, "OK, opened i-want-my-lvm. Shutting down LVM volumes...");
391    if (find_home_of_exe("lvm"))    // found it :) cool
392    {
393        strcpy(lvscan_sz, "lvm lvscan");
394        strcpy(lvremove_sz, "lvm lvremove");
395        strcpy(vgscan_sz, "lvm vgscan");
396        strcpy(pvscan_sz, "lvm pvscan");
397        strcpy(vgcreate_sz, "lvm vgcreate");
398        strcpy(vgchange_sz, "lvm vgchange");
399        strcpy(vgremove_sz, "lvm vgremove");
400    } else {
401        strcpy(lvscan_sz, "lvscan");
402        strcpy(lvremove_sz, "lvremove");
403        strcpy(vgscan_sz, "vgscan");
404        strcpy(pvscan_sz, "pvscan");
405        strcpy(vgcreate_sz, "vgcreate");
406        strcpy(vgchange_sz, "vgchange");
407        strcpy(vgremove_sz, "vgremove");
408    }
409    sprintf(command,
410            "for i in `%s | cut -d\"'\" -f2 | sort -r` ; do echo \"Shutting down lv $i\" >> "
411            MONDO_LOGFILE "; %s -f $i; done", lvscan_sz, 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\" >> "
416            MONDO_LOGFILE "; done; %s -a n", vgscan_sz, vgchange_sz,
417            vgremove_sz, vgremove_sz);
418    run_program_and_log_output(command, 5);
419    if (just_erase_existing_volumes) {
420        paranoid_fclose(fin);
421        log_msg(1, "Closed i-want-my-lvm. Finished erasing LVMs.");
422        retval = 0;
423        goto end_of_i_want_my_lvm;
424    }
425
426    log_msg(1, "OK, rewound i-want-my-lvm. Doing funky stuff...");
427    rewind(fin);
428    for (fgets(incoming, 512, fin); !feof(fin); fgets(incoming, 512, fin)) {
429        fgetpos(fin, &orig_pos);
430        if (incoming[0] != '#') {
431            continue;
432        }
433        if (res && strstr(command, "create") && vacuum_pack) {
434            sleep(2);
435            system("sync");
436            system("sync");
437            system("sync");
438        }
439        if ((p = strstr(incoming, "vgcreate"))) {
440// include next line(s) if they end in /dev (cos we've got a broken i-want-my-lvm)
441            for (fgets(tmp, 512, fin); !feof(fin); fgets(tmp, 512, fin)) {
442                if (tmp[0] == '#') {
443                    fsetpos(fin, &orig_pos);
444                    break;
445                } else {
446                    fgetpos(fin, &orig_pos);
447                    strcat(incoming, tmp);
448                }
449            }
450            for (q = incoming; *q != '\0'; q++) {
451                if (*q < 32) {
452                    *q = ' ';
453                }
454            }
455            strcpy(tmp, p + strlen("vgcreate") + 1);
456            for (q = tmp; *q > 32; q++);
457            *q = '\0';
458            log_msg(1, "Deleting old entries at /dev/%s", tmp);
459//             sprintf(command, "%s -f %s", vgremove_sz, tmp);
460//             run_program_and_log_output(command, 1);
461            sprintf(command, "rm -Rf /dev/%s", tmp);
462            run_program_and_log_output(command, 1);
463            run_program_and_log_output(vgscan_sz, 1);
464            run_program_and_log_output(pvscan_sz, 1);
465            log_msg(3,
466                    "After working around potentially broken i-want-my-lvm, incoming[] is now '%s'",
467                    incoming);
468        }
469        for (p = incoming + 1; *p == ' '; p++);
470        strcpy(command, p);
471        for (p = command; *p != '\0'; p++);
472        for (; *(p - 1) < 32; p--);
473        *p = '\0';
474        res = run_program_and_log_output(command, 5);
475        if (res > 0 && (p = strstr(command, "lvm "))) {
476            *p = *(p + 1) = *(p + 2) = ' ';
477            res = run_program_and_log_output(command, 5);
478        }
479        log_msg(0, "%s --> %d", command, res);
480        if (res > 0) {
481            res = 1;
482        }
483        if (res && strstr(command, "lvcreate") && vacuum_pack) {
484            res = 0;
485            if (strstr(command, "lvm lvcreate"))
486                lvmversion = 2;
487            log_it("%s... so I'll get creative.", tmp);
488            if (lvmversion == 2) {
489                strcpy(tmp, call_program_and_get_last_line_of_output
490                       ("tail -n5 /var/log/mondo-archive.log | grep Insufficient | tail -n1"));
491            } else {
492                strcpy(tmp, call_program_and_get_last_line_of_output
493                       ("tail -n5 /var/log/mondo-archive.log | grep lvcreate | tail -n1"));
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 %s%d", drivename, 1);
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 %s%d", drivename,
1302                current_devno);
1303        log_it(tmp);
1304        g_maximum_progress++;
1305        res =
1306            partition_device(pout_to_fdisk, drivename, current_devno,
1307                             previous_devno, OSSWAP("ext2", "ufs"), 32000);
1308        retval += res;
1309        previous_devno = current_devno;
1310    }
1311    paranoid_free(tmp);
1312    return (previous_devno);
1313}
1314
1315
1316/**
1317 * Decide whether @p mountlist contains any RAID devices.
1318 * @param mountlist The mountlist to examine.
1319 * @return TRUE if it does, FALSE if it doesn't.
1320 */
1321bool mountlist_contains_raid_devices(struct mountlist_itself * mountlist)
1322{
1323    /** int *************************************************************/
1324    int i;
1325    int matching = 0;
1326
1327    /** end **************************************************************/
1328
1329    assert(mountlist != NULL);
1330
1331    for (i = 0; i < mountlist->entries; i++) {
1332        if (strstr(mountlist->el[i].device, RAID_DEVICE_STUB)) {
1333            matching++;
1334        }
1335    }
1336    if (matching) {
1337        return (TRUE);
1338    } else {
1339        return (FALSE);
1340    }
1341}
1342
1343/* The following 2 functions are stolen from /usr/src/sbin/disklabel/disklabel.c */
1344#ifdef __FreeBSD__
1345static void display_disklabel(FILE * f, const struct disklabel *lp)
1346{
1347    int i, j;
1348    const struct partition *pp;
1349
1350    fprintf(f, "# %s\n", "Generated by Mondo Rescue");
1351    if (lp->d_type < DKMAXTYPES)
1352        fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
1353    else
1354        fprintf(f, "type: %u\n", lp->d_type);
1355    fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename),
1356            lp->d_typename);
1357    fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname),
1358            lp->d_packname);
1359    fprintf(f, "flags:");
1360    if (lp->d_flags & D_REMOVABLE)
1361        fprintf(f, " removeable");
1362    if (lp->d_flags & D_ECC)
1363        fprintf(f, " ecc");
1364    if (lp->d_flags & D_BADSECT)
1365        fprintf(f, " badsect");
1366    fprintf(f, "\n");
1367    fprintf(f, "bytes/sector: %lu\n", (u_long) lp->d_secsize);
1368    fprintf(f, "sectors/track: %lu\n", (u_long) lp->d_nsectors);
1369    fprintf(f, "tracks/cylinder: %lu\n", (u_long) lp->d_ntracks);
1370    fprintf(f, "sectors/cylinder: %lu\n", (u_long) lp->d_secpercyl);
1371    fprintf(f, "cylinders: %lu\n", (u_long) lp->d_ncylinders);
1372    fprintf(f, "sectors/unit: %lu\n", (u_long) lp->d_secperunit);
1373    fprintf(f, "rpm: %u\n", lp->d_rpm);
1374    fprintf(f, "interleave: %u\n", lp->d_interleave);
1375    fprintf(f, "trackskew: %u\n", lp->d_trackskew);
1376    fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
1377    fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
1378            (u_long) lp->d_headswitch);
1379    fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
1380            (u_long) lp->d_trkseek);
1381    fprintf(f, "drivedata: ");
1382    for (i = NDDATA - 1; i >= 0; i--)
1383        if (lp->d_drivedata[i])
1384            break;
1385    if (i < 0)
1386        i = 0;
1387    for (j = 0; j <= i; j++)
1388        fprintf(f, "%lu ", (u_long) lp->d_drivedata[j]);
1389    fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
1390    fprintf(f,
1391            "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
1392    pp = lp->d_partitions;
1393    for (i = 0; i < lp->d_npartitions; i++, pp++) {
1394        if (pp->p_size) {
1395            fprintf(f, "  %c: %8lu %8lu  ", 'a' + i, (u_long) pp->p_size,
1396                    (u_long) pp->p_offset);
1397            if (pp->p_fstype < FSMAXTYPES)
1398                fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
1399            else
1400                fprintf(f, "%8d", pp->p_fstype);
1401            switch (pp->p_fstype) {
1402
1403            case FS_UNUSED: /* XXX */
1404                fprintf(f, "    %5lu %5lu %5.5s ", (u_long) pp->p_fsize,
1405                        (u_long) (pp->p_fsize * pp->p_frag), "");
1406                break;
1407
1408            case FS_BSDFFS:
1409                fprintf(f, "    %5lu %5lu %5u ", (u_long) pp->p_fsize,
1410                        (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1411                break;
1412
1413            case FS_BSDLFS:
1414                fprintf(f, "    %5lu %5lu %5d", (u_long) pp->p_fsize,
1415                        (u_long) (pp->p_fsize * pp->p_frag), pp->p_cpg);
1416                break;
1417
1418            default:
1419                fprintf(f, "%20.20s", "");
1420                break;
1421            }
1422            fprintf(f, "\t# (Cyl. %4lu",
1423                    (u_long) (pp->p_offset / lp->d_secpercyl));
1424            if (pp->p_offset % lp->d_secpercyl)
1425                putc('*', f);
1426            else
1427                putc(' ', f);
1428            fprintf(f, "- %lu",
1429                    (u_long) ((pp->p_offset + pp->p_size +
1430                               lp->d_secpercyl - 1) / lp->d_secpercyl -
1431                              1));
1432            if (pp->p_size % lp->d_secpercyl)
1433                putc('*', f);
1434            fprintf(f, ")\n");
1435        }
1436    }
1437    fflush(f);
1438}
1439
1440static struct disklabel *get_virgin_disklabel(char *dkname)
1441{
1442    static struct disklabel loclab;
1443    struct partition *dp;
1444    char lnamebuf[BBSIZE];
1445    int f;
1446    u_int secsize, u;
1447    off_t mediasize;
1448
1449    (void) snprintf(lnamebuf, BBSIZE, "%s", dkname);
1450    if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1451        warn("cannot open %s", lnamebuf);
1452        return (NULL);
1453    }
1454
1455    /* New world order */
1456    if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0)
1457        || (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1458        close(f);
1459        return (NULL);
1460    }
1461    memset(&loclab, 0, sizeof loclab);
1462    loclab.d_magic = DISKMAGIC;
1463    loclab.d_magic2 = DISKMAGIC;
1464    loclab.d_secsize = secsize;
1465    loclab.d_secperunit = mediasize / secsize;
1466
1467    /*
1468     * Nobody in these enligthened days uses the CHS geometry for
1469     * anything, but nontheless try to get it right.  If we fail
1470     * to get any good ideas from the device, construct something
1471     * which is IBM-PC friendly.
1472     */
1473    if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1474        loclab.d_nsectors = u;
1475    else
1476        loclab.d_nsectors = 63;
1477    if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1478        loclab.d_ntracks = u;
1479    else if (loclab.d_secperunit <= 63 * 1 * 1024)
1480        loclab.d_ntracks = 1;
1481    else if (loclab.d_secperunit <= 63 * 16 * 1024)
1482        loclab.d_ntracks = 16;
1483    else
1484        loclab.d_ntracks = 255;
1485    loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1486    loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1487    loclab.d_npartitions = MAXPARTITIONS;
1488
1489    /* Various (unneeded) compat stuff */
1490    loclab.d_rpm = 3600;
1491    loclab.d_bbsize = BBSIZE;
1492    loclab.d_interleave = 1;;
1493    strncpy(loclab.d_typename, "amnesiac", sizeof(loclab.d_typename));
1494
1495    dp = &loclab.d_partitions[RAW_PART];
1496    dp->p_size = loclab.d_secperunit;
1497    loclab.d_checksum = dkcksum(&loclab);
1498    close(f);
1499    return (&loclab);
1500}
1501
1502/* End stolen from /usr/src/sbin/disklabel/disklabel.c. */
1503
1504char *canonical_name(char *drivename)
1505{
1506    if (drivename) {
1507        if (strncmp(drivename, "/dev/", 5) == 0) {
1508            return drivename + 5;
1509        }
1510    }
1511    return drivename;
1512}
1513
1514/**
1515 * (BSD only) Create a disklabel on @p drivename according to @p mountlist.
1516 * @param mountlist The mountlist to get the subpartition information from.
1517 * @param drivename The drive or slice to create a disklabel on.
1518 * @param ret If non-NULL, store the created disklabel here.
1519 * @return The number of errors encountered (0 for success).
1520 */
1521int label_drive_or_slice(struct mountlist_itself *mountlist,
1522                         char *drivename, struct disklabel *ret)
1523{
1524    char subdev_str[MAX_STR_LEN];
1525    char command[MAX_STR_LEN];
1526    struct disklabel *lp;
1527    int i, lo = 0;
1528    int retval = 0;
1529    char c;
1530    FILE *ftmp;
1531
1532    lp = get_virgin_disklabel(drivename);
1533    for (c = 'a'; c <= 'z'; ++c) {
1534        int idx;
1535        sprintf(subdev_str, "%s%c", drivename, c);
1536        if ((idx = find_device_in_mountlist(mountlist, subdev_str)) < 0) {
1537            lp->d_partitions[c - 'a'].p_size = 0;
1538            lp->d_partitions[c - 'a'].p_fstype = FS_UNUSED;
1539        } else {
1540            lo = c - 'a';
1541            lp->d_partitions[c - 'a'].p_size = mountlist->el[idx].size * 2;
1542            lp->d_partitions[c - 'a'].p_fsize = 0;
1543            lp->d_partitions[c - 'a'].p_frag = 0;
1544            lp->d_partitions[c - 'a'].p_cpg = 0;
1545            if (!strcmp(mountlist->el[idx].format, "ufs")
1546                || !strcmp(mountlist->el[idx].format, "ffs")
1547                || !strcmp(mountlist->el[idx].format, "4.2BSD")) {
1548                lp->d_partitions[c - 'a'].p_fstype = FS_BSDFFS;
1549                lp->d_partitions[c - 'a'].p_fsize = 2048;
1550                lp->d_partitions[c - 'a'].p_frag = 8;
1551                lp->d_partitions[c - 'a'].p_cpg = 64;
1552            } else if (!strcasecmp(mountlist->el[idx].format, "raid")
1553                       || !strcasecmp(mountlist->el[idx].format, "vinum")) {
1554                lp->d_partitions[c - 'a'].p_fstype = FS_VINUM;
1555            } else if (!strcmp(mountlist->el[idx].format, "swap")) {
1556                lp->d_partitions[c - 'a'].p_fstype = FS_SWAP;
1557            } else
1558                lp->d_partitions[c - 'a'].p_fstype = FS_OTHER;
1559        }
1560    }
1561
1562    // fix up the offsets
1563    lp->d_partitions[0].p_offset = 0;
1564    lp->d_partitions[RAW_PART].p_offset = 0;
1565    lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1566    lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1567
1568    for (i = 1; i < lp->d_npartitions; ++i) {
1569        int lastone;
1570        if ((i == RAW_PART) || (lp->d_partitions[i].p_size == 0))
1571            continue;
1572        for (lastone = i - 1; lastone >= 0; lastone--) {
1573            if ((lp->d_partitions[lastone].p_size)
1574                && (lastone != RAW_PART))
1575                break;
1576        }
1577        lp->d_partitions[i].p_offset =
1578            lp->d_partitions[lastone].p_offset +
1579            lp->d_partitions[lastone].p_size;
1580    }
1581    if (lp->d_partitions[lo].p_offset + lp->d_partitions[lo].p_size >
1582        lp->d_secperunit) {
1583        lp->d_partitions[lo].p_size =
1584            lp->d_secperunit - lp->d_partitions[lo].p_offset;
1585    }
1586
1587    ftmp = fopen("/tmp/disklabel", "w");
1588    display_disklabel(ftmp, lp);
1589    fclose(ftmp);
1590    sprintf(command, "disklabel -wr %s auto", canonical_name(drivename));
1591    retval += run_program_and_log_output(command, TRUE);
1592    sprintf(command, "disklabel -R %s /tmp/disklabel",
1593            canonical_name(drivename));
1594    retval += run_program_and_log_output(command, TRUE);
1595    if (ret)
1596        *ret = *lp;
1597    return retval;
1598}
1599#endif
1600
1601
1602/**
1603 * Partition @p drivename based on @p mountlist.
1604 * @param mountlist The mountlist to use to guide the partitioning.
1605 * @param drivename The drive to partition.
1606 * @return 0 for success, nonzero for failure.
1607 */
1608int partition_drive(struct mountlist_itself *mountlist, char *drivename)
1609{
1610    /** int *************************************************************/
1611    int current_devno;
1612    int previous_devno = 0;
1613    int lino;
1614    int retval = 0;
1615    int i;
1616    FILE *pout_to_fdisk = NULL;
1617
1618#ifdef __FreeBSD__
1619    bool fbsd_part = FALSE;
1620    char subdev_str[MAX_STR_LEN];
1621#endif
1622
1623    /** long long *******************************************************/
1624    long long partsize;
1625
1626    /** buffers *********************************************************/
1627    char *device_str;
1628    char *format;
1629    char *tmp;
1630
1631    /** end *************************************************************/
1632
1633    assert(mountlist != NULL);
1634    assert_string_is_neither_NULL_nor_zerolength(drivename);
1635
1636    malloc_string(device_str);
1637    malloc_string(format);
1638    malloc_string(tmp);
1639
1640    sprintf(tmp, "Partitioning drive %s", drivename);
1641    log_it(tmp);
1642
1643#if __FreeBSD__
1644    log_it("(Not opening fdisk now; that's the Linux guy's job)");
1645    pout_to_fdisk = NULL;
1646#else
1647    make_hole_for_file(FDISK_LOG);
1648    sprintf(tmp, "parted2fdisk %s >> %s 2>> %s", drivename, FDISK_LOG, FDISK_LOG);
1649    pout_to_fdisk = popen(tmp, "w");
1650    if (!pout_to_fdisk) {
1651        log_to_screen("Cannot call parted2fdisk to configure %s", drivename);
1652        paranoid_free(device_str);
1653        paranoid_free(format);
1654        paranoid_free(tmp);
1655        return (1);
1656    }
1657#endif
1658    for (current_devno = 1; current_devno < 99; current_devno++) {
1659        build_partition_name(device_str, drivename, current_devno);
1660        lino = find_device_in_mountlist(mountlist, device_str);
1661
1662        if (lino < 0) {
1663            // device not found in mountlist
1664#if __FreeBSD__
1665            // If this is the first partition (just as a sentinel value),
1666            // then see if the user has picked 'dangerously-dedicated' mode.
1667            // If so, then we just call label_drive_or_slice() and return.
1668            char c;
1669            if (current_devno == 1) {
1670                // try DangerouslyDedicated mode
1671                for (c = 'a'; c <= 'z'; c++) {
1672                    sprintf(subdev_str, "%s%c", drivename, c);
1673                    if (find_device_in_mountlist(mountlist, subdev_str) >
1674                        0) {
1675                        fbsd_part = TRUE;
1676                    }
1677                }
1678                if (fbsd_part) {
1679                    int r = label_drive_or_slice(mountlist,
1680                                                 drivename,
1681                                                 0);
1682                    char command[MAX_STR_LEN];
1683                    sprintf(command, "disklabel -B %s",
1684                            basename(drivename));
1685                    if (system(command)) {
1686                        log_to_screen
1687                            ("Warning! Unable to make the drive bootable.");
1688                    }
1689                    paranoid_free(device_str);
1690                    paranoid_free(format);
1691                    paranoid_free(tmp);
1692                    return r;
1693                }
1694            }
1695            for (c = 'a'; c <= 'z'; c++) {
1696                sprintf(subdev_str, "%s%c", device_str, c);
1697                if (find_device_in_mountlist(mountlist, subdev_str) > 0) {
1698                    fbsd_part = TRUE;
1699                }
1700            }
1701            // Now we check the subpartitions of the current partition.
1702            if (fbsd_part) {
1703                int i, line;
1704
1705                strcpy(format, "ufs");
1706                partsize = 0;
1707                for (i = 'a'; i < 'z'; ++i) {
1708                    sprintf(subdev_str, "%s%c", device_str, i);
1709                    line = find_device_in_mountlist(mountlist, subdev_str);
1710                    if (line > 0) {
1711                        // We found one! Add its size to the total size.
1712                        partsize += mountlist->el[line].size;
1713                    }
1714                }
1715            } else {
1716                continue;
1717            }
1718#else
1719            continue;
1720#endif
1721        }
1722
1723        /* OK, we've found partition /dev/hdxN in mountlist; let's prep it */
1724        /* For FreeBSD, that is      /dev/adXsY */
1725
1726        log_it("Found partition %s in mountlist", device_str);
1727        if (!previous_devno) {
1728
1729            log_it("Wiping %s's partition table", drivename);
1730#if __FreeBSD__
1731            // FreeBSD doesn't let you write to blk devices in <512byte chunks.
1732//          sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1733//          if (run_program_and_log_output(tmp, TRUE)) {
1734            file = open(drivename, O_WRONLY);
1735            if (!file) {
1736                sprintf(tmp,
1737                        "Warning - unable to open %s for wiping it's partition table",
1738                        drivename);
1739                log_to_screen(tmp);
1740            }
1741
1742            for (i = 0; i < 512; i++) {
1743                if (!write(file, "\0", 1)) {
1744                    sprintf(tmp, "Warning - unable to write to %s",
1745                            drivename);
1746                    log_to_screen(tmp);
1747                }
1748            }
1749            system("sync");
1750#else
1751            iamhere("New, kernel-friendly partition remover");
1752            for (i = 20; i > 0; i--) {
1753                fprintf(pout_to_fdisk, "d\n%d\n", i);
1754                fflush(pout_to_fdisk);
1755            }
1756//          sprintf(tmp, "dd if=/dev/zero of=%s count=1 bs=512", drivename);
1757//          run_program_and_log_output(tmp, 1);
1758#endif
1759            if (current_devno > 1) {
1760                previous_devno =
1761                    make_dummy_partitions(pout_to_fdisk, drivename,
1762                                          current_devno);
1763            }
1764        }
1765#ifdef __FreeBSD__
1766        if (!fbsd_part) {
1767#endif
1768
1769            strcpy(format, mountlist->el[lino].format);
1770            partsize = mountlist->el[lino].size;
1771
1772#ifdef __FreeBSD__
1773        }
1774#endif
1775
1776#ifndef __IA64__
1777        if (current_devno == 5 && previous_devno == 4) {
1778            log_to_screen
1779                ("You must leave at least one partition spare as the Extended partition.");
1780            paranoid_free(device_str);
1781            paranoid_free(format);
1782            paranoid_free(tmp);
1783            return (1);
1784        }
1785#endif
1786
1787        retval +=
1788            partition_device(pout_to_fdisk, drivename, current_devno,
1789                             previous_devno, format, partsize);
1790
1791#ifdef __FreeBSD__
1792        if ((current_devno <= 4) && fbsd_part) {
1793            sprintf(tmp, "disklabel -B %s", basename(device_str));
1794            retval += label_drive_or_slice(mountlist, device_str, 0);
1795            if (system(tmp)) {
1796                log_to_screen
1797                    ("Warning! Unable to make the slice bootable.");
1798            }
1799        }
1800#endif
1801
1802        previous_devno = current_devno;
1803    }
1804
1805    if (pout_to_fdisk) {
1806// mark relevant partition as bootable
1807        sprintf(tmp, "a\n%s\n",
1808                call_program_and_get_last_line_of_output
1809                ("make-me-bootable /tmp/mountlist.txt dummy"));
1810        fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
1811// close fdisk
1812        fput_string_one_char_at_a_time(pout_to_fdisk, "w\n");
1813        system("sync");
1814        paranoid_pclose(pout_to_fdisk);
1815        log_msg(0,
1816                "------------------- fdisk.log looks like this ------------------");
1817        sprintf(tmp, "cat %s >> %s", FDISK_LOG, MONDO_LOGFILE);
1818        system(tmp);
1819        log_msg(0,
1820                "------------------- end of fdisk.log... word! ------------------");
1821        sprintf(tmp, "tail -n6 %s | grep -F \"16: \"", FDISK_LOG);
1822        if (!run_program_and_log_output(tmp, 5)) {
1823            g_partition_table_locked_up++;
1824            log_to_screen
1825                ("A flaw in the Linux kernel has locked the partition table.");
1826        }
1827    }
1828    paranoid_free(device_str);
1829    paranoid_free(format);
1830    paranoid_free(tmp);
1831    return (retval);
1832}
1833
1834/**
1835 * Create partition number @p partno on @p drive with @p fdisk.
1836 * @param drive The drive to create the partition on.
1837//  * @param partno The partition number of the new partition (1-4 are primary, >=5 is logical).
1838 * @param prev_partno The partition number of the most recently prepped partition.
1839 * @param format The filesystem type of this partition (used to set the type).
1840 * @param partsize The size of the partition in @e bytes.
1841 * @return 0 for success, nonzero for failure.
1842 */
1843int partition_device(FILE * pout_to_fdisk, const char *drive, int partno,
1844                     int prev_partno, const char *format,
1845                     long long partsize)
1846{
1847    /** int **************************************************************/
1848    int retval = 0;
1849    int res = 0;
1850
1851    /** buffers **********************************************************/
1852    char *program;
1853    char *partition_name;
1854    char *tmp;
1855    char *logfile;
1856    char *output;
1857
1858    /** pointers **********************************************************/
1859    char *p;
1860    char *part_table_fmt;
1861    FILE *fout;
1862
1863    /** end ***************************************************************/
1864
1865    malloc_string(program);
1866    malloc_string(partition_name);
1867    malloc_string(tmp);
1868    malloc_string(logfile);
1869    malloc_string(output);
1870
1871    assert_string_is_neither_NULL_nor_zerolength(drive);
1872    assert(format != NULL);
1873
1874    log_it("partition_device('%s', %d, %d, '%s', %lld) --- starting",
1875           drive, partno, prev_partno, format, partsize);
1876
1877    if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
1878        sprintf(tmp, "Not partitioning %s - it is a virtual drive", drive);
1879        log_it(tmp);
1880        paranoid_free(program);
1881        paranoid_free(partition_name);
1882        paranoid_free(tmp);
1883        paranoid_free(logfile);
1884        paranoid_free(output);
1885        return (0);
1886    }
1887    build_partition_name(partition_name, drive, partno);
1888    if (partsize <= 0) {
1889        sprintf(tmp, "Partitioning device %s (max size)", partition_name);
1890    } else {
1891        sprintf(tmp, "Partitioning device %s (%lld MB)", partition_name,
1892                (long long) partsize / 1024);
1893    }
1894    update_progress_form(tmp);
1895    log_it(tmp);
1896
1897    if (is_this_device_mounted(partition_name)) {
1898        sprintf(tmp, "%s is mounted, and should not be partitioned",
1899                partition_name);
1900        log_to_screen(tmp);
1901        paranoid_free(program);
1902        paranoid_free(partition_name);
1903        paranoid_free(tmp);
1904        paranoid_free(logfile);
1905        paranoid_free(output);
1906        return (1);
1907/*
1908    } else if (does_partition_exist(drive, partno)) {
1909        sprintf(tmp, "%s already has a partition", partition_name);
1910        log_to_screen(tmp);
1911        return (1);
1912*/
1913    }
1914
1915
1916    /*  sprintf(tmp,"Partitioning %s  ",partition_name); */
1917    /*  mvaddstr_and_log_it(g_currentY+1,30,tmp); */
1918    p = (char *) strrchr(partition_name, '/');
1919    sprintf(logfile, "/tmp/fdisk.log.%s", ++p);
1920    sprintf(program, "parted2fdisk %s >> %s 2>> %s", drive, MONDO_LOGFILE,
1921            MONDO_LOGFILE);
1922
1923    /* BERLIOS: shoould not be called each time */
1924    part_table_fmt = which_partition_format(drive);
1925    output[0] = '\0';
1926    /* make it a primary/extended/logical */
1927    if (partno <= 4) {
1928        sprintf(output + strlen(output), "n\np\n%d\n", partno);
1929    } else {
1930        /* MBR needs an extended partition if more than 4 partitions */
1931        if (strcmp(part_table_fmt, "MBR") == 0) {
1932            if (partno == 5) {
1933                if (prev_partno >= 4) {
1934                    log_to_screen
1935                        ("You need to leave at least one partition free, for 'extended/logical'");
1936                    paranoid_free(program);
1937                    paranoid_free(partition_name);
1938                    paranoid_free(tmp);
1939                    paranoid_free(logfile);
1940                    paranoid_free(output);
1941                    return (1);
1942                } else {
1943                    sprintf(output + strlen(output), "n\ne\n%d\n\n\n",
1944                            prev_partno + 1);
1945                }
1946            }
1947            strcat(output + strlen(output), "n\nl\n");
1948        } else {
1949            /* GPT allows more than 4 primary partitions */
1950            sprintf(output + strlen(output), "n\np\n%d\n", partno);
1951        }
1952    }
1953    strcat(output + strlen(output), "\n");  /*start block (ENTER for next free blk */
1954    if (partsize > 0) {
1955        if (!strcmp(format, "7")) {
1956            log_msg(1, "Adding 512K, just in case");
1957            partsize += 512;
1958        }
1959        sprintf(output + strlen(output), "+%lldK", (long long) (partsize));
1960    }
1961    strcat(output + strlen(output), "\n");
1962#if 0
1963/*
1964#endif
1965    sprintf(tmp,"PARTSIZE = +%ld",(long)partsize);
1966    log_it(tmp);
1967    log_it("---fdisk command---");
1968    log_it(output);
1969    log_it("---end of fdisk---");
1970#if 0
1971*/
1972#endif
1973
1974
1975    if (pout_to_fdisk) {
1976        log_msg(1, "Doing the new all-in-one fdisk thing");
1977        log_msg(1, "output = '%s'", output);
1978        fput_string_one_char_at_a_time(pout_to_fdisk, output);
1979        fput_string_one_char_at_a_time(pout_to_fdisk, "\n\np\n");
1980        strcpy(tmp, last_line_of_file(FDISK_LOG));
1981        if (strstr(tmp, " (m ")) {
1982            log_msg(1, "Successfully created %s%d", drive, partno);
1983        } else {
1984            log_msg(1, "last line = %s", tmp);
1985            log_msg(1, "Failed to create %s%d; sending 'Enter'...", drive,
1986                    partno);
1987        }
1988        if (!retval) {
1989            log_msg(1, "Trying to set %s%d's partition type now", drive,
1990                    partno);
1991            retval =
1992                set_partition_type(pout_to_fdisk, drive, partno, format,
1993                                   partsize);
1994            if (retval) {
1995                log_msg(1, "Failed. Trying again...");
1996                retval =
1997                    set_partition_type(pout_to_fdisk, drive, partno,
1998                                       format, partsize);
1999            }
2000        }
2001        if (retval) {
2002            log_msg(1, "...but failed to set type");
2003        }
2004    } else {
2005        strcat(output, "w\n\n");
2006        if (g_fprep) {
2007            fprintf(g_fprep, "echo \"%s\" | %s\n", output, program);
2008        }
2009        /* write to disk; close fdisk's stream */
2010        if (!(fout = popen(program, "w"))) {
2011            log_OS_error("can't popen-out to program");
2012        } else {
2013            fputs(output, fout);
2014            paranoid_pclose(fout);
2015        }
2016        if (!does_partition_exist(drive, partno) && partsize > 0) {
2017            log_it("Vaccum-packing");
2018            g_current_progress--;
2019            res =
2020                partition_device(pout_to_fdisk, drive, partno, prev_partno,
2021                                 format, -1);
2022            if (res) {
2023                sprintf(tmp, "Failed to vacuum-pack %s", partition_name);
2024                log_it(tmp);
2025                retval++;
2026            } else {
2027                retval = 0;
2028            }
2029        }
2030        if (does_partition_exist(drive, partno)) {
2031            retval =
2032                set_partition_type(pout_to_fdisk, drive, partno, format,
2033                                   partsize);
2034            if (retval) {
2035                sprintf(tmp, "Partitioned %s but failed to set its type",
2036                        partition_name);
2037                log_it(tmp);
2038            } else {
2039                if (partsize > 0) {
2040                    sprintf(tmp, "Partition %s created+configured OK",
2041                            partition_name);
2042                    log_to_screen(tmp);
2043                } else {
2044                    log_it("Returning from a successful vacuum-pack");
2045                }
2046            }
2047        } else {
2048            sprintf(tmp, "Failed to partition %s", partition_name);
2049            if (partsize > 0) {
2050                log_to_screen(tmp);
2051            } else {
2052                log_it(tmp);
2053            }
2054            retval++;
2055        }
2056    }
2057    g_current_progress++;
2058    log_it("partition_device() --- leaving");
2059    paranoid_free(program);
2060    paranoid_free(partition_name);
2061    paranoid_free(tmp);
2062    paranoid_free(logfile);
2063    paranoid_free(output);
2064    return (retval);
2065}
2066
2067
2068
2069/**
2070 * Create all partitions listed in @p mountlist.
2071 * @param mountlist The mountlist to use to guide the partitioning.
2072 * @return The number of errors encountered (0 for success).
2073 * @note This sets the partition types but doesn't actually do the formatting.
2074 * Use format_everything() for that.
2075 */
2076int partition_everything(struct mountlist_itself *mountlist)
2077{
2078    /** int ************************************************************/
2079    int lino;
2080    int retval = 0;
2081    int i;
2082    int res;
2083
2084    /** buffer *********************************************************/
2085    struct list_of_disks *drivelist;
2086    /*  struct mountlist_itself new_mtlist, *mountlist; */
2087
2088    /** end ************************************************************/
2089
2090    drivelist = malloc(sizeof(struct list_of_disks));
2091    assert(mountlist != NULL);
2092
2093    log_it("partition_everything() --- starting");
2094    mvaddstr_and_log_it(g_currentY, 0, "Partitioning hard drives      ");
2095    /*  mountlist=orig_mtlist; */
2096    if (mountlist_contains_raid_devices(mountlist)) {
2097        /*      mountlist=&new_mtlist; */
2098        /*      extrapolate_mountlist_to_include_raid_partitions(mountlist,orig_mtlist); */
2099        log_msg(0,
2100                "Mountlist, including the partitions incorporated in RAID devices:-");
2101        for (i = 0; i < mountlist->entries; i++) {
2102            log_it(mountlist->el[i].device);
2103        }
2104        log_msg(0, "End of mountlist.");
2105    }
2106    log_msg(0, "Stopping all LVMs, just in case");
2107    if (!g_text_mode) {
2108        newtSuspend();
2109    }
2110    do_my_funky_lvm_stuff(TRUE, FALSE); // just remove old partitions
2111    if (!g_text_mode) {
2112        newtResume();
2113    }
2114    log_msg(0, "Stopping all software RAID devices, just in case");
2115    stop_all_raid_devices(mountlist);
2116    log_msg(0, "Done.");
2117
2118/* 
2119    if (does_file_exist("/tmp/i-want-my-lvm"))
2120      {
2121        wipe_MBRs_and_reboot_if_necessary(mountlist); // i.e. if it wasn't done recently
2122      }
2123*/
2124
2125    open_progress_form("Partitioning devices",
2126                       "I am now going to partition all your drives.",
2127                       "This should not take more than five minutes.", "",
2128                       mountlist->entries);
2129
2130    make_list_of_drives_in_mountlist(mountlist, drivelist);
2131
2132    /* partition each drive */
2133    for (lino = 0; lino < drivelist->entries; lino++) {
2134        res = partition_drive(mountlist, drivelist->el[lino].device);
2135        retval += res;
2136    }
2137    close_progress_form();
2138    if (retval) {
2139        mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
2140        log_to_screen
2141            ("Errors occurred during the partitioning of your hard drives.");
2142    } else {
2143        mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2144        paranoid_system("rm -f /tmp/fdisk*.log 2> /dev/null");
2145    }
2146    newtSuspend();
2147    system("clear");
2148    newtResume();
2149    paranoid_free(drivelist);
2150    return (retval);
2151}
2152
2153
2154
2155
2156
2157
2158/**
2159 * Set the type of partition number @p partno on @p drive to @p format.
2160 * @param drive The drive to change the type of a partition on.
2161 * @param partno The partition number on @p drive to change the type of.
2162 * @param format The filesystem type this partition will eventually contain.
2163 * @param partsize The size of this partition, in @e bytes (used for vfat
2164 * type calculations).
2165 * @return 0 for success, nonzero for failure.
2166 */
2167int set_partition_type(FILE * pout_to_fdisk, const char *drive, int partno,
2168                       const char *format, long long partsize)
2169{
2170    /** buffers *********************************************************/
2171    char *partition;
2172    char *command;
2173    char *output;
2174    char *tmp;
2175    char *partcode;
2176    char *logfile;
2177
2178    /** pointers *********************************************************/
2179    char *p;
2180    FILE *fout;
2181
2182    /** int **************************************************************/
2183    int res = 0;
2184
2185    /** end **************************************************************/
2186
2187    assert_string_is_neither_NULL_nor_zerolength(drive);
2188    assert(format != NULL);
2189
2190    malloc_string(partition);
2191    malloc_string(command);
2192    malloc_string(output);
2193    malloc_string(tmp);
2194    malloc_string(partcode);
2195    malloc_string(logfile);
2196
2197    build_partition_name(partition, drive, partno);
2198    p = (char *) strrchr(partition, '/');
2199    sprintf(logfile, "/tmp/fdisk-set-type.%s.log", ++p);
2200    if (strcmp(format, "swap") == 0) {
2201        strcpy(partcode, "82");
2202    } else if (strcmp(format, "vfat") == 0) {
2203        if (partsize / 1024 > 8192) {
2204            strcpy(partcode, "c");
2205        } else {
2206            strcpy(partcode, "b");
2207        }
2208    } else if (strcmp(format, "ext2") == 0
2209               || strcmp(format, "reiserfs") == 0
2210               || strcmp(format, "ext3") == 0 || strcmp(format, "xfs") == 0
2211               || strcmp(format, "jfs") == 0) {
2212        strcpy(partcode, "83");
2213    } else if (strcmp(format, "minix") == 0) {
2214        strcpy(partcode, "81");
2215    } else if (strcmp(format, "raid") == 0) {
2216        strcpy(partcode, "fd");
2217    } else if ((strcmp(format, "ufs") == 0)
2218               || (strcmp(format, "ffs") == 0)) {   /* raid autodetect */
2219        strcpy(partcode, "a5");
2220    } else if (strcmp(format, "lvm") == 0) {
2221        strcpy(partcode, "8e");
2222    } else if (format[0] == '\0') { /* LVM physical partition */
2223        partcode[0] = '\0';
2224    } else if (strlen(format) >= 1 && strlen(format) <= 2) {
2225        strcpy(partcode, format);
2226    } else {
2227        /* probably an image */
2228        sprintf(tmp,
2229                "Unknown format ('%s') - using supplied string anyway",
2230                format);
2231        mvaddstr_and_log_it(g_currentY++, 0, tmp);
2232#ifdef __FreeBSD__
2233        strcpy(partcode, format);   // was a5
2234#else
2235        strcpy(partcode, format);   // was 83
2236#endif
2237    }
2238    sprintf(tmp, "Setting %s's type to %s (%s)", partition, format,
2239            partcode);
2240    log_msg(1, tmp);
2241    if (partcode[0] != '\0' && strcmp(partcode, "83")) {    /* no need to set type if 83: 83 is default */
2242
2243        if (pout_to_fdisk) {
2244            res = 0;
2245            fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
2246            if (partno > 1
2247                || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
2248                log_msg(5, "Specifying partno (%d) - yay", partno);
2249                sprintf(tmp, "%d\n", partno);
2250                fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2251                log_msg(5, "A - last line = '%s'",
2252                        last_line_of_file(FDISK_LOG));
2253            }
2254
2255            sprintf(tmp, "%s\n", partcode);
2256            fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2257            log_msg(5, "B - last line = '%s'",
2258                    last_line_of_file(FDISK_LOG));
2259            fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2260            log_msg(5, "C - last line = '%s'",
2261                    last_line_of_file(FDISK_LOG));
2262
2263            strcpy(tmp, last_line_of_file(FDISK_LOG));
2264            if (!strstr(tmp, " (m ")) {
2265                log_msg(1, "last line = '%s'; part type set failed", tmp);
2266                res++;
2267                fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2268            }
2269            fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2270        } else {
2271            sprintf(output, "t\n%d\n%s\n", partno, partcode);
2272            strcat(output, "w\n");
2273            sprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2274                    MONDO_LOGFILE, MONDO_LOGFILE);
2275            log_msg(5, "output = '%s'", output);
2276            log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2277            log_msg(5, "command = '%s'", command);
2278            fout = popen(command, "w");
2279            if (!fout) {
2280                log_OS_error(command);
2281                res = 1;
2282            } else {
2283                res = 0;
2284                fprintf(fout, output);
2285                paranoid_pclose(fout);
2286            }
2287        }
2288        if (res) {
2289            log_OS_error(command);
2290        }
2291    }
2292
2293    paranoid_free(partition);
2294    paranoid_free(command);
2295    paranoid_free(output);
2296    paranoid_free(tmp);
2297    paranoid_free(partcode);
2298    paranoid_free(logfile);
2299
2300    return (res);
2301}
2302
2303
2304int start_raid_device(char *raid_device)
2305{
2306    /** int *************************************************************/
2307    int res;
2308    int retval = 0;
2309
2310    /** buffers *********************************************************/
2311    char *program;
2312
2313    /** end *************************************************************/
2314
2315    assert_string_is_neither_NULL_nor_zerolength(raid_device);
2316    malloc_string(program);
2317
2318#ifdef __FreeBSD__
2319    if (is_this_device_mounted(raid_device)) {
2320        log_it("Can't start %s when it's mounted!", raid_device);
2321        return 1;
2322    }
2323    sprintf(program, "vinum start -f %s", raid_device);
2324#else
2325    sprintf(program, "raidstart %s", raid_device);
2326//      sprintf (program, "raidstart " RAID_DEVICE_STUB "*");
2327#endif
2328    log_msg(1, "program = %s", program);
2329    res = run_program_and_log_output(program, 1);
2330    if (g_fprep) {
2331        fprintf(g_fprep, "%s\n", program);
2332    }
2333    if (res) {
2334        log_msg(1, "Warning - failed to start RAID device %s",
2335                raid_device);
2336    }
2337    retval += res;
2338    sleep(1);
2339    return (retval);
2340}
2341
2342
2343
2344/**
2345 * Stop @p raid_device using @p raidstop.
2346 * @param raid_device The software RAID device to stop.
2347 * @return 0 for success, nonzero for failure.
2348 */
2349int stop_raid_device(char *raid_device)
2350{
2351    /** int *************************************************************/
2352    int res;
2353    int retval = 0;
2354
2355    /** buffers *********************************************************/
2356    char *program;
2357
2358    /** end *************************************************************/
2359
2360    assert_string_is_neither_NULL_nor_zerolength(raid_device);
2361    malloc_string(program);
2362
2363#ifdef __FreeBSD__
2364    if (is_this_device_mounted(raid_device)) {
2365        log_it("Can't stop %s when it's mounted!", raid_device);
2366        return 1;
2367    }
2368    sprintf(program, "vinum stop -f %s", raid_device);
2369#else
2370    // use raidstop if it exists, otherwise use mdadm
2371    if (run_program_and_log_output("which raidstop", FALSE)) {
2372        sprintf(program, "mdadm -S %s", raid_device);
2373    } else {
2374        sprintf(program, "raidstop %s", raid_device);
2375    }
2376#endif
2377    log_msg(1, "program = %s", program);
2378    res = run_program_and_log_output(program, 1);
2379    if (g_fprep) {
2380        fprintf(g_fprep, "%s\n", program);
2381    }
2382    if (res) {
2383        log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2384    }
2385    retval += res;
2386    return (retval);
2387}
2388
2389
2390int start_all_raid_devices(struct mountlist_itself *mountlist)
2391{
2392    int i;
2393    int retval = 0;
2394    int res;
2395
2396    for (i = 0; i < mountlist->entries; i++) {
2397        if (!strncmp
2398            (mountlist->el[i].device, RAID_DEVICE_STUB,
2399             strlen(RAID_DEVICE_STUB))) {
2400            log_msg(1, "Starting %s", mountlist->el[i].device);
2401            res = start_raid_device(mountlist->el[i].device);
2402            retval += res;
2403        }
2404    }
2405    if (retval) {
2406        log_msg(1, "Started all s/w raid devices OK");
2407    } else {
2408        log_msg(1, "Failed to start some/all s/w raid devices");
2409    }
2410    return (retval);
2411}
2412
2413/**
2414 * Stop all software RAID devices listed in @p mountlist.
2415 * @param mountlist The mountlist to stop the RAID devices in.
2416 * @return The number of errors encountered (0 for success).
2417 * @bug @p mountlist is not used.
2418 */
2419int stop_all_raid_devices(struct mountlist_itself *mountlist)
2420{
2421    /** int *************************************************************/
2422    int retval = 0;
2423#ifndef __FreeBSD__
2424    int res;
2425#endif
2426
2427    /** char ************************************************************/
2428    char *incoming;
2429#ifndef __FreeBSD__
2430    char *dev;
2431#endif
2432    /** pointers ********************************************************/
2433#ifndef __FreeBSD__
2434    char *p;
2435#endif
2436    FILE *fin;
2437    int i;
2438
2439    /** end ****************************************************************/
2440
2441    malloc_string(dev);
2442    malloc_string(incoming);
2443    assert(mountlist != NULL);
2444
2445    for (i = 0; i < 3; i++) {
2446#ifdef __FreeBSD__
2447        fin =
2448            popen
2449            ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2450             "r");
2451        if (!fin) {
2452            paranoid_free(dev);
2453            paranoid_free(incoming);
2454            return (1);
2455        }
2456        for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2457             fgets(incoming, MAX_STR_LEN - 1, fin)) {
2458            retval += stop_raid_device(incoming);
2459        }
2460#else
2461        fin = fopen("/proc/mdstat", "r");
2462        if (!fin) {
2463            log_OS_error("/proc/mdstat");
2464            paranoid_free(dev);
2465            paranoid_free(incoming);
2466            return (1);
2467        }
2468        for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2469             fgets(incoming, MAX_STR_LEN - 1, fin)) {
2470            for (p = incoming;
2471                 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2472                                || !isdigit(*(p + 2))); p++);
2473            if (*p != '\0') {
2474                sprintf(dev, "/dev/%s", p);
2475                for (p = dev; *p > 32; p++);
2476                *p = '\0';
2477                res = stop_raid_device(dev);
2478            }
2479        }
2480#endif
2481    }
2482    paranoid_fclose(fin);
2483    if (retval) {
2484        log_msg(1, "Warning - unable to stop some RAID devices");
2485    }
2486    paranoid_free(dev);
2487    paranoid_free(incoming);
2488    system("sync");
2489    system("sync");
2490    system("sync");
2491    sleep(1);
2492    return (retval);
2493}
2494
2495
2496
2497/**
2498 * Decide which command we need to use to format a device of type @p format.
2499 * @param format The filesystem type we are about to format.
2500 * @param program Where to put the binary name for this format.
2501 * @return 0 for success, nonzero for failure.
2502 */
2503int which_format_command_do_i_need(char *format, char *program)
2504{
2505    /** int *************************************************************/
2506    int res = 0;
2507
2508    /** buffers *********************************************************/
2509    char *tmp;
2510
2511    /** end ***************************************************************/
2512
2513    malloc_string(tmp);
2514    assert_string_is_neither_NULL_nor_zerolength(format);
2515    assert(program != NULL);
2516
2517    if (strcmp(format, "swap") == 0) {
2518#ifdef __FreeBSD__
2519        strcpy(program, "true");
2520#else
2521        strcpy(program, "mkswap");
2522#endif
2523    } else if (strcmp(format, "vfat") == 0) {
2524        strcpy(program, "format-and-kludge-vfat");
2525#ifndef __FreeBSD__
2526    } else if (strcmp(format, "reiserfs") == 0) {
2527        strcpy(program, "mkreiserfs -ff");
2528    } else if (strcmp(format, "xfs") == 0) {
2529        strcpy(program, "mkfs.xfs -f -q");
2530    } else if (strcmp(format, "jfs") == 0) {
2531        strcpy(program, "mkfs.jfs");
2532    } else if (strcmp(format, "ext3") == 0) {
2533        strcpy(program, "mkfs -t ext2 -F -j -q");
2534    } else if (strcmp(format, "minix") == 0) {
2535        strcpy(program, "mkfs.minix");
2536#endif
2537    } else if (strcmp(format, "ext2") == 0) {
2538        strcpy(program, "mke2fs -F -q");
2539    } else {
2540#ifdef __FreeBSD__
2541        sprintf(program, "newfs_%s", format);
2542#else
2543        sprintf(program, "mkfs -t %s -c", format);  // -c checks for bad blocks
2544#endif
2545        sprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format,
2546                program);
2547        log_it(tmp);
2548        res = 0;
2549    }
2550    paranoid_free(tmp);
2551    return (res);
2552}
2553
2554
2555/**
2556 * Calculate the probable size of @p drive_name by adding up sizes in
2557 * @p mountlist.
2558 * @param mountlist The mountlist to use to calculate the size.
2559 * @param drive_name The drive to calculate the original size of.
2560 * @return The size of @p drive_name in kilobytes.
2561 */
2562long calc_orig_size_of_drive_from_mountlist(struct mountlist_itself
2563                                            *mountlist, char *drive_name)
2564{
2565    /** long ************************************************************/
2566    long original_size_of_drive;
2567
2568    /** int *************************************************************/
2569    int partno;
2570
2571    /** buffers *********************************************************/
2572    char *tmp;
2573
2574    /** end *************************************************************/
2575
2576    malloc_string(tmp);
2577    assert(mountlist != NULL);
2578    assert_string_is_neither_NULL_nor_zerolength(drive_name);
2579
2580    for (original_size_of_drive = 0, partno = 0;
2581         partno < mountlist->entries; partno++) {
2582        if (strncmp
2583            (mountlist->el[partno].device, drive_name,
2584             strlen(drive_name)) == 0) {
2585            original_size_of_drive += mountlist->el[partno].size;
2586        } else {
2587            sprintf(tmp, "Skipping %s", mountlist->el[partno].device);
2588//                      log_to_screen(tmp);
2589        }
2590    }
2591    original_size_of_drive = original_size_of_drive / 1024;
2592    paranoid_free(tmp);
2593    return (original_size_of_drive);
2594}
2595
2596
2597/**
2598 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2599 * There are a few problems with this function:
2600 * - It won't work if there was any unallocated space on the user's hard drive
2601 *   when it was backed up.
2602 * - It won't work if the user's hard drive lies about its size (more common
2603 *   than you'd think).
2604 *
2605 * @param mountlist The mountlist to use for resizing @p drive_name.
2606 * @param drive_name The drive to resize.
2607 */
2608void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2609                                                     *mountlist,
2610                                                     char *drive_name)
2611{
2612    /**buffers **********************************************************/
2613    char *tmp;
2614
2615    /** int *************************************************************/
2616    int partno, lastpart;
2617               /** remove driveno, noof_drives stan benoit apr 2002**/
2618
2619    /** float ***********************************************************/
2620    float factor;
2621    float new_size;
2622//  float newcylinderno;
2623
2624    /** long *************************************************************/
2625    long newsizL;
2626    long current_size_of_drive = 0;
2627    long original_size_of_drive = 0;
2628    long final_size;            /* all in Megabytes */
2629    struct mountlist_reference *drivemntlist;
2630
2631    /** structures *******************************************************/
2632
2633    /** end **************************************************************/
2634
2635    malloc_string(tmp);
2636    assert(mountlist != NULL);
2637    assert_string_is_neither_NULL_nor_zerolength(drive_name);
2638
2639    if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2640        if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2641            == 0) {
2642            paranoid_free(tmp);
2643            return;
2644        }
2645    }
2646
2647    /*
2648       sprintf (tmp, "cp -f %s %s.pre-resize", g_mountlist_fname, g_mountlist_fname);
2649       run_program_and_log_output (tmp, FALSE);
2650     */
2651
2652    current_size_of_drive = get_phys_size_of_drive(drive_name);
2653
2654    if (current_size_of_drive <= 0) {
2655        log_it("Not resizing to match %s - can't find drive", drive_name);
2656        paranoid_free(tmp);
2657        return;
2658    }
2659    sprintf(tmp, "Expanding entries to suit drive %s (%ld MB)", drive_name,
2660            current_size_of_drive);
2661    log_to_screen(tmp);
2662
2663    drivemntlist = malloc(sizeof(struct mountlist_reference));
2664    drivemntlist->el =
2665        malloc(sizeof(struct mountlist_line *) * MAX_TAPECATALOG_ENTRIES);
2666
2667    if (!drivemntlist) {
2668        fatal_error("Cannot malloc temporary mountlist\n");
2669    }
2670    create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2671
2672    for (partno = 0; partno < drivemntlist->entries; partno++) {
2673        original_size_of_drive += drivemntlist->el[partno]->size;
2674    }
2675    original_size_of_drive = original_size_of_drive / 1024;
2676
2677    if (original_size_of_drive <= 0) {
2678        sprintf(tmp, "Cannot resize %s's entries. Drive not found.",
2679                drive_name);
2680        log_to_screen(tmp);
2681        paranoid_free(tmp);
2682        return;
2683    }
2684    factor =
2685        (float) (current_size_of_drive) / (float) (original_size_of_drive);
2686    sprintf(tmp, "Disk %s was %ld MB; is now %ld MB; factor = %f",
2687            drive_name, original_size_of_drive, current_size_of_drive,
2688            factor);
2689    log_to_screen(tmp);
2690
2691    lastpart = drivemntlist->entries - 1;
2692    for (partno = 0; partno < drivemntlist->entries; partno++) {
2693        /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2694        if (!atoi(drivemntlist->el[partno]->format)) {
2695            new_size = (float) (drivemntlist->el[partno]->size) * factor;
2696        } else {
2697            new_size = drivemntlist->el[partno]->size;
2698        }
2699
2700        if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2701            log_msg(1, "Skipping %s (%s) because it's an image",
2702                    drivemntlist->el[partno]->device,
2703                    drivemntlist->el[partno]->mountpoint);
2704            newsizL = (long) new_size;  // It looks wrong but it's not
2705        } else {
2706            newsizL = (long) new_size;
2707        }
2708        sprintf(tmp, "Changing %s from %lld KB to %ld KB",
2709                drivemntlist->el[partno]->device,
2710                drivemntlist->el[partno]->size, newsizL);
2711        log_to_screen(tmp);
2712        drivemntlist->el[partno]->size = newsizL;
2713    }
2714    final_size = get_phys_size_of_drive(drive_name);
2715    sprintf(tmp, "final_size = %ld MB", final_size);
2716    paranoid_free(tmp);
2717    log_to_screen(tmp);
2718}
2719
2720
2721/**
2722 * Resize all partitions in @p mountlist proportionately (each one
2723 * grows or shrinks by the same percentage) to fit them into the new
2724 * drives (presumably different from the old ones).
2725 * @param mountlist The mountlist to resize the drives in.
2726 */
2727void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2728                                                         *mountlist)
2729{
2730    /** buffers *********************************************************/
2731    struct list_of_disks *drivelist;
2732
2733    /** int *************************************************************/
2734    int driveno;
2735
2736    /** end *************************************************************/
2737
2738    drivelist = malloc(sizeof(struct list_of_disks));
2739    assert(mountlist != NULL);
2740
2741    if (g_mountlist_fname[0] == '\0') {
2742        log_it
2743            ("resize_mountlist_prop...() - warning - mountlist fname is blank");
2744        log_it("That does NOT affect the functioning of this subroutine.");
2745        log_it("--- Hugo, 2002/11/20");
2746    }
2747    iamhere("Resizing mountlist");
2748    make_list_of_drives_in_mountlist(mountlist, drivelist);
2749    iamhere("Back from MLoDiM");
2750    for (driveno = 0; driveno < drivelist->entries; driveno++) {
2751        resize_drive_proportionately_to_suit_new_drives(mountlist,
2752                                                        drivelist->
2753                                                        el[driveno].
2754                                                        device);
2755    }
2756    log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2757    paranoid_free(drivelist);
2758}
2759
2760/**
2761 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2762 * @param mountlist The complete mountlist to get the drive references from.
2763 * @param drive_name The drive to put in @p drivemntlist.
2764 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2765 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2766 * @author Ralph Grewe
2767 */
2768void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2769                                char *drive_name,
2770                                struct mountlist_reference *drivemntlist)
2771{
2772    int partno;
2773    char *tmp_drive_name, *c;
2774
2775    assert(mountlist != NULL);
2776    assert(drive_name != NULL);
2777    assert(drivemntlist != NULL);
2778
2779    log_msg(1, "Creating list of partitions for drive %s", drive_name);
2780
2781    tmp_drive_name = strdup(drive_name);
2782    if (!tmp_drive_name)
2783        fatal_error("Out of memory");
2784
2785    /* devfs devices? */
2786    c = strrchr(tmp_drive_name, '/');
2787    if (c && strncmp(c, "/disc", 5) == 0) {
2788        /* yup its devfs, change the "disc" to "part" so the existing code works */
2789        strcpy(c + 1, "part");
2790    }
2791    drivemntlist->entries = 0;
2792    for (partno = 0; partno < mountlist->entries; partno++) {
2793        if (strncmp
2794            (mountlist->el[partno].device, tmp_drive_name,
2795             strlen(tmp_drive_name)) == 0) {
2796            drivemntlist->el[drivemntlist->entries] =
2797                &mountlist->el[partno];
2798            drivemntlist->entries++;
2799        }
2800    }
2801    if (tmp_drive_name)
2802        free(tmp_drive_name);
2803}
2804
2805/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.