source: branches/2.2.9/mondo/src/mondorestore/mondo-prep.c @ 2154

Last change on this file since 2154 was 2154, checked in by bruno, 11 years ago
  • for ia64 parted2fdisk should fake in the log the return line of normal fdisk looking like "command (m ..." for n, d and t orders (reported by Grassi Giuseppe giuseppe.grassi2_at_italtel.it)
  • Property svn:keywords set to Id
File size: 74.9 KB
Line 
1/***************************************************************************
2$Id: mondo-prep.c 2154 2009-02-18 23:03:57Z 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 2154 2009-02-18 23:03:57Z 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: should 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, "ntfs") == 0) {
2085        strcpy(partcode, "7");
2086    } else if ((strcmp(format, "ufs") == 0)
2087               || (strcmp(format, "ffs") == 0)) {   /* raid autodetect */
2088        strcpy(partcode, "a5");
2089    } else if (strcmp(format, "lvm") == 0) {
2090        strcpy(partcode, "8e");
2091    } else if (format[0] == '\0') { /* LVM physical partition */
2092        partcode[0] = '\0';
2093    } else if (strlen(format) >= 1 && strlen(format) <= 2) {
2094        strcpy(partcode, format);
2095    } else {
2096        /* probably an image */
2097        sprintf(tmp,
2098                "Unknown format ('%s') - using supplied string anyway",
2099                format);
2100        mvaddstr_and_log_it(g_currentY++, 0, tmp);
2101#ifdef __FreeBSD__
2102        strcpy(partcode, format);   // was a5
2103#else
2104        strcpy(partcode, format);   // was 83
2105#endif
2106    }
2107    sprintf(tmp, "Setting %s's type to %s (%s)", partition, format,
2108            partcode);
2109    log_msg(1, tmp);
2110    if (partcode[0] != '\0' && strcmp(partcode, "83")) {    /* no need to set type if 83: 83 is default */
2111
2112        if (pout_to_fdisk) {
2113            res = 0;
2114            fput_string_one_char_at_a_time(pout_to_fdisk, "t\n");
2115            if (partno > 1
2116                || strstr(last_line_of_file(FDISK_LOG), " (1-4)")) {
2117                log_msg(5, "Specifying partno (%d) - yay", partno);
2118                sprintf(tmp, "%d\n", partno);
2119                fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2120                log_msg(5, "A - last line = '%s'",
2121                        last_line_of_file(FDISK_LOG));
2122            }
2123
2124            sprintf(tmp, "%s\n", partcode);
2125            fput_string_one_char_at_a_time(pout_to_fdisk, tmp);
2126            log_msg(5, "B - last line = '%s'",
2127                    last_line_of_file(FDISK_LOG));
2128            fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2129            log_msg(5, "C - last line = '%s'",
2130                    last_line_of_file(FDISK_LOG));
2131
2132            strcpy(tmp, last_line_of_file(FDISK_LOG));
2133            if (!strstr(tmp, " (m ")) {
2134                log_msg(1, "last line = '%s'; part type set failed", tmp);
2135                res++;
2136                fput_string_one_char_at_a_time(pout_to_fdisk, "\n");
2137            }
2138            fput_string_one_char_at_a_time(pout_to_fdisk, "p\n");
2139        } else {
2140            sprintf(output, "t\n%d\n%s\n", partno, partcode);
2141            strcat(output, "w\n");
2142            sprintf(command, "parted2fdisk %s >> %s 2>> %s", drive,
2143                    MONDO_LOGFILE, MONDO_LOGFILE);
2144            log_msg(5, "output = '%s'", output);
2145            log_msg(5, "partno=%d; partcode=%s", partno, partcode);
2146            log_msg(5, "command = '%s'", command);
2147            fout = popen(command, "w");
2148            if (!fout) {
2149                log_OS_error(command);
2150                res = 1;
2151            } else {
2152                res = 0;
2153                fprintf(fout, output);
2154                paranoid_pclose(fout);
2155            }
2156        }
2157        if (res) {
2158            log_OS_error(command);
2159        }
2160    }
2161
2162    paranoid_free(partition);
2163    paranoid_free(command);
2164    paranoid_free(output);
2165    paranoid_free(tmp);
2166    paranoid_free(partcode);
2167    paranoid_free(logfile);
2168
2169    return (res);
2170}
2171
2172
2173int start_raid_device(char *raid_device)
2174{
2175    /** int *************************************************************/
2176    int res;
2177    int retval = 0;
2178
2179    /** buffers *********************************************************/
2180    char *program;
2181
2182    /** end *************************************************************/
2183
2184    assert_string_is_neither_NULL_nor_zerolength(raid_device);
2185    malloc_string(program);
2186
2187#ifdef __FreeBSD__
2188    if (is_this_device_mounted(raid_device)) {
2189        log_it("Can't start %s when it's mounted!", raid_device);
2190        return 1;
2191    }
2192    sprintf(program, "vinum start -f %s", raid_device);
2193#else
2194    sprintf(program, "raidstart %s", raid_device);
2195#endif
2196    log_msg(1, "program = %s", program);
2197    res = run_program_and_log_output(program, 1);
2198    if (g_fprep) {
2199        fprintf(g_fprep, "%s\n", program);
2200    }
2201    if (res) {
2202        log_msg(1, "Warning - failed to start RAID device %s",
2203                raid_device);
2204    }
2205    retval += res;
2206    sleep(1);
2207    return (retval);
2208}
2209
2210
2211
2212/**
2213 * Stop @p raid_device using @p raidstop.
2214 * @param raid_device The software RAID device to stop.
2215 * @return 0 for success, nonzero for failure.
2216 */
2217int stop_raid_device(char *raid_device)
2218{
2219    /** int *************************************************************/
2220    int res;
2221    int retval = 0;
2222
2223    /** buffers *********************************************************/
2224    char *program;
2225
2226    /** end *************************************************************/
2227
2228    assert_string_is_neither_NULL_nor_zerolength(raid_device);
2229    malloc_string(program);
2230
2231#ifdef __FreeBSD__
2232    if (is_this_device_mounted(raid_device)) {
2233        log_it("Can't stop %s when it's mounted!", raid_device);
2234        return 1;
2235    }
2236    sprintf(program, "vinum stop -f %s", raid_device);
2237#else
2238    // use raidstop if it exists, otherwise use mdadm
2239    if (run_program_and_log_output("which raidstop", FALSE)) {
2240        sprintf(program, "mdadm -S %s", raid_device);
2241    } else {
2242        sprintf(program, "raidstop %s", raid_device);
2243    }
2244#endif
2245    log_msg(1, "program = %s", program);
2246    res = run_program_and_log_output(program, 1);
2247    if (g_fprep) {
2248        fprintf(g_fprep, "%s\n", program);
2249    }
2250    if (res) {
2251        log_msg(1, "Warning - failed to stop RAID device %s", raid_device);
2252    }
2253    retval += res;
2254    return (retval);
2255}
2256
2257
2258int start_all_raid_devices(struct mountlist_itself *mountlist)
2259{
2260    int i;
2261    int retval = 0;
2262    int res;
2263
2264    for (i = 0; i < mountlist->entries; i++) {
2265        if (!strncmp
2266            (mountlist->el[i].device, RAID_DEVICE_STUB,
2267             strlen(RAID_DEVICE_STUB))) {
2268            log_msg(1, "Starting %s", mountlist->el[i].device);
2269            res = start_raid_device(mountlist->el[i].device);
2270            retval += res;
2271        }
2272    }
2273    if (retval) {
2274        log_msg(1, "Started all s/w raid devices OK");
2275    } else {
2276        log_msg(1, "Failed to start some/all s/w raid devices");
2277    }
2278    return (retval);
2279}
2280
2281/**
2282 * Stop all software RAID devices listed in @p mountlist.
2283 * @param mountlist The mountlist to stop the RAID devices in.
2284 * @return The number of errors encountered (0 for success).
2285 * @bug @p mountlist is not used.
2286 */
2287int stop_all_raid_devices(struct mountlist_itself *mountlist)
2288{
2289    /** int *************************************************************/
2290    int retval = 0;
2291#ifndef __FreeBSD__
2292    int res;
2293#endif
2294
2295    /** char ************************************************************/
2296    char *incoming;
2297#ifndef __FreeBSD__
2298    char *dev;
2299#endif
2300    /** pointers ********************************************************/
2301#ifndef __FreeBSD__
2302    char *p;
2303#endif
2304    FILE *fin;
2305    int i;
2306
2307    /** end ****************************************************************/
2308
2309    malloc_string(dev);
2310    malloc_string(incoming);
2311    assert(mountlist != NULL);
2312
2313    for (i = 0; i < 3; i++) {
2314#ifdef __FreeBSD__
2315        fin =
2316            popen
2317            ("vinum list | grep '^[PVS]' | sed 's/S/1/;s/P/2/;s/V/3/' | sort | cut -d' ' -f2",
2318             "r");
2319        if (!fin) {
2320            paranoid_free(dev);
2321            paranoid_free(incoming);
2322            return (1);
2323        }
2324        for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2325             fgets(incoming, MAX_STR_LEN - 1, fin)) {
2326            retval += stop_raid_device(incoming);
2327        }
2328#else
2329        fin = fopen("/proc/mdstat", "r");
2330        if (!fin) {
2331            log_OS_error("/proc/mdstat");
2332            paranoid_free(dev);
2333            paranoid_free(incoming);
2334            return (1);
2335        }
2336        for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
2337             fgets(incoming, MAX_STR_LEN - 1, fin)) {
2338            for (p = incoming;
2339                 *p != '\0' && (*p != 'm' || *(p + 1) != 'd'
2340                                || !isdigit(*(p + 2))); p++);
2341            if (*p != '\0') {
2342                sprintf(dev, "/dev/%s", p);
2343                for (p = dev; *p > 32; p++);
2344                *p = '\0';
2345                res = stop_raid_device(dev);
2346            }
2347        }
2348#endif
2349    }
2350    paranoid_fclose(fin);
2351    if (retval) {
2352        log_msg(1, "Warning - unable to stop some RAID devices");
2353    }
2354    paranoid_free(dev);
2355    paranoid_free(incoming);
2356    system("sync");
2357    system("sync");
2358    system("sync");
2359    sleep(1);
2360    return (retval);
2361}
2362
2363
2364
2365/**
2366 * Decide which command we need to use to format a device of type @p format.
2367 * @param format The filesystem type we are about to format.
2368 * @param program Where to put the binary name for this format.
2369 * @return 0 for success, nonzero for failure.
2370 */
2371int which_format_command_do_i_need(char *format, char *program)
2372{
2373    /** int *************************************************************/
2374    int res = 0;
2375
2376    /** buffers *********************************************************/
2377    char *tmp;
2378
2379    /** end ***************************************************************/
2380
2381    malloc_string(tmp);
2382    assert_string_is_neither_NULL_nor_zerolength(format);
2383    assert(program != NULL);
2384
2385    if (strcmp(format, "swap") == 0) {
2386#ifdef __FreeBSD__
2387        strcpy(program, "true");
2388#else
2389        strcpy(program, "mkswap");
2390#endif
2391    } else if (strcmp(format, "vfat") == 0) {
2392        strcpy(program, "format-and-kludge-vfat");
2393#ifndef __FreeBSD__
2394    } else if (strcmp(format, "reiserfs") == 0) {
2395        strcpy(program, "mkreiserfs -ff");
2396    } else if (strcmp(format, "xfs") == 0) {
2397        strcpy(program, "mkfs.xfs -f -q");
2398    } else if (strcmp(format, "jfs") == 0) {
2399        strcpy(program, "mkfs.jfs");
2400    } else if (strcmp(format, "ext3") == 0) {
2401        strcpy(program, "mkfs -t ext3 -F -q");
2402    } else if (strcmp(format, "ext4") == 0) {
2403        strcpy(program, "mkfs -t ext4 -F -q");
2404    } else if (strcmp(format, "minix") == 0) {
2405        strcpy(program, "mkfs.minix");
2406    } else if (strcmp(format, "vmfs") == 0) {
2407        strcpy(program, "mkfs -t vmfs");
2408    } else if (strcmp(format, "ntfs") == 0) { 
2409        /*
2410         * mkfs.ntfs treats the '-c' switch as 'specify cluster size'
2411         * so the default "mkfs -t %s -c" command structure fails
2412         */ 
2413        strcpy(program, "mkfs -t ntfs");
2414    } else if (strcmp(format, "ocfs2") == 0) {
2415        /*
2416         * 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.
2417         *
2418         */
2419        strcpy(program, "mkfs -t ocfs2 -F");
2420#endif
2421    } else if (strcmp(format, "ext2") == 0) {
2422        strcpy(program, "mke2fs -F -q");
2423    } else {
2424#ifdef __FreeBSD__
2425        sprintf(program, "newfs_%s", format);
2426#else
2427        sprintf(program, "mkfs -t %s -c", format);  // -c checks for bad blocks
2428#endif
2429        sprintf(tmp, "Unknown format (%s) - assuming '%s' will do", format,
2430                program);
2431        log_it(tmp);
2432        res = 0;
2433    }
2434    paranoid_free(tmp);
2435    return (res);
2436}
2437
2438
2439/**
2440 * Resize a drive's entries in @p mountlist proportionately to fit its new size.
2441 * There are a few problems with this function:
2442 * - It won't work if there was any unallocated space on the user's hard drive
2443 *   when it was backed up.
2444 * - It won't work if the user's hard drive lies about its size (more common
2445 *   than you'd think).
2446 *
2447 * @param mountlist The mountlist to use for resizing @p drive_name.
2448 * @param drive_name The drive to resize.
2449 */
2450void resize_drive_proportionately_to_suit_new_drives(struct mountlist_itself
2451                                                     *mountlist,
2452                                                     char *drive_name)
2453{
2454    /**buffers **********************************************************/
2455    char *tmp;
2456
2457    /** int *************************************************************/
2458    int partno, lastpart;
2459               /** remove driveno, noof_drives stan benoit apr 2002**/
2460
2461    /** float ***********************************************************/
2462    float factor;
2463    float new_size;
2464//  float newcylinderno;
2465
2466    /** long *************************************************************/
2467    long newsizL = 0L;
2468    long current_size_of_drive = 0L;
2469    long original_size_of_drive = 0L;
2470    long final_size = 0L;           /* all in Megabytes */
2471    struct mountlist_reference *drivemntlist;
2472
2473    /** structures *******************************************************/
2474
2475    /** end **************************************************************/
2476
2477    malloc_string(tmp);
2478    assert(mountlist != NULL);
2479    assert_string_is_neither_NULL_nor_zerolength(drive_name);
2480
2481    if (strlen(drive_name) >= strlen(RAID_DEVICE_STUB)) {
2482        if (strncmp(drive_name, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))
2483            == 0) {
2484            paranoid_free(tmp);
2485            return;
2486        }
2487    }
2488
2489    current_size_of_drive = get_phys_size_of_drive(drive_name);
2490
2491    if (current_size_of_drive <= 0) {
2492        log_it("Not resizing to match %s - can't find drive", drive_name);
2493        paranoid_free(tmp);
2494        return;
2495    }
2496    sprintf(tmp, "Expanding entries to suit drive %s (%ld MB)", drive_name,
2497            current_size_of_drive);
2498    log_to_screen(tmp);
2499
2500    drivemntlist = malloc(sizeof(struct mountlist_reference));
2501    drivemntlist->el =
2502        malloc(sizeof(struct mountlist_line *) * MAX_TAPECATALOG_ENTRIES);
2503
2504    if (!drivemntlist) {
2505        fatal_error("Cannot malloc temporary mountlist\n");
2506    }
2507    create_mountlist_for_drive(mountlist, drive_name, drivemntlist);
2508
2509    for (partno = 0; partno < drivemntlist->entries; partno++) {
2510        if (drivemntlist->el[partno]->size > 0) {
2511            original_size_of_drive += (drivemntlist->el[partno]->size / 1024L);
2512        }
2513    }
2514
2515    if (original_size_of_drive <= 0) {
2516        sprintf(tmp, "Cannot resize %s's entries. Drive not found.",
2517                drive_name);
2518        log_to_screen(tmp);
2519        paranoid_free(tmp);
2520        return;
2521    }
2522    factor =
2523        (float) (current_size_of_drive) / (float) (original_size_of_drive);
2524    sprintf(tmp, "Disk %s was %ld MB; is now %ld MB; factor = %f",
2525            drive_name, original_size_of_drive, current_size_of_drive,
2526            factor);
2527    log_to_screen(tmp);
2528
2529    lastpart = drivemntlist->entries - 1;
2530    for (partno = 0; partno < drivemntlist->entries; partno++) {
2531        /* the 'atoi' thing is to make sure we don't try to resize _images_, whose formats will be numeric */
2532        if (!atoi(drivemntlist->el[partno]->format)) {
2533            new_size = (float) (drivemntlist->el[partno]->size) * factor;
2534        } else {
2535            new_size = drivemntlist->el[partno]->size;
2536        }
2537
2538        if (!strcmp(drivemntlist->el[partno]->mountpoint, "image")) {
2539            log_msg(1, "Skipping %s (%s) because it's an image",
2540                    drivemntlist->el[partno]->device,
2541                    drivemntlist->el[partno]->mountpoint);
2542            newsizL = (long) new_size;  // It looks wrong but it's not
2543        } else {
2544            newsizL = (long) new_size;
2545        }
2546
2547        /* Do not apply the factor if partition was of negative size */
2548        if (newsizL < 0) {
2549            newsizL = drivemntlist->el[partno]->size;
2550        }
2551
2552        sprintf(tmp, "Changing %s from %lld KB to %ld KB",
2553                drivemntlist->el[partno]->device,
2554                drivemntlist->el[partno]->size, newsizL);
2555        log_to_screen(tmp);
2556        drivemntlist->el[partno]->size = newsizL;
2557    }
2558    final_size = get_phys_size_of_drive(drive_name);
2559    sprintf(tmp, "final_size = %ld MB", final_size);
2560    log_to_screen(tmp);
2561    paranoid_free(tmp);
2562}
2563
2564
2565/**
2566 * Resize all partitions in @p mountlist proportionately (each one
2567 * grows or shrinks by the same percentage) to fit them into the new
2568 * drives (presumably different from the old ones).
2569 * @param mountlist The mountlist to resize the drives in.
2570 */
2571void resize_mountlist_proportionately_to_suit_new_drives(struct mountlist_itself
2572                                                         *mountlist)
2573{
2574    /** buffers *********************************************************/
2575    struct list_of_disks *drivelist;
2576
2577    /** int *************************************************************/
2578    int driveno;
2579
2580    /** end *************************************************************/
2581
2582    drivelist = malloc(sizeof(struct list_of_disks));
2583    assert(mountlist != NULL);
2584
2585    if (g_mountlist_fname[0] == '\0') {
2586        log_it
2587            ("resize_mountlist_prop...() - warning - mountlist fname is blank");
2588        log_it("That does NOT affect the functioning of this subroutine.");
2589        log_it("--- Hugo, 2002/11/20");
2590    }
2591    iamhere("Resizing mountlist");
2592    make_list_of_drives_in_mountlist(mountlist, drivelist);
2593    iamhere("Back from MLoDiM");
2594    for (driveno = 0; driveno < drivelist->entries; driveno++) {
2595        resize_drive_proportionately_to_suit_new_drives(mountlist,
2596                                                        drivelist->
2597                                                        el[driveno].
2598                                                        device);
2599    }
2600    log_to_screen("Mountlist adjusted to suit current hard drive(s)");
2601    paranoid_free(drivelist);
2602}
2603
2604/**
2605 * Create a mountlist_reference structure for @p drive_name in @p mountlist.
2606 * @param mountlist The complete mountlist to get the drive references from.
2607 * @param drive_name The drive to put in @p drivemntlist.
2608 * @param drivemntlist The mountlist_reference structure to put the drive's entries in.
2609 * @note @p drivemntlist and @p drivemntlist->el must be allocated by the caller.
2610 * @author Ralph Grewe
2611 */
2612void create_mountlist_for_drive(struct mountlist_itself *mountlist,
2613                                char *drive_name,
2614                                struct mountlist_reference *drivemntlist)
2615{
2616    int partno;
2617    char *tmp_drive_name, *c;
2618
2619    assert(mountlist != NULL);
2620    assert(drive_name != NULL);
2621    assert(drivemntlist != NULL);
2622
2623    log_msg(1, "Creating list of partitions for drive %s", drive_name);
2624
2625    tmp_drive_name = strdup(drive_name);
2626    if (!tmp_drive_name)
2627        fatal_error("Out of memory");
2628
2629    /* devfs devices? */
2630    c = strrchr(tmp_drive_name, '/');
2631    if (c && strncmp(c, "/disc", 5) == 0) {
2632        /* yup its devfs, change the "disc" to "part" so the existing code works */
2633        strcpy(c + 1, "part");
2634    }
2635    drivemntlist->entries = 0;
2636    for (partno = 0; partno < mountlist->entries; partno++) {
2637        if (strncmp
2638            (mountlist->el[partno].device, tmp_drive_name,
2639             strlen(tmp_drive_name)) == 0) {
2640            drivemntlist->el[drivemntlist->entries] =
2641                &mountlist->el[partno];
2642            drivemntlist->entries++;
2643        }
2644    }
2645    if (tmp_drive_name)
2646        free(tmp_drive_name);
2647}
2648
2649/* @} - end of prepGroup */
Note: See TracBrowser for help on using the repository browser.