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

Last change on this file since 2405 was 2405, checked in by bruno, 10 years ago

Removes some malloc_string static allocation

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