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

Last change on this file since 541 was 541, checked in by bcornec, 13 years ago

Stable is reverted to r436 (2.0.7) to put it in line with 2.0.8 and start from there over

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