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

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