source: trunk/mondo/src/mondorestore/mondo-prep.c @ 1106

Last change on this file since 1106 was 1106, checked in by bruno, 13 years ago

merge -r1082:1105 $SVN_M/branches/stable

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