source: branches/stable/mondo/src/mondorestore/mondo-prep.c @ 1080

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