1 /* growisofs.c
2  * Copyright (C) 2005 Sylvain Cresto <scresto@gmail.com>
3  *
4  * This file is part of graveman!
5  *
6  * graveman! is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or
9  * (at your option) any later version.
10  *
11  * graveman! is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with program; see the file COPYING. If not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19  * MA 02111-1307, USA.
20  *
21  * URL: http://www.nongnu.org/graveman/
22  *
23  */
24 
25 #include "graveman.h"
26 
27 #define GROWISOFS_CURRENT_WRITE_SPEED "\"Current Write Speed\" is "
28 #define GROWISOFS_DONE " done, estimate finish"
29 #define GROWISOFS_FLUSHING_CACHE ": flushing cache"
30 #define GROWISOFS_WRITING_LEADOUT ": writing lead-out"
31 #define GROWISOFS_FAILED ":-( write failed:"
32 #define GROWISOFS_USING "Using "
33 
34 /* communication avec growisofs */
35 
36 /* mise a jour du titre depuis le template prepare avec prepare_title */
set_title(Tgrave * Ag,gchar * Avitesse)37 void set_title(Tgrave *Ag, gchar *Avitesse) {
38   GtkLabel *Llabel = GTK_LABEL(sc_grave_get_data(Ag, "gravetitle"));
39   gchar *Ltitleshow = g_strdup_printf(_("Writing DVD in progress at %sx..."), Avitesse);
40 
41   gtk_label_set_text(Llabel, Ltitleshow);
42   g_free(Ltitleshow);
43 }
44 
get_title_preparing(gint Anbrgravure,gint Acurcd,gboolean Adosimul)45 gchar *get_title_preparing(gint Anbrgravure, gint Acurcd, gboolean Adosimul)
46 {
47   if (Anbrgravure==1) {
48     if (!Adosimul) {
49       return g_strdup(_("DVD writing will start..."));
50     } else {
51       return g_strdup(_("Simulated DVD writing will start..."));
52     }
53   } else {
54     if (!Adosimul) {
55       return g_strdup_printf(_("DVD writing %d/%d will start..."), Acurcd, Anbrgravure);
56     } else {
57       return g_strdup_printf(_("Simulated DVD writing %d/%d will start..."), Acurcd, Anbrgravure);
58     }
59   }
60 }
61 
62 /* callback appele lorsque cdrecord grave les pistes */
growisofs_grave_callback(GIOChannel * Astd,GIOCondition Acond,gpointer Adata)63 gboolean growisofs_grave_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata)
64 {
65   GIOStatus Lstatus;
66   Tgrave *Lg = (Tgrave *)Adata;
67   gchar *Lbuffer;
68   gchar *s, *t;
69   GtkProgressBar *Lprogressbar = GTK_PROGRESS_BAR(sc_grave_get_data(Lg, "pb_total"));
70   GtkProgressBar *Lprogressbar2 = GTK_PROGRESS_BAR(sc_grave_get_data(Lg, "pb_step"));
71   GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Lg, "gravetitle"));
72   GError **Lerreur = (GError **) sc_grave_get_data(Lg, "gerror"); /* pointeur erreur */
73   gdouble Lpct, Ltava;
74   gchar Lsbuf[100], Lsbuf2[100];
75   gint *Lcont = (gint *) sc_grave_get_data(Lg, "cont"); /* on traite encore des donnees ? */
76   gint *Ltodo = (gint *) sc_grave_get_data(Lg, "todo"); /* nombre de piste a traiter */
77   gint *Ldone = (gint *) sc_grave_get_data(Lg, "done"); /* nombre de piste deja traite */
78 
79   if (Acond == G_IO_HUP || Acond == G_IO_ERR) {
80     *Lcont = 0;
81     return FALSE;
82   }
83 
84   Lstatus = g_io_channel_read_line(Astd, &Lbuffer, NULL, NULL, NULL);
85   if (!Lbuffer) {
86     if (Lstatus == G_IO_STATUS_ERROR || Lstatus == G_IO_STATUS_EOF)
87       return FALSE;
88     else
89       return TRUE;
90   }
91 
92 _DEB("===>%s", Lbuffer);
93 
94 
95   if ((s=strstr(Lbuffer, GROWISOFS_CURRENT_WRITE_SPEED))) {
96     /* mise a jour du titre lorsque l'on recois la vitesse */
97     s+=strlen(GROWISOFS_CURRENT_WRITE_SPEED);
98     if ((t = strchr(s, 'x'))) {
99       *t = 0;
100       set_title(Lg, s);
101     }
102   } else if (!strncmp(Lbuffer, GROWISOFS_USING, strlen(GROWISOFS_USING))) {
103     /* rien pour le moment */
104   } else if (strstr(Lbuffer, GROWISOFS_DONE)) {
105     /* gravure en cours ... */
106     if ((t=strchr(Lbuffer, '.'))) {
107       s=ltrim(Lbuffer);
108 
109       /* avancement tache */
110       Lpct = 0.01 * atof(s);
111       *t=0;
112 
113       gtk_progress_bar_set_fraction(Lprogressbar2, Lpct);
114       g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%s%%", s);
115       gtk_progress_bar_set_text(Lprogressbar2, Lsbuf);
116       /* avancement total */
117       Ltava = (1.0 / (*Ltodo)) * ((*Ldone)-1+Lpct);
118       gtk_progress_bar_set_fraction(Lprogressbar, Ltava);
119       g_snprintf(Lsbuf2, sizeof(Lsbuf2)-1, "%.0f%%", Ltava*100);
120       gtk_progress_bar_set_text(Lprogressbar, Lsbuf2);
121     }
122   } else if (strstr(Lbuffer, GROWISOFS_FLUSHING_CACHE)) {
123     gtk_label_set_text(Ltitle, _("Flushing cache..."));
124     gtk_progress_bar_set_fraction(Lprogressbar2, 1);
125     gtk_progress_bar_set_text(Lprogressbar2, _("100%"));
126     Ltava = (1.0 / (*Ltodo)) * ((*Ldone));
127     gtk_progress_bar_set_fraction(Lprogressbar, Ltava);
128     g_snprintf(Lsbuf2, sizeof(Lsbuf2)-1, "%.0f%%", Ltava*100);
129     gtk_progress_bar_set_text(Lprogressbar, Lsbuf2);
130   } else if (strstr(Lbuffer, GROWISOFS_WRITING_LEADOUT)) {
131     gtk_label_set_text(Ltitle, _("Writing lead-out..."));
132   } else if ((s=strstr(Lbuffer, GROWISOFS_FAILED))) {
133     gtk_label_set_text(Ltitle, _("Operation failed !"));
134     s+=strlen(GROWISOFS_FAILED);
135     g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_GROWISOFS, s ? s : _("Operation failed !"));
136     return FALSE;
137   }
138 
139   g_free(Lbuffer);
140 
141   return TRUE;
142 }
143 
144 /* copie de donnees */
burn_data2dvd(Tgrave * Ag,GError ** Aerror)145 gboolean burn_data2dvd(Tgrave *Ag, GError **Aerror) {
146   gchar **Lcmd;
147   gchar *Lcommandline, *Ltxt;
148   gchar *Lrepertoire = (gchar *)sc_grave_get_data(Ag, "tmpdir");
149   gint *Lcont = (gint *) sc_grave_get_data(Ag, "cont");
150   gboolean *Labort = (gboolean *) sc_grave_get_data(Ag, "gabort");
151   GtkWindow *Lwindow = GTK_WINDOW(sc_grave_get_data(Ag, "window_burn"));
152   gboolean Lsimul = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "dvddatasimul")));
153   gint Lnbrgravure = gtk_spin_button_get_value(GTK_SPIN_BUTTON(sc_grave_get_widget(Ag, "nbrdvddata")));
154   gint *Ldone = (gint *)sc_grave_get_data(Ag, "done"); /* fais */
155 
156   gboolean Lwanteject = conf_get_boolean("eject");
157 
158   gint *Lpid = (gint *) sc_grave_get_data(Ag, "pid");
159   GtkWidget *Lvitesse = sc_grave_get_widget(Ag, "dstdvddataspeed");
160   Tdriveinfo *Ldevice = matos_get_drive_info(Ag, "dstdvddatacombo");
161   GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Ag, "gravetitle"));
162   gchar *Loperation = sc_grave_get_data(Ag, "typeburn");
163   gboolean Leject = FALSE;
164   gboolean Ldosimul;
165   gchar *Lbufvitesse;
166   gint Lcurcd;
167   gint Lnbrpass=1;
168   gint g_out, g_err, Lnbrarg;
169   guint Lcomevent, Lcomerrevent;
170   GIOChannel *Lcom, *Lcomerr;
171   gchar *Lisopara = NULL;
172   gboolean Lstatus;
173   gint Lmediadetect1 = _MEDIA_CDRW;
174   GtkToggleButton *Lbtnnotfix = GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "dvddatanotfix"));
175   gboolean Lnotfix = Lbtnnotfix ? gtk_toggle_button_get_active(Lbtnnotfix) : FALSE;
176 _DEB("DVD DATA\n");
177 _DEB("nbr gravure = [%d]\n", Lnbrgravure);
178 
179   Lbufvitesse = get_combo_value(Lvitesse);
180   Lisopara = make_image_getextrapara(Ag, "dvddata");
181 
182   for (Lcurcd=1; Lcurcd<= Lnbrgravure;
183       ((Lsimul && Lnbrpass>1) || (!Lsimul)) ? ( Lcurcd++, Lnbrpass=1 ) : ( Lnbrpass++ )) {
184 
185     Ldosimul = (Lsimul && Lnbrpass==1);
186     if (Lcurcd > 1 && !Ldosimul) {
187       /* copie sur un nouveau dvd, on demande a l'utilisateur d'inserer le
188        * nouveau dvdvierge */
189       GSList *Llmediarequis1 = sc_grave_get_data(Ag, "mediarequis1");
190       gint *Lmediatitle1 = sc_grave_get_data(Ag, "mediatitle1");
191       gboolean Lstatus;
192       Tgrave *Ldialoghash;
193       GtkWidget *Lconfirm;
194       gint Lrep;
195 
196       eject_cd(matos_get_device(Ldevice), NULL);
197       Lstatus = waiting_for_user(*Lmediatitle1, Ag, Llmediarequis1 , &Lmediadetect1, Ldevice);
198 
199       if (Lstatus==FALSE) {
200         /* si c'est non alors on arrete */
201         *Labort = TRUE; Lstatus = TRUE; break;
202       }
203 
204       Ldialoghash = create_dialog_select_dvdoperation(GTK_WIDGET(Lwindow), Lmediadetect1);
205       Lconfirm = sc_grave_get_data(Ldialoghash, "window");
206       Lrep = gtk_dialog_run(GTK_DIALOG(Lconfirm));
207 
208       if (Lrep != GTK_RESPONSE_YES) {
209         /* si c'est non alors on arrete */
210         *Labort = TRUE; Lstatus = TRUE;
211       } else {
212         GtkRadioButton *Labradio = GTK_RADIO_BUTTON(sc_grave_get_widget(Ldialoghash, "burninitial"));
213         g_free(Loperation);
214         Loperation = g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Labradio)) ? "-Z" : "-M");
215       }
216       gtk_widget_destroy(Lconfirm);
217 
218       if (*Labort == TRUE) break;
219     }
220 
221     /* faut il ejecter le DVD apres l'operation ?
222      * oui si l'utilisateur a cocher la case "ejecter le cd" ou
223      * si il faut realiser d'autre gravure sur d'autres DVD */
224     Leject = ((Lcurcd > 1 && (Lwanteject || Lcurcd<Lnbrgravure)) || (Lcurcd == 1 && !Ldosimul && Lwanteject));
225 
226     _DEB("gravure du cd [%d]", Lcurcd);
227 
228     Ltxt = get_title_preparing(Lnbrgravure, Lcurcd, Ldosimul);
229     gtk_label_set_text(Ltitle, Ltxt);
230     g_free(Ltxt);
231 
232     Lcommandline = g_strdup_printf("%s %s %s %s %s%s %s -gui -use-the-force-luke=tty%s %s -graft-points -path-list %s/pathlist",
233         conf_get_string("growisofs"),
234         Lnotfix ? "" : "-dvd-compat",
235         Loperation,
236         matos_get_device(Ldevice),
237         *Lbufvitesse != '0' ? "-speed=" : "", *Lbufvitesse != '0' ? Lbufvitesse : "",
238         conf_get_boolean("overburn") ? "-overburn" : "",
239         Ldosimul ? ",dummy" : "",  /* simulation ? */
240         Lisopara,  /* parametres supplementaires tel que le nom de volume du cd */
241         Lrepertoire
242       );
243 
244     _DEB("execution [%s]\n", Lcommandline);
245     Lstatus = g_shell_parse_argv(Lcommandline, &Lnbrarg, &Lcmd, Aerror);
246     g_free(Lcommandline);
247 
248     if (Lstatus == FALSE) {
249       break;
250     }
251 
252     Lstatus = g_spawn_async_with_pipes(NULL, Lcmd, NULL, /* env argument */
253         (GSpawnFlags ) (G_SPAWN_DO_NOT_REAP_CHILD),
254         NULL, NULL, Lpid, NULL, &g_out, &g_err, Aerror);
255     g_strfreev(Lcmd);
256 
257     if (Lstatus == FALSE) {
258       g_warning("ERROR EXECUTION !\n");
259       break;
260     }
261 
262     *Lcont = 1;
263 
264     Lcom = g_io_channel_unix_new( g_out );
265     g_io_channel_set_encoding (Lcom, NULL, NULL);
266     g_io_channel_set_flags( Lcom, G_IO_FLAG_NONBLOCK, NULL );
267     Lcomevent = g_io_add_watch (Lcom, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
268                                         growisofs_grave_callback, Ag);
269 
270     Lcomerr = g_io_channel_unix_new( g_err );
271     g_io_channel_set_encoding (Lcomerr, NULL, NULL);
272     g_io_channel_set_flags( Lcomerr, G_IO_FLAG_NONBLOCK, NULL );
273     Lcomerrevent = g_io_add_watch (Lcomerr, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
274                                         growisofs_grave_callback, Ag);
275 
276     while (*Lcont>0 && *Labort == FALSE) {
277       gtk_main_iteration();
278     }
279     exit_prog(*Lpid, *Labort, Aerror, NULL);
280 
281     g_source_remove(Lcomerrevent);
282     g_source_remove(Lcomevent);
283 
284     g_io_channel_shutdown(Lcomerr, FALSE, NULL);
285     g_io_channel_unref(Lcomerr);
286     g_io_channel_shutdown(Lcom, FALSE, NULL);
287     g_io_channel_unref(Lcom);
288 
289     g_spawn_close_pid(*Lpid);
290     *Lpid = 0;
291 
292     if (*Aerror) {
293       Lstatus = FALSE;
294       break;
295     }
296 
297     if (Ldosimul) {
298       /* fin de la simulation, tout s'est apparement bien passe
299        * on demande confirmation avent de commencer la vrai gravure */
300       gint Lrep;
301       GtkWidget *Lconfirm = gtk_message_dialog_new(Lwindow,
302                                             GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
303                                             GTK_BUTTONS_YES_NO,
304                       _("Simulation successful. Do you want to write the DVD for real?"));
305       Lrep = gtk_dialog_run(GTK_DIALOG(Lconfirm));
306       gtk_widget_destroy(Lconfirm);
307       if (Lrep == GTK_RESPONSE_NO) {
308         /* si c'est non alors on arrete */
309         *Labort = TRUE;
310         Lstatus = TRUE;
311         break;
312       }
313     }
314     (*Ldone)++;
315   }
316 
317   g_free(Lisopara);
318   g_free(Lbufvitesse);
319 
320 
321   return *Aerror ? FALSE : TRUE;
322 }
323 
324 /* copie d'une image iso */
burn_iso2dvd(Tgrave * Ag,GError ** Aerror)325 gboolean burn_iso2dvd(Tgrave *Ag, GError **Aerror) {
326   gchar **Lcmd;
327   gchar *Lcommandline, *Ltxt;
328   gchar *Lrepertoire = (gchar *)sc_grave_get_data(Ag, "tmpdir");
329   gint *Lcont = (gint *) sc_grave_get_data(Ag, "cont");
330   gboolean *Labort = (gboolean *) sc_grave_get_data(Ag, "gabort");
331   GtkWindow *Lwindow = GTK_WINDOW(sc_grave_get_data(Ag, "window_burn"));
332   gboolean Lsimul = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "dvddatasimul")));
333   gint Lnbrgravure = gtk_spin_button_get_value(GTK_SPIN_BUTTON(sc_grave_get_widget(Ag, "nbrdvddata")));
334   gint *Ldone = (gint *)sc_grave_get_data(Ag, "done"); /* fais */
335 
336   gboolean Lwanteject = conf_get_boolean("eject");
337 
338   gint *Lpid = (gint *) sc_grave_get_data(Ag, "pid");
339   GtkWidget *Lvitesse = sc_grave_get_widget(Ag, "dstdvddataspeed");
340   Tdriveinfo *Ldevice = matos_get_drive_info(Ag, "dstdvddatacombo");
341   GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Ag, "gravetitle"));
342   gchar *Loperation = sc_grave_get_data(Ag, "typeburn");
343   gboolean Leject = FALSE;
344   gboolean Ldosimul;
345   gchar *Lbufvitesse;
346   gint Lcurcd;
347   gint Lnbrpass=1;
348   gint g_out, g_err, Lnbrarg;
349   guint Lcomevent, Lcomerrevent;
350   GIOChannel *Lcom, *Lcomerr;
351   gchar *Lisopara = NULL;
352   gboolean Lstatus;
353   gint Lmediadetect1 = _MEDIA_CDRW;
354   GtkToggleButton *Lbtnnotfix = GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "dvddatanotfix"));
355   gboolean Lnotfix = Lbtnnotfix ? gtk_toggle_button_get_active(Lbtnnotfix) : FALSE;
356 _DEB("DVD DATA\n");
357 _DEB("nbr gravure = [%d]\n", Lnbrgravure);
358 
359   Lbufvitesse = get_combo_value(Lvitesse);
360   Lisopara = make_image_getextrapara(Ag, "dvddata");
361 
362   for (Lcurcd=1; Lcurcd<= Lnbrgravure;
363       ((Lsimul && Lnbrpass>1) || (!Lsimul)) ? ( Lcurcd++, Lnbrpass=1 ) : ( Lnbrpass++ )) {
364 
365     Ldosimul = (Lsimul && Lnbrpass==1);
366     if (Lcurcd > 1 && !Ldosimul) {
367       /* copie sur un nouveau dvd, on demande a l'utilisateur d'inserer le
368        * nouveau dvdvierge */
369       GSList *Llmediarequis1 = sc_grave_get_data(Ag, "mediarequis1");
370       gint *Lmediatitle1 = sc_grave_get_data(Ag, "mediatitle1");
371       gboolean Lstatus;
372       Tgrave *Ldialoghash;
373       GtkWidget *Lconfirm;
374       gint Lrep;
375 
376       eject_cd(matos_get_device(Ldevice), NULL);
377       Lstatus = waiting_for_user(*Lmediatitle1, Ag, Llmediarequis1 , &Lmediadetect1, Ldevice);
378 
379       if (Lstatus==FALSE) {
380         /* si c'est non alors on arrete */
381         *Labort = TRUE; Lstatus = TRUE; break;
382       }
383 
384       Ldialoghash = create_dialog_select_dvdoperation(GTK_WIDGET(Lwindow), Lmediadetect1);
385       Lconfirm = sc_grave_get_data(Ldialoghash, "window");
386       Lrep = gtk_dialog_run(GTK_DIALOG(Lconfirm));
387 
388       if (Lrep != GTK_RESPONSE_YES) {
389         /* si c'est non alors on arrete */
390         *Labort = TRUE; Lstatus = TRUE;
391       } else {
392         GtkRadioButton *Labradio = GTK_RADIO_BUTTON(sc_grave_get_widget(Ldialoghash, "burninitial"));
393         g_free(Loperation);
394         Loperation = g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Labradio)) ? "-Z" : "-M");
395       }
396       gtk_widget_destroy(Lconfirm);
397 
398       if (*Labort == TRUE) break;
399     }
400 
401     /* faut il ejecter le DVD apres l'operation ?
402      * oui si l'utilisateur a cocher la case "ejecter le cd" ou
403      * si il faut realiser d'autre gravure sur d'autres DVD */
404     Leject = ((Lcurcd > 1 && (Lwanteject || Lcurcd<Lnbrgravure)) || (Lcurcd == 1 && !Ldosimul && Lwanteject));
405 
406     _DEB("gravure du cd [%d]", Lcurcd);
407 
408     Ltxt = get_title_preparing(Lnbrgravure, Lcurcd, Ldosimul);
409     gtk_label_set_text(Ltitle, Ltxt);
410     g_free(Ltxt);
411 
412     Lcommandline = g_strdup_printf("%s %s %s %s %s%s %s -gui -use-the-force-luke=tty%s %s -graft-points -path-list %s/pathlist",
413         conf_get_string("growisofs"),
414         Lnotfix ? "" : "-dvd-compat",
415         Loperation,
416         matos_get_device(Ldevice),
417         *Lbufvitesse != '0' ? "-speed=" : "", *Lbufvitesse != '0' ? Lbufvitesse : "",
418         conf_get_boolean("overburn") ? "-overburn" : "",
419         Ldosimul ? ",dummy" : "",  /* simulation ? */
420         Lisopara,  /* parametres supplementaires tel que le nom de volume du cd */
421         Lrepertoire
422       );
423 
424     _DEB("execution [%s]\n", Lcommandline);
425     Lstatus = g_shell_parse_argv(Lcommandline, &Lnbrarg, &Lcmd, Aerror);
426     g_free(Lcommandline);
427 
428     if (Lstatus == FALSE) {
429       break;
430     }
431 
432     /* try to umount device before device access */
433     matos_umount_device(Ldevice, NULL);
434 
435     Lstatus = g_spawn_async_with_pipes(NULL, Lcmd, NULL, /* env argument */
436         (GSpawnFlags ) (G_SPAWN_DO_NOT_REAP_CHILD),
437         NULL, NULL, Lpid, NULL, &g_out, &g_err, Aerror);
438     g_strfreev(Lcmd);
439 
440     if (Lstatus == FALSE) {
441       g_warning("ERROR EXECUTION !\n");
442       break;
443     }
444 
445     *Lcont = 1;
446 
447     Lcom = g_io_channel_unix_new( g_out );
448     g_io_channel_set_encoding (Lcom, NULL, NULL);
449     g_io_channel_set_flags( Lcom, G_IO_FLAG_NONBLOCK, NULL );
450     Lcomevent = g_io_add_watch (Lcom, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
451                                         growisofs_grave_callback, Ag);
452 
453     Lcomerr = g_io_channel_unix_new( g_err );
454     g_io_channel_set_encoding (Lcomerr, NULL, NULL);
455     g_io_channel_set_flags( Lcomerr, G_IO_FLAG_NONBLOCK, NULL );
456     Lcomerrevent = g_io_add_watch (Lcomerr, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
457                                         growisofs_grave_callback, Ag);
458 
459     while (*Lcont>0 && *Labort == FALSE) {
460       gtk_main_iteration();
461     }
462     exit_prog(*Lpid, *Labort, Aerror, NULL);
463 
464     g_source_remove(Lcomerrevent);
465     g_source_remove(Lcomevent);
466 
467     g_io_channel_shutdown(Lcomerr, FALSE, NULL);
468     g_io_channel_unref(Lcomerr);
469     g_io_channel_shutdown(Lcom, FALSE, NULL);
470     g_io_channel_unref(Lcom);
471 
472     g_spawn_close_pid(*Lpid);
473     *Lpid = 0;
474 
475     if (*Aerror) {
476       Lstatus = FALSE;
477       break;
478     }
479 
480     if (Ldosimul) {
481       /* fin de la simulation, tout s'est apparement bien passe
482        * on demande confirmation avent de commencer la vrai gravure */
483       gint Lrep;
484       GtkWidget *Lconfirm = gtk_message_dialog_new(Lwindow,
485                                             GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
486                                             GTK_BUTTONS_YES_NO,
487                       _("Simulation successful. Do you want to write the DVD for real?"));
488       Lrep = gtk_dialog_run(GTK_DIALOG(Lconfirm));
489       gtk_widget_destroy(Lconfirm);
490       if (Lrep == GTK_RESPONSE_NO) {
491         /* si c'est non alors on arrete */
492         *Labort = TRUE;
493         Lstatus = TRUE;
494         break;
495       }
496     }
497     (*Ldone)++;
498   }
499 
500   g_free(Lisopara);
501   g_free(Lbufvitesse);
502 
503 
504   return *Aerror ? FALSE : TRUE;
505 }
506 
507 /*
508  * vim:et:ts=8:sts=2:sw=2
509  */
510