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

Last change on this file since 2603 was 2603, checked in by Bruno Cornec, 10 years ago

r3757@localhost: bruno | 2010-03-17 15:05:13 +0100

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