source: MondoRescue/branches/3.2/mondo/src/mondorestore/mondo-prep.c@ 3434

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