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

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

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

  • Property svn:keywords set to Id
File size: 19.0 KB
Line 
1/* libmondo-fork.c - subroutines for handling forking/pthreads/etc.
2 * $Id: libmondo-fork.c 1140 2007-02-12 01:05:43Z bruno $
3 */
4#include "my-stuff.h"
5#include "mr_mem.h"
6#include "mr_msg.h"
7#include "mondostructures.h"
8#include "libmondo-fork.h"
9#include "libmondo-string-EXT.h"
10#include "newt-specific-EXT.h"
11#include "libmondo-files-EXT.h"
12#include "libmondo-tools-EXT.h"
13
14/*@unused@*/
15//static char cvsid[] = "$Id: libmondo-fork.c 1140 2007-02-12 01:05:43Z bruno $";
16
17extern char *g_tmpfs_mountpt;
18extern t_bkptype g_backup_media_type;
19extern bool g_text_mode;
20pid_t g_buffer_pid = 0;
21
22
23/**
24 * Call a program and retrieve its last line of output.
25 * @param call The program to run.
26 * @return The last line of its output.
27 * @note The returned value points to static storage that will be overwritten with each call.
28 */
29char *call_program_and_get_last_line_of_output(char *call)
30{
31    /*@ buffers ***************************************************** */
32    static char result[512];
33    char *tmp;
34
35    /*@ pointers **************************************************** */
36    FILE *fin;
37
38    /*@ initialize data ********************************************* */
39    malloc_string(tmp);
40    result[0] = '\0';
41    tmp[0] = '\0';
42
43    /*@******************************************************************** */
44
45    assert_string_is_neither_NULL_nor_zerolength(call);
46    if ((fin = popen(call, "r"))) {
47        for (fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
48             fgets(tmp, MAX_STR_LEN, fin)) {
49            if (strlen(tmp) > 1) {
50                strcpy(result, tmp);
51            }
52        }
53        paranoid_pclose(fin);
54    } else {
55        log_OS_error("Unable to popen call");
56    }
57    strip_spaces(result);
58    return (result);
59}
60
61
62
63
64
65
66#define MONDO_POPMSG  "Your PC will not retract the CD tray automatically. Please call mondoarchive with the -m (manual CD tray) flag."
67
68/**
69 * Call mkisofs to create an ISO image.
70 * @param bkpinfo The backup information structure. Fields used:
71 * - @c bkpinfo->manual_cd_tray
72 * - @c bkpinfo->backup_media_type
73 * - @c bkpinfo->please_dont_eject_when_restoring
74 * @param basic_call The call to mkisofs. May contain tokens that will be resolved to actual data. The tokens are:
75 * - @c _ISO_ will become the ISO file (@p isofile)
76 * - @c _CD#_ becomes the CD number (@p cd_no)
77 * - @c _ERR_ becomes the logfile (@p g_logfile)
78 * @param isofile Replaces @c _ISO_ in @p basic_call. Should probably be the ISO image to create (-o parameter to mkisofs).
79 * @param cd_no Replaces @c _CD#_ in @p basic_call. Should probably be the CD number.
80 * @param logstub Unused.
81 * @param what_i_am_doing The action taking place (e.g. "Making ISO #1"). Used as the title of the progress dialog.
82 * @return Exit code of @c mkisofs (0 is success, anything else indicates failure).
83 * @bug @p logstub is unused.
84 */
85int
86eval_call_to_make_ISO(struct s_bkpinfo *bkpinfo,
87                      char *basic_call, char *isofile,
88                      int cd_no, char *logstub, char *what_i_am_doing)
89{
90
91    /*@ int's  *** */
92    int retval = 0;
93
94
95    /*@ buffers      *** */
96    char *midway_call, *ultimate_call, *tmp;
97    char *p = NULL; 
98    char *cd_number_str = NULL;
99    char *command = NULL;
100   
101
102/*@***********   End Variables ***************************************/
103
104    mr_msg(3, "Starting");
105    assert(bkpinfo != NULL);
106    assert_string_is_neither_NULL_nor_zerolength(basic_call);
107    assert_string_is_neither_NULL_nor_zerolength(isofile);
108    assert_string_is_neither_NULL_nor_zerolength(logstub);
109
110    midway_call = mr_malloc(1200);
111    ultimate_call = mr_malloc(1200);
112    tmp = mr_malloc(1200);
113
114    mr_asprintf(&cd_number_str, "%d", cd_no);
115    resolve_naff_tokens(midway_call, basic_call, isofile, "_ISO_");
116    resolve_naff_tokens(tmp, midway_call, cd_number_str, "_CD#_");
117    mr_free(cd_number_str);
118
119    resolve_naff_tokens(ultimate_call, tmp, MONDO_LOGFILE, "_ERR_");
120    mr_msg(4, "basic call = '%s'", basic_call);
121    mr_msg(4, "midway_call = '%s'", midway_call);
122    mr_msg(4, "tmp = '%s'", tmp);
123    mr_msg(4, "ultimate call = '%s'", ultimate_call);
124    mr_asprintf(&command, "%s >> %s", ultimate_call, MONDO_LOGFILE);
125
126    log_to_screen
127        (_("Please be patient. Do not be alarmed by on-screen inactivity."));
128    mr_msg(4, "Calling open_evalcall_form() with what_i_am_doing='%s'",
129            what_i_am_doing);
130    if (bkpinfo->manual_cd_tray) {
131        /* Find everything after a 2>> and remove it */
132        p = strstr(command, "2>>");
133        if (p) {
134            for (; *p != ' ' && *p != '\0'; p++) {
135                *p = ' ';
136            }
137        }
138#ifndef _XWIN
139        if (!g_text_mode) {
140            newtSuspend();
141        }
142#endif
143        mr_msg(1, "command = '%s'", command);
144        retval += system(command);
145        if (!g_text_mode) {
146            newtResume();
147        }
148        if (retval) {
149            mr_msg(2, "Basic call '%s' returned an error.", basic_call);
150            popup_and_OK(_("Press ENTER to continue."));
151            popup_and_OK
152                (_("mkisofs and/or cdrecord returned an error. CD was not created"));
153        }
154    }
155    /* if text mode then do the above & RETURN; if not text mode, do this... */
156    else {
157        mr_msg(3, "command = '%s'", command);
158//      yes_this_is_a_goto:
159        retval =
160            run_external_binary_with_percentage_indicator_NEW
161            (what_i_am_doing, command);
162    }
163    mr_free(command);
164
165    mr_free(midway_call);
166    mr_free(ultimate_call);
167    mr_free(tmp);
168    return (retval);
169}
170
171
172/**
173 * Run a program and log its output (stdout and stderr) to the logfile.
174 * @param program The program to run. Passed to the shell, so you can use pipes etc.
175 * @param debug_level If @p g_loglevel is higher than this, do not log the output.
176 * @return The exit code of @p program (depends on the command, but 0 almost always indicates success).
177 */
178int run_program_and_log_output(char *program, int debug_level)
179{
180    /*@ buffer ****************************************************** */
181    char *callstr = NULL;
182    char *incoming = NULL;
183    char *tmp = NULL;
184
185    /*@ int ********************************************************* */
186    int res = 0;
187    size_t n = 0;
188    int i;
189    int len;
190    bool log_if_failure = FALSE;
191    bool log_if_success = FALSE;
192
193    /*@ pointers *************************************************** */
194    FILE *fin = NULL;
195    char *p = NULL;
196
197    /*@ end vars *************************************************** */
198
199    assert(program != NULL);
200    if (!program[0]) {
201        mr_msg(2, "Warning - asked to run zerolength program");
202        return (1);
203    }
204
205    if (debug_level <= g_loglevel) {
206        log_if_success = TRUE;
207        log_if_failure = TRUE;
208    }
209    mr_asprintf(&callstr,
210            "%s > /tmp/mondo-run-prog-thing.tmp 2> /tmp/mondo-run-prog-thing.err",
211            program);
212    while ((p = strchr(callstr, '\r'))) {
213        *p = ' ';
214    }
215    while ((p = strchr(callstr, '\n'))) {
216        *p = ' ';
217    }                           /* single '=' is intentional */
218
219    res = system(callstr);
220    if (((res == 0) && log_if_success) || ((res != 0) && log_if_failure)) {
221        mr_msg(0, "running: %s", callstr);
222        mr_msg(0,
223                "--------------------------------start of output-----------------------------");
224    }
225    mr_free(callstr);
226
227    if (log_if_failure
228        &&
229        system
230        ("cat /tmp/mondo-run-prog-thing.err >> /tmp/mondo-run-prog-thing.tmp 2> /dev/null"))
231    {
232        log_OS_error("Command failed");
233    }
234    unlink("/tmp/mondo-run-prog-thing.err");
235    fin = fopen("/tmp/mondo-run-prog-thing.tmp", "r");
236    if (fin) {
237        for (mr_getline(&incoming, &n, fin); !feof(fin); mr_getline(&incoming, &n, fin)) {
238            /* patch by Heiko Schlittermann */
239            p = incoming;
240            while (p && *p) {
241                if ((p = strchr(p, '%'))) {
242                    memmove(p, p + 1, strlen(p) + 1);
243                    p += 2;
244                }
245            }
246            /* end of patch */
247            strip_spaces(incoming);
248            if ((res == 0 && log_if_success)
249                || (res != 0 && log_if_failure)) {
250                mr_msg(0, incoming);
251            }
252        }
253        mr_free(incoming);
254        paranoid_fclose(fin);
255    }
256    unlink("/tmp/mondo-run-prog-thing.tmp");
257    if ((res == 0 && log_if_success) || (res != 0 && log_if_failure)) {
258        mr_msg(0,
259                "--------------------------------end of output------------------------------");
260        if (res) {
261            mr_msg(0, "...ran with res=%d", res);
262        } else {
263            mr_msg(0, "...ran just fine. :-)");
264        }
265    }
266    return (res);
267}
268
269
270/**
271 * Run a program and log its output to the screen.
272 * @param basic_call The program to run.
273 * @param what_i_am_doing The title of the evalcall form.
274 * @return The return value of the command (varies, but 0 almost always means success).
275 * @see run_program_and_log_output
276 * @see log_to_screen
277 */
278int run_program_and_log_to_screen(char *basic_call, char *what_i_am_doing)
279{
280    /*@ int ******************************************************** */
281    int retval = 0;
282    int res = 0;
283    int i;
284
285    /*@ pointers **************************************************** */
286    FILE *fin;
287
288    /*@ buffers **************************************************** */
289    char *tmp = NULL;
290    char *command = NULL;
291    char *lockfile = NULL;
292
293    /*@ end vars *************************************************** */
294
295    assert_string_is_neither_NULL_nor_zerolength(basic_call);
296
297    mr_asprintf(&lockfile, "/tmp/mojo-jojo.blah.XXXXXX");
298    mkstemp(lockfile);
299    mr_asprintf(&command,
300            "echo hi > %s ; %s >> %s 2>> %s; res=$?; sleep 1; rm -f %s; exit $res",
301            lockfile, basic_call, MONDO_LOGFILE, MONDO_LOGFILE, lockfile);
302    open_evalcall_form(what_i_am_doing);
303    mr_asprintf(&tmp, "Executing %s", basic_call);
304    mr_msg(2, tmp);
305    mr_free(tmp);
306
307    if (!(fin = popen(command, "r"))) {
308        log_OS_error("Unable to popen-in command");
309        mr_asprintf(&tmp, _("Failed utterly to call '%s'"), command);
310        log_to_screen(tmp);
311        mr_free(tmp);
312        mr_free(lockfile);
313        mr_free(command);
314        return (1);
315    }
316    mr_free(command);
317
318    if (!does_file_exist(lockfile)) {
319        log_to_screen(_("Waiting for external binary to start"));
320        for (i = 0; i < 60 && !does_file_exist(lockfile); sleep(1), i++) {
321            mr_msg(3, "Waiting for lockfile %s to exist", lockfile);
322        }
323    }
324#ifdef _XWIN
325    /* This only can update when newline goes into the file,
326       but it's *much* prettier/faster on Qt. */
327    while (does_file_exist(lockfile)) {
328        while (!feof(fin)) {
329            if (!fgets(tmp, 512, fin))
330                break;
331            log_to_screen(tmp);
332        }
333        usleep(500000);
334    }
335#else
336    /* This works on Newt, and it gives quicker updates. */
337    for (; does_file_exist(lockfile); sleep(1)) {
338        log_file_end_to_screen(MONDO_LOGFILE, "");
339        update_evalcall_form(1);
340    }
341#endif
342    /* Evaluate the status returned by pclose to get the exit code of the called program. */
343    errno = 0;
344    res = pclose(fin);
345    /* Log actual pclose errors. */
346    if (errno) {
347        mr_msg(5, "pclose err: %d", errno);
348    }
349    /* Check if we have a valid status. If we do, extract the called program's exit code. */
350    /* If we don't, highlight this fact by returning -1. */
351    if (WIFEXITED(res)) {
352        retval = WEXITSTATUS(res);
353    } else {
354        retval = -1;
355    }
356    close_evalcall_form();
357    unlink(lockfile);
358    mr_free(lockfile);
359
360    return (retval);
361}
362
363
364/**
365 * Apparently used. @bug This has a purpose, but what?
366 */
367#define PIMP_START_SZ "STARTSTARTSTART9ff3kff9a82gv34r7fghbkaBBC2T231hc81h42vws8"
368#define PIMP_END_SZ "ENDENDEND0xBBC10xBBC2T231hc81h42vws89ff3kff9a82gv34r7fghbka"
369
370
371
372
373int copy_from_src_to_dest(FILE * f_orig, FILE * f_archived, char direction)
374{
375// if dir=='w' then copy from orig to archived
376// if dir=='r' then copy from archived to orig
377    char *tmp = NULL;
378    char *buf = NULL;
379    long int bytes_to_be_read, bytes_read_in, bytes_written_out =
380        0, bufcap, subsliceno = 0;
381    int retval = 0;
382    FILE *fin = NULL;
383    FILE *fout = NULL;
384    FILE *ftmp = NULL;
385
386    mr_msg(5, "Opening.");
387    malloc_string(tmp);
388    tmp[0] = '\0';
389    bufcap = 256L * 1024L;
390    buf = mr_malloc(bufcap);
391
392    if (direction == 'w') {
393        fin = f_orig;
394        fout = f_archived;
395        sprintf(tmp, "%-64s", PIMP_START_SZ);
396        if (fwrite(tmp, 1, 64, fout) != 64) {
397            fatal_error("Can't write the introductory block");
398        }
399        while (1) {
400            bytes_to_be_read = bytes_read_in = fread(buf, 1, bufcap, fin);
401            if (bytes_read_in == 0) {
402                break;
403            }
404            sprintf(tmp, "%-64ld", bytes_read_in);
405            if (fwrite(tmp, 1, 64, fout) != 64) {
406                fatal_error("Cannot write introductory block");
407            }
408            mr_msg(7,
409                    "subslice #%ld --- I have read %ld of %ld bytes in from f_orig",
410                    subsliceno, bytes_read_in, bytes_to_be_read);
411            bytes_written_out += fwrite(buf, 1, bytes_read_in, fout);
412            sprintf(tmp, "%-64ld", subsliceno);
413            if (fwrite(tmp, 1, 64, fout) != 64) {
414                fatal_error("Cannot write post-thingy block");
415            }
416            mr_msg(7, "Subslice #%d written OK", subsliceno);
417            subsliceno++;
418        }
419        sprintf(tmp, "%-64ld", 0L);
420        if (fwrite(tmp, 1, 64L, fout) != 64L) {
421            fatal_error("Cannot write final introductory block");
422        }
423    } else {
424        fin = f_archived;
425        fout = f_orig;
426        if (fread(tmp, 1, 64L, fin) != 64L) {
427            fatal_error("Cannot read the introductory block");
428        }
429        mr_msg(5, "tmp is %s", tmp);
430        if (!strstr(tmp, PIMP_START_SZ)) {
431            fatal_error("Can't find intro blk");
432        }
433        if (fread(tmp, 1, 64L, fin) != 64L) {
434            fatal_error("Cannot read introductory blk");
435        }
436        bytes_to_be_read = atol(tmp);
437        while (bytes_to_be_read > 0) {
438            mr_msg(7, "subslice#%ld, bytes=%ld", subsliceno,
439                    bytes_to_be_read);
440            bytes_read_in = fread(buf, 1, bytes_to_be_read, fin);
441            if (bytes_read_in != bytes_to_be_read) {
442                fatal_error
443                    ("Danger, WIll Robinson. Failed to read whole subvol from archives.");
444            }
445            bytes_written_out += fwrite(buf, 1, bytes_read_in, fout);
446            if (fread(tmp, 1, 64, fin) != 64) {
447                fatal_error("Cannot read post-thingy block");
448            }
449            if (atol(tmp) != subsliceno) {
450                mr_msg(1, "Wanted subslice %ld but got %ld ('%s')",
451                        subsliceno, atol(tmp), tmp);
452            }
453            mr_msg(7, "Subslice #%ld read OK", subsliceno);
454            subsliceno++;
455            if (fread(tmp, 1, 64, fin) != 64) {
456                fatal_error("Cannot read introductory block");
457            }
458            bytes_to_be_read = atol(tmp);
459        }
460    }
461
462//  mr_msg(4, "Written %ld of %ld bytes", bytes_written_out, bytes_read_in);
463
464    if (direction == 'w') {
465        sprintf(tmp, "%-64s", PIMP_END_SZ);
466        if (fwrite(tmp, 1, 64, fout) != 64) {
467            fatal_error("Can't write the final block");
468        }
469    } else {
470        mr_msg(1, "tmpA is %s", tmp);
471        if (!strstr(tmp, PIMP_END_SZ)) {
472            if (fread(tmp, 1, 64, fin) != 64) {
473                fatal_error("Can't read the final block");
474            }
475            mr_msg(5, "tmpB is %s", tmp);
476            if (!strstr(tmp, PIMP_END_SZ)) {
477                ftmp = fopen("/tmp/out.leftover", "w");
478                bytes_read_in = fread(tmp, 1, 64, fin);
479                mr_msg(1, "bytes_read_in = %ld", bytes_read_in);
480//      if (bytes_read_in!=128+64) { fatal_error("Can't read the terminating block"); }
481                fwrite(tmp, 1, bytes_read_in, ftmp);
482                sprintf(tmp, "I am here - %lld", (long long)ftello(fin));
483//    mr_msg(0, tmp);
484                fread(tmp, 1, 512, fin);
485                mr_msg(0, "tmp = '%s'", tmp);
486                fwrite(tmp, 1, 512, ftmp);
487                fclose(ftmp);
488                fatal_error("Missing terminating block");
489            }
490        }
491    }
492
493    mr_free(buf);
494    mr_free(tmp);
495    mr_msg(3, "Successfully copied %ld bytes", bytes_written_out);
496    return (retval);
497}
498
499/**
500 * Feed @p input_device through ntfsclone to @p output_fname.
501 * @param input_device The device to image.
502 * @param output_fname The file to write.
503 * @return 0 for success, nonzero for failure.
504 */
505int feed_into_ntfsprog(char *input_device, char *output_fname)
506{
507// BACKUP
508    int res = -1;
509    char *command = NULL;
510
511    if (!does_file_exist(input_device)) {
512        fatal_error("input device does not exist");
513    }
514    if ( !find_home_of_exe("ntfsclone")) {
515        fatal_error("ntfsclone not found");
516    }
517    mr_asprintf(&command, "ntfsclone --force --save-image --overwrite %s %s", output_fname, input_device);
518    res = run_program_and_log_output(command, 5);
519    mr_free(command);
520
521    unlink(output_fname);
522    return (res);
523}
524
525
526int run_external_binary_with_percentage_indicator_OLD(char *tt, char *cmd)
527{
528
529    int res = 0;
530    int percentage = 0;
531    int maxpc = 0;
532    int pcno = 0;
533    int last_pcno = 0;
534
535    char *command = NULL;
536    char *tempfile;
537    char *title;
538    /*@ pointers ********************************************************** */
539    FILE *pin;
540
541    malloc_string(title);
542    malloc_string(tempfile);
543    assert_string_is_neither_NULL_nor_zerolength(cmd);
544    assert_string_is_neither_NULL_nor_zerolength(title);
545
546    strcpy(title, tt);
547    strcpy(tempfile,
548           call_program_and_get_last_line_of_output
549           ("mktemp -q /tmp/mondo.XXXXXXXX"));
550    mr_asprintf(&command, "%s >> %s 2>> %s; rm -f %s", cmd, tempfile, tempfile,
551            tempfile);
552    mr_msg(3, command);
553    open_evalcall_form(title);
554    if (!(pin = popen(command, "r"))) {
555        log_OS_error("fmt err");
556        mr_free(command);
557        return (1);
558    }
559    mr_free(command);
560
561    maxpc = 100;
562// OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
563    for (sleep(1); does_file_exist(tempfile); sleep(1)) {
564        pcno = grab_percentage_from_last_line_of_file(MONDO_LOGFILE);
565        if (pcno < 0 || pcno > 100) {
566            mr_msg(5, "Weird pc#");
567            continue;
568        }
569        percentage = pcno * 100 / maxpc;
570        if (pcno <= 5 && last_pcno > 40) {
571            close_evalcall_form();
572            strcpy(title, "Verifying...");
573            open_evalcall_form(title);
574        }
575        last_pcno = pcno;
576        update_evalcall_form(percentage);
577    }
578// OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
579    close_evalcall_form();
580    if (pclose(pin)) {
581        res++;
582        log_OS_error("Unable to pclose");
583    }
584    unlink(tempfile);
585    mr_free(tempfile);
586    mr_free(title);
587    return (res);
588}
589
590
591void *run_prog_in_bkgd_then_exit(void *info)
592{
593    char *sz_command;
594    static int res = 4444;
595
596    res = 999;
597    sz_command = (char *) info;
598    mr_msg(4, "sz_command = '%s'", sz_command);
599    res = system(sz_command);
600    if (res > 256 && res != 4444) {
601        res = res / 256;
602    }
603    mr_msg(4, "child res = %d", res);
604    sz_command[0] = '\0';
605    pthread_exit((void *) (&res));
606}
607
608
609int run_external_binary_with_percentage_indicator_NEW(char *tt, char *cmd)
610{
611
612    /*@ int *************************************************************** */
613    int res = 0;
614    int percentage = 0;
615    int maxpc = 100;
616    int pcno = 0;
617    int last_pcno = 0;
618    int counter = 0;
619
620    /*@ buffers *********************************************************** */
621    char *command = NULL;
622    char *title;
623    /*@ pointers ********************************************************** */
624    static int chldres = 0;
625    int *pchild_result;
626    pthread_t childthread;
627
628    pchild_result = &chldres;
629    assert_string_is_neither_NULL_nor_zerolength(cmd);
630    assert_string_is_neither_NULL_nor_zerolength(tt);
631    *pchild_result = 999;
632
633    malloc_string(title);
634    strcpy(title, tt);
635    mr_asprintf(&command, "%s 2>> %s", cmd, MONDO_LOGFILE);
636    mr_msg(3, "command = '%s'", command);
637    if ((res =
638         pthread_create(&childthread, NULL, run_prog_in_bkgd_then_exit,
639                        (void *) command))) {
640        fatal_error("Unable to create an archival thread");
641    }
642
643    mr_msg(8, "Parent running");
644    open_evalcall_form(title);
645    for (sleep(1); command[0] != '\0'; sleep(1)) {
646        pcno = grab_percentage_from_last_line_of_file(MONDO_LOGFILE);
647        if (pcno <= 0 || pcno > 100) {
648            mr_msg(8, "Weird pc#");
649            continue;
650        }
651        percentage = pcno * 100 / maxpc;
652        if (pcno <= 5 && last_pcno >= 40) {
653            close_evalcall_form();
654            strcpy(title, "Verifying...");
655            open_evalcall_form(title);
656        }
657        if (counter++ >= 5) {
658            counter = 0;
659            log_file_end_to_screen(MONDO_LOGFILE, "");
660        }
661        last_pcno = pcno;
662        update_evalcall_form(percentage);
663    }
664    mr_free(command);
665
666    log_file_end_to_screen(MONDO_LOGFILE, "");
667    close_evalcall_form();
668    pthread_join(childthread, (void *) (&pchild_result));
669    if (pchild_result) {
670        res = *pchild_result;
671    } else {
672        res = 666;
673    }
674    mr_msg(3, "Parent res = %d", res);
675    mr_free(title);
676    return (res);
677}
678
679
680/**
681 * Feed @p input_fifo through ntfsclone (restore) to @p output_device.
682 * @param input_fifo The ntfsclone file to read.
683 * @param output_device Where to put the output.
684 * @return The return value of ntfsclone (0 for success).
685 */
686int feed_outfrom_ntfsprog(char *output_device, char *input_fifo)
687{
688// RESTORE
689    int res = -1;
690    char *command = NULL;
691
692    if ( !find_home_of_exe("ntfsclone")) {
693        fatal_error("ntfsclone not found");
694    }
695    mr_asprintf(&command, "ntfsclone --force --restore-image --overwrite %s %s", output_device, input_fifo);
696    res = run_program_and_log_output(command, 5);
697    mr_free(command);
698    return (res);
699}
Note: See TracBrowser for help on using the repository browser.