source: branches/2.2.9/mondo/src/mondorestore/mondo-prep.c @ 2770

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