source: MondoRescue/branches/2.2.10/mondo/src/mondorestore/mondo-prep.c @ 2330

Last change on this file since 2330 was 2330, checked in by Bruno Cornec, 12 years ago

r3341@localhost: bruno | 2009-08-13 22:36:24 +0200

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