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

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

r3336@localhost: bruno | 2009-08-11 16:32:36 +0200

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