source: branches/2.2.8/mondo/src/mondorestore/mondo-prep.c @ 2087

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