source: branches/2.2.10/mondo/src/common/libmondo-fork.c @ 2607

Last change on this file since 2607 was 2607, checked in by bruno, 9 years ago

r3763@localhost: bruno | 2010-03-18 12:03:49 +0100

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