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

Last change on this file since 2323 was 2323, checked in by Bruno Cornec, 11 years ago

r3334@localhost: bruno | 2009-08-08 12:17:37 +0200

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