source: MondoRescue/trunk/mondo/mondo/common/libmondo-fork.c@ 75

Last change on this file since 75 was 68, checked in by andree, 19 years ago

At the end of function run_program_and_log_to_screen, paranoid_pclose is
used to close the process stream. This means - as we don't evaluate the
exit code of the called program - that mondoarchive will happily
continue even if mondo has failed. Only later will it give an error when
it tries to burn an image that miondi has actually failed to create.

The change to libmondo-fork.c.diff addresses this by using pclose
directly (rather than the paranoid_pclose macro) and by then evaluating
the status information and extracting the exit code of the called
program.

The change to libmondo-archive.c makes it so that at the end of function
call_mindi_to_supply_boot_disks popup_and_OK is called in case of an
error rather than log_to_screen. This ensures that the main error is not
drowned in a sea of other messages.

  • Property svn:keywords set to Id
File size: 32.2 KB
Line 
1/* libmondo-fork.c
2 $Id: libmondo-fork.c 68 2005-10-17 12:37:16Z andree $
3
4- subroutines for handling forking/pthreads/etc.
5
6
706/20/2004
8- create fifo /var/log/partimagehack-debug.log and empty it
9 to keep ramdisk from filling up
10
1104/13/2004
12- >= should be <= g_loglevel
13
1411/15/2003
15- changed a few []s to char*s
16
1710/12
18- rewrote partimagehack handling (multiple fifos, chunks, etc.)
19
2010/11
21- partimagehack now has debug level of N (set in my-stuff.h)
22
2310/08
24- call to partimagehack when restoring will now log errors to /var/log/....log
25
2610/06
27- cleaned up logging a bit
28
2909/30
30- line 735 - missing char* cmd in sprintf()
31
3209/28
33- added run_external_binary_with_percentage_indicator()
34- rewritten eval_call_to_make_ISO()
35
3609/18
37- call mkstemp instead of mktemp
38
3909/13
40- major NTFS hackage
41
4209/12
43- paranoid_system("rm -f /tmp/ *PARTIMAGE*") before calling partimagehack
44
4509/11
46- forward-ported unbroken feed_*_partimage() subroutines
47 from early August 2003
48
4909/08
50- detect & use partimagehack if it exists
51
5209/05
53- finally finished partimagehack hack :)
54
5507/04
56- added subroutines to wrap around partimagehack
57
5804/27
59- don't echo (...res=%d...) at end of log_it()
60 unnecessarily
61- replace newtFinished() and newtInit() with
62 newtSuspend() and newtResume()
63
6404/24
65- added some assert()'s and log_OS_error()'s
66
6704/09
68- cleaned up run_program_and_log_output()
69
7004/07
71- cleaned up code a bit
72- let run_program_and_log_output() accept -1 (only log if _no error_)
73
7401/02/2003
75- in eval_call_to_make_ISO(), append output to MONDO_LOGFILE
76 instead of a temporary stderr text file
77
7812/10
79- patch by Heiko Schlittermann to handle % chars in issue.net
80
8111/18
82- if mkisofs in eval_call_to_make_ISO() returns an error then return it,
83 whether ISO was created or not
84
8510/30
86- if mkisofs in eval_call_to_make_ISO() returns an error then find out if
87 the output (ISO) file has been created; if it has then return 0 anyway
88
8908/01 - 09/30
90- run_program_and_log_output() now takes boolean operator to specify
91 whether it will log its activities in the event of _success_
92- system() now includes 2>/dev/null
93- enlarged some tmp[]'s
94- added run_program_and_log_to_screen() and run_program_and_log_output()
95
9607/24
97- created
98*/
99
100
101#include "my-stuff.h"
102#include "mondostructures.h"
103#include "libmondo-fork.h"
104#include "libmondo-string-EXT.h"
105#include "libmondo-gui-EXT.h"
106#include "libmondo-files-EXT.h"
107#include "libmondo-tools-EXT.h"
108#include "lib-common-externs.h"
109
110/*@unused@*/
111//static char cvsid[] = "$Id: libmondo-fork.c 68 2005-10-17 12:37:16Z andree $";
112
113extern char *g_tmpfs_mountpt;
114extern t_bkptype g_backup_media_type;
115extern bool g_text_mode;
116pid_t g_buffer_pid = 0;
117
118
119/**
120 * Call a program and retrieve its last line of output.
121 * @param call The program to run.
122 * @return The last line of its output.
123 * @note The returned value points to static storage that will be overwritten with each call.
124 */
125char *call_program_and_get_last_line_of_output(char *call)
126{
127 /*@ buffers ***************************************************** */
128 static char result[512];
129 char *tmp;
130
131 /*@ pointers **************************************************** */
132 FILE *fin;
133
134 /*@ initialize data ********************************************* */
135 malloc_string(tmp);
136 result[0] = '\0';
137 tmp[0] = '\0';
138
139 /*@******************************************************************** */
140
141 assert_string_is_neither_NULL_nor_zerolength(call);
142 if ((fin = popen(call, "r"))) {
143 for (fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
144 fgets(tmp, MAX_STR_LEN, fin)) {
145 if (strlen(tmp) > 1) {
146 strcpy(result, tmp);
147 }
148 }
149 paranoid_pclose(fin);
150 } else {
151 log_OS_error("Unable to popen call");
152 }
153 strip_spaces(result);
154 return (result);
155}
156
157
158
159
160
161
162#define MONDO_POPMSG "Your PC will not retract the CD tray automatically. Please call mondoarchive with the -m (manual CD tray) flag."
163
164/**
165 * Call mkisofs to create an ISO image.
166 * @param bkpinfo The backup information structure. Fields used:
167 * - @c bkpinfo->manual_cd_tray
168 * - @c bkpinfo->backup_media_type
169 * - @c bkpinfo->please_dont_eject_when_restoring
170 * @param basic_call The call to mkisofs. May contain tokens that will be resolved to actual data. The tokens are:
171 * - @c _ISO_ will become the ISO file (@p isofile)
172 * - @c _CD#_ becomes the CD number (@p cd_no)
173 * - @c _ERR_ becomes the logfile (@p g_logfile)
174 * @param isofile Replaces @c _ISO_ in @p basic_call. Should probably be the ISO image to create (-o parameter to mkisofs).
175 * @param cd_no Replaces @c _CD#_ in @p basic_call. Should probably be the CD number.
176 * @param logstub Unused.
177 * @param what_i_am_doing The action taking place (e.g. "Making ISO #1"). Used as the title of the progress dialog.
178 * @return Exit code of @c mkisofs (0 is success, anything else indicates failure).
179 * @bug @p logstub is unused.
180 */
181int
182eval_call_to_make_ISO(struct s_bkpinfo *bkpinfo,
183 char *basic_call, char *isofile,
184 int cd_no, char *logstub, char *what_i_am_doing)
185{
186
187 /*@ int's *** */
188 int retval = 0;
189
190
191 /*@ buffers *** */
192 char *midway_call, *ultimate_call, *tmp, *command, *incoming,
193 *old_stderr, *cd_number_str;
194 char *p;
195
196/*@*********** End Variables ***************************************/
197
198 log_msg(3, "Starting");
199 assert(bkpinfo != NULL);
200 assert_string_is_neither_NULL_nor_zerolength(basic_call);
201 assert_string_is_neither_NULL_nor_zerolength(isofile);
202 assert_string_is_neither_NULL_nor_zerolength(logstub);
203 if (!(midway_call = malloc(1200))) {
204 fatal_error("Cannot malloc midway_call");
205 }
206 if (!(ultimate_call = malloc(1200))) {
207 fatal_error("Cannot malloc ultimate_call");
208 }
209 if (!(tmp = malloc(1200))) {
210 fatal_error("Cannot malloc tmp");
211 }
212 if (!(command = malloc(1200))) {
213 fatal_error("Cannot malloc command");
214 }
215 malloc_string(incoming);
216 malloc_string(old_stderr);
217 malloc_string(cd_number_str);
218
219 incoming[0] = '\0';
220 old_stderr[0] = '\0';
221
222 sprintf(cd_number_str, "%d", cd_no);
223 resolve_naff_tokens(midway_call, basic_call, isofile, "_ISO_");
224 resolve_naff_tokens(tmp, midway_call, cd_number_str, "_CD#_");
225 resolve_naff_tokens(ultimate_call, tmp, MONDO_LOGFILE, "_ERR_");
226 log_msg(4, "basic call = '%s'", basic_call);
227 log_msg(4, "midway_call = '%s'", midway_call);
228 log_msg(4, "tmp = '%s'", tmp);
229 log_msg(4, "ultimate call = '%s'", ultimate_call);
230 sprintf(command, "%s >> %s", ultimate_call, MONDO_LOGFILE);
231
232 log_to_screen
233 ("Please be patient. Do not be alarmed by on-screen inactivity.");
234 log_msg(4, "Calling open_evalcall_form() with what_i_am_doing='%s'",
235 what_i_am_doing);
236 strcpy(tmp, command);
237 if (bkpinfo->manual_cd_tray) {
238 p = strstr(tmp, "2>>");
239 if (p) {
240 sprintf(p, " ");
241 while (*p == ' ') {
242 p++;
243 }
244 for (; *p != ' '; p++) {
245 *p = ' ';
246 }
247 }
248 strcpy(command, tmp);
249#ifndef _XWIN
250 if (!g_text_mode) {
251 newtSuspend();
252 }
253#endif
254 log_msg(1, "command = '%s'", command);
255 retval += system(command);
256 if (!g_text_mode) {
257 newtResume();
258 }
259 if (retval) {
260 log_msg(2, "Basic call '%s' returned an error.", basic_call);
261 popup_and_OK("Press ENTER to continue.");
262 popup_and_OK
263 ("mkisofs and/or cdrecord returned an error. CD was not created");
264 }
265 }
266 /* if text mode then do the above & RETURN; if not text mode, do this... */
267 else {
268 log_msg(3, "command = '%s'", command);
269// yes_this_is_a_goto:
270 retval =
271 run_external_binary_with_percentage_indicator_NEW
272 (what_i_am_doing, command);
273 }
274
275 paranoid_free(midway_call);
276 paranoid_free(ultimate_call);
277 paranoid_free(tmp);
278 paranoid_free(command);
279 paranoid_free(incoming);
280 paranoid_free(old_stderr);
281 paranoid_free(cd_number_str);
282/*
283 if (bkpinfo->backup_media_type == dvd && !bkpinfo->please_dont_eject_when_restoring)
284 {
285 log_msg(3, "Ejecting DVD device");
286 eject_device(bkpinfo->media_device);
287 }
288*/
289 return (retval);
290}
291
292
293
294
295/**
296 * Run a program and log its output (stdout and stderr) to the logfile.
297 * @param program The program to run. Passed to the shell, so you can use pipes etc.
298 * @param debug_level If @p g_loglevel is higher than this, do not log the output.
299 * @return The exit code of @p program (depends on the command, but 0 almost always indicates success).
300 */
301int run_program_and_log_output(char *program, int debug_level)
302{
303 /*@ buffer ****************************************************** */
304 char callstr[MAX_STR_LEN * 2];
305 char incoming[MAX_STR_LEN * 2];
306 char tmp[MAX_STR_LEN * 2];
307 char initial_label[MAX_STR_LEN * 2];
308
309 /*@ int ********************************************************* */
310 int res;
311 int i;
312 int len;
313 bool log_if_failure = FALSE;
314 bool log_if_success = FALSE;
315
316 /*@ pointers *************************************************** */
317 FILE *fin;
318 char *p;
319
320 /*@ end vars *************************************************** */
321
322 assert(program != NULL);
323 if (!program[0]) {
324 log_msg(2, "Warning - asked to run zerolength program");
325 return (1);
326 }
327// if (debug_level == TRUE) { debug_level=5; }
328
329 // assert_string_is_neither_NULL_nor_zerolength(program);
330
331 if (debug_level <= g_loglevel) {
332 log_if_success = TRUE;
333 log_if_failure = TRUE;
334 }
335 sprintf(callstr,
336 "%s > /tmp/mondo-run-prog-thing.tmp 2> /tmp/mondo-run-prog-thing.err",
337 program);
338 while ((p = strchr(callstr, '\r'))) {
339 *p = ' ';
340 }
341 while ((p = strchr(callstr, '\n'))) {
342 *p = ' ';
343 } /* single '=' is intentional */
344
345
346 len = (int) strlen(program);
347 for (i = 0; i < 35 - len / 2; i++) {
348 tmp[i] = '-';
349 }
350 tmp[i] = '\0';
351 strcat(tmp, " ");
352 strcat(tmp, program);
353 strcat(tmp, " ");
354 for (i = 0; i < 35 - len / 2; i++) {
355 strcat(tmp, "-");
356 }
357 strcpy(initial_label, tmp);
358 res = system(callstr);
359 if (((res == 0) && log_if_success) || ((res != 0) && log_if_failure)) {
360 log_msg(0, "running: %s", callstr);
361 log_msg(0,
362 "--------------------------------start of output-----------------------------");
363 }
364 if (log_if_failure
365 &&
366 system
367 ("cat /tmp/mondo-run-prog-thing.err >> /tmp/mondo-run-prog-thing.tmp 2> /dev/null"))
368 {
369 log_OS_error("Command failed");
370 }
371 unlink("/tmp/mondo-run-prog-thing.err");
372 fin = fopen("/tmp/mondo-run-prog-thing.tmp", "r");
373 if (fin) {
374 for (fgets(incoming, MAX_STR_LEN, fin); !feof(fin);
375 fgets(incoming, MAX_STR_LEN, fin)) {
376 /* patch by Heiko Schlittermann */
377 p = incoming;
378 while (p && *p) {
379 if ((p = strchr(p, '%'))) {
380 memmove(p, p + 1, strlen(p) + 1);
381 p += 2;
382 }
383 }
384 /* end of patch */
385 strip_spaces(incoming);
386 if ((res == 0 && log_if_success)
387 || (res != 0 && log_if_failure)) {
388 log_msg(0, incoming);
389 }
390 }
391 paranoid_fclose(fin);
392 }
393 unlink("/tmp/mondo-run-prog-thing.tmp");
394 if ((res == 0 && log_if_success) || (res != 0 && log_if_failure)) {
395 log_msg(0,
396 "--------------------------------end of output------------------------------");
397 if (res) {
398 log_msg(0, "...ran with res=%d", res);
399 } else {
400 log_msg(0, "...ran just fine. :-)");
401 }
402 }
403// else
404// { log_msg (0, "-------------------------------ran w/ res=%d------------------------------", res); }
405 return (res);
406}
407
408
409
410/**
411 * Run a program and log its output to the screen.
412 * @param basic_call The program to run.
413 * @param what_i_am_doing The title of the evalcall form.
414 * @return The return value of the command (varies, but 0 almost always means success).
415 * @see run_program_and_log_output
416 * @see log_to_screen
417 */
418int run_program_and_log_to_screen(char *basic_call, char *what_i_am_doing)
419{
420 /*@ int ******************************************************** */
421 int retval = 0;
422 int res = 0;
423 int i;
424
425 /*@ pointers **************************************************** */
426 FILE *fin;
427
428 /*@ buffers **************************************************** */
429 char tmp[MAX_STR_LEN * 2];
430 char command[MAX_STR_LEN * 2];
431 char lockfile[MAX_STR_LEN];
432
433 /*@ end vars *************************************************** */
434
435 assert_string_is_neither_NULL_nor_zerolength(basic_call);
436
437 sprintf(lockfile, "/tmp/mojo-jojo.blah.XXXXXX");
438 mkstemp(lockfile);
439 sprintf(command,
440 "echo hi > %s ; %s >> %s 2>> %s; res=$?; sleep 1; rm -f %s; exit $res",
441 lockfile, basic_call, MONDO_LOGFILE, MONDO_LOGFILE, lockfile);
442 open_evalcall_form(what_i_am_doing);
443 sprintf(tmp, "Executing %s", basic_call);
444 log_msg(2, tmp);
445 if (!(fin = popen(command, "r"))) {
446 log_OS_error("Unable to popen-in command");
447 sprintf(tmp, "Failed utterly to call '%s'", command);
448 log_to_screen(tmp);
449 return (1);
450 }
451 if (!does_file_exist(lockfile)) {
452 log_to_screen("Waiting for external binary to start");
453 for (i = 0; i < 60 && !does_file_exist(lockfile); sleep(1), i++) {
454 log_msg(3, "Waiting for lockfile %s to exist", lockfile);
455 }
456 }
457#ifdef _XWIN
458 /* This only can update when newline goes into the file,
459 but it's *much* prettier/faster on Qt. */
460 while (does_file_exist(lockfile)) {
461 while (!feof(fin)) {
462 if (!fgets(tmp, 512, fin))
463 break;
464 log_to_screen(tmp);
465 }
466 usleep(500000);
467 }
468#else
469 /* This works on Newt, and it gives quicker updates. */
470 for (; does_file_exist(lockfile); sleep(1)) {
471 log_file_end_to_screen(MONDO_LOGFILE, "");
472 update_evalcall_form(1);
473 }
474#endif
475 /* Evaluate the status returned by pclose to get the exit code of the called program. */
476 errno = 0;
477 res = pclose(fin);
478 /* Log actual pclose errors. */
479 if (errno) log_msg(5, "pclose err: %d", errno);
480 /* Check if we have a valid status. If we do, extract the called program's exit code. */
481 /* If we don't, highlight this fact by returning -1. */
482 if (WIFEXITED(res)) {
483 retval = WEXITSTATUS(res);
484 } else {
485 retval = -1;
486 }
487 close_evalcall_form();
488 unlink(lockfile);
489 return (retval);
490}
491
492
493
494
495
496/**
497 * Thread callback to run a command (partimage) in the background.
498 * @param xfb A transfer block of @c char, containing:
499 * - xfb:[0] A marker, should be set to 2. Decremented to 1 while the command is running and 0 when it's finished.
500 * - xfb:[1] The command's return value, if xfb:[0] is 0.
501 * - xfb+2: A <tt>NULL</tt>-terminated string containing the command to be run.
502 * @return NULL to pthread_join.
503 */
504void *call_partimage_in_bkgd(void *xfb)
505{
506 char *transfer_block;
507 int retval = 0;
508
509 g_buffer_pid = getpid();
510 unlink("/tmp/null");
511 log_msg(1, "starting");
512 transfer_block = (char *) xfb;
513 transfer_block[0]--; // should now be 1
514 retval = system(transfer_block + 2);
515 if (retval) {
516 log_OS_error("partimage returned an error");
517 }
518 transfer_block[1] = retval;
519 transfer_block[0]--; // should now be 0
520 g_buffer_pid = 0;
521 log_msg(1, "returning");
522 pthread_exit(NULL);
523}
524
525
526/**
527 * File to touch if we want partimage to wait for us.
528 */
529#define PAUSE_PARTIMAGE_FNAME "/tmp/PAUSE-PARTIMAGE-FOR-MONDO"
530
531/**
532 * Apparently unused. @bug This has a purpose, but what?
533 */
534#define PIMP_START_SZ "STARTSTARTSTART9ff3kff9a82gv34r7fghbkaBBC2T231hc81h42vws8"
535#define PIMP_END_SZ "ENDENDEND0xBBC10xBBC2T231hc81h42vws89ff3kff9a82gv34r7fghbka"
536
537/**
538 * Marker to start the next subvolume for Partimage.
539 */
540#define NEXT_SUBVOL_PLEASE "I-grew-up-on-the-crime-side,-the-New-York-Times-side,-where-staying-alive-was-no-jive"
541
542/**
543 * Marker to end the partimage file.
544 */
545#define NO_MORE_SUBVOLS "On-second-hand,momma-bounced-on-old-man,-and-so-we-moved-to-Shaolin-Land."
546
547int copy_from_src_to_dest(FILE * f_orig, FILE * f_archived, char direction)
548{
549// if dir=='w' then copy from orig to archived
550// if dir=='r' then copy from archived to orig
551 char *tmp;
552 char *buf;
553 long int bytes_to_be_read, bytes_read_in, bytes_written_out =
554 0, bufcap, subsliceno = 0;
555 int retval = 0;
556 FILE *fin;
557 FILE *fout;
558 FILE *ftmp;
559
560 log_msg(5, "Opening.");
561 malloc_string(tmp);
562 tmp[0] = '\0';
563 bufcap = 256L * 1024L;
564 if (!(buf = malloc(bufcap))) {
565 fatal_error("Failed to malloc() buf");
566 }
567
568 if (direction == 'w') {
569 fin = f_orig;
570 fout = f_archived;
571 sprintf(tmp, "%-64s", PIMP_START_SZ);
572 if (fwrite(tmp, 1, 64, fout) != 64) {
573 fatal_error("Can't write the introductory block");
574 }
575 while (1) {
576 bytes_to_be_read = bytes_read_in = fread(buf, 1, bufcap, fin);
577 if (bytes_read_in == 0) {
578 break;
579 }
580 sprintf(tmp, "%-64ld", bytes_read_in);
581 if (fwrite(tmp, 1, 64, fout) != 64) {
582 fatal_error("Cannot write introductory block");
583 }
584 log_msg(7,
585 "subslice #%ld --- I have read %ld of %ld bytes in from f_orig",
586 subsliceno, bytes_read_in, bytes_to_be_read);
587 bytes_written_out += fwrite(buf, 1, bytes_read_in, fout);
588 sprintf(tmp, "%-64ld", subsliceno);
589 if (fwrite(tmp, 1, 64, fout) != 64) {
590 fatal_error("Cannot write post-thingy block");
591 }
592 log_msg(7, "Subslice #%d written OK", subsliceno);
593 subsliceno++;
594 }
595 sprintf(tmp, "%-64ld", 0L);
596 if (fwrite(tmp, 1, 64L, fout) != 64L) {
597 fatal_error("Cannot write final introductory block");
598 }
599 } else {
600 fin = f_archived;
601 fout = f_orig;
602 if (fread(tmp, 1, 64L, fin) != 64L) {
603 fatal_error("Cannot read the introductory block");
604 }
605 log_msg(5, "tmp is %s", tmp);
606 if (!strstr(tmp, PIMP_START_SZ)) {
607 fatal_error("Can't find intro blk");
608 }
609 if (fread(tmp, 1, 64L, fin) != 64L) {
610 fatal_error("Cannot read introductory blk");
611 }
612 bytes_to_be_read = atol(tmp);
613 while (bytes_to_be_read > 0) {
614 log_msg(7, "subslice#%ld, bytes=%ld", subsliceno,
615 bytes_to_be_read);
616 bytes_read_in = fread(buf, 1, bytes_to_be_read, fin);
617 if (bytes_read_in != bytes_to_be_read) {
618 fatal_error
619 ("Danger, WIll Robinson. Failed to read whole subvol from archives.");
620 }
621 bytes_written_out += fwrite(buf, 1, bytes_read_in, fout);
622 if (fread(tmp, 1, 64, fin) != 64) {
623 fatal_error("Cannot read post-thingy block");
624 }
625 if (atol(tmp) != subsliceno) {
626 log_msg(1, "Wanted subslice %ld but got %ld ('%s')",
627 subsliceno, atol(tmp), tmp);
628 }
629 log_msg(7, "Subslice #%ld read OK", subsliceno);
630 subsliceno++;
631 if (fread(tmp, 1, 64, fin) != 64) {
632 fatal_error("Cannot read introductory block");
633 }
634 bytes_to_be_read = atol(tmp);
635 }
636 }
637
638// log_msg(4, "Written %ld of %ld bytes", bytes_written_out, bytes_read_in);
639
640 if (direction == 'w') {
641 sprintf(tmp, "%-64s", PIMP_END_SZ);
642 if (fwrite(tmp, 1, 64, fout) != 64) {
643 fatal_error("Can't write the final block");
644 }
645 } else {
646 log_msg(1, "tmpA is %s", tmp);
647 if (!strstr(tmp, PIMP_END_SZ)) {
648 if (fread(tmp, 1, 64, fin) != 64) {
649 fatal_error("Can't read the final block");
650 }
651 log_msg(5, "tmpB is %s", tmp);
652 if (!strstr(tmp, PIMP_END_SZ)) {
653 ftmp = fopen("/tmp/out.leftover", "w");
654 bytes_read_in = fread(tmp, 1, 64, fin);
655 log_msg(1, "bytes_read_in = %ld", bytes_read_in);
656// if (bytes_read_in!=128+64) { fatal_error("Can't read the terminating block"); }
657 fwrite(tmp, 1, bytes_read_in, ftmp);
658 sprintf(tmp, "I am here - %ld", ftell(fin));
659// log_msg(0, tmp);
660 fread(tmp, 1, 512, fin);
661 log_msg(0, "tmp = '%s'", tmp);
662 fwrite(tmp, 1, 512, ftmp);
663 fclose(ftmp);
664 fatal_error("Missing terminating block");
665 }
666 }
667 }
668
669 paranoid_free(buf);
670 paranoid_free(tmp);
671 log_msg(3, "Successfully copied %ld bytes", bytes_written_out);
672 return (retval);
673}
674
675
676/**
677 * Call partimage from @p input_device to @p output_fname.
678 * @param input_device The device to read.
679 * @param output_fname The file to write.
680 * @return 0 for success, nonzero for failure.
681 */
682int dynamically_create_pipes_and_copy_from_them_to_output_file(char
683 *input_device,
684 char
685 *output_fname)
686{
687 char *curr_fifo;
688 char *prev_fifo;
689 char *next_fifo;
690 char *command;
691 char *sz_call_to_partimage;
692 int fifo_number = 0;
693 struct stat buf;
694 pthread_t partimage_thread;
695 int res = 0;
696 char *tmpstub;
697 FILE *fout;
698 FILE *fin;
699 char *tmp;
700
701 malloc_string(tmpstub);
702 malloc_string(curr_fifo);
703 malloc_string(prev_fifo);
704 malloc_string(next_fifo);
705 malloc_string(command);
706 malloc_string(sz_call_to_partimage);
707 malloc_string(tmp);
708
709 log_msg(1, "g_tmpfs_mountpt = %s", g_tmpfs_mountpt);
710 if (g_tmpfs_mountpt && g_tmpfs_mountpt[0]
711 && does_file_exist(g_tmpfs_mountpt)) {
712 strcpy(tmpstub, g_tmpfs_mountpt);
713 } else {
714 strcpy(tmpstub, "/tmp");
715 }
716 paranoid_system("rm -f /tmp/*PARTIMAGE*");
717 sprintf(command, "rm -Rf %s/pih-fifo-*", tmpstub);
718 paranoid_system(command);
719 sprintf(tmpstub + strlen(tmpstub), "/pih-fifo-%ld",
720 (long int) random());
721 mkfifo(tmpstub, S_IRWXU | S_IRWXG); // never used, though...
722 sprintf(curr_fifo, "%s.%03d", tmpstub, fifo_number);
723 sprintf(next_fifo, "%s.%03d", tmpstub, fifo_number + 1);
724 mkfifo(curr_fifo, S_IRWXU | S_IRWXG);
725 mkfifo(next_fifo, S_IRWXU | S_IRWXG); // make sure _next_ fifo already exists before we call partimage
726 sz_call_to_partimage[0] = 2;
727 sz_call_to_partimage[1] = 0;
728 sprintf(sz_call_to_partimage + 2,
729 "partimagehack " PARTIMAGE_PARAMS
730 " save %s %s > /tmp/stdout 2> /tmp/stderr", input_device,
731 tmpstub);
732 log_msg(5, "curr_fifo = %s", curr_fifo);
733 log_msg(5, "next_fifo = %s", next_fifo);
734 log_msg(5, "sz_call_to_partimage call is '%s'",
735 sz_call_to_partimage + 2);
736 if (!lstat(output_fname, &buf) && S_ISREG(buf.st_mode)) {
737 log_msg(5, "Deleting %s", output_fname);
738 unlink(output_fname);
739 }
740 if (!(fout = fopen(output_fname, "w"))) {
741 fatal_error("Unable to openout to output_fname");
742 }
743 res =
744 pthread_create(&partimage_thread, NULL, call_partimage_in_bkgd,
745 (void *) sz_call_to_partimage);
746 if (res) {
747 fatal_error("Failed to create thread to call partimage");
748 }
749 log_msg(1, "Running fore/back at same time");
750 log_to_screen("Working with partimagehack...");
751 while (sz_call_to_partimage[0] > 0) {
752 sprintf(tmp, "%s\n", NEXT_SUBVOL_PLEASE);
753 if (fwrite(tmp, 1, 128, fout) != 128) {
754 fatal_error("Cannot write interim block");
755 }
756 log_msg(5, "fifo_number=%d", fifo_number);
757 log_msg(4, "Cat'ting %s", curr_fifo);
758 if (!(fin = fopen(curr_fifo, "r"))) {
759 fatal_error("Unable to openin from fifo");
760 }
761// if (!sz_call_to_partimage[0]) { break; }
762 log_msg(5, "Deleting %s", prev_fifo);
763 unlink(prev_fifo); // just in case
764 copy_from_src_to_dest(fin, fout, 'w');
765 paranoid_fclose(fin);
766 fifo_number++;
767 strcpy(prev_fifo, curr_fifo);
768 strcpy(curr_fifo, next_fifo);
769 log_msg(5, "Creating %s", next_fifo);
770 sprintf(next_fifo, "%s.%03d", tmpstub, fifo_number + 1);
771 mkfifo(next_fifo, S_IRWXU | S_IRWXG); // make sure _next_ fifo exists before we cat this one
772 system("sync");
773 sleep(5);
774 }
775 sprintf(tmp, "%s\n", NO_MORE_SUBVOLS);
776 if (fwrite(tmp, 1, 128, fout) != 128) {
777 fatal_error("Cannot write interim block");
778 }
779 if (fwrite(tmp, 1, 128, fout) != 128) {
780 fatal_error("Cannot write interim block");
781 }
782 if (fwrite(tmp, 1, 128, fout) != 128) {
783 fatal_error("Cannot write interim block");
784 }
785 if (fwrite(tmp, 1, 128, fout) != 128) {
786 fatal_error("Cannot write interim block");
787 }
788 paranoid_fclose(fout);
789 log_to_screen("Cleaning up after partimagehack...");
790 log_msg(3, "Final fifo_number=%d", fifo_number);
791 paranoid_system("sync");
792 unlink(next_fifo);
793 unlink(curr_fifo);
794 unlink(prev_fifo);
795 log_to_screen("Finished cleaning up.");
796
797// if (!lstat(sz_wait_for_this_file, &statbuf))
798// { log_msg(3, "WARNING! %s was not processed.", sz_wait_for_this_file); }
799 log_msg(2, "Waiting for pthread_join() to join.");
800 pthread_join(partimage_thread, NULL);
801 res = sz_call_to_partimage[1];
802 log_msg(2, "pthread_join() joined OK.");
803 log_msg(1, "Partimagehack(save) returned %d", res);
804 unlink(tmpstub);
805 paranoid_free(curr_fifo);
806 paranoid_free(prev_fifo);
807 paranoid_free(next_fifo);
808 paranoid_free(tmpstub);
809 paranoid_free(tmp);
810 paranoid_free(command);
811 return (res);
812}
813
814
815/**
816 * Feed @p input_device through partimage to @p output_fname.
817 * @param input_device The device to image.
818 * @param output_fname The file to write.
819 * @return 0 for success, nonzero for failure.
820 */
821int feed_into_partimage(char *input_device, char *output_fname)
822{
823// BACKUP
824 int res;
825
826 if (!does_file_exist(input_device)) {
827 fatal_error("input device does not exist");
828 }
829 if (!find_home_of_exe("partimagehack")) {
830 fatal_error("partimagehack not found");
831 }
832 res =
833 dynamically_create_pipes_and_copy_from_them_to_output_file
834 (input_device, output_fname);
835 return (res);
836}
837
838
839
840
841
842int run_external_binary_with_percentage_indicator_OLD(char *tt, char *cmd)
843{
844
845 /*@ int *************************************************************** */
846 int res = 0;
847 int percentage = 0;
848 int maxpc = 0;
849 int pcno = 0;
850 int last_pcno = 0;
851
852 /*@ buffers *********************************************************** */
853 char *command;
854 char *tempfile;
855 char *title;
856 /*@ pointers ********************************************************** */
857 FILE *pin;
858
859 malloc_string(title);
860 malloc_string(command);
861 malloc_string(tempfile);
862 assert_string_is_neither_NULL_nor_zerolength(cmd);
863 assert_string_is_neither_NULL_nor_zerolength(title);
864
865 strcpy(title, tt);
866 strcpy(tempfile,
867 call_program_and_get_last_line_of_output
868 ("mktemp -q /tmp/mondo.XXXXXXXX"));
869 sprintf(command, "%s >> %s 2>> %s; rm -f %s", cmd, tempfile, tempfile,
870 tempfile);
871 log_msg(3, command);
872 open_evalcall_form(title);
873 if (!(pin = popen(command, "r"))) {
874 log_OS_error("fmt err");
875 return (1);
876 }
877 maxpc = 100;
878// OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
879 for (sleep(1); does_file_exist(tempfile); sleep(1)) {
880 pcno = grab_percentage_from_last_line_of_file(MONDO_LOGFILE);
881 if (pcno < 0 || pcno > 100) {
882 log_msg(5, "Weird pc#");
883 continue;
884 }
885 percentage = pcno * 100 / maxpc;
886 if (pcno <= 5 && last_pcno > 40) {
887 close_evalcall_form();
888 strcpy(title, "Verifying...");
889 open_evalcall_form(title);
890 }
891 last_pcno = pcno;
892 update_evalcall_form(percentage);
893 }
894// OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
895 close_evalcall_form();
896 if (pclose(pin)) {
897 res++;
898 log_OS_error("Unable to pclose");
899 }
900 unlink(tempfile);
901 paranoid_free(command);
902 paranoid_free(tempfile);
903 paranoid_free(title);
904 return (res);
905}
906
907
908
909
910void *run_prog_in_bkgd_then_exit(void *info)
911{
912 char *sz_command;
913 static int res = 4444;
914
915 res = 999;
916 sz_command = (char *) info;
917 log_msg(4, "sz_command = '%s'", sz_command);
918 res = system(sz_command);
919 if (res > 256 && res != 4444) {
920 res = res / 256;
921 }
922 log_msg(4, "child res = %d", res);
923 sz_command[0] = '\0';
924 pthread_exit((void *) (&res));
925}
926
927
928
929
930int run_external_binary_with_percentage_indicator_NEW(char *tt, char *cmd)
931{
932
933 /*@ int *************************************************************** */
934 int res = 0;
935 int percentage = 0;
936 int maxpc = 100;
937 int pcno = 0;
938 int last_pcno = 0;
939 int counter = 0;
940
941 /*@ buffers *********************************************************** */
942 char *command;
943 char *title;
944 /*@ pointers ********************************************************** */
945 static int chldres = 0;
946 int *pchild_result;
947 pthread_t childthread;
948
949 pchild_result = &chldres;
950 assert_string_is_neither_NULL_nor_zerolength(cmd);
951 assert_string_is_neither_NULL_nor_zerolength(tt);
952 *pchild_result = 999;
953
954 malloc_string(title);
955 malloc_string(command);
956 strcpy(title, tt);
957 sprintf(command, "%s 2>> %s", cmd, MONDO_LOGFILE);
958 log_msg(3, "command = '%s'", command);
959 if ((res =
960 pthread_create(&childthread, NULL, run_prog_in_bkgd_then_exit,
961 (void *) command))) {
962 fatal_error("Unable to create an archival thread");
963 }
964
965 log_msg(8, "Parent running");
966 open_evalcall_form(title);
967 for (sleep(1); command[0] != '\0'; sleep(1)) {
968 pcno = grab_percentage_from_last_line_of_file(MONDO_LOGFILE);
969 if (pcno <= 0 || pcno > 100) {
970 log_msg(8, "Weird pc#");
971 continue;
972 }
973 percentage = pcno * 100 / maxpc;
974 if (pcno <= 5 && last_pcno >= 40) {
975 close_evalcall_form();
976 strcpy(title, "Verifying...");
977 open_evalcall_form(title);
978 }
979 if (counter++ >= 5) {
980 counter = 0;
981 log_file_end_to_screen(MONDO_LOGFILE, "");
982 }
983 last_pcno = pcno;
984 update_evalcall_form(percentage);
985 }
986 log_file_end_to_screen(MONDO_LOGFILE, "");
987 close_evalcall_form();
988 pthread_join(childthread, (void *) (&pchild_result));
989 if (pchild_result) {
990 res = *pchild_result;
991 } else {
992 res = 666;
993 }
994 log_msg(3, "Parent res = %d", res);
995 paranoid_free(command);
996 paranoid_free(title);
997 return (res);
998}
999
1000
1001
1002#define PIH_LOG "/var/log/partimage-debug.log"
1003
1004
1005/**
1006 * Feed @p input_fifo through partimage (restore) to @p output_device.
1007 * @param input_fifo The partimage file to read.
1008 * @param output_device Where to put the output.
1009 * @return The return value of partimagehack (0 for success).
1010 * @bug Probably unnecessary, as the partimage is just a sparse file. We could use @c dd to restore it.
1011 */
1012int feed_outfrom_partimage(char *output_device, char *input_fifo)
1013{
1014// RESTORE
1015 char *tmp;
1016// char *command;
1017 char *stuff;
1018 char *sz_call_to_partimage;
1019 pthread_t partimage_thread;
1020 int res;
1021 char *curr_fifo;
1022 char *prev_fifo;
1023 char *oldest_fifo;
1024 char *next_fifo;
1025 char *afternxt_fifo;
1026 int fifo_number = 0;
1027 char *tmpstub;
1028 FILE *fin;
1029 FILE *fout;
1030
1031 malloc_string(curr_fifo);
1032 malloc_string(prev_fifo);
1033 malloc_string(next_fifo);
1034 malloc_string(afternxt_fifo);
1035 malloc_string(oldest_fifo);
1036 malloc_string(tmp);
1037 sz_call_to_partimage = malloc(1000);
1038 malloc_string(stuff);
1039 malloc_string(tmpstub);
1040
1041 log_msg(1, "output_device=%s", output_device);
1042 log_msg(1, "input_fifo=%s", input_fifo);
1043/* I don't trust g_tmpfs_mountpt
1044 if (g_tmpfs_mountpt[0])
1045 {
1046 strcpy(tmpstub, g_tmpfs_mountpt);
1047 }
1048 else
1049 {
1050*/
1051 strcpy(tmpstub, "/tmp");
1052// }
1053 log_msg(1, "tmpstub was %s", tmpstub);
1054 strcpy(stuff, tmpstub);
1055 sprintf(tmpstub, "%s/pih-fifo-%ld", stuff, (long int) random());
1056 log_msg(1, "tmpstub is now %s", tmpstub);
1057 unlink("/tmp/PARTIMAGEHACK-POSITION");
1058 unlink(PAUSE_PARTIMAGE_FNAME);
1059 paranoid_system("rm -f /tmp/*PARTIMAGE*");
1060 sprintf(curr_fifo, "%s.%03d", tmpstub, fifo_number);
1061 sprintf(next_fifo, "%s.%03d", tmpstub, fifo_number + 1);
1062 sprintf(afternxt_fifo, "%s.%03d", tmpstub, fifo_number + 2);
1063 mkfifo(PIH_LOG, S_IRWXU | S_IRWXG);
1064 mkfifo(curr_fifo, S_IRWXU | S_IRWXG);
1065 mkfifo(next_fifo, S_IRWXU | S_IRWXG); // make sure _next_ fifo already exists before we call partimage
1066 mkfifo(afternxt_fifo, S_IRWXU | S_IRWXG);
1067 system("cat " PIH_LOG " > /dev/null &");
1068 log_msg(3, "curr_fifo = %s", curr_fifo);
1069 log_msg(3, "next_fifo = %s", next_fifo);
1070 if (!does_file_exist(input_fifo)) {
1071 fatal_error("input fifo does not exist");
1072 }
1073 if (!(fin = fopen(input_fifo, "r"))) {
1074 fatal_error("Unable to openin from input_fifo");
1075 }
1076 if (!find_home_of_exe("partimagehack")) {
1077 fatal_error("partimagehack not found");
1078 }
1079 sz_call_to_partimage[0] = 2;
1080 sz_call_to_partimage[1] = 0;
1081 sprintf(sz_call_to_partimage + 2,
1082 "partimagehack " PARTIMAGE_PARAMS
1083 " restore %s %s > /dev/null 2>> %s", output_device, curr_fifo,
1084 MONDO_LOGFILE);
1085 log_msg(1, "output_device = %s", output_device);
1086 log_msg(1, "curr_fifo = %s", curr_fifo);
1087 log_msg(1, "sz_call_to_partimage+2 = %s", sz_call_to_partimage + 2);
1088 res =
1089 pthread_create(&partimage_thread, NULL, call_partimage_in_bkgd,
1090 (void *) sz_call_to_partimage);
1091 if (res) {
1092 fatal_error("Failed to create thread to call partimage");
1093 }
1094 log_msg(1, "Running fore/back at same time");
1095 log_msg(2, " Trying to openin %s", input_fifo);
1096 if (!does_file_exist(input_fifo)) {
1097 log_msg(2, "Warning - %s does not exist", input_fifo);
1098 }
1099 while (!does_file_exist("/tmp/PARTIMAGEHACK-POSITION")) {
1100 log_msg(6, "Waiting for partimagehack (restore) to start");
1101 sleep(1);
1102 }
1103 while (sz_call_to_partimage[0] > 0) {
1104 if (fread(tmp, 1, 128, fin) != 128) {
1105 fatal_error("Cannot read introductory block");
1106 }
1107 if (strstr(tmp, NEXT_SUBVOL_PLEASE)) {
1108 log_msg(2, "Great. Next subvol coming up.");
1109 } else if (strstr(tmp, NO_MORE_SUBVOLS)) {
1110 log_msg(2, "Great. That was the last subvol.");
1111 break;
1112 } else {
1113 log_msg(2, "WTF is this? '%s'", tmp);
1114 fatal_error("Unknown interim block");
1115 }
1116 if (feof(fin)) {
1117 log_msg(1, "Eof(fin) detected. Breaking.");
1118 break;
1119 }
1120 log_msg(3, "Processing subvol %d", fifo_number);
1121 log_msg(5, "fifo_number=%d", fifo_number);
1122 if (!(fout = fopen(curr_fifo, "w"))) {
1123 fatal_error("Cannot openout to curr_fifo");
1124 }
1125 log_msg(6, "Deleting %s", oldest_fifo);
1126 copy_from_src_to_dest(fout, fin, 'r');
1127 paranoid_fclose(fout);
1128 fifo_number++;
1129 unlink(oldest_fifo); // just in case
1130 strcpy(oldest_fifo, prev_fifo);
1131 strcpy(prev_fifo, curr_fifo);
1132 strcpy(curr_fifo, next_fifo);
1133 strcpy(next_fifo, afternxt_fifo);
1134 sprintf(afternxt_fifo, "%s.%03d", tmpstub, fifo_number + 2);
1135 log_msg(6, "Creating %s", afternxt_fifo);
1136 mkfifo(afternxt_fifo, S_IRWXU | S_IRWXG); // make sure _next_ fifo already exists before we access current fifo
1137 fflush(fin);
1138// system("sync");
1139 usleep(1000L * 100L);
1140 }
1141 paranoid_fclose(fin);
1142 paranoid_system("sync");
1143 log_msg(1, "Partimagehack has finished. Great. Fin-closing.");
1144 log_msg(1, "Waiting for pthread_join");
1145 pthread_join(partimage_thread, NULL);
1146 res = sz_call_to_partimage[1];
1147 log_msg(1, "Yay. Partimagehack (restore) returned %d", res);
1148 unlink(prev_fifo);
1149 unlink(curr_fifo);
1150 unlink(next_fifo);
1151 unlink(afternxt_fifo);
1152 unlink(PIH_LOG);
1153 paranoid_free(tmp);
1154 paranoid_free(sz_call_to_partimage);
1155 paranoid_free(stuff);
1156 paranoid_free(prev_fifo);
1157 paranoid_free(curr_fifo);
1158 paranoid_free(next_fifo);
1159 paranoid_free(afternxt_fifo);
1160 paranoid_free(oldest_fifo);
1161 paranoid_free(tmpstub);
1162 return (res);
1163}
Note: See TracBrowser for help on using the repository browser.