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

Last change on this file since 89 was 89, checked in by bcornec, 14 years ago

merge r87:88 of the 2.04_berlios branch
indent some files

  • Property svn:keywords set to Id
File size: 32.1 KB
Line 
1/* libmondo-fork.c
2   $Id: libmondo-fork.c 89 2005-10-27 20:45:34Z bcornec $
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 89 2005-10-27 20:45:34Z bcornec $";
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)
480        log_msg(5, "pclose err: %d", errno);
481    /* Check if we have a valid status. If we do, extract the called program's exit code. */
482    /* If we don't, highlight this fact by returning -1. */
483    if (WIFEXITED(res)) {
484        retval = WEXITSTATUS(res);
485    } else {
486        retval = -1;
487    }
488    close_evalcall_form();
489    unlink(lockfile);
490    return (retval);
491}
492
493
494
495
496
497/**
498 * Thread callback to run a command (partimage) in the background.
499 * @param xfb A transfer block of @c char, containing:
500 * - xfb:[0] A marker, should be set to 2. Decremented to 1 while the command is running and 0 when it's finished.
501 * - xfb:[1] The command's return value, if xfb:[0] is 0.
502 * - xfb+2:  A <tt>NULL</tt>-terminated string containing the command to be run.
503 * @return NULL to pthread_join.
504 */
505void *call_partimage_in_bkgd(void *xfb)
506{
507    char *transfer_block;
508    int retval = 0;
509
510    g_buffer_pid = getpid();
511    unlink("/tmp/null");
512    log_msg(1, "starting");
513    transfer_block = (char *) xfb;
514    transfer_block[0]--;        // should now be 1
515    retval = system(transfer_block + 2);
516    if (retval) {
517        log_OS_error("partimage returned an error");
518    }
519    transfer_block[1] = retval;
520    transfer_block[0]--;        // should now be 0
521    g_buffer_pid = 0;
522    log_msg(1, "returning");
523    pthread_exit(NULL);
524}
525
526
527/**
528 * File to touch if we want partimage to wait for us.
529 */
530#define PAUSE_PARTIMAGE_FNAME "/tmp/PAUSE-PARTIMAGE-FOR-MONDO"
531
532/**
533 * Apparently unused. @bug This has a purpose, but what?
534 */
535#define PIMP_START_SZ "STARTSTARTSTART9ff3kff9a82gv34r7fghbkaBBC2T231hc81h42vws8"
536#define PIMP_END_SZ "ENDENDEND0xBBC10xBBC2T231hc81h42vws89ff3kff9a82gv34r7fghbka"
537
538/**
539 * Marker to start the next subvolume for Partimage.
540 */
541#define NEXT_SUBVOL_PLEASE "I-grew-up-on-the-crime-side,-the-New-York-Times-side,-where-staying-alive-was-no-jive"
542
543/**
544 * Marker to end the partimage file.
545 */
546#define NO_MORE_SUBVOLS "On-second-hand,momma-bounced-on-old-man,-and-so-we-moved-to-Shaolin-Land."
547
548int copy_from_src_to_dest(FILE * f_orig, FILE * f_archived, char direction)
549{
550// if dir=='w' then copy from orig to archived
551// if dir=='r' then copy from archived to orig
552    char *tmp;
553    char *buf;
554    long int bytes_to_be_read, bytes_read_in, bytes_written_out =
555        0, bufcap, subsliceno = 0;
556    int retval = 0;
557    FILE *fin;
558    FILE *fout;
559    FILE *ftmp;
560
561    log_msg(5, "Opening.");
562    malloc_string(tmp);
563    tmp[0] = '\0';
564    bufcap = 256L * 1024L;
565    if (!(buf = malloc(bufcap))) {
566        fatal_error("Failed to malloc() buf");
567    }
568
569    if (direction == 'w') {
570        fin = f_orig;
571        fout = f_archived;
572        sprintf(tmp, "%-64s", PIMP_START_SZ);
573        if (fwrite(tmp, 1, 64, fout) != 64) {
574            fatal_error("Can't write the introductory block");
575        }
576        while (1) {
577            bytes_to_be_read = bytes_read_in = fread(buf, 1, bufcap, fin);
578            if (bytes_read_in == 0) {
579                break;
580            }
581            sprintf(tmp, "%-64ld", bytes_read_in);
582            if (fwrite(tmp, 1, 64, fout) != 64) {
583                fatal_error("Cannot write introductory block");
584            }
585            log_msg(7,
586                    "subslice #%ld --- I have read %ld of %ld bytes in from f_orig",
587                    subsliceno, bytes_read_in, bytes_to_be_read);
588            bytes_written_out += fwrite(buf, 1, bytes_read_in, fout);
589            sprintf(tmp, "%-64ld", subsliceno);
590            if (fwrite(tmp, 1, 64, fout) != 64) {
591                fatal_error("Cannot write post-thingy block");
592            }
593            log_msg(7, "Subslice #%d written OK", subsliceno);
594            subsliceno++;
595        }
596        sprintf(tmp, "%-64ld", 0L);
597        if (fwrite(tmp, 1, 64L, fout) != 64L) {
598            fatal_error("Cannot write final introductory block");
599        }
600    } else {
601        fin = f_archived;
602        fout = f_orig;
603        if (fread(tmp, 1, 64L, fin) != 64L) {
604            fatal_error("Cannot read the introductory block");
605        }
606        log_msg(5, "tmp is %s", tmp);
607        if (!strstr(tmp, PIMP_START_SZ)) {
608            fatal_error("Can't find intro blk");
609        }
610        if (fread(tmp, 1, 64L, fin) != 64L) {
611            fatal_error("Cannot read introductory blk");
612        }
613        bytes_to_be_read = atol(tmp);
614        while (bytes_to_be_read > 0) {
615            log_msg(7, "subslice#%ld, bytes=%ld", subsliceno,
616                    bytes_to_be_read);
617            bytes_read_in = fread(buf, 1, bytes_to_be_read, fin);
618            if (bytes_read_in != bytes_to_be_read) {
619                fatal_error
620                    ("Danger, WIll Robinson. Failed to read whole subvol from archives.");
621            }
622            bytes_written_out += fwrite(buf, 1, bytes_read_in, fout);
623            if (fread(tmp, 1, 64, fin) != 64) {
624                fatal_error("Cannot read post-thingy block");
625            }
626            if (atol(tmp) != subsliceno) {
627                log_msg(1, "Wanted subslice %ld but got %ld ('%s')",
628                        subsliceno, atol(tmp), tmp);
629            }
630            log_msg(7, "Subslice #%ld read OK", subsliceno);
631            subsliceno++;
632            if (fread(tmp, 1, 64, fin) != 64) {
633                fatal_error("Cannot read introductory block");
634            }
635            bytes_to_be_read = atol(tmp);
636        }
637    }
638
639//  log_msg(4, "Written %ld of %ld bytes", bytes_written_out, bytes_read_in);
640
641    if (direction == 'w') {
642        sprintf(tmp, "%-64s", PIMP_END_SZ);
643        if (fwrite(tmp, 1, 64, fout) != 64) {
644            fatal_error("Can't write the final block");
645        }
646    } else {
647        log_msg(1, "tmpA is %s", tmp);
648        if (!strstr(tmp, PIMP_END_SZ)) {
649            if (fread(tmp, 1, 64, fin) != 64) {
650                fatal_error("Can't read the final block");
651            }
652            log_msg(5, "tmpB is %s", tmp);
653            if (!strstr(tmp, PIMP_END_SZ)) {
654                ftmp = fopen("/tmp/out.leftover", "w");
655                bytes_read_in = fread(tmp, 1, 64, fin);
656                log_msg(1, "bytes_read_in = %ld", bytes_read_in);
657//      if (bytes_read_in!=128+64) { fatal_error("Can't read the terminating block"); }
658                fwrite(tmp, 1, bytes_read_in, ftmp);
659                sprintf(tmp, "I am here - %ld", ftell(fin));
660//    log_msg(0, tmp);
661                fread(tmp, 1, 512, fin);
662                log_msg(0, "tmp = '%s'", tmp);
663                fwrite(tmp, 1, 512, ftmp);
664                fclose(ftmp);
665                fatal_error("Missing terminating block");
666            }
667        }
668    }
669
670    paranoid_free(buf);
671    paranoid_free(tmp);
672    log_msg(3, "Successfully copied %ld bytes", bytes_written_out);
673    return (retval);
674}
675
676
677/**
678 * Call partimage from @p input_device to @p output_fname.
679 * @param input_device The device to read.
680 * @param output_fname The file to write.
681 * @return 0 for success, nonzero for failure.
682 */
683int dynamically_create_pipes_and_copy_from_them_to_output_file(char
684                                                               *input_device, 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.