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