1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
2
3 /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
4 Copyright (c) 2006 - 2017 Thomas Schmitt <scdbackup@gmx.net>
5 Provided under GPL version 2 or later.
6 */
7
8 /* ts A71019 */
9
10 /* Standard measure should be: Threads are created detached.
11 According to the man pages they should then care for disposing themselves.
12
13 >>> ??? It is yet unclear why the threads vanish from the process list
14 even if joinable and even if never joined.
15
16 To be activated after release of libburn-0.4.0
17 */
18 #define Libburn_create_detached_threadS 1
19
20 /* Alternative : Threads are created joinable.
21 Threads get detached in remove_worker() and thus should dispose themselves.
22
23 #define Libburn_detach_done_workeR 1
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "../config.h"
28 #endif
29
30 #include "libburn.h"
31 #include "transport.h"
32 #include "drive.h"
33 #include "write.h"
34 #include "options.h"
35 #include "file.h"
36 #include "async.h"
37 #include "init.h"
38 #include "back_hacks.h"
39
40 #include <pthread.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <signal.h>
47
48 /*
49 #include <a ssert.h>
50 */
51 #include "libdax_msgs.h"
52 extern struct libdax_msgs *libdax_messenger;
53
54 /* ts A80714 : introduced type codes for the worker list */
55 #define Burnworker_type_scaN 0
56 #define Burnworker_type_erasE 1
57 #define Burnworker_type_formaT 2
58 #define Burnworker_type_writE 3
59 #define Burnworker_type_fifO 4
60
61 #define SCAN_GOING() (workers != NULL && \
62 workers->w_type == Burnworker_type_scaN)
63
64 typedef void *(*WorkerFunc) (void *);
65
66 struct scan_opts
67 {
68 struct burn_drive_info **drives;
69 unsigned int *n_drives;
70
71 int done;
72 };
73
74 struct erase_opts
75 {
76 struct burn_drive *drive;
77 int fast;
78 };
79
80 /* ts A61230 */
81 struct format_opts
82 {
83 struct burn_drive *drive;
84 off_t size;
85 int flag;
86 };
87
88 struct write_opts
89 {
90 struct burn_drive *drive;
91 struct burn_write_opts *opts;
92 struct burn_disc *disc;
93 };
94
95 struct fifo_opts
96 {
97 struct burn_source *source;
98 int flag;
99 };
100
101 union w_list_data
102 {
103 struct scan_opts scan;
104 struct erase_opts erase;
105 struct format_opts format;
106 struct write_opts write;
107 struct fifo_opts fifo;
108 };
109
110 struct w_list
111 {
112 /* ts A80714 */
113 int w_type; /* see above define Burnworker_type_* */
114
115 struct burn_drive *drive;
116 pthread_t thread;
117
118 struct w_list *next;
119
120 union w_list_data u;
121 };
122
123 static struct w_list *workers = NULL;
124
125 static void *fifo_worker_func(struct w_list *w);
126
127
burn_async_manage_lock(int mode)128 int burn_async_manage_lock(int mode)
129 {
130 int ret;
131
132 static pthread_mutex_t access_lock;
133 static int mutex_initialized = 0;
134 static int mutex_locked = 0;
135
136 if (mode == BURN_ASYNC_LOCK_INIT) {
137 if (mutex_initialized)
138 return 2;
139 ret = pthread_mutex_init(&access_lock, NULL);
140 if (ret != 0)
141 return 0;
142 mutex_initialized = 1;
143 return 1;
144 }
145 if (!mutex_initialized)
146 return 0;
147 if (mode == BURN_ASYNC_LOCK_OBTAIN) {
148 ret = pthread_mutex_lock(&access_lock);
149 if (ret != 0)
150 return 0;
151 mutex_locked = 1;
152 } else if (mode == BURN_ASYNC_LOCK_RELEASE) {
153 if (!mutex_locked)
154 return 2;
155 ret = pthread_mutex_unlock(&access_lock);
156 if (ret != 0)
157 return 0;
158 mutex_locked = 0;
159 }
160 return 1;
161 }
162
163
find_worker(struct burn_drive * d)164 static struct w_list *find_worker(struct burn_drive *d)
165 {
166 struct w_list *a;
167
168 for (a = workers; a; a = a->next)
169 if (a->drive == d)
170 return a;
171 return NULL;
172 }
173
add_worker(int w_type,struct burn_drive * d,WorkerFunc f,union w_list_data * data)174 static void add_worker(int w_type, struct burn_drive *d,
175 WorkerFunc f, union w_list_data *data)
176 {
177 struct w_list *a;
178 struct w_list *tmp;
179 pthread_attr_t *attr_pt = NULL;
180
181 #ifdef Libburn_create_detached_threadS
182 pthread_attr_t attr;
183 #endif
184
185 a = calloc(1, sizeof(struct w_list));
186 a->w_type = w_type;
187 a->drive = d;
188
189 a->u = *data;
190
191 burn_async_manage_lock(BURN_ASYNC_LOCK_INIT);
192
193 /* insert at front of the list */
194 a->next = workers;
195 tmp = workers;
196 workers = a;
197
198 if (d != NULL)
199 d->busy = BURN_DRIVE_SPAWNING;
200
201 #ifdef Libburn_create_detached_threadS
202
203 /* ts A71019 :
204 Trying to start the threads detached to get rid of the zombies
205 which do neither react on pthread_join() nor on pthread_detach().
206 */
207 pthread_attr_init(&attr);
208 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
209 attr_pt= &attr;
210
211 #endif /* Libburn_create_detached_threadS */
212
213 /* Worker specific locks are to be released early by the worker */
214 if (f == (WorkerFunc) fifo_worker_func)
215 burn_async_manage_lock(BURN_ASYNC_LOCK_OBTAIN);
216
217 if (pthread_create(&a->thread, attr_pt, f, a)) {
218 free(a);
219 workers = tmp;
220 return;
221 }
222 }
223
224
remove_worker(pthread_t th)225 static void remove_worker(pthread_t th)
226 {
227 struct w_list *a, *l = NULL;
228
229 for (a = workers; a; l = a, a = a->next)
230 if (a->thread == th) {
231 if (l)
232 l->next = a->next;
233 else
234 workers = a->next;
235
236 #ifdef Libburn_detach_done_workeR
237 /* ts A71019 : burry dead puppy before forgetting it */
238 /* Alternative : threads get detached and thus should
239 dispose themselves.
240 */
241 pthread_detach(th);
242 /*
243 int ret;
244 char msg[80];
245
246 ret = pthread_detach(th);
247 sprintf(msg,
248 "remove_workers(): pid= %lu pthread_detach(%lu)= %d",
249 (unsigned long) getpid(), (unsigned long) th, ret);
250 libdax_msgs_submit(libdax_messenger, -1, 0x00020158,
251 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW,
252 msg, 0, 0);
253 */
254
255 #endif /* Libburn_detach_done_workeR */
256
257 free(a);
258 break;
259 }
260
261 /* ts A61006 */
262 /* a ssert(a != NULL);/ * wasn't found.. this should not be possible */
263 if (a == NULL)
264 libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
265 LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
266 "remove_worker() cannot find given worker item", 0, 0);
267 }
268
scan_worker_func(struct w_list * w)269 static void *scan_worker_func(struct w_list *w)
270 {
271 int ret;
272
273 ret = burn_drive_scan_sync(w->u.scan.drives, w->u.scan.n_drives, 1);
274 if (ret <= 0)
275 w->u.scan.done = -1;
276 else
277 w->u.scan.done = 1;
278 return NULL;
279 }
280
reset_progress(struct burn_drive * d,int sessions,int tracks,int indices,int sectors,int flag)281 static void reset_progress(struct burn_drive *d, int sessions, int tracks,
282 int indices, int sectors, int flag)
283 {
284 /* reset the progress indicator */
285 d->progress.session = 0;
286 d->progress.sessions = sessions;
287 d->progress.track = 0;
288 d->progress.tracks = tracks;
289 d->progress.index = 0;
290 d->progress.indices = indices;
291 d->progress.start_sector = 0;
292 d->progress.sectors = sectors;
293 d->progress.sector = 0;
294 }
295
296
burn_drive_scan(struct burn_drive_info * drives[],unsigned int * n_drives)297 int burn_drive_scan(struct burn_drive_info *drives[], unsigned int *n_drives)
298 {
299 union w_list_data o;
300 int ret = 0;
301
302 /* ts A61006 : moved up from burn_drive_scan_sync , former Assert */
303 if (!burn_running) {
304 libdax_msgs_submit(libdax_messenger, -1, 0x00020109,
305 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
306 "Library not running (on attempt to scan)", 0, 0);
307 *drives = NULL;
308 *n_drives = 0;
309 return -1;
310 }
311
312 /* cannot be anything working! */
313
314 /* ts A61006 */
315 /* a ssert(!(workers && workers->drive)); */
316 if (workers != NULL && workers->drive != NULL) {
317 drive_is_active:;
318 libdax_msgs_submit(libdax_messenger, -1, 0x00020102,
319 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
320 "A drive operation is still going on (want to scan)",
321 0, 0);
322 *drives = NULL;
323 *n_drives = 0;
324 return -1;
325 }
326
327 if (workers == NULL) {
328 /* start it */
329
330 /* ts A61007 : test moved up from burn_drive_scan_sync()
331 was burn_wait_all() */
332 /* ts A70907 : now demanding freed drives, not only released */
333 if (!burn_drives_are_clear(1))
334 goto drive_is_active;
335 *drives = NULL;
336 *n_drives = 0;
337
338 o.scan.drives = drives;
339 o.scan.n_drives = n_drives;
340 o.scan.done = 0;
341 add_worker(Burnworker_type_scaN, NULL,
342 (WorkerFunc) scan_worker_func, &o);
343 } else if (workers->u.scan.done) {
344 /* its done */
345 ret = workers->u.scan.done;
346 remove_worker(workers->thread);
347
348 /* ts A61006 */
349 /* a ssert(workers == NULL); */
350 if (workers != NULL) {
351 libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
352 LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
353 "After scan a drive operation is still going on",
354 0, 0);
355 return -1;
356 }
357
358 } else {
359 /* still going */
360 }
361 return ret;
362 }
363
erase_worker_func(struct w_list * w)364 static void *erase_worker_func(struct w_list *w)
365 {
366
367 #define Libburn_protect_erase_threaD 1
368
369 #ifdef Libburn_protect_erase_threaD
370 sigset_t sigset, oldset;
371
372 /* Protect blank thread from being interrupted by external signals */
373 sigfillset(&sigset);
374 sigdelset(&sigset, SIGSEGV);
375 sigdelset(&sigset, SIGILL);
376 pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
377 #endif /* Libburn_protect_erase_threaD */
378
379 burn_disc_erase_sync(w->u.erase.drive, w->u.erase.fast);
380 remove_worker(pthread_self());
381
382 #ifdef Libburn_protect_erase_threaD
383 /* (just in case it would not end with all signals blocked) */
384 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
385 #endif /* Libburn_protect_erase_threaD */
386
387 return NULL;
388 }
389
burn_disc_erase(struct burn_drive * drive,int fast)390 void burn_disc_erase(struct burn_drive *drive, int fast)
391 {
392 union w_list_data o;
393
394 /* ts A61006 */
395 /* a ssert(drive); */
396 /* a ssert(!SCAN_GOING()); */
397 /* a ssert(!find_worker(drive)); */
398
399 if(drive == NULL) {
400 libdax_msgs_submit(libdax_messenger, -1,
401 0x00020104,
402 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
403 "NULL pointer caught in burn_disc_erase", 0, 0);
404 return;
405 }
406 if ((SCAN_GOING()) || find_worker(drive) != NULL) {
407 libdax_msgs_submit(libdax_messenger, drive->global_index,
408 0x00020102,
409 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
410 "A drive operation is still going on (want to erase)",
411 0, 0);
412 return;
413 }
414
415 reset_progress(drive, 1, 1, 1, 0x10000, 0);
416
417 /* A70103 : will be set to 0 by burn_disc_erase_sync() */
418 drive->cancel = 1;
419
420 /* ts A70103 moved up from burn_disc_erase_sync() */
421 /* ts A60825 : allow on parole to blank appendable CDs */
422 /* ts A70131 : allow blanking of overwritable DVD-RW (profile 0x13) */
423 /* ts A70216 : allow blanking of CD-RW or DVD-RW in any regular state
424 and of any kind of full media */
425 /* ts A70909 : the willingness to burn any BURN_DISC_FULL media is
426 inappropriate. One would rather need a -force option
427 Note: keep this in sync with mmc_read_disc_info() */
428 /* ts B10321 : Allowed role 5 to be blanked */
429 if ((drive->drive_role == 1 &&
430 drive->current_profile != 0x0a &&
431 drive->current_profile != 0x13 &&
432 drive->current_profile != 0x14 &&
433 drive->status != BURN_DISC_FULL)
434 ||
435 (drive->status != BURN_DISC_FULL &&
436 drive->status != BURN_DISC_APPENDABLE &&
437 drive->status != BURN_DISC_BLANK)
438 ||
439 (drive->drive_role != 1 && drive->drive_role != 5)
440 ) {
441 char msg[160];
442
443 sprintf(msg, "Drive and media state unsuitable for blanking. (role= %d , profile= 0x%x , status= %d)",
444 drive->drive_role,
445 (unsigned int) drive->current_profile,
446 drive->status);
447 libdax_msgs_submit(libdax_messenger, drive->global_index,
448 0x00020130,
449 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
450 msg, 0, 0);
451 return;
452 }
453
454 o.erase.drive = drive;
455 o.erase.fast = fast;
456 add_worker(Burnworker_type_erasE, drive,
457 (WorkerFunc) erase_worker_func, &o);
458 }
459
460
461 /* ts A61230 */
format_worker_func(struct w_list * w)462 static void *format_worker_func(struct w_list *w)
463 {
464
465 #define Libburn_protect_format_threaD 1
466
467 #ifdef Libburn_protect_format_threaD
468 sigset_t sigset, oldset;
469
470 /* Protect format thread from being interrupted by external signals */
471 sigfillset(&sigset);
472 sigdelset(&sigset, SIGSEGV);
473 sigdelset(&sigset, SIGILL);
474 pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
475 #endif /* Libburn_protect_format_threaD */
476
477 burn_disc_format_sync(w->u.format.drive, w->u.format.size,
478 w->u.format.flag);
479 remove_worker(pthread_self());
480
481 #ifdef Libburn_protect_format_threaD
482 /* (just in case it would not end with all signals blocked) */
483 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
484 #endif /* Libburn_protect_format_threaD */
485
486 return NULL;
487 }
488
489
490 /* ts A61230 */
burn_disc_format(struct burn_drive * drive,off_t size,int flag)491 void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
492 {
493 union w_list_data o;
494 int ok = 0, ret;
495 char msg[40];
496
497 reset_progress(drive, 1, 1, 1, 0x10000, 0);
498
499 if ((SCAN_GOING()) || find_worker(drive) != NULL) {
500 libdax_msgs_submit(libdax_messenger, drive->global_index,
501 0x00020102,
502 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
503 "A drive operation is still going on (want to format)",
504 0, 0);
505 return;
506 }
507 if (drive->drive_role != 1) {
508 libdax_msgs_submit(libdax_messenger, drive->global_index,
509 0x00020146,
510 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
511 "Drive is a virtual placeholder", 0, 0);
512 drive->cancel = 1;
513 return;
514 }
515 if (flag & 128) /* application prescribed format type */
516 flag |= 16; /* enforce re-format */
517
518 if (drive->current_profile == 0x14)
519 ok = 1; /* DVD-RW sequential */
520 else if (drive->current_profile == 0x13 && (flag & 16))
521 ok = 1; /* DVD-RW Restricted Overwrite with force bit */
522 else if (drive->current_profile == 0x1a) {
523 ok = 1; /* DVD+RW */
524 size = 0;
525 flag &= ~(2|8); /* no insisting in size 0, no expansion */
526 flag |= 4; /* format up to maximum size */
527 } else if (drive->current_profile == 0x12) {
528 ok = 1; /* DVD-RAM */
529
530 } else if (drive->current_profile == 0x41) {
531 /* BD-R SRM */
532 ok= 1;
533 ret = drive->read_format_capacities(drive, 0x00);
534 if (ret > 0 &&
535 drive->format_descr_type == BURN_FORMAT_IS_FORMATTED)
536 ok = 0;
537 if (drive->status != BURN_DISC_BLANK)
538 ok = 0;
539 if (!ok) {
540 libdax_msgs_submit(libdax_messenger,
541 drive->global_index, 0x00020162,
542 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
543 "BD-R not unformatted blank any more. Cannot format.",
544 0, 0);
545 drive->cancel = 1;
546 return;
547 }
548 if (flag & 32) {
549 libdax_msgs_submit(libdax_messenger,
550 drive->global_index, 0x00020163,
551 LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
552 "Blank BD-R left unformatted for zero spare capacity.",
553 0, 0);
554 return;
555 }
556 } else if (drive->current_profile == 0x43) {
557 ok = 1; /* BD-RE */
558
559 if ((flag & 32) && !(drive->current_feat23h_byte4 & 8)) {
560 libdax_msgs_submit(libdax_messenger,
561 drive->global_index, 0x00020164,
562 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
563 "Drive does not format BD-RE without spares.",
564 0, 0);
565 drive->cancel = 1;
566 return;
567
568 }
569 }
570
571 if (!ok) {
572 sprintf(msg,"Will not format media type %4.4Xh",
573 drive->current_profile);
574 libdax_msgs_submit(libdax_messenger, drive->global_index,
575 0x00020129,
576 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
577 msg, 0, 0);
578 drive->cancel = 1;
579 return;
580 }
581 o.format.drive = drive;
582 o.format.size = size;
583 o.format.flag = flag;
584 add_worker(Burnworker_type_formaT, drive,
585 (WorkerFunc) format_worker_func, &o);
586 }
587
588
write_disc_worker_func(struct w_list * w)589 static void *write_disc_worker_func(struct w_list *w)
590 {
591 struct burn_drive *d = w->u.write.drive;
592 char msg[80];
593
594 #define Libburn_protect_write_threaD 1
595
596 #ifdef Libburn_protect_write_threaD
597 sigset_t sigset, oldset;
598
599 /* Protect write thread from being interrupted by external signals */
600 sigfillset(&sigset);
601 sigdelset(&sigset, SIGSEGV);
602 sigdelset(&sigset, SIGILL);
603 pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
604 #endif /* Libburn_protect_write_threaD */
605
606 d->thread_pid = getpid();
607 d->thread_tid = pthread_self();
608 d->thread_pid_valid= 1;
609 burn_disc_write_sync(w->u.write.opts, w->u.write.disc);
610 d->thread_pid_valid= 0;
611 d->thread_pid = 0;
612
613 /* the options are refcounted, free out ref count which we added below
614 */
615 burn_write_opts_free(w->u.write.opts);
616
617 sprintf(msg, "Write thread on drive %d ended", d->global_index);
618 libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020178,
619 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
620 msg, 0, 0);
621
622 remove_worker(pthread_self());
623 d->busy = BURN_DRIVE_IDLE;
624
625 #ifdef Libburn_protect_write_threaD
626 /* (just in case it would not end with all signals blocked) */
627 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
628 #endif /* Libburn_protect_write_threaD */
629
630 return NULL;
631 }
632
burn_disc_write(struct burn_write_opts * opts,struct burn_disc * disc)633 void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
634 {
635 union w_list_data o;
636 char *reasons= NULL;
637 struct burn_drive *d;
638 int mvalid;
639
640 d = opts->drive;
641
642 /* ts A61006 */
643 /* a ssert(!SCAN_GOING()); */
644 /* a ssert(!find_worker(opts->drive)); */
645 if ((SCAN_GOING()) || find_worker(opts->drive) != NULL) {
646 libdax_msgs_submit(libdax_messenger, d->global_index,
647 0x00020102,
648 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
649 "A drive operation is still going on (want to write)",
650 0, 0);
651 return;
652 }
653
654 reset_progress(d, disc->sessions, disc->session[0]->tracks,
655 disc->session[0]->track[0]->indices, 0, 0);
656
657 /* For the next lines any return indicates failure */
658 d->cancel = 1;
659
660 /* ts A70203 : people have been warned in API specs */
661 if (opts->write_type == BURN_WRITE_NONE) {
662 libdax_msgs_submit(libdax_messenger, d->global_index,
663 0x0002017c,
664 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
665 "No valid write type selected", 0, 0);
666 return;
667 }
668
669 if (d->drive_role == 0) {
670 libdax_msgs_submit(libdax_messenger, d->global_index,
671 0x00020146,
672 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
673 "Drive is a virtual placeholder (null-drive)", 0, 0);
674 return;
675 }
676 if (d->drive_role == 4) {
677 libdax_msgs_submit(libdax_messenger, d->global_index,
678 0x00020181,
679 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
680 "Pseudo-drive is a read-only file. Cannot write.",
681 0, 0);
682 return;
683 }
684
685 /* ts A61007 : obsolete Assert in spc_select_write_params() */
686 if (d->drive_role == 1) {
687 mvalid = 0;
688 if (d->mdata != NULL)
689 mvalid = 1;
690 if (!mvalid) {
691 libdax_msgs_submit(libdax_messenger,
692 d->global_index, 0x00020113,
693 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
694 "Drive capabilities not inquired yet", 0, 0);
695 return;
696 }
697 }
698
699 /* ts A70219 : intended to replace all further tests here and many
700 tests in burn_*_write_sync()
701 */
702
703 BURN_ALLOC_MEM_VOID(reasons, char, BURN_REASONS_LEN + 80);
704 strcpy(reasons, "Write job parameters are unsuitable:\n");
705 if (burn_precheck_write(opts, disc, reasons + strlen(reasons), 1)
706 <= 0) {
707 libdax_msgs_submit(libdax_messenger,
708 d->global_index, 0x00020139,
709 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
710 reasons, 0, 0);
711 goto ex;
712 }
713 BURN_FREE_MEM(reasons); reasons= NULL;
714
715 /* ts A90106 : early catching of unformatted BD-RE */
716 if (d->current_profile == 0x43)
717 if (d->read_format_capacities(d, 0x00) > 0 &&
718 d->format_descr_type != BURN_FORMAT_IS_FORMATTED) {
719 libdax_msgs_submit(libdax_messenger,
720 d->global_index, 0x00020168,
721 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
722 "Media not properly formatted. Cannot write.",
723 0, 0);
724 return;
725 }
726
727 d->cancel = 0; /* End of the return = failure area */
728
729 o.write.drive = d;
730 o.write.opts = opts;
731 o.write.disc = disc;
732
733 opts->refcount++;
734
735 add_worker(Burnworker_type_writE, d,
736 (WorkerFunc) write_disc_worker_func, &o);
737
738 ex:;
739 BURN_FREE_MEM(reasons);
740 }
741
742
fifo_worker_func(struct w_list * w)743 static void *fifo_worker_func(struct w_list *w)
744 {
745
746 #define Libburn_protect_fifo_threaD 1
747
748 #ifdef Libburn_protect_fifo_threaD
749 sigset_t sigset, oldset;
750
751 /* Protect fifo thread from being interrupted by external signals */
752 sigfillset(&sigset);
753 sigdelset(&sigset, SIGSEGV);
754 sigdelset(&sigset, SIGILL);
755 pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
756 #endif /* Libburn_protect_fifo_threaD */
757
758 burn_fifo_source_shoveller(w->u.fifo.source, w->u.fifo.flag);
759 remove_worker(pthread_self());
760
761 #ifdef Libburn_protect_fifo_threaD
762 /* (just in case it would not end with all signals blocked) */
763 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
764 #endif /* Libburn_protect_fifo_threaD */
765
766 return NULL;
767 }
768
769
burn_fifo_start(struct burn_source * source,int flag)770 int burn_fifo_start(struct burn_source *source, int flag)
771 {
772 union w_list_data o;
773 struct burn_source_fifo *fs = source->data;
774
775 fs->is_started = -1;
776
777 /* create and set up ring buffer */;
778 fs->buf = burn_os_alloc_buffer(
779 ((size_t) fs->chunksize) * (size_t) fs->chunks, 0);
780 if (fs->buf == NULL) {
781 /* >>> could not start ring buffer */;
782 return -1;
783 }
784
785 o.fifo.source = source;
786 o.fifo.flag = flag;
787 add_worker(Burnworker_type_fifO, NULL,
788 (WorkerFunc) fifo_worker_func, &o);
789 fs->is_started = 1;
790
791 return 1;
792 }
793
794
burn_fifo_abort(struct burn_source_fifo * fs,int flag)795 int burn_fifo_abort(struct burn_source_fifo *fs, int flag)
796 {
797 int ret;
798 pthread_t pt;
799
800 burn_async_manage_lock(BURN_ASYNC_LOCK_OBTAIN);
801
802 if (fs->thread_is_valid <= 0 || fs->thread_handle == NULL) {
803 burn_async_manage_lock(BURN_ASYNC_LOCK_RELEASE);
804 return 2;
805 }
806 pt = *((pthread_t *) fs->thread_handle);
807
808 burn_async_manage_lock(BURN_ASYNC_LOCK_RELEASE);
809
810 fs->do_abort = 1;
811 ret = pthread_join(pt, NULL);
812
813 return (ret == 0);
814 }
815
816
817 #ifdef Libburn_has_burn_async_join_alL
818
819 /* ts A71019 : never used */
burn_async_join_all(void)820 void burn_async_join_all(void)
821 {
822 void *ret;
823
824 while (workers)
825 pthread_join(workers->thread, &ret);
826 }
827
828 #endif /* Libburn_has_burn_async_join_alL */
829
830
831