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

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