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

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

r3342@localhost: bruno | 2009-08-14 00:46:51 +0200

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