source: branches/2.2.2/mondo/src/mondorestore/mondo-prep.c @ 1315

Last change on this file since 1315 was 1315, checked in by bruno, 12 years ago

Log files are now consistent: mondoarchive.log for mondoarchive (containing also mindi.log) and mondorestore.log for mondorestore (copied from /tmp (ram) to /var/log (disk) at the end of the restore)
One include has been created for each bianry containing only that declaration ofr the moment, but which will be extended to include all local definitions (ps_* e.g.)
Doc updated accordingly
LOGFILE in restore process is now passed in the environment and not duplicated anymore
LogIt? is not redifined either
LOGFILE should be put in environment by mondoarchive for mindi's usage but that's a step left for later.

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