source: MondoRescue/trunk/mondo/src/common/libmondo-tools.c@ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 18 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

  • Property svn:keywords set to Id
File size: 35.7 KB
Line 
1/* $Id: libmondo-tools.c 900 2006-10-24 06:49:18Z bruno $
2misc tools
3*/
4
5/**
6 * @file
7 * Miscellaneous tools that didn't really fit anywhere else.
8 */
9
10#include "my-stuff.h"
11#include "mondostructures.h"
12#include "libmondo-tools.h"
13#include "newt-specific-EXT.h"
14#include "libmondo-files-EXT.h"
15#include "libmondo-fork-EXT.h"
16#include "libmondo-raid-EXT.h"
17#include <sys/socket.h>
18#include <netdb.h>
19#include <netinet/in.h>
20#ifndef S_SPLINT_S
21#include <arpa/inet.h>
22#endif
23#include "mr_mem.h"
24
25/*@unused@*/
26//static char cvsid[] = "$Id: libmondo-tools.c 900 2006-10-24 06:49:18Z bruno $";
27
28extern int g_tape_buffer_size_MB;
29extern char *g_erase_tmpdir_and_scratchdir;
30extern char *g_serial_string;
31extern bool g_text_mode;
32extern int g_currentY;
33extern int g_current_media_number;
34
35/**
36 * @addtogroup globalGroup
37 * @{
38 */
39bool g_remount_cdrom_at_end, ///< TRUE if we unmounted the CD-ROM and should remount it when done with the backup.
40 g_remount_floppy_at_end; ///< TRUE if we unmounted the floppy and should remount it when done with the backup.
41bool g_cd_recovery; ///< TRUE if we're making an "autonuke" backup.
42double g_kernel_version;
43
44/**
45 * The place where /boot is mounted. - Used locally only
46 */
47static char *g_boot_mountpt = NULL;
48
49/**
50 * The location of Mondo's home directory.
51 */
52char *g_mondo_home = NULL;
53
54/**
55 * The serial string (used to differentiate between backups) of the current backup.
56 */
57char *g_serial_string = NULL;
58
59/**
60 * The location where tmpfs is mounted, or "" if it's not mounted.
61 */
62char *g_tmpfs_mountpt = NULL;
63char *g_magicdev_command = NULL;
64
65/**
66 * The default maximum level to log messages at or below.
67 */
68int g_loglevel = DEFAULT_DEBUG_LEVEL;
69
70/* @} - end of globalGroup */
71
72
73extern pid_t g_buffer_pid;
74extern pid_t g_main_pid;
75
76extern t_bkptype g_backup_media_type;
77extern char *g_backup_media_string;
78
79extern bool am_I_in_disaster_recovery_mode(void);
80
81
82/**
83 * @addtogroup utilityGroup
84 * @{
85 */
86/**
87 * Assertion handler. Prints a friendly message to the user,
88 * offering to ignore all, dump core, break to debugger,
89 * exit, or ignore. Intended to be used with an assert() macro.
90 *
91 * @param file The file in which the assertion triggered.
92 * @param function The function (@c __FUNCTION__) in which the assertion triggered.
93 * @param line The line number of the assert() statement.
94 * @param exp The expression that failed (as a string).
95 */
96void _mondo_assert_fail(const char *file,
97 const char *function, int line, const char *exp)
98{
99 static int ignoring_assertions = 0;
100 bool is_valid = TRUE;
101
102 log_it("ASSERTION FAILED: `%s' at %s:%d in %s", exp, file, line,
103 function);
104 if (ignoring_assertions) {
105 log_it("Well, the user doesn't care...");
106 return;
107 }
108#ifndef _XWIN
109 if (!g_text_mode)
110 newtSuspend();
111#endif
112 printf(_("ASSERTION FAILED: `%s'\n"), exp);
113 printf(_("\tat %s:%d in %s\n\n"), file, line, function);
114 printf(_("(I)gnore, ignore (A)ll, (D)ebug, a(B)ort, or (E)xit? "));
115 do {
116 is_valid = TRUE;
117 switch (toupper(getchar())) {
118 case 'A': // ignore (A)ll
119 ignoring_assertions = 1;
120 break;
121 case 'B': // a(B)ort
122 signal(SIGABRT, SIG_DFL); /* prevent SIGABRT handler from running */
123 raise(SIGABRT);
124 break; /* "can't get here" */
125 case 'D': // (D)ebug, aka asm("int 3")
126#ifdef __IA32__
127 __asm__ __volatile__("int $3"); // break to debugger
128#endif
129 break;
130 case 'E': // (E)xit
131 fatal_error("Failed assertion -- see above for details");
132 break; /* "can't get here" */
133 case 'I': // (I)gnore
134 break;
135 /* These next two work as follows:
136 the `default' catches the user's invalid choice and says so;
137 the '\n' catches the newline on the end and prints the prompt again.
138 */
139 case '\n':
140 printf
141 (_("(I)gnore, ignore (A)ll, (D)ebug, a(B)ort, or (E)xit? "));
142 break;
143 default:
144 is_valid = FALSE;
145 printf(_("Invalid choice.\n"));
146 break;
147 }
148 } while (!is_valid);
149
150 if (ignoring_assertions) {
151 log_it("Ignoring ALL assertions from now on.");
152 } else {
153 log_it("Ignoring assertion: %s", exp);
154 }
155
156 getchar(); // skip \n
157
158#ifndef _XWIN
159 if (!g_text_mode)
160 newtResume();
161#endif
162}
163
164/**
165 * Clean's up users' KDE desktops.
166 * @bug Details about this function are unknown.
167 */
168void clean_up_KDE_desktop_if_necessary(void)
169{
170 char *tmp;
171
172 mr_asprintf(&tmp,
173 "for i in `find /root /home -type d -name Desktop -maxdepth 2`; do \
174file=$i/.directory; if [ -f \"$file\" ] ; then mv -f $file $file.old ; \
175awk '{if (index($0, \"rootimagesmindi\")) { while (length($0)>2) { getline;} ; } \
176else { print $0;};}' $file.old > $file ; fi ; done");
177 run_program_and_log_output(tmp, 5);
178 mr_free(tmp);
179}
180
181
182/**
183 * Locate mondoarchive's home directory. Searches in /usr/local/mondo, /usr/share/mondo,
184 * /usr/local/share/mondo, /opt, or if all else fails, search /usr.
185 *
186 * @param home_sz String to store the home directory ("" if it could not be found).
187 * @return 0 for success, nonzero for failure.
188 */
189char *find_and_store_mondoarchives_home()
190{
191 char *home_sz = NULL;
192
193 mr_asprintf(&home_sz, MONDO_SHARE);
194 return (home_sz);
195}
196
197
198char *get_architecture()
199{
200#ifdef __IA32__
201 return ("i386");
202#endif
203#ifdef __X86_64__
204 return ("x86-64");
205#endif
206#ifdef __IA64__
207 return ("ia64");
208#endif
209 return ("unknown");
210}
211
212
213
214double get_kernel_version()
215{
216 char *p, *tmp;
217 double d;
218#ifdef __FreeBSD__
219 // JOSH - FIXME :)
220 d = 5.2; // :-)
221#else
222 tmp = call_program_and_get_last_line_of_output("uname -r");
223 p = strchr(tmp, '.');
224 if (p) {
225 p = strchr(++p, '.');
226 if (p) {
227 while (*p) {
228 *p = *(p + 1);
229 p++;
230 }
231 }
232 }
233// log_msg(1, "tmp = '%s'", tmp);
234 d = atof(tmp);
235#endif
236 log_msg(1, "g_kernel_version = %f", d);
237 return (d);
238}
239
240
241
242
243
244/**
245 * Get the current time.
246 * @return number of seconds since the epoch.
247 */
248long get_time()
249{
250 return (long) time((void *) 0);
251}
252
253
254
255
256
257
258
259/**
260 * Initialize a RAID volume structure, setting fields to zero. The
261 * actual hard drive is unaffected.
262 *
263 * @param raidrec The RAID volume structure to initialize.
264 * @note This function is system dependent.
265 */
266#ifdef __FreeBSD__
267void initialize_raidrec(struct vinum_volume *raidrec)
268{
269 int i, j;
270 raidrec->volname[0] = '\0';
271 raidrec->plexes = 0;
272 for (i = 0; i < 9; ++i) {
273 raidrec->plex[i].raidlevel = -1;
274 raidrec->plex[i].stripesize = 0;
275 raidrec->plex[i].subdisks = 0;
276 for (j = 0; j < 9; ++j) {
277 strcpy(raidrec->plex[i].sd[j].which_device, "");
278 }
279 }
280}
281#else
282void initialize_raidrec(struct raid_device_record *raidrec)
283{
284 assert(raidrec != NULL);
285 raidrec->raid_device = NULL;
286 raidrec->raid_level = -9;
287 raidrec->persistent_superblock = 1;
288 raidrec->chunk_size = 64;
289 raidrec->parity = -1;
290 raidrec->data_disks.entries = 0;
291 raidrec->spare_disks.entries = 0;
292 raidrec->parity_disks.entries = 0;
293 raidrec->failed_disks.entries = 0;
294 raidrec->additional_vars.entries = 0;
295}
296#endif
297
298
299
300
301/**
302 * Insert modules that Mondo requires.
303 * Currently inserts @c dos, @c fat, @c vfat, and @c osst for Linux;
304 * @c msdosfs and @c ext2fs for FreeBSD.
305 */
306void insmod_crucial_modules(void)
307{
308#ifdef __FreeBSD__
309 system("kldstat | grep msdosfs || kldload msdosfs 2> /dev/null");
310 system("kldstat | grep ext2fs || kldload ext2fs 2> /dev/null");
311#else
312 system("modprobe -a dos fat vfat loop &> /dev/null");
313#endif
314}
315
316
317/**
318 * Finish configuring the backup information structure. Call this function
319 * to set the parameters that depend on those that can be given on the command
320 * line.
321 *
322 * @param bkpinfo The backup information structure. Fields modified/used:
323 * - Used: @c bkpinfo->backup_data
324 * - Used: @c bkpinfo->backup_media_type
325 * - Used: @c bkpinfo->cdrw_speed
326 * - Used: @c bkpinfo->compression_level
327 * - Used: @c bkpinfo->include_paths
328 * - Used: @c bkpinfo->prefix
329 * - Used: @c bkpinfo->isodir
330 * - Used: @c bkpinfo->manual_cd_tray
331 * - Used: @c bkpinfo->make_cd_use_lilo
332 * - Used: @c bkpinfo->media_device
333 * - Used: @c bkpinfo->nfs_mount
334 * - Used: @c bkpinfo->nonbootable_backup
335 * - Used: @c bkpinfo->scratchdir
336 * - Used: @c bkpinfo->tmpdir
337 * - Used: @c bkpinfo->use_lzo
338 * - Modified: @c bkpinfo->call_before_iso
339 * - Modified: @c bkpinfo->call_make_iso
340 * - Modified: @c bkpinfo->optimal_set_size
341 * - Modified: @c bkpinfo->zip_exe
342 * - Modified: @c bkpinfo->zip_suffix
343 *
344 * @return number of errors, or 0 for success.
345 * @note Also creates directories that are specified in the @c bkpinfo structure but
346 * do not exist.
347 */
348int post_param_configuration(struct s_bkpinfo *bkpinfo)
349{
350 char *extra_cdrom_params = NULL;
351 char *mondo_mkisofs_sz = NULL;
352 char *command = NULL;
353 char *hostname = NULL, *ip_address = NULL;
354 int retval = 0;
355 long avm = 0;
356 char *colon = NULL;
357 char *cdr_exe = NULL;
358 char *tmp = NULL;
359 char *tmp1 = NULL;
360 char *call_before_iso_user = NULL;
361 int rdsiz_MB;
362 char *iso_path = NULL;
363
364 assert(bkpinfo != NULL);
365 bkpinfo->optimal_set_size =
366 (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type) ? 16 : 16) *
367 1024;
368
369 log_msg(1, "Foo");
370 if (bkpinfo->backup_media_type == tape) {
371 log_msg(1, "Bar");
372 mr_asprintf(&tmp, "mt -f %s status", bkpinfo->media_device);
373 log_msg(1, "tmp = '%s'", tmp);
374 if (run_program_and_log_output(tmp, 3)) {
375 fatal_error
376 ("Unable to open tape device. If you haven't specified it with -d, do so. If you already have, check your parameter. I think it's wrong.");
377 }
378 mr_free(tmp);
379 }
380 make_hole_for_dir(bkpinfo->scratchdir);
381 make_hole_for_dir(bkpinfo->tmpdir);
382 if (bkpinfo->backup_media_type == iso)
383 make_hole_for_dir(bkpinfo->isodir);
384
385 run_program_and_log_output("uname -a", 5);
386 run_program_and_log_output("cat /etc/*-release", 5);
387 run_program_and_log_output("cat /etc/*issue*", 5);
388 mr_asprintf(&g_tmpfs_mountpt, "%s/tmpfs", bkpinfo->tmpdir);
389 mr_asprintf(&command, "mkdir -p %s", g_tmpfs_mountpt);
390 paranoid_system(command);
391 mr_free(command);
392 rdsiz_MB = PPCFG_RAMDISK_SIZE + g_tape_buffer_size_MB;
393#ifdef __FreeBSD__
394 tmp = call_program_and_get_last_line_of_output
395 ("vmstat | tail -1 | tr -s ' ' | cut -d' ' -f6");
396 avm += atol(tmp);
397 mr_free(tmp);
398 tmp = call_program_and_get_last_line_of_output
399 ("swapinfo | grep -v Device | tr -s ' ' | cut -d' ' -f4 | tr '\n' '+' | sed 's/+$//' | bc");
400 avm += atol(tmp);
401 mr_free(tmp);
402 mr_asprintf(&command, "mdmfs -s %d%c md9 %s", rdsiz_MB, 'm',
403 g_tmpfs_mountpt);
404#else
405 tmp = call_program_and_get_last_line_of_output
406 ("free | grep \":\" | tr -s ' ' '\t' | cut -f2 | head -n1");
407 avm += atol(tmp);
408 mr_free(tmp);
409 mr_asprintf(&command, "mount /dev/shm -t tmpfs %s -o size=%d%c",
410 g_tmpfs_mountpt, rdsiz_MB, 'm');
411 run_program_and_log_output("cat /proc/cpuinfo", 5);
412 /* BERLIOS: rpm is not necessarily there ! */
413 run_program_and_log_output
414 ("rpm -q newt newt-devel slang slang-devel ncurses ncurses-devel gcc",
415 5);
416#endif
417 if (avm / 1024 > rdsiz_MB * 3) {
418 if (run_program_and_log_output(command, 5)) {
419 mr_free(g_tmpfs_mountpt);
420 log_it("Failed to mount tmpfs");
421 } else {
422 log_it("Tmpfs mounted OK - %d MB", rdsiz_MB);
423 }
424 } else {
425 mr_free(g_tmpfs_mountpt);
426 log_it("It doesn't seem you have enough swap to use tmpfs. Fine.");
427 }
428 mr_free(command);
429
430 if (bkpinfo->use_lzo) {
431 mr_allocstr(bkpinfo->zip_exe, "lzop");
432 mr_allocstr(bkpinfo->zip_suffix, "lzo");
433 } else if (bkpinfo->compression_level != 0) {
434 mr_allocstr(bkpinfo->zip_exe, "bzip2");
435 mr_allocstr(bkpinfo->zip_suffix, "bz2");
436 } else {
437 bkpinfo->zip_exe = NULL;
438 bkpinfo->zip_suffix = NULL;
439 }
440
441// DVD
442
443 if (bkpinfo->backup_media_type == dvd) {
444 tmp = find_home_of_exe("growisofs");
445 if (!tmp) {
446 fatal_error("Please install growisofs.");
447 }
448 mr_free(tmp);
449
450 if (bkpinfo->nonbootable_backup) {
451 mr_asprintf(&mondo_mkisofs_sz, MONDO_GROWISOFS_NONBOOT);
452 } else if
453#ifdef __FreeBSD__
454 (TRUE)
455#else
456 (bkpinfo->make_cd_use_lilo)
457#endif
458#ifdef __IA64__
459 {
460 mr_asprintf(&mondo_mkisofs_sz, MONDO_GROWISOFS_REGULAR_ELILO);
461 }
462#else
463 {
464 mr_asprintf(&mondo_mkisofs_sz, MONDO_GROWISOFS_REGULAR_LILO);
465 }
466#endif
467 else
468 {
469 mr_asprintf(&mondo_mkisofs_sz, MONDO_GROWISOFS_REGULAR_SYSLINUX);
470 }
471 if (bkpinfo->manual_cd_tray) {
472 fatal_error("Manual CD tray + DVD not supported yet.");
473 // -m isn't supported by growisofs, BTW...
474 } else {
475 mr_asprintf(&bkpinfo->call_make_iso,
476 "%s %s -Z %s . 2>> _ERR_",
477 mondo_mkisofs_sz, "", bkpinfo->media_device);
478 }
479 mr_free(mondo_mkisofs_sz);
480
481 if (getenv ("SUDO_COMMAND")) {
482 mr_asprintf(&command, "strings `which growisofs` | grep -c SUDO_COMMAND");
483 tmp = call_program_and_get_last_line_of_output(command);
484 if (!strcmp(tmp, "1")) {
485 popup_and_OK("Fatal Error: Can't write DVDs as sudo because growisofs doesn't support this - see the growisofs manpage for details.");
486 fatal_error("Can't write DVDs as sudo because growisofs doesn't support this - see the growisofs manpage for details.");
487 }
488 mr_free(tmp);
489 mr_free(command);
490 }
491 log_msg(2, "call_make_iso (DVD res) is ... %s",
492 bkpinfo->call_make_iso);
493 } // end of DVD code
494
495// CD-R or CD-RW
496 if (bkpinfo->backup_media_type == cdrw
497 || bkpinfo->backup_media_type == cdr) {
498 if (!bkpinfo->manual_cd_tray) {
499 mr_asprintf(&extra_cdrom_params, "-waiti ");
500 }
501 if (bkpinfo->backup_media_type == cdrw) {
502 if (extra_cdrom_params != NULL) {
503 mr_asprintf(&tmp, extra_cdrom_params);
504 mr_free(extra_cdrom_params);
505 mr_asprintf(&extra_cdrom_params, "%s blank=fast ", tmp);
506 } else {
507 mr_asprintf(&extra_cdrom_params, "blank=fast ");
508 }
509 }
510 tmp = find_home_of_exe("cdrecord");
511 tmp1 = find_home_of_exe("dvdrecord");
512 if (tmp) {
513 mr_asprintf(&cdr_exe, "cdrecord");
514 } else if (tmp1) {
515 mr_asprintf(&cdr_exe, "dvdrecord");
516 } else {
517 fatal_error("Please install either cdrecord or dvdrecord.");
518 }
519 mr_free(tmp);
520 mr_free(tmp1);
521
522 if (bkpinfo->nonbootable_backup) {
523 mr_asprintf(&mondo_mkisofs_sz, "%s -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL_Version -V _CD#_", bkpinfo->mr_conf->mondo_iso_creation_cmd);
524 } else if
525#ifdef __FreeBSD__
526 (TRUE)
527#else
528 (bkpinfo->make_cd_use_lilo)
529#endif
530#ifdef __IA64__
531 {
532 mr_asprintf(&mondo_mkisofs_sz, MONDO_MKISOFS_REGULAR_ELILO);
533 }
534#else
535 {
536 mr_asprintf(&mondo_mkisofs_sz, MONDO_MKISOFS_REGULAR_LILO);
537 }
538#endif
539 else
540 {
541 mr_asprintf(&mondo_mkisofs_sz, MONDO_MKISOFS_REGULAR_SYSLINUX);
542 }
543 if (bkpinfo->manual_cd_tray) {
544 if (bkpinfo->call_before_iso == NULL) {
545 mr_asprintf(&bkpinfo->call_before_iso,
546 "%s -o %s/temporary.iso . 2>> _ERR_",
547 mondo_mkisofs_sz, bkpinfo->tmpdir);
548 } else {
549 mr_asprintf(&call_before_iso_user, bkpinfo->call_before_iso);
550 mr_asprintf(&bkpinfo->call_before_iso,
551 "( %s -o %s/temporary.iso . 2>> _ERR_ ; %s )",
552 mondo_mkisofs_sz, bkpinfo->tmpdir, call_before_iso_user);
553 mr_free(call_before_iso_user);
554 }
555 log_it("bkpinfo->call_before_iso = %s", bkpinfo->call_before_iso);
556 mr_asprintf(&bkpinfo->call_make_iso,
557 "%s %s -v %s fs=4m dev=%s speed=%d %s/temporary.iso",
558 cdr_exe, (bkpinfo->please_dont_eject) ? " " : "-eject",
559 extra_cdrom_params, bkpinfo->media_device,
560 bkpinfo->cdrw_speed, bkpinfo->tmpdir);
561 } else {
562 mr_asprintf(&bkpinfo->call_make_iso,
563 "%s . 2>> _ERR_ | %s %s %s fs=4m dev=%s speed=%d -",
564 mondo_mkisofs_sz, cdr_exe,
565 (bkpinfo->please_dont_eject) ? " " : "-eject",
566 extra_cdrom_params, bkpinfo->media_device,
567 bkpinfo->cdrw_speed);
568 }
569 mr_free(mondo_mkisofs_sz);
570 mr_free(cdr_exe);
571 mr_free(extra_cdrom_params);
572 } // end of CD code
573
574 if (bkpinfo->backup_media_type == iso) {
575
576/* Patch by Conor Daly <conor.daly@met.ie>
577 * 23-june-2004
578 * Break up isodir into iso_mnt and iso_path
579 * These will be used along with iso-dev at restore time
580 * to locate the ISOs where ever they're mounted
581 */
582
583 log_it("isodir = %s", bkpinfo->isodir);
584 mr_asprintf(&command, "df -P %s | tail -n1 | cut -d' ' -f1",
585 bkpinfo->isodir);
586 log_it("command = %s", command);
587 tmp = call_program_and_get_last_line_of_output(command);
588 mr_free(command);
589 log_it("res of it = %s", tmp);
590 mr_asprintf(&tmp1, "%s/ISO-DEV", bkpinfo->tmpdir);
591 write_one_liner_data_file(tmp1, tmp);
592 mr_free(tmp1);
593
594 mr_asprintf(&command, "mount | grep -w %s | tail -n1 | cut -d' ' -f3",
595 tmp);
596 mr_free(tmp);
597 log_it("command = %s", command);
598 tmp = call_program_and_get_last_line_of_output(command);
599 mr_free(command);
600 log_it("res of it = %s", tmp);
601
602 mr_asprintf(&tmp1, "%s/ISO-MNT", bkpinfo->tmpdir);
603 write_one_liner_data_file(tmp1, tmp);
604 mr_free(tmp1);
605
606 log_it("isomnt: %s, %d", tmp, strlen(tmp));
607 if (strlen(bkpinfo->isodir) < strlen(tmp)) {
608 mr_asprintf(&iso_path, " ");
609 } else {
610 mr_asprintf(&iso_path, "%s", bkpinfo->isodir + strlen(tmp));
611 }
612 mr_free(tmp);
613
614 mr_asprintf(&tmp, "%s/ISODIR", bkpinfo->tmpdir);
615 write_one_liner_data_file(tmp, iso_path);
616 mr_free(tmp);
617 log_it("isodir: %s", iso_path);
618 mr_free(iso_path);
619 mr_asprintf(&tmp, "%s/ISO-PREFIX", bkpinfo->tmpdir);
620 write_one_liner_data_file(tmp, bkpinfo->prefix);
621 log_it("iso-prefix: %s", bkpinfo->prefix);
622 mr_free(tmp);
623/* End patch */
624 } // end of iso code
625
626 if (bkpinfo->backup_media_type == nfs) {
627 mr_asprintf(&hostname, bkpinfo->nfs_mount);
628 colon = strchr(hostname, ':');
629 if (!colon) {
630 log_it("nfs mount doesn't have a colon in it");
631 retval++;
632 } else {
633 struct hostent *hent;
634
635 *colon = '\0';
636 hent = gethostbyname(hostname);
637 if (!hent) {
638 log_it("Can't resolve NFS mount (%s): %s", hostname,
639 hstrerror(h_errno));
640 retval++;
641 } else {
642 mr_asprintf(&ip_address, "%s%s", inet_ntoa((struct in_addr)
643 *((struct in_addr
644 *) hent->
645 h_addr)),
646 strchr(bkpinfo->nfs_mount, ':'));
647 mr_allocstr(bkpinfo->nfs_mount, ip_address);
648 mr_free(ip_address);
649 }
650 }
651 store_nfs_config(bkpinfo);
652 mr_free(hostname);
653 }
654
655 log_it("Finished processing incoming params");
656 if (retval) {
657 fprintf(stderr, "Type 'man mondoarchive' for help.\n");
658 }
659 mr_asprintf(&tmp, "%s", MONDO_TMPISOS);
660 if (does_file_exist(tmp)) {
661 unlink(tmp);
662 }
663 mr_free(tmp);
664
665 if (strlen(bkpinfo->tmpdir) < 2 || strlen(bkpinfo->scratchdir) < 2) {
666 log_it("tmpdir or scratchdir are blank/missing");
667 retval++;
668 }
669 if (bkpinfo->include_paths == NULL) {
670 // fatal_error ("Why no backup path?");
671 mr_asprintf(&bkpinfo->include_paths, "/");
672 }
673 chmod(bkpinfo->scratchdir, 0700);
674 chmod(bkpinfo->tmpdir, 0700);
675 g_backup_media_type = bkpinfo->backup_media_type;
676 mr_allocstr(g_backup_media_string,bkpinfo->backup_media_string);
677 return (retval);
678}
679
680
681
682/**
683 * Do some miscellaneous setup tasks to be performed before filling @c bkpinfo.
684 * Seeds the random-number generator, loads important modules, checks the sanity
685 * of the user's Linux distribution, and deletes logfile.
686 * @param bkpinfo The backup information structure. Will be initialized.
687 * @return number of errors (0 for success)
688 */
689int pre_param_configuration(struct s_bkpinfo *bkpinfo)
690{
691 int res = 0;
692
693 make_hole_for_dir(MNT_CDROM);
694 assert(bkpinfo != NULL);
695 srandom((unsigned long) (time(NULL)));
696 insmod_crucial_modules();
697 reset_bkpinfo(bkpinfo); // also sets defaults ('/'=backup path, 3=compression level)
698 if (bkpinfo->disaster_recovery) {
699 if (!does_nonMS_partition_exist()) {
700 fatal_error
701 ("I am in disaster recovery mode\nPlease don't run mondoarchive.");
702 }
703 }
704
705 unlink(MONDO_TRACEFILE);
706 run_program_and_log_output("rm -Rf /tmp/changed.files*", FALSE);
707 if ((g_mondo_home = find_and_store_mondoarchives_home()) == NULL) {
708 fprintf(stderr,
709 "Cannot find Mondo's homedir. I think you have >1 'mondo' directory on your hard disk. Please delete the superfluous 'mondo' directories and try again\n");
710 res++;
711 return (res);
712 }
713 res += some_basic_system_sanity_checks();
714 if (res) {
715 log_it("Your distribution did not pass Mondo's sanity test.");
716 }
717 g_current_media_number = 1;
718 bkpinfo->postnuke_tarball = NULL;
719 mr_free(bkpinfo->nfs_mount);
720 return (res);
721}
722
723
724
725
726/**
727 * Reset all fields of the backup information structure to a sensible default.
728 * @param bkpinfo The @c bkpinfo to reset.
729 */
730void reset_bkpinfo(struct s_bkpinfo *bkpinfo)
731{
732 int i = 0;
733
734 log_msg(1, "Hi");
735
736 assert(bkpinfo != NULL);
737 /* BERLIOS : Useless
738 memset((void *) bkpinfo, 0, sizeof(struct s_bkpinfo));
739 */
740
741 bkpinfo->manual_cd_tray = FALSE;
742 bkpinfo->internal_tape_block_size = DEFAULT_INTERNAL_TAPE_BLOCK_SIZE;
743 bkpinfo->boot_loader = '\0';
744
745 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
746 bkpinfo->media_size[i] = -1;
747 }
748
749 mr_free(bkpinfo->media_device);
750 mr_free(bkpinfo->boot_device);
751 mr_free(bkpinfo->zip_exe);
752 mr_free(bkpinfo->zip_suffix);
753 mr_free(bkpinfo->restore_path);
754 bkpinfo->use_lzo = FALSE;
755 bkpinfo->verify_data = FALSE;
756 bkpinfo->backup_data = FALSE;
757 bkpinfo->restore_data = FALSE;
758 bkpinfo->disaster_recovery =
759 (am_I_in_disaster_recovery_mode()? TRUE : FALSE);
760 if (bkpinfo->disaster_recovery) {
761 mr_allocstr(bkpinfo->isodir, "/");
762 } else {
763 mr_allocstr(bkpinfo->isodir, "/var/cache/mondo/iso");
764 }
765 mr_allocstr(bkpinfo->prefix, STD_PREFIX);
766
767 mr_free(bkpinfo->scratchdir);
768 bkpinfo->make_filelist = TRUE; // unless -J supplied to mondoarchive
769 mr_free(bkpinfo->tmpdir);
770 mr_asprintf(&bkpinfo->tmpdir, "/tmp/tmpfs/mondo.tmp.%d", (int) (random() % 32768)); // for mondorestore
771 bkpinfo->optimal_set_size = 0;
772 bkpinfo->backup_media_type = none;
773 mr_free(bkpinfo->backup_media_string);
774 mr_allocstr(bkpinfo->include_paths, "/");
775 mr_free(bkpinfo->exclude_paths);
776 mr_free(bkpinfo->call_before_iso);
777 mr_free(bkpinfo->call_make_iso);
778 mr_free(bkpinfo->call_burn_iso);
779 mr_free(bkpinfo->call_after_iso);
780 mr_free(bkpinfo->image_devs);
781 mr_free(bkpinfo->postnuke_tarball);
782 mr_free(bkpinfo->kernel_path);
783 mr_free(bkpinfo->nfs_mount);
784 mr_free(bkpinfo->nfs_remote_dir);
785 bkpinfo->wipe_media_first = FALSE;
786 bkpinfo->differential = FALSE;
787 bkpinfo->cdrw_speed = 0;
788// patch by Herman Kuster
789 bkpinfo->differential = 0;
790// patch end
791 bkpinfo->compression_level = 3;
792}
793
794
795/**
796 * Get the remaining free space (in MB) on @p partition.
797 * @param partition The partition to check free space on (either a device or a mountpoint).
798 * @return The free space on @p partition, in MB.
799 */
800long free_space_on_given_partition(char *partition)
801{
802 char *command = NULL;
803 char *out_sz = NULL;
804 long res;
805
806 assert_string_is_neither_NULL_nor_zerolength(partition);
807
808 mr_asprintf(&command, "df -m -P %s &> /dev/null", partition);
809 if (system(command)) {
810 return (-1);
811 } // partition does not exist
812 mr_free(command);
813
814 mr_asprintf(&command, "df -m -P %s | tail -n1 | tr -s ' ' '\t' | cut -f4",
815 partition);
816 out_sz = call_program_and_get_last_line_of_output(command);
817 mr_free(command);
818 if (strlen(out_sz) == 0) {
819 return (-1);
820 } // error within df, probably
821 res = atol(out_sz);
822 mr_free(out_sz);
823 return (res);
824}
825
826
827
828/**
829 * Check the user's system for sanity. Checks performed:
830 * - make sure user has enough RAM (32mb required, 64mb recommended)
831 * - make sure user has enough free space in @c /
832 * - check kernel for ramdisk support
833 * - make sure afio, cdrecord, mkisofs, bzip2, awk, md5sum, strings, mindi, and buffer exist
834 * - make sure CD-ROM is unmounted
835 * - make sure /etc/modules.conf exists
836 * - make sure user's mountlist is OK by running <tt>mindi --makemountlist</tt>
837 *
838 * @return number of problems with the user's setup (0 for success)
839 */
840int some_basic_system_sanity_checks()
841{
842
843 /*@ buffers ************ */
844 char *tmp = NULL;
845
846 /*@ int's *************** */
847 int retval = 0;
848 long Lres;
849
850
851 mvaddstr_and_log_it(g_currentY, 0,
852 "Checking sanity of your Linux distribution");
853#ifndef __FreeBSD__
854 if (system("which mkfs.vfat &> /dev/null")
855 && !system("which mkfs.msdos &> /dev/null")) {
856 log_it
857 ("OK, you've got mkfs.msdos but not mkfs.vfat; time for the fairy to wave her magic wand...");
858 run_program_and_log_output
859 ("ln -sf `which mkfs.msdos` /sbin/mkfs.vfat", FALSE);
860 }
861 tmp = call_program_and_get_last_line_of_output
862 ("free | grep Mem | head -n1 | tr -s ' ' '\t' | cut -f2");
863 if (atol(tmp) < 35000) {
864 retval++;
865 log_to_screen(_("You must have at least 32MB of RAM to use Mondo."));
866 }
867 if (atol(tmp) < 66000) {
868 log_to_screen
869 (_("WARNING! You have very little RAM. Please upgrade to 64MB or more."));
870 }
871 mr_free(tmp);
872#endif
873
874 if ((Lres = free_space_on_given_partition("/var/cache/mondo")) == -1) /* {
875 Lres = free_space_on_given_partition("/");
876 }
877 */
878 log_it("Free space on given partition = %ld MB", Lres);
879
880 if (Lres < 50) {
881 fatal_error("Your /var/cache/mondo partition has <50MB free. Please adjust your partition table to something saner.");
882 }
883
884 if (system("which " MKE2FS_OR_NEWFS " > /dev/null 2> /dev/null")) {
885 retval++;
886 log_to_screen
887 ("Unable to find " MKE2FS_OR_NEWFS " in system path.");
888 fatal_error
889 ("Please use \"su -\", not \"su\" to become root. OK? ...and please don't e-mail the mailing list or me about this. Just read the message. :)");
890 }
891#ifndef __FreeBSD__
892 if (run_program_and_log_output
893 ("grep ramdisk /proc/devices", FALSE)) {
894 if (!ask_me_yes_or_no
895 (_("Your kernel has no ramdisk support. That's mind-numbingly stupid but I'll allow it if you're planning to use a failsafe kernel. Are you?")))
896 {
897 // retval++;
898 log_to_screen
899 (_("It looks as if your kernel lacks ramdisk and initrd support."));
900 log_to_screen
901 (_("I'll allow you to proceed but FYI, if I'm right, your kernel is broken."));
902 }
903 }
904#endif
905 retval += whine_if_not_found(MKE2FS_OR_NEWFS);
906 retval += whine_if_not_found("mkisofs");
907 if (system("which dvdrecord > /dev/null 2> /dev/null")) {
908 retval += whine_if_not_found("cdrecord");
909 }
910 retval += whine_if_not_found("bzip2");
911 retval += whine_if_not_found("awk");
912 retval += whine_if_not_found("md5sum");
913 retval += whine_if_not_found("strings");
914 retval += whine_if_not_found("mindi");
915 retval += whine_if_not_found("buffer");
916
917 // abort if Windows partition but no ms-sys and parted
918 if (!run_program_and_log_output
919 ("mount | grep -w vfat | grep -vE \"/dev/fd|nexdisk\"", 0)
920 ||
921 !run_program_and_log_output
922 ("mount | grep -w dos | grep -vE \"/dev/fd|nexdisk\"", 0)) {
923 log_to_screen(_("I think you have a Windows 9x partition."));
924 retval += whine_if_not_found("parted");
925#ifndef __IA64__
926 /* IA64 always has one vfat partition for EFI even without Windows */
927 // retval +=
928 tmp = find_home_of_exe("ms-sys");
929 if (!tmp) {
930 log_to_screen(_("Please install ms-sys just in case."));
931 }
932 mr_free(tmp);
933#endif
934 }
935
936 tmp = find_home_of_exe("cmp");
937 if (!tmp) {
938 whine_if_not_found("cmp");
939 }
940 mr_free(tmp);
941
942 run_program_and_log_output
943 ("umount `mount | grep cdr | cut -d' ' -f3 | tr '\n' ' '`", 5);
944 tmp = call_program_and_get_last_line_of_output("mount | grep -E \"cdr(om|w)\"");
945 if (strcmp("", tmp)) {
946 if (strstr(tmp, "autofs")) {
947 log_to_screen
948 (_("Your CD-ROM is mounted via autofs. I therefore cannot tell"));
949 log_to_screen
950 (_("if a CD actually is inserted. If a CD is inserted, please"));
951 log_to_screen(_("eject it. Thank you."));
952 log_it
953 ("Ignoring autofs CD-ROM 'mount' since we hope nothing's in it.");
954 } else
955 if (run_program_and_log_output("uname -a | grep Knoppix", 5)) {
956 retval++;
957 fatal_error
958 ("Your CD-ROM drive is mounted. Please unmount it.");
959 }
960 }
961 mr_free(tmp);
962#ifndef __FreeBSD__
963 if (!does_file_exist("/etc/modules.conf")) {
964 if (does_file_exist("/etc/conf.modules")) {
965 log_it("Linking /etc/modules.conf to /etc/conf.modules");
966 run_program_and_log_output
967 ("ln -sf /etc/conf.modules /etc/modules.conf", 5);
968 } else if (does_file_exist("/etc/modprobe.d")) {
969 log_it
970 ("Directory /etc/modprobe.d found. mindi will use its contents.");
971 } else if (does_file_exist("/etc/modprobe.conf")) {
972 log_it("Linking /etc/modules.conf to /etc/modprobe.conf");
973 run_program_and_log_output
974 ("ln -sf /etc/modprobe.conf /etc/modules.conf", 5);
975 } else {
976 retval++;
977 log_to_screen
978 (_("Please find out what happened to /etc/modules.conf"));
979 }
980 }
981#endif
982
983 run_program_and_log_output("cat /etc/fstab", 5);
984#ifdef __FreeBSD__
985 run_program_and_log_output("vinum printconfig", 5);
986#else
987 run_program_and_log_output("cat /etc/raidtab", 5);
988#endif
989
990 if (run_program_and_log_output("mindi -V", 1)) {
991 log_to_screen(_("Could not ascertain mindi's version number."));
992 log_to_screen
993 (_("You have not installed Mondo and/or Mindi properly."));
994 log_to_screen(_("Please uninstall and reinstall them both."));
995 fatal_error("Please reinstall Mondo and Mindi.");
996 }
997 if (run_program_and_log_output
998 ("mindi --makemountlist /tmp/mountlist.txt.test", 5)) {
999 log_to_screen
1000 (_("Mindi --makemountlist /tmp/mountlist.txt.test failed for some reason."));
1001 log_to_screen
1002 (_("Please run that command by hand and examine /var/log/mindi.log"));
1003 log_to_screen
1004 (_("for more information. Perhaps your /etc/fstab file is insane."));
1005 log_to_screen
1006 (_("Perhaps Mindi's MakeMountlist() subroutine has a bug. We'll see."));
1007 retval++;
1008 }
1009
1010 if (!run_program_and_log_output("parted2fdisk -l | grep -i raid", 1)
1011 && !does_file_exist("/etc/raidtab")) {
1012 log_to_screen
1013 (_("You have RAID partitions but no /etc/raidtab - creating one from /proc/mdstat"));
1014 create_raidtab_from_mdstat("/etc/raidtab");
1015 }
1016
1017 if (retval) {
1018 mvaddstr_and_log_it(g_currentY++, 74, _("Failed."));
1019 } else {
1020 mvaddstr_and_log_it(g_currentY++, 74, _("Done."));
1021 }
1022 return (retval);
1023}
1024
1025/**
1026 * Retrieve the line containing @p label from the config file.
1027 * @param config_file The file to read from, usually @c /tmp/mondo-restore.cfg.
1028 * @param label What to read from the file.
1029 * @param value Where to put it.
1030 * @return 0 for success, 1 for failure.
1031 */
1032int read_cfg_var(char *config_file, char *label, char *value)
1033{
1034 /*@ buffer ****************************************************** */
1035 char *command = NULL;
1036 char *tmp = NULL;
1037
1038 /*@ end vars *************************************************** */
1039
1040 assert_string_is_neither_NULL_nor_zerolength(config_file);
1041 assert_string_is_neither_NULL_nor_zerolength(label);
1042
1043 if (!does_file_exist(config_file)) {
1044 mr_asprintf(&tmp, "(read_cfg_var) Cannot find %s config file",
1045 config_file);
1046 log_to_screen(tmp);
1047 mr_free(tmp);
1048 value = NULL;
1049 return (1);
1050 /* } BERLIOS: Useless:
1051 else if (strstr(value, "/dev/") && strstr(value, "t0")
1052 && !strcmp(label, "media-dev")) {
1053 log_msg(2, "FYI, I shan't read new value for %s - already got %s",
1054 label, value);
1055 return (0);
1056 */ } else {
1057 mr_asprintf(&command, "grep '%s .*' %s| cut -d' ' -f2,3,4,5",
1058 label, config_file);
1059 value = call_program_and_get_last_line_of_output(command);
1060 mr_free(command);
1061 if (strlen(value) == 0) {
1062 return (1);
1063 } else {
1064 return (0);
1065 }
1066 }
1067}
1068
1069
1070/**
1071 * Remount @c supermount if it was unmounted earlier.
1072 */
1073void remount_supermounts_if_necessary()
1074{
1075 if (g_remount_cdrom_at_end) {
1076 run_program_and_log_output("mount " MNT_CDROM, FALSE);
1077 }
1078 if (g_remount_floppy_at_end) {
1079 run_program_and_log_output("mount " MNT_FLOPPY, FALSE);
1080 }
1081}
1082
1083/**
1084 * Unmount @c supermount if it's mounted.
1085 */
1086void unmount_supermounts_if_necessary()
1087{
1088 if (run_program_and_log_output
1089 ("mount | grep cdrom | grep super", FALSE) == 0) {
1090 g_remount_cdrom_at_end = TRUE;
1091 run_program_and_log_output("umount " MNT_CDROM, FALSE);
1092 }
1093 if (run_program_and_log_output
1094 ("mount | grep floppy | grep super", FALSE) == 0) {
1095 g_remount_floppy_at_end = TRUE;
1096 run_program_and_log_output("umount " MNT_FLOPPY, FALSE);
1097 }
1098}
1099
1100/**
1101 * If this is a distribution like Gentoo that doesn't keep /boot mounted, mount it.
1102 */
1103void mount_boot_if_necessary()
1104{
1105 char *tmp;
1106 char *tmp1;
1107 char *command;
1108
1109 log_msg(1, "Started sub");
1110 log_msg(4, "Setting command to something");
1111 mr_asprintf(&command,
1112 "grep -v \":\" /etc/fstab | grep -vx \"#.*\" | grep -w \"/boot\" | tr -s ' ' '\t' | cut -f1 | head -n1");
1113 log_msg(4, "Cool. Command = '%s'", command);
1114 tmp = call_program_and_get_last_line_of_output(command);
1115 mr_free(command);
1116
1117 log_msg(4, "tmp = '%s'", tmp);
1118 if (tmp) {
1119 log_it("/boot is at %s according to /etc/fstab", tmp);
1120 if (strstr(tmp, "LABEL=")) {
1121 if (!run_program_and_log_output("mount /boot", 5)) {
1122 mr_free(g_boot_mountpt);
1123 mr_asprintf(&g_boot_mountpt, "/boot");
1124 log_msg(1, "Mounted /boot");
1125 } else {
1126 log_it("...ignored cos it's a label :-)");
1127 }
1128 } else {
1129 mr_asprintf(&command, "mount | grep -w \"%s\"", tmp);
1130 log_msg(3, "command = %s", command);
1131 if (run_program_and_log_output(command, 5)) {
1132 mr_free(g_boot_mountpt);
1133 mr_asprintf(&g_boot_mountpt, tmp);
1134 mr_asprintf(&tmp1,
1135 "%s (your /boot partition) is not mounted. I'll mount it before backing up",
1136 g_boot_mountpt);
1137 log_it(tmp1);
1138 mr_free(tmp1);
1139
1140 mr_asprintf(&tmp1, "mount %s", g_boot_mountpt);
1141 if (run_program_and_log_output(tmp1, 5)) {
1142 /* BERLIOS: Useless ???
1143 mr_free(g_boot_mountpt);
1144 mr_asprintf(&g_boot_mountpt, " ");
1145 */
1146 log_msg(1, "Plan B");
1147 if (!run_program_and_log_output("mount /boot", 5)) {
1148 mr_free(g_boot_mountpt);
1149 mr_asprintf(&g_boot_mountpt, "/boot");
1150 log_msg(1, "Plan B worked");
1151 } else {
1152 log_msg(1,
1153 "Plan B failed. Unable to mount /boot for backup purposes. This probably means /boot is mounted already, or doesn't have its own partition.");
1154 }
1155 }
1156 mr_free(tmp1);
1157 }
1158 mr_free(command);
1159 }
1160 }
1161 mr_free(tmp);
1162 log_msg(1, "Ended sub");
1163}
1164
1165
1166/**
1167 * If we mounted /boot earlier, unmount it.
1168 */
1169void unmount_boot_if_necessary()
1170{
1171 char *tmp;
1172
1173 log_msg(3, "starting");
1174 if (g_boot_mountpt != NULL) {
1175 mr_asprintf(&tmp, "umount %s", g_boot_mountpt);
1176 if (run_program_and_log_output(tmp, 5)) {
1177 log_it("WARNING - unable to unmount /boot");
1178 }
1179 mr_free(tmp);
1180 }
1181 log_msg(3, "leaving");
1182}
1183
1184
1185
1186/**
1187 * Write a line to a configuration file. Writes a line of the form,
1188 * @c label @c value.
1189 * @param config_file The file to write to. Usually @c mondo-restore.cfg.
1190 * @param label What to call this bit of data you're writing.
1191 * @param value The bit of data you're writing.
1192 * @return 0 for success, 1 for failure.
1193 */
1194int write_cfg_var(char *config_file, char *label, char *value)
1195{
1196 /*@ buffers ***************************************************** */
1197 char *command;
1198 char *tempfile;
1199 char *tmp;
1200
1201
1202 /*@ end vars *************************************************** */
1203 assert_string_is_neither_NULL_nor_zerolength(config_file);
1204 assert_string_is_neither_NULL_nor_zerolength(label);
1205 assert(value != NULL);
1206
1207 if (!does_file_exist(config_file)) {
1208 mr_asprintf(&tmp, "(write_cfg_file) Cannot find %s config file",
1209 config_file);
1210 log_to_screen(tmp);
1211 mr_free(tmp);
1212 return (1);
1213 }
1214 tempfile = call_program_and_get_last_line_of_output
1215 ("mktemp -q /tmp/mojo-jojo.blah.XXXXXX");
1216 if (does_file_exist(config_file)) {
1217 mr_asprintf(&command, "grep -vx '%s .*' %s > %s",
1218 label, config_file, tempfile);
1219 paranoid_system(command);
1220 mr_free(command);
1221 }
1222 mr_asprintf(&command, "echo \"%s %s\" >> %s", label, value, tempfile);
1223 paranoid_system(command);
1224 mr_free(command);
1225
1226 mr_asprintf(&command, "mv -f %s %s", tempfile, config_file);
1227 paranoid_system(command);
1228 mr_free(command);
1229 unlink(tempfile);
1230 mr_free(tempfile);
1231 return (0);
1232}
1233
1234/**
1235 * Allocate or free important globals, depending on @p mal.
1236 * @param mal If TRUE, malloc; if FALSE, free.
1237 */
1238void do_libmondo_global_strings_thing(int mal)
1239{
1240 if (mal) {
1241 iamhere("Malloc'ing globals");
1242 g_erase_tmpdir_and_scratchdir = NULL;
1243 malloc_string(g_serial_string);
1244 } else {
1245 iamhere("Freeing globals");
1246 mr_free(g_boot_mountpt);
1247 mr_free(g_mondo_home);
1248 mr_free(g_tmpfs_mountpt);
1249 mr_free(g_erase_tmpdir_and_scratchdir);
1250 mr_free(g_serial_string);
1251 mr_free(g_magicdev_command);
1252 }
1253}
1254
1255/**
1256 * Allocate important globals.
1257 * @see do_libmondo_global_strings_thing
1258 */
1259void malloc_libmondo_global_strings(void)
1260{
1261 do_libmondo_global_strings_thing(1);
1262}
1263
1264/**
1265 * Free important globals.
1266 * @see do_libmondo_global_strings_thing
1267 */
1268void free_libmondo_global_strings(void)
1269{
1270 do_libmondo_global_strings_thing(0);
1271}
1272
1273
1274
1275/**
1276 * Stop @c magicdev if it's running.
1277 * The command used to start it is saved in @p g_magicdev_command.
1278 */
1279void stop_magicdev_if_necessary()
1280{
1281 g_magicdev_command = call_program_and_get_last_line_of_output
1282 ("ps ax | grep -w magicdev | grep -v grep | tr -s '\t' ' '| cut -d' ' -f6-99");
1283 if (g_magicdev_command) {
1284 log_msg(1, "g_magicdev_command = '%s'", g_magicdev_command);
1285 paranoid_system("killall magicdev");
1286 }
1287}
1288
1289
1290/**
1291 * Restart magicdev if it was stopped.
1292 */
1293void restart_magicdev_if_necessary()
1294{
1295 char *tmp = NULL;
1296
1297 if (!g_magicdev_command) {
1298 mr_asprintf(&tmp, "%s &", g_magicdev_command);
1299 paranoid_system(tmp);
1300 mr_free(tmp);
1301 }
1302}
1303
1304/* @} - end of utilityGroup */
Note: See TracBrowser for help on using the repository browser.