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

Last change on this file since 900 was 900, checked in by Bruno Cornec, 17 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: 34.4 KB
RevLine 
[171]1/* $Id: libmondo-files.c 900 2006-10-24 06:49:18Z bruno $
2 * file manipulation
[1]3*/
4
5/**
6 * @file
7 * Functions to manipulate files.
8 */
9
10
11#include "my-stuff.h"
12#include "mondostructures.h"
13#include "libmondo-files.h"
14
15#include "libmondo-tools-EXT.h"
[507]16#include "newt-specific-EXT.h"
[1]17#include "libmondo-devices-EXT.h"
18#include "libmondo-fork-EXT.h"
19#include "libmondo-string-EXT.h"
[900]20#include "mr_mem.h"
[1]21
22/*@unused@*/
[59]23//static char cvsid[] = "$Id: libmondo-files.c 900 2006-10-24 06:49:18Z bruno $";
[1]24
[688]25extern char **err_log_lines;
[1]26
27extern int g_currentY;
[783]28extern int g_noof_log_lines;
[1]29extern char *g_mondo_home;
30
31/**
32 * @addtogroup fileGroup
33 * @{
34 */
35/**
36 * Get an md5 checksum of the specified file.
37 * @param filename The file to checksum.
38 * @return The 32-character ASCII representation of the 128-bit checksum.
39 * @note The returned string points to static storage that will be overwritten with each call.
40 */
[59]41char *calc_checksum_of_file(char *filename)
[1]42{
[59]43 /*@ buffers ***************************************************** */
[171]44 static char *output = NULL;
45 char *command;
46 char *tmp;
47 size_t n = 0;
[1]48
[59]49 /*@ pointers **************************************************** */
50 char *p;
51 FILE *fin;
[1]52
[59]53 /*@ initialize pointers ***************************************** */
[1]54
[59]55 p = output;
[1]56
[59]57 /*@************************************************************** */
[1]58
[59]59 assert_string_is_neither_NULL_nor_zerolength(filename);
[171]60
[59]61 if (does_file_exist(filename)) {
[900]62 mr_asprintf(&command, "md5sum \"%s\"", filename);
[59]63 fin = popen(command, "r");
[900]64 mr_free(command);
[171]65
[59]66 if (fin) {
[900]67 mr_getline(&output, &n, fin);
[59]68 p = strchr(output, ' ');
69 paranoid_pclose(fin);
70 }
71 } else {
[900]72 mr_asprintf(&tmp, "File '%s' not found; cannot calc checksum",
[59]73 filename);
74 log_it(tmp);
[900]75 mr_free(tmp);
[1]76 }
[59]77 if (p) {
78 *p = '\0';
79 }
80 return (output);
[1]81}
82
83
84/**
85 * Get the number of lines in @p filename.
86 * @param filename The file to count lines in.
87 * @return The number of lines in @p filename.
88 * @bug This function uses the shell and "wc -l"; it should probably be rewritten in C.
89 */
[59]90long count_lines_in_file(char *filename)
[1]91{
92
[59]93 /*@ buffers ***************************************************** */
[171]94 char *command;
95 char *incoming = NULL;
96 char *tmp;
[1]97
[59]98 /*@ long ******************************************************** */
99 long noof_lines = -1L;
[1]100
[171]101 /*@ int ******************************************************** */
102 size_t n = 0;
103
[59]104 /*@ pointers **************************************************** */
105 FILE *fin;
[1]106
[59]107 assert_string_is_neither_NULL_nor_zerolength(filename);
108 if (!does_file_exist(filename)) {
[900]109 mr_asprintf(&tmp,
[59]110 "%s does not exist, so I cannot found the number of lines in it",
111 filename);
112 log_it(tmp);
[900]113 mr_free(tmp);
[59]114 return (0);
[1]115 }
[900]116 mr_asprintf(&command, "cat %s | wc -l", filename);
[59]117 if (!does_file_exist(filename)) {
118 return (-1);
[1]119 }
[59]120 fin = popen(command, "r");
[900]121 mr_free(command);
[171]122
[59]123 if (fin) {
124 if (feof(fin)) {
125 noof_lines = 0;
126 } else {
[900]127 mr_getline(&incoming, &n, fin);
[59]128 while (strlen(incoming) > 0
129 && incoming[strlen(incoming) - 1] < 32) {
130 incoming[strlen(incoming) - 1] = '\0';
131 }
132 noof_lines = atol(incoming);
[900]133 mr_free(incoming);
[59]134 }
135 paranoid_pclose(fin);
136 }
137 return (noof_lines);
[1]138}
139
140
141/**
142 * Check for existence of given @p filename.
143 * @param filename The file to check for.
144 * @return TRUE if it exists, FALSE otherwise.
145 */
[59]146bool does_file_exist(char *filename)
[1]147{
148
[59]149 /*@ structures ************************************************** */
150 struct stat buf;
[1]151
[59]152 /*@************************************************************** */
[1]153
[59]154 assert(filename != NULL);
[171]155
[59]156 if (lstat(filename, &buf)) {
157 log_msg(20, "%s does not exist", filename);
158 return (FALSE);
159 } else {
160 log_msg(20, "%s exists", filename);
161 return (TRUE);
162 }
[1]163}
164
165
166/**
167 * Modify @p inout (a file containing a list of files) to only contain files
168 * that exist.
169 * @param inout The filelist to operate on.
170 * @note The original file is renamed beforehand, so it will not be accessible
171 * while the modification is in progress.
172 */
[59]173void exclude_nonexistent_files(char *inout)
[1]174{
[171]175 char *infname;
176 char *outfname;
177 char *tmp;
178 char *incoming = NULL;
[1]179
[59]180 /*@ int ********************************************************* */
181 int i;
[171]182 size_t n = 0;
[1]183
[59]184 /*@ pointers **************************************************** */
185 FILE *fin, *fout;
[1]186
187
[59]188 /*@ end vars *********************************************************** */
[1]189
[59]190 assert_string_is_neither_NULL_nor_zerolength(inout);
[171]191
[900]192 mr_asprintf(&infname, "%s.in", inout);
[171]193
[900]194 mr_asprintf(&tmp, "cp -f %s %s", inout, infname);
[59]195 run_program_and_log_output(tmp, FALSE);
[900]196 mr_free(tmp);
[171]197
[59]198 if (!(fin = fopen(infname, "r"))) {
199 log_OS_error("Unable to openin infname");
[900]200 mr_free(infname);
[59]201 return;
[1]202 }
[171]203
[900]204 mr_asprintf(&outfname, "%s", inout);
[59]205 if (!(fout = fopen(outfname, "w"))) {
206 log_OS_error("Unable to openout outfname");
[900]207 mr_free(outfname);
[59]208 return;
[1]209 }
[900]210 mr_free(outfname);
[171]211
[900]212 for (mr_getline(&incoming, &n, fin); !feof(fin);
213 mr_getline(&incoming, &n, fin)) {
[59]214 i = strlen(incoming) - 1;
215 if (i >= 0 && incoming[i] < 32) {
216 incoming[i] = '\0';
217 }
218 if (does_file_exist(incoming)) {
219 fprintf(fout, "%s\n", incoming);
220 } else {
[900]221 mr_asprintf(&tmp, "Excluding '%s'-nonexistent\n", incoming);
[59]222 log_it(tmp);
[900]223 mr_free(tmp);
[59]224 }
[1]225 }
[900]226 mr_free(incoming);
[59]227 paranoid_fclose(fout);
228 paranoid_fclose(fin);
229 unlink(infname);
[900]230 mr_free(infname);
[1]231}
232
233
234/**
235 * Attempt to find the user's kernel by calling Mindi.
236 * If Mindi can't find the kernel, ask user. If @p kernel is not empty,
237 * don't do anything.
238 * @param kernel Where to put the found kernel.
239 * @return 0 for success, 1 for failure.
240 */
[59]241int figure_out_kernel_path_interactively_if_necessary(char *kernel)
[1]242{
[688]243 char *tmp = NULL;
244 char *command = NULL;
[1]245
[688]246 if (kernel == NULL) {
247 kernel = call_program_and_get_last_line_of_output
[783]248 ("mindi --findkernel 2> /dev/null");
[59]249 }
[393]250 // If we didn't get anything back, check whether mindi raised a fatal error
[688]251 if (kernel == NULL) {
[900]252 mr_asprintf(&command, "grep 'Fatal error' /var/log/mindi.log");
[688]253 tmp = call_program_and_get_last_line_of_output(command);
[393]254 if (strlen(tmp) > 1) {
255 popup_and_OK(tmp);
256 fatal_error("Mindi gave a fatal error. Please check '/var/log/mindi.log'.");
257 }
[900]258 mr_free(command);
259 mr_free(tmp);
[393]260 }
[688]261
262 if (kernel != NULL) {
263 log_it("Calling Mindi with kernel path of '%s'", kernel);
264 } else {
265 log_it("Calling Mindi without kernel, so asking one");
266 }
267
268 while (kernel == NULL) {
[59]269 if (!ask_me_yes_or_no
[507]270 (_("Kernel not found or invalid. Choose another?"))) {
[59]271 return (1);
272 }
273 if (!popup_and_get_string
[507]274 (_("Kernel path"),
275 _("What is the full path and filename of your kernel, please?"),
[688]276 kernel)) {
[59]277 fatal_error
278 ("Kernel not found. Please specify with the '-k' flag.");
279 }
[688]280 log_it("User says kernel is at %s", kernel);
[59]281 }
282 return (0);
[1]283}
284
285
286/**
287 * Find location of specified executable in user's PATH.
288 * @param fname The basename of the executable to search for (e.g. @c afio).
289 * @return The full path to the executable, or "" if it does not exist, or NULL if @c file could not be found.
290 * @note The returned string points to static storage that will be overwritten with each call.
291 * @bug The checks with @c file and @c dirname seem pointless. If @c incoming is "", then you're calling
292 * <tt>dirname 2\>/dev/null</tt> or <tt>file 2\>/dev/null | cut -d':' -f1 2\>/dev/null</tt>, which basically amounts
293 * to nothing.
294 */
[59]295char *find_home_of_exe(char *fname)
[1]296{
[59]297 /*@ buffers ********************* */
[688]298 char *output = NULL;
299 char *incoming = NULL;
300 char *command = NULL;
[1]301
[59]302 /*@******************************* */
[1]303
[59]304 assert_string_is_neither_NULL_nor_zerolength(fname);
[688]305
[900]306 mr_asprintf(&command, "which %s 2> /dev/null", fname);
[688]307 incoming = call_program_and_get_last_line_of_output(command);
[900]308 mr_free(command);
[171]309
[688]310 if (incoming == NULL) {
[59]311 if (system("which file > /dev/null 2> /dev/null")) {
312 return (NULL); // forget it :)
313 }
[900]314 mr_asprintf(&command,
[59]315 "file %s 2> /dev/null | cut -d':' -f1 2> /dev/null",
316 incoming);
[900]317 mr_free(incoming);
[171]318
[688]319 incoming = call_program_and_get_last_line_of_output(command);
[900]320 mr_free(command);
[59]321 }
[688]322 if (incoming == NULL) // yes, it is == '\0' twice, not once :)
[1]323 {
[900]324 mr_asprintf(&command, "dirname %s 2> /dev/null", incoming);
325 mr_free(incoming);
[171]326
[688]327 incoming = call_program_and_get_last_line_of_output(command);
[900]328 mr_free(command);
[1]329 }
[688]330 output = incoming;
[171]331
[688]332 if (output != NULL && does_file_exist(output)) {
333 log_msg(4, "find_home_of_exe () --- Found %s at %s", fname, output);
[59]334 } else {
[900]335 mr_free(output);
[59]336 log_msg(4, "find_home_of_exe() --- Could not find %s", fname);
337 }
[688]338 return (output);
[1]339}
340
341
342/**
343 * Get the last sequence of digits surrounded by non-digits in the first 32k of
344 * a file.
345 * @param logfile The file to look in.
346 * @return The number found, or 0 if none.
347 */
[59]348int get_trackno_from_logfile(char *logfile)
[1]349{
350
[59]351 /*@ pointers ********************************************************* */
352 FILE *fin;
[1]353
[59]354 /*@ int ************************************************************** */
355 int trackno = 0;
356 size_t len = 0;
[1]357
[59]358 /*@ buffer ************************************************************ */
359 char datablock[32701];
[1]360
[59]361 assert_string_is_neither_NULL_nor_zerolength(logfile);
[171]362
[59]363 if (!(fin = fopen(logfile, "r"))) {
364 log_OS_error("Unable to open logfile");
365 fatal_error("Unable to open logfile to read trackno");
366 }
367 len = fread(datablock, 1, 32700, fin);
368 paranoid_fclose(fin);
369 if (len <= 0) {
370 return (0);
371 }
372 for (; len > 0 && !isdigit(datablock[len - 1]); len--);
373 datablock[len--] = '\0';
374 for (; len > 0 && isdigit(datablock[len - 1]); len--);
375 trackno = atoi(datablock + len);
376 return (trackno);
[1]377}
378
379
380/**
381 * Get a percentage from the last line of @p filename. We look for the string
382 * "% done" on the last line and, if we find it, grab the number before the last % sign.
383 * @param filename The file to get the percentage from.
384 * @return The percentage found, or 0 for error.
385 */
[59]386int grab_percentage_from_last_line_of_file(char *filename)
[1]387{
388
[688]389 char *lastline = NULL;
390 char *command = NULL;
391 char *p = NULL;
[59]392 int i;
[1]393
[688]394 for (i = g_noof_log_lines - 1;
[59]395 i >= 0 && !strstr(err_log_lines[i], "% Done")
396 && !strstr(err_log_lines[i], "% done"); i--);
397 if (i < 0) {
[900]398 mr_asprintf(&command,
[687]399 "tail -n3 %s | grep -Fi \"%c\" | tail -n1 | awk '{print $0;}'",
[59]400 filename, '%');
[688]401 lastline = call_program_and_get_last_line_of_output(command);
[900]402 mr_free(command);
[688]403 if (!lastline) {
[59]404 return (0);
405 }
406 } else {
[900]407 mr_asprintf(&lastline, err_log_lines[i]);
[1]408 }
409
[59]410 p = strrchr(lastline, '%');
411 if (p) {
412 *p = '\0';
413 }
414 if (!p) {
[900]415 mr_free(lastline);
[59]416 return (0);
417 }
418 *p = '\0';
419 for (p--; *p != ' ' && p != lastline; p--);
420 if (p != lastline) {
421 p++;
422 }
423 i = atoi(p);
[900]424 mr_free(lastline);
[1]425
[59]426 return (i);
[1]427}
428
429
430/**
431 * Return the last line of @p filename.
432 * @param filename The file to get the last line of.
433 * @return The last line of the file.
434 * @note The returned string points to static storage that will be overwritten with each call.
435 */
[59]436char *last_line_of_file(char *filename)
[1]437{
[59]438 /*@ buffers ***************************************************** */
[688]439 char *output = NULL;
440 char *command = NULL;
441 char *tmp = NULL;
[1]442
[59]443 /*@ pointers **************************************************** */
444 FILE *fin;
[688]445 size_t n = 0;
[1]446
[59]447 /*@ end vars **************************************************** */
[1]448
[59]449 if (!does_file_exist(filename)) {
[900]450 mr_asprintf(&tmp, _("Tring to get last line of nonexistent file (%s)"),
[59]451 filename);
452 log_it(tmp);
[900]453 mr_free(tmp);
[783]454 return (NULL);
[59]455 }
[900]456 mr_asprintf(&command, "tail -n1 %s", filename);
[59]457 fin = popen(command, "r");
[900]458 mr_free(command);
[171]459
[900]460 mr_getline(&output, &n, fin);
[59]461 paranoid_pclose(fin);
462 while (strlen(output) > 0 && output[strlen(output) - 1] < 32) {
463 output[strlen(output) - 1] = '\0';
464 }
465 return (output);
[1]466}
467
[171]468
[1]469/**
470 * Get the length of @p filename in bytes.
471 * @param filename The file to get the length of.
472 * @return The length of the file, or -1 for error.
473 */
[687]474off_t length_of_file(char *filename)
[1]475{
[59]476 /*@ pointers *************************************************** */
477 FILE *fin;
[1]478
[59]479 /*@ long long ************************************************* */
[687]480 off_t length;
[1]481
[59]482 fin = fopen(filename, "r");
483 if (!fin) {
484 log_it("filename=%s", filename);
485 log_OS_error("Unable to openin filename");
486 return (-1);
487 }
[416]488 fseeko(fin, 0, SEEK_END);
[687]489 length = ftello(fin);
[59]490 paranoid_fclose(fin);
491 return (length);
[1]492}
493
494
495/**
496 * Create the directory @p outdir_fname and all parent directories. Equivalent to <tt>mkdir -p</tt>.
497 * @param outdir_fname The directory to create.
498 * @return The return value of @c mkdir.
499 */
[87]500/* BERLIOS: This function shouldn't call system at all */
[59]501int make_hole_for_dir(char *outdir_fname)
[1]502{
[171]503 char *tmp;
[59]504 int res = 0;
[1]505
[59]506 assert_string_is_neither_NULL_nor_zerolength(outdir_fname);
[900]507 mr_asprintf(&tmp, "mkdir -p %s", outdir_fname);
[59]508 res = system(tmp);
[900]509 mr_free(tmp);
[59]510 return (res);
[1]511}
512
513
514/**
515 * Create the parent directories of @p outfile_fname.
516 * @param outfile_fname The file to make a "hole" for.
517 * @return 0, always.
518 * @bug Return value unnecessary.
519 */
[87]520/* BERLIOS: This function shouldn't call system at all */
[59]521int make_hole_for_file(char *outfile_fname)
[1]522{
[59]523 /*@ buffer ****************************************************** */
[171]524 char *command;
[1]525
[59]526 /*@ int ******************************************************** */
527 int res = 0;
[1]528
[59]529 /*@ end vars *************************************************** */
[1]530
[59]531 assert_string_is_neither_NULL_nor_zerolength(outfile_fname);
532 assert(!strstr(outfile_fname, MNT_CDROM));
533 assert(!strstr(outfile_fname, "/dev/cdrom"));
[171]534
[900]535 mr_asprintf(&command, "mkdir -p \"%s\" 2> /dev/null", outfile_fname);
[59]536 res += system(command);
[900]537 mr_free(command);
[171]538
[900]539 mr_asprintf(&command, "rmdir \"%s\" 2> /dev/null", outfile_fname);
[59]540 res += system(command);
[900]541 mr_free(command);
[171]542
[900]543 mr_asprintf(&command, "rm -f \"%s\" 2> /dev/null", outfile_fname);
[59]544 res += system(command);
[900]545 mr_free(command);
[59]546 unlink(outfile_fname);
547 return (0);
[1]548}
549
550
551/**
552 * Get the number of lines in @p filelist_fname that contain the string @p wildcard.
553 * @param filelist_fname The file to search through.
554 * @param wildcard The string to search for. This is @e not a shell glob or a regular expression.
555 * @return The number of lines matched.
556 */
[59]557long noof_lines_that_match_wildcard(char *filelist_fname, char *wildcard)
[1]558{
[59]559 /*@ long ******************************************************* */
560 long matches = 0;
[1]561
[59]562 /*@ pointers *************************************************** */
563 FILE *fin;
[1]564
[59]565 /*@ buffers **************************************************** */
[171]566 char *incoming = NULL;
[1]567
[171]568 size_t n = 0;
[59]569 /*@ end vars *************************************************** */
[1]570
571
[59]572 fin = fopen(filelist_fname, "r");
[1]573
[59]574 if (!fin) {
575 log_OS_error("Unable to openin filelist_fname");
576 return (0);
[1]577 }
[900]578 mr_getline(&incoming, &n, fin);
[59]579 while (!feof(fin)) {
580 if (strstr(incoming, wildcard)) {
581 matches++;
582 }
[900]583 mr_getline(&incoming, &n, fin);
[59]584 }
585 paranoid_fclose(fin);
[900]586 mr_free(incoming);
[59]587 return (matches);
[1]588}
589
590
591/**
592 * Register our PID in a file in /var/run.
593 * The PID will be put in /var/run/monitas-<tt>name_str</tt>.pid.
594 * @param pid 0 to remove file, anything else to create it.
595 * @param name_str The basename of the PID file (e.g. "mondo" or "server")
596 * @note This function does not provide support against multiple instances, unless you check for that yourself.
597 */
[59]598void register_pid(pid_t pid, char *name_str)
[1]599{
[171]600 char *tmp;
601 char *lockfile_fname;
[59]602 int res;
[171]603 size_t n = 0;
[59]604 FILE *fin;
[1]605
[900]606 mr_asprintf(&lockfile_fname, "/var/run/monitas-%s.pid", name_str);
[59]607 if (!pid) {
608 log_it("Unregistering PID");
609 if (unlink(lockfile_fname)) {
610 log_it("Error unregistering PID");
611 }
[900]612 mr_free(lockfile_fname);
[59]613 return;
614 }
615 if (does_file_exist(lockfile_fname)) {
616 if ((fin = fopen(lockfile_fname, "r"))) {
[900]617 mr_getline(&tmp, &n, fin);
[59]618 paranoid_fclose(fin);
619 } else {
620 log_OS_error("Unable to openin lockfile_fname");
621 }
622 pid = (pid_t) atol(tmp);
[900]623 mr_free(tmp);
[171]624
[900]625 mr_asprintf(&tmp, "ps %ld > /dev/null 2> /dev/null", (long int) pid);
[59]626 res = system(tmp);
[900]627 mr_free(tmp);
[59]628 if (!res) {
629 log_it
630 ("I believe the daemon is already running. If it isn't, please delete %s and try again.",
631 lockfile_fname);
632 }
633 }
[900]634 mr_asprintf(&tmp, "echo %ld > %s 2> /dev/null", (long int) getpid(),
[59]635 lockfile_fname);
[900]636 mr_free(lockfile_fname);
[171]637
[59]638 if (system(tmp)) {
639 fatal_error("Cannot register PID");
640 }
[900]641 mr_free(tmp);
[171]642 return;
[1]643}
644
645
646/**
647 * Determine the size (in KB) of @p dev in the mountlist in <tt>tmpdir</tt>/mountlist.txt.
648 * @param tmpdir The tempdir where the mountlist is stored.
649 * @param dev The device to search for.
650 * @return The size of the partition in KB.
651 */
[59]652long size_of_partition_in_mountlist_K(char *tmpdir, char *dev)
[1]653{
[688]654 char *command = NULL;
655 char *sz_res = NULL;
656 long file_len_K = 0L;
[59]657
[900]658 mr_asprintf(&command,
[171]659 "grep '%s ' %s/mountlist.txt | head -n1 | awk '{print $4;}'",
660 dev, tmpdir);
[59]661 log_it(command);
[688]662 sz_res = call_program_and_get_last_line_of_output(command);
[59]663 file_len_K = atol(sz_res);
664 log_msg(4, "%s --> %s --> %ld", command, sz_res, file_len_K);
[900]665 mr_free(command);
666 mr_free(sz_res);
[59]667 return (file_len_K);
[1]668}
669
[171]670
[1]671/**
672 * Calculate the total size (in KB) of all the biggiefiles in this backup.
673 * @param bkpinfo The backup information structure. Only the @c bkpinfo->tmpdir field is used.
674 * @return The total size of all biggiefiles in KB.
675 */
[59]676long size_of_all_biggiefiles_K(struct s_bkpinfo *bkpinfo)
[1]677{
[688]678 char *fname = NULL;
679 char *biggielist = NULL;
680 char *comment = NULL;
681 char *tmp = NULL;
682 char *command = NULL;
[1]683
[59]684 /*@ long ******************************************************** */
[688]685 long scratchL = 0L;
686 long file_len_K = 0L;
[1]687
[59]688 /*@ pointers *************************************************** */
689 FILE *fin = NULL;
[171]690 size_t n = 0;
[1]691
[59]692 /*@ end vars *************************************************** */
[1]693
[59]694 log_it("Calculating size of all biggiefiles (in total)");
[900]695 mr_asprintf(&biggielist, "%s/biggielist.txt", bkpinfo->tmpdir);
[59]696 log_it("biggielist = %s", biggielist);
697 if (!(fin = fopen(biggielist, "r"))) {
698 log_OS_error
699 ("Cannot open biggielist. OK, so estimate is based on filesets only.");
700 } else {
701 log_msg(4, "Reading it...");
[900]702 for (mr_getline(&fname, &n, fin); !feof(fin);
703 mr_getline(&fname, &n, fin)) {
[59]704 if (fname[strlen(fname) - 1] <= 32) {
705 fname[strlen(fname) - 1] = '\0';
706 }
707 if (0 == strncmp(fname, "/dev/", 5)) {
[300]708 if (is_dev_an_NTFS_dev(fname)) {
[689]709 tmp = find_home_of_exe("ntfsresize");
710 if (!tmp) {
[300]711 fatal_error("ntfsresize not found");
712 }
[900]713 mr_free(tmp);
[689]714
[900]715 mr_asprintf(&command, "ntfsresize --force --info %s|grep '^You might resize at '|cut -d' ' -f5", fname);
[300]716 log_it("command = %s", command);
[688]717 tmp = call_program_and_get_last_line_of_output(command);
[900]718 mr_free(command);
[688]719
[300]720 log_it("res of it = %s", tmp);
721 file_len_K = atoll(tmp) / 1024L;
[900]722 mr_free(tmp);
[300]723 } else {
724 file_len_K = get_phys_size_of_drive(fname) * 1024L;
725 }
[59]726 } else {
[687]727 /* BERLIOS: more than long here ??? */
[59]728 file_len_K = (long) (length_of_file(fname) / 1024);
729 }
730 if (file_len_K > 0) {
731 scratchL += file_len_K;
732 log_msg(4, "%s --> %ld K", fname, file_len_K);
733 }
[900]734 mr_asprintf(&comment,
[59]735 "After adding %s, scratchL+%ld now equals %ld", fname,
736 file_len_K, scratchL);
737 log_msg(4, comment);
[900]738 mr_free(comment);
[171]739
[59]740 if (feof(fin)) {
741 break;
742 }
743 }
[900]744 mr_free(fname);
[1]745 }
[900]746 mr_free(biggielist);
[171]747
[59]748 log_it("Closing...");
749 paranoid_fclose(fin);
750 log_it("Finished calculating total size of all biggiefiles");
751 return (scratchL);
[1]752}
753
[171]754
[1]755/**
756 * Determine the amount of space (in KB) occupied by a mounted CD.
757 * This can also be used to find the space used for other directories.
758 * @param mountpt The mountpoint/directory to check.
759 * @return The amount of space occupied in KB.
760 */
[59]761long long space_occupied_by_cd(char *mountpt)
[1]762{
[59]763 /*@ buffer ****************************************************** */
[171]764 char *tmp = NULL;
[688]765 char *command = NULL;
[59]766 long long llres;
[171]767 size_t n = 0;
[59]768 /*@ pointers **************************************************** */
[688]769 char *p = NULL;
770 FILE *fin = NULL;
[1]771
[59]772 /*@ end vars *************************************************** */
[1]773
[900]774 mr_asprintf(&command, "du -sk %s", mountpt);
[839]775 errno = 0;
[59]776 fin = popen(command, "r");
[839]777 if (errno) {
778 log_it("popen() FAILED: command=%s, mountpt=%s, fin=%d, errno=%d, strerror=%s", command, mountpt, fin, errno, strerror(errno));
779 llres = 0;
780 } else {
[900]781 mr_getline(&tmp, &n, fin);
[839]782 paranoid_pclose(fin);
783 p = strchr(tmp, '\t');
784 if (p) {
785 *p = '\0';
786 }
787 for (p = tmp, llres = 0; *p != '\0'; p++) {
788 llres *= 10;
789 llres += (int) (*p - '0');
790 }
791 }
792
[900]793 mr_free(command);
794 mr_free(tmp);
[59]795 return (llres);
[1]796}
797
798
799/**
800 * Update a CRC checksum to include another character.
801 * @param crc The original CRC checksum.
802 * @param c The character to add.
803 * @return The new CRC checksum.
804 * @ingroup utilityGroup
805 */
[59]806unsigned int updcrc(unsigned int crc, unsigned int c)
[1]807{
[59]808 unsigned int tmp;
809 tmp = (crc >> 8) ^ c;
810 crc = (crc << 8) ^ crctttab[tmp & 255];
811 return crc;
[1]812}
813
[171]814
[1]815/**
816 * Update a reverse CRC checksum to include another character.
817 * @param crc The original CRC checksum.
818 * @param c The character to add.
819 * @return The new CRC checksum.
820 * @ingroup utilityGroup
821 */
[59]822unsigned int updcrcr(unsigned int crc, unsigned int c)
[1]823{
[59]824 unsigned int tmp;
825 tmp = crc ^ c;
826 crc = (crc >> 8) ^ crc16tab[tmp & 0xff];
827 return crc;
[1]828}
829
830
831/**
832 * Check for an executable on the user's system; write a message to the
833 * screen and the log if we can't find it.
834 * @param fname The executable basename to look for.
835 * @return 0 if it's found, nonzero if not.
836 */
[59]837int whine_if_not_found(char *fname)
[1]838{
[59]839 /*@ buffers *** */
[171]840 char *command;
841 char *errorstr;
842 int res = 0;
[1]843
844
[900]845 mr_asprintf(&command, "which %s > /dev/null 2> /dev/null", fname);
[171]846 res = system(command);
[900]847 mr_free(command);
[171]848
849 if (res) {
[900]850 mr_asprintf(&errorstr,
[507]851 _("Please install '%s'. I cannot find it on your system."),
[59]852 fname);
853 log_to_screen(errorstr);
[900]854 mr_free(errorstr);
[59]855 log_to_screen
[507]856 (_("There may be an hyperlink at http://www.mondorescue.org which"));
857 log_to_screen(_("will take you to the relevant (missing) package."));
[59]858 return (1);
859 } else {
860 return (0);
861 }
[1]862}
863
864
865/**
866 * Create a data file at @p fname containing @p contents.
867 * The data actually can be multiple lines, despite the name.
868 * @param fname The file to create.
869 * @param contents The data to put in it.
870 * @return 0 for success, 1 for failure.
871 */
[59]872int write_one_liner_data_file(char *fname, char *contents)
[1]873{
[59]874 /*@ pointers *************************************************** */
875 FILE *fout;
876 int res = 0;
[1]877
[59]878 /*@ end vars *************************************************** */
[1]879
[59]880 assert_string_is_neither_NULL_nor_zerolength(fname);
881 if (!contents) {
882 log_it("%d: Warning - writing NULL to %s", __LINE__, fname);
883 }
884 if (!(fout = fopen(fname, "w"))) {
885 log_it("fname=%s");
886 log_OS_error("Unable to openout fname");
887 return (1);
888 }
889 fprintf(fout, "%s\n", contents);
890 paranoid_fclose(fout);
891 return (res);
[1]892}
893
894
895/**
896 * Read @p fname into @p contents.
897 * @param fname The file to read.
898 * @param contents Where to put its contents.
899 * @return 0 for success, nonzero for failure.
900 */
[59]901int read_one_liner_data_file(char *fname, char *contents)
[1]902{
[59]903 /*@ pointers *************************************************** */
904 FILE *fin;
905 int res = 0;
906 int i;
[1]907
[59]908 /*@ end vars *************************************************** */
[1]909
[59]910 assert_string_is_neither_NULL_nor_zerolength(fname);
911 if (!contents) {
912 log_it("%d: Warning - reading NULL from %s", __LINE__, fname);
913 }
914 if (!(fin = fopen(fname, "r"))) {
915 log_it("fname=%s", fname);
916 log_OS_error("Unable to openin fname");
917 return (1);
918 }
919 fscanf(fin, "%s\n", contents);
920 i = strlen(contents);
921 if (i > 0 && contents[i - 1] < 32) {
922 contents[i - 1] = '\0';
923 }
924 paranoid_fclose(fin);
925 return (res);
[1]926}
927
928
929/**
930 * Copy the files that Mondo/Mindi need to run to the scratchdir or tempdir.
931 * Currently this includes: copy Mondo's home directory to scratchdir, untar "mondo_home/payload.tgz"
932 * if it exists, copy LAST-FILELIST-NUMBER to scratchdir, copy mondorestore
933 * and post-nuke.tgz (if it exists) to tmpdir, and run "hostname > scratchdir/HOSTNAME".
934 * @param bkpinfo The backup information structure. Fields used:
935 * - @c bkpinfo->postnuke_tarball
936 * - @c bkpinfo->scratchdir
937 * - @c bkpinfo->tmpdir
938 */
[59]939void copy_mondo_and_mindi_stuff_to_scratchdir(struct s_bkpinfo *bkpinfo)
[1]940{
[59]941 /*@ Char buffers ** */
[171]942 char *command;
943 char *tmp;
[59]944 char old_pwd[MAX_STR_LEN];
[1]945
[59]946 mvaddstr_and_log_it(g_currentY, 0,
947 "Copying Mondo's core files to the scratch directory");
[1]948
[94]949 /* BERLIOS: Why do we need to do it here as well ? */
[59]950 log_msg(4, "g_mondo_home='%s'", g_mondo_home);
[94]951 if ((g_mondo_home == NULL) || strlen(g_mondo_home) < 2) {
[900]952 mr_free(g_mondo_home);
[94]953 g_mondo_home = find_and_store_mondoarchives_home();
[59]954 }
[900]955 mr_asprintf(&command, CP_BIN " --parents -pRdf %s %s", g_mondo_home,
[59]956 bkpinfo->scratchdir);
[1]957
[59]958 log_msg(4, "command = %s", command);
959 if (run_program_and_log_output(command, 1)) {
960 fatal_error("Failed to copy Mondo's stuff to scratchdir");
961 }
[900]962 mr_free(command);
[1]963
[900]964 mr_asprintf(&tmp, "%s/payload.tgz", g_mondo_home);
[507]965
966 /* i18n */
[900]967 mr_asprintf(&command, CP_BIN " --parents /usr/share/locale/*/LC_MESSAGES/mondo.mo %s",bkpinfo->scratchdir);
[507]968 log_msg(4, "command = %s", command);
969 run_program_and_log_output(command, 1);
[900]970 mr_free(command);
[507]971
[59]972 if (does_file_exist(tmp)) {
973 log_it("Untarring payload %s to scratchdir %s", tmp,
974 bkpinfo->scratchdir);
975 (void) getcwd(old_pwd, MAX_STR_LEN - 1);
976 chdir(bkpinfo->scratchdir);
[900]977 mr_asprintf(&command, "tar -zxvf %s", tmp);
[59]978 if (run_program_and_log_output(command, FALSE)) {
979 fatal_error("Failed to untar payload");
980 }
[900]981 mr_free(command);
[59]982 chdir(old_pwd);
983 }
[900]984 mr_free(tmp);
[1]985
[900]986 mr_asprintf(&command, "cp -f %s/LAST-FILELIST-NUMBER %s", bkpinfo->tmpdir,
[59]987 bkpinfo->scratchdir);
988 if (run_program_and_log_output(command, FALSE)) {
989 fatal_error("Failed to copy LAST-FILELIST-NUMBER to scratchdir");
990 }
[900]991 mr_free(command);
[1]992
[688]993 tmp = call_program_and_get_last_line_of_output("which mondorestore");
994 if (!tmp) {
[59]995 fatal_error
996 ("'which mondorestore' returned null. Where's your mondorestore? `which` can't find it. That's odd. Did you install mondorestore?");
997 }
[900]998 mr_asprintf(&command, "cp -f %s %s", tmp, bkpinfo->tmpdir);
999 mr_free(tmp);
[171]1000
[59]1001 if (run_program_and_log_output(command, FALSE)) {
1002 fatal_error("Failed to copy mondorestore to tmpdir");
1003 }
[900]1004 mr_free(command);
[1]1005
[900]1006 mr_asprintf(&command, "hostname > %s/HOSTNAME", bkpinfo->scratchdir);
[59]1007 paranoid_system(command);
[900]1008 mr_free(command);
[1]1009
[783]1010 if (bkpinfo->postnuke_tarball) {
[900]1011 mr_asprintf(&command, "cp -f %s %s/post-nuke.tgz",
[59]1012 bkpinfo->postnuke_tarball, bkpinfo->tmpdir);
1013 if (run_program_and_log_output(command, FALSE)) {
1014 fatal_error("Unable to copy post-nuke tarball to tmpdir");
1015 }
[900]1016 mr_free(command);
[59]1017 }
[1]1018
[59]1019 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
[1]1020}
1021
1022
1023/**
1024 * Store the client's NFS configuration in files to be restored at restore-time.
1025 * Assumes that @c bkpinfo->media_type = nfs, but does not check for this.
1026 * @param bkpinfo The backup information structure. Fields used:
1027 * - @c nfs_mount
1028 * - @c nfs_remote_dir
1029 * - @c tmpdir
1030 */
[59]1031void store_nfs_config(struct s_bkpinfo *bkpinfo)
[1]1032{
1033
[59]1034 /*@ buffers ******** */
[688]1035 char *nfs_dev = NULL;
[808]1036 char *mac_addr = NULL;
[688]1037 char *nfs_mount = NULL;
1038 char *nfs_client_ipaddr = NULL;
1039 char *nfs_client_netmask = NULL;
1040 char *nfs_client_broadcast = NULL;
1041 char *nfs_client_defgw = NULL;
1042 char *nfs_server_ipaddr = NULL;
1043 char *tmp = NULL;
1044 char *command = NULL;
[1]1045
[59]1046 /*@ pointers ***** */
1047 char *p;
[1]1048
[59]1049 log_it("Storing NFS configuration");
[900]1050 mr_asprintf(&tmp, bkpinfo->nfs_mount);
[59]1051 p = strchr(tmp, ':');
1052 if (!p) {
1053 fatal_error
1054 ("NFS mount doesn't have a colon in it, e.g. 192.168.1.4:/home/nfs");
1055 }
1056 *(p++) = '\0';
[900]1057 mr_asprintf(&nfs_server_ipaddr, tmp);
1058 mr_free(tmp);
[171]1059
[900]1060 mr_asprintf(&nfs_mount, p);
[808]1061 /* BERLIOS : there is a bug #67 here as it only considers the first NIC */
[900]1062 mr_asprintf(&command,
[59]1063 "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\n' | head -n1 | cut -d' ' -f1");
[688]1064 nfs_dev = call_program_and_get_last_line_of_output(command);
[900]1065 mr_free(command);
[171]1066
[900]1067 mr_asprintf(&command,
[59]1068 "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\\n' | head -n1 | tr -s '\t' ' ' | cut -d' ' -f7 | cut -d':' -f2");
[688]1069 nfs_client_ipaddr = call_program_and_get_last_line_of_output(command);
[900]1070 mr_free(command);
[171]1071
[900]1072 mr_asprintf(&command,
[149]1073 "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\\n' | head -n1 | tr -s '\t' ' ' | cut -d' ' -f9 | cut -d':' -f2");
[688]1074 nfs_client_netmask = call_program_and_get_last_line_of_output(command);
[900]1075 mr_free(command);
[171]1076
[900]1077 mr_asprintf(&command,
[197]1078 "ifconfig | tr '\n' '#' | sed s/##// | tr '#' ' ' | tr '' '\\n' | head -n1 | tr -s '\t' ' ' | cut -d' ' -f8 | cut -d':' -f2");
[688]1079 nfs_client_broadcast = call_program_and_get_last_line_of_output(command);
[900]1080 mr_free(command);
[688]1081
[900]1082 mr_asprintf(&command,
[226]1083 "route -n | grep '^0.0.0.0' | awk '{print $2}'");
[688]1084 nfs_client_defgw = call_program_and_get_last_line_of_output(command);
[900]1085 mr_free(command);
[171]1086
[900]1087 mr_asprintf(&tmp,
[171]1088 "nfs_client_ipaddr=%s; nfs_client_netmask=%s; nfs_server_ipaddr=%s; nfs_mount=%s; nfs_client_defgw=%s; ",
1089 nfs_client_ipaddr, nfs_client_netmask, nfs_server_ipaddr, nfs_mount, nfs_client_defgw);
[900]1090 mr_free(nfs_mount);
[171]1091 log_it(tmp);
[900]1092 mr_free(tmp);
[171]1093
[59]1094 if (strlen(nfs_dev) < 2) {
1095 fatal_error
1096 ("Unable to find ethN (eth0, eth1, ...) adapter via NFS mount you specified.");
1097 }
1098 make_hole_for_dir("/var/cache/mondo-archive");
[808]1099 /********
1100 * If the NFS device that found above is a bonded device,
1101 * we need to replace it with an ethN device or the
1102 * networking will not start during an NFS restore.
1103 *
1104 * If the NFS device in nfs_dev begins with the word "bond",
1105 * look for the corresponding slave ethN device and copy it to nfs_dev.
1106 * Using the common MAC address
1107 ********/
1108 if (!strncmp(nfs_dev, "bond", 4)) {
1109 log_to_screen("Found bonding device %s; looking for corresponding ethN slave device\n", nfs_dev);
[900]1110 mr_asprintf(&command,
[808]1111 "ifconfig %s | awk '{print $5}'", nfs_dev);
1112 mac_addr = call_program_and_get_last_line_of_output(command);
[900]1113 mr_asprintf(&command,
[808]1114 "ifconfig | grep -E '%s' | head -n1 | cut -d' ' -f1", mac_addr);
[900]1115 mr_free(nfs_dev);
[808]1116 nfs_dev = call_program_and_get_last_line_of_output(command);
[900]1117 mr_free(command);
1118 mr_free(mac_addr);
[1]1119
[808]1120 log_to_screen("Replacing it with %s\n", nfs_dev);
1121 }
1122
[900]1123 mr_asprintf(&tmp, "%s/NFS-DEV", bkpinfo->tmpdir);
[59]1124 write_one_liner_data_file(tmp, nfs_dev);
[900]1125 mr_free(nfs_dev);
1126 mr_free(tmp);
[1]1127
[900]1128 mr_asprintf(&tmp, "%s/NFS-CLIENT-IPADDR", bkpinfo->tmpdir);
[59]1129 write_one_liner_data_file(tmp, nfs_client_ipaddr);
[900]1130 mr_free(nfs_client_ipaddr);
1131 mr_free(tmp);
[171]1132
[900]1133 mr_asprintf(&tmp, "%s/NFS-CLIENT-NETMASK", bkpinfo->tmpdir);
[149]1134 write_one_liner_data_file(tmp, nfs_client_netmask);
[900]1135 mr_free(nfs_client_netmask);
1136 mr_free(tmp);
[171]1137
[900]1138 mr_asprintf(&tmp, "%s/NFS-CLIENT-DEFGW", bkpinfo->tmpdir);
[149]1139 write_one_liner_data_file(tmp, nfs_client_defgw);
[900]1140 mr_free(nfs_client_defgw);
1141 mr_free(tmp);
[171]1142
[900]1143 mr_asprintf(&tmp, "%s/NFS-CLIENT-BROADCAST", bkpinfo->tmpdir);
[197]1144 write_one_liner_data_file(tmp, nfs_client_broadcast);
[900]1145 mr_free(nfs_client_broadcast);
1146 mr_free(tmp);
[197]1147
[900]1148 mr_asprintf(&tmp, "%s/NFS-SERVER-IPADDR", bkpinfo->tmpdir);
[59]1149 write_one_liner_data_file(tmp, nfs_server_ipaddr);
[900]1150 mr_free(nfs_server_ipaddr);
1151 mr_free(tmp);
[171]1152
[900]1153 mr_asprintf(&tmp, "%s/NFS-SERVER-MOUNT", bkpinfo->tmpdir);
[59]1154 write_one_liner_data_file(tmp, bkpinfo->nfs_mount);
[900]1155 mr_free(tmp);
[171]1156
[900]1157 mr_asprintf(&tmp, "%s/NFS-SERVER-PATH", bkpinfo->tmpdir);
[59]1158 write_one_liner_data_file(tmp, bkpinfo->nfs_remote_dir);
[900]1159 mr_free(tmp);
[171]1160
[900]1161 mr_asprintf(&tmp, "%s/ISO-PREFIX", bkpinfo->tmpdir);
[149]1162 write_one_liner_data_file(tmp, bkpinfo->prefix);
[900]1163 mr_free(tmp);
[171]1164
[59]1165 log_it("Finished storing NFS configuration");
[1]1166}
1167
1168
1169/**
1170 * Determine the approximate number of media that the backup will take up,
1171 * and tell the user. The uncompressed size is estimated as size_of_all_biggiefiles_K()
1172 * plus (noof_sets x bkpinfo->optimal_set_size). The compression factor is estimated as
1173 * 2/3 for LZO and 1/2 for bzip2. The data is not saved anywhere. If there are any
1174 * "imagedevs", the estimate is not shown as it will be wildly inaccurate.
1175 * If there are more than 50 media estimated, the estimate will not be shown.
1176 * @param bkpinfo The backup information structure. Fields used:
1177 * - @c bkpinfo->backup_media_type
1178 * - @c bkpinfo->image_devs
1179 * - @c bkpinfo->media_size
1180 * - @c bkpinfo->optimal_set_size
1181 * - @c bkpinfo->use_lzo
1182 * @param noof_sets The number of filesets created.
1183 * @ingroup archiveGroup
1184 */
1185void
[59]1186estimate_noof_media_required(struct s_bkpinfo *bkpinfo, long noof_sets)
[1]1187{
[59]1188 /*@ buffers *************** */
[783]1189 char *tmp = NULL;
[1]1190
[59]1191 /*@ long long ************* */
1192 long long scratchLL;
[1]1193
[59]1194 if (bkpinfo->media_size[1] <= 0 || bkpinfo->backup_media_type == nfs) {
1195 log_to_screen("Number of media required: UNKNOWN");
1196 return;
1197 }
[1]1198
[59]1199 log_it("Estimating number of media required...");
1200 scratchLL =
1201 (long long) (noof_sets) * (long long) (bkpinfo->optimal_set_size)
1202 + (long long) (size_of_all_biggiefiles_K(bkpinfo));
1203 scratchLL = (scratchLL / 1024) / bkpinfo->media_size[1];
1204 scratchLL++;
1205 if (bkpinfo->use_lzo) {
1206 scratchLL = (scratchLL * 2) / 3;
1207 } else {
1208 scratchLL = scratchLL / 2;
1209 }
1210 if (!scratchLL) {
1211 scratchLL++;
1212 }
1213 if (scratchLL <= 1) {
[900]1214 mr_asprintf(&tmp,
[507]1215 _("Your backup will probably occupy a single %s. Maybe two."),
[783]1216 bkpinfo->backup_media_string);
[59]1217 } else {
[900]1218 mr_asprintf(&tmp, _("Your backup will occupy approximately %s media."),
[59]1219 number_to_text((int) (scratchLL + 1)));
1220 }
[783]1221 if (!bkpinfo->image_devs && (scratchLL < 50)) {
[59]1222 log_to_screen(tmp);
1223 }
[900]1224 mr_free(tmp);
[171]1225 return;
[1]1226}
1227
1228
1229/**
1230 * Determine whether a file is compressed. This is done
1231 * by reading through the "do-not-compress-these" file distributed with Mondo.
1232 * @param filename The file to check.
1233 * @return TRUE if it's compressed, FALSE if not.
1234 */
[59]1235bool is_this_file_compressed(char *filename)
[1]1236{
[783]1237 char *do_not_compress_these = NULL;
1238 char *tmp = NULL;
1239 char *p = NULL;
[1]1240
[900]1241 mr_asprintf(&tmp, "%s/do-not-compress-these", g_mondo_home);
[59]1242 if (!does_file_exist(tmp)) {
[900]1243 mr_free(tmp);
[59]1244 return (FALSE);
1245 }
[900]1246 mr_free(tmp);
[171]1247
[688]1248 do_not_compress_these = last_line_of_file(tmp);
[59]1249 for (p = do_not_compress_these; p != NULL; p++) {
[900]1250 mr_asprintf(&tmp, p);
[59]1251 if (strchr(tmp, ' ')) {
1252 *(strchr(tmp, ' ')) = '\0';
1253 }
[171]1254 if (!strcmp(strrchr(filename, '.'), tmp)) {
[900]1255 mr_free(do_not_compress_these);
1256 mr_free(tmp);
[59]1257 return (TRUE);
1258 }
[900]1259 mr_free(tmp);
[171]1260
[59]1261 if (!(p = strchr(p, ' '))) {
1262 break;
1263 }
1264 }
[900]1265 mr_free(do_not_compress_these);
[59]1266 return (FALSE);
[1]1267}
1268
1269
[59]1270int mode_of_file(char *fname)
[1]1271{
[59]1272 struct stat buf;
[1]1273
[59]1274 if (lstat(fname, &buf)) {
1275 return (-1);
1276 } // error
1277 else {
1278 return (buf.st_mode);
1279 }
[1]1280}
1281
1282
1283/**
1284 * Create a small script that mounts /boot, calls @c grub-install, and syncs the disks.
1285 * @param outfile Where to put the script.
1286 * @return 0 for success, 1 for failure.
1287 */
[59]1288int make_grub_install_scriptlet(char *outfile)
[1]1289{
[59]1290 FILE *fout;
1291 char *tmp;
1292 int retval = 0;
[1]1293
[59]1294 if ((fout = fopen(outfile, "w"))) {
1295 fprintf(fout,
1296 "#!/bin/sh\n\nmount /boot > /dev/null 2> /dev/null\ngrub-install $@\nres=$?\nsync;sync;sync\nexit $res\n");
1297 paranoid_fclose(fout);
1298 log_msg(2, "Created %s", outfile);
[900]1299 mr_asprintf(&tmp, "chmod +x %s", outfile);
[59]1300 paranoid_system(tmp);
[900]1301 mr_free(tmp);
[171]1302
[59]1303 retval = 0;
1304 } else {
1305 retval = 1;
[1]1306 }
[59]1307 return (retval);
[1]1308}
1309
1310/* @} - end fileGroup */
Note: See TracBrowser for help on using the repository browser.