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

Last change on this file since 75 was 68, checked in by andree, 14 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.