source: branches/3.0/mondo/src/mondorestore/mondo-prep.c @ 2928

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