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

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

Linker fixes for mondo
mount in logfile added for mindi

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