source: MondoRescue/branches/stable/mondo/src/common/libmondo-files.c@ 1140

Last change on this file since 1140 was 1140, checked in by Bruno Cornec, 17 years ago

Try to fix some valgrind reports (note that this version still doesn't work)

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