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 - 2013 Thomas Schmitt <scdbackup@gmx.net>
5 Provided under GPL version 2 or later.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include "../config.h"
10 #endif
11
12
13 #include <unistd.h>
14
15 /* ts A61007 */
16 /* #include <a ssert.h> */
17
18 #include <stdio.h>
19 #include <signal.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <pthread.h>
23
24 /* ts A70928 : init.h is for others, not for init .c
25 #include "init.h"
26 */
27
28
29 #include "sg.h"
30 #include "error.h"
31 #include "libburn.h"
32 #include "drive.h"
33 #include "transport.h"
34 #include "util.h"
35
36 /* ts A60825 : The storage location for back_hacks.h variables. */
37 #define BURN_BACK_HACKS_INIT 1
38 #include "back_hacks.h"
39
40 /* ts A60924 : a new message handling facility */
41 #include "libdax_msgs.h"
42 struct libdax_msgs *libdax_messenger= NULL;
43
44
45 int burn_running = 0;
46
47 double lib_start_time;
48
49
50 /* ts A60813 : GNU/Linux: whether to use O_EXCL on open() of device files
51 ts B00212 : FreeBSD: whether to use flock(LOCK_EX) after open()
52 */
53 int burn_sg_open_o_excl = 1;
54
55 /* ts A70403 : GNU/Linux: whether to use fcntl(,F_SETLK,)
56 after open() of device files */
57 int burn_sg_fcntl_f_setlk = 1;
58
59 /* ts A70314 : GNU/Linux: what device family to use :
60 0= default family
61 1= sr
62 2= scd
63 (3= st)
64 4= sg
65 */
66 int burn_sg_use_family = 0;
67
68 /* O_NONBLOCK was hardcoded in enumerate_ata() which i hardly use.
69 For enumerate_sg() it seems ok.
70 So it should stay default mode until enumerate_ata() without O_NONBLOCK
71 has been thoroughly tested. */
72 int burn_sg_open_o_nonblock = 1;
73
74 /* whether to take a busy drive as an error */
75 /* Caution: this is implemented by a rough hack and eventually leads
76 to unconditional abort of the process */
77 int burn_sg_open_abort_busy = 0;
78
79
80 /* The message returned from sg_id_string() and/or sg_initialize()
81 */
82 static char sg_initialize_msg[1024] = {""};
83
84
85 /* ts A61002 */
86
87 #include "cleanup.h"
88
89 /* Parameters for builtin abort handler */
90 static char abort_message_prefix[81] = {"libburn : "};
91 static pid_t abort_control_pid= 0;
92 static pthread_t abort_control_thread;
93 volatile int burn_global_abort_level= 0;
94 int burn_global_abort_signum= 0;
95 void *burn_global_signal_handle = NULL;
96 burn_abort_handler_t burn_global_signal_handler = NULL;
97 int burn_builtin_signal_action = 0; /* burn_set_signal_handling() */
98 volatile int burn_builtin_triggered_action = 0; /* burn_is_aborting() */
99
100
101 /* ts A70223 : whether implemented untested profiles are supported */
102 int burn_support_untested_profiles = 0;
103
104 /* ts A91111 :
105 whether to log SCSI commands (to be implemented in sg-*.c)
106 bit0= log in /tmp/libburn_sg_command_log
107 bit1= log to stderr
108 bit2= flush every line
109 */
110 int burn_sg_log_scsi = 0;
111
112
113 /* ts B10312 :
114 Whether to map random-access readonly files to drive role 4.
115 Else it is role 2 overwritable drive
116 */
117 int burn_drive_role_4_allowed = 0;
118
119
120 /* ts A60925 : ticket 74 */
121 /** Create the messenger object for libburn. */
burn_msgs_initialize(void)122 int burn_msgs_initialize(void)
123 {
124 int ret;
125
126 if(libdax_messenger == NULL) {
127 ret = libdax_msgs_new(&libdax_messenger,0);
128 if (ret <= 0)
129 return 0;
130 }
131 libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
132 LIBDAX_MSGS_SEV_FATAL, "libburn: ", 0);
133 return 1;
134 }
135
136 /* ts A60924 : ticket 74 : Added use of global libdax_messenger */
burn_initialize(void)137 int burn_initialize(void)
138 {
139 int ret;
140
141 if (burn_running)
142 return 1;
143
144 lib_start_time = burn_get_time(0);
145 burn_support_untested_profiles = 0;
146 ret = burn_msgs_initialize();
147 if (ret <= 0)
148 return 0;
149 ret = sg_initialize(sg_initialize_msg, 0);
150 if (ret <= 0) {
151 libdax_msgs_submit(libdax_messenger, -1,
152 0x00020175,
153 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
154 sg_initialize_msg, 0, 0);
155 return 0;
156 }
157 burn_running = 1;
158 return 1;
159 }
160
burn_finish(void)161 void burn_finish(void)
162 {
163 /* ts A61007 : assume no messageing system */
164 /* a ssert(burn_running); */
165 if (!burn_running)
166 return;
167
168 /* ts A61007 */
169 /* burn_wait_all(); */
170 if (!burn_drives_are_clear(0)) {
171 libdax_msgs_submit(libdax_messenger, -1, 0x00020107,
172 LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
173 "A drive is still busy on shutdown of library", 0, 0);
174 usleep(1000001);
175 burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
176 }
177
178 /* ts A60904 : ticket 62, contribution by elmom : name addon "_all" */
179 burn_drive_free_all();
180
181 /* ts A60924 : ticket 74 */
182 libdax_msgs_destroy(&libdax_messenger,0);
183
184 sg_shutdown(0);
185
186 burn_drive_clear_whitelist();
187
188 burn_running = 0;
189 }
190
191
192 /* ts A91226 */
193 /** API function. See libburn.h */
burn_scsi_transport_id(int flag)194 char *burn_scsi_transport_id(int flag)
195 {
196 if (!burn_running)
197 sg_id_string(sg_initialize_msg, 0);
198 return sg_initialize_msg;
199 }
200
201
202 /* ts A60813 */
203 /** API function. See libburn.h */
burn_preset_device_open(int exclusive,int blocking,int abort_on_busy)204 void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
205 {
206 /* ts A61007 */
207 /* a ssert(burn_running); */
208 if (!burn_running)
209 return;
210 burn_sg_open_o_excl = exclusive & 3;
211 burn_sg_fcntl_f_setlk = !!(exclusive & 32);
212 burn_sg_use_family = (exclusive >> 2) & 7;
213 burn_sg_open_o_nonblock = !blocking;
214 burn_sg_open_abort_busy = !!abort_on_busy;
215 }
216
217
218 /* ts A60924 : ticket 74 */
219 /** Control queueing and stderr printing of messages from libburn.
220 Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
221 "NOTE", "UPDATE", "DEBUG", "ALL".
222 @param queue_severity Gives the minimum limit for messages to be queued.
223 Default: "NEVER". If you queue messages then you
224 must consume them by burn_msgs_obtain().
225 @param print_severity Does the same for messages to be printed directly
226 to stderr.
227 @param print_id A text prefix to be printed before the message.
228 @return >0 for success, <=0 for error
229
230 */
burn_msgs_set_severities(char * queue_severity,char * print_severity,char * print_id)231 int burn_msgs_set_severities(char *queue_severity,
232 char *print_severity, char *print_id)
233 {
234 int ret, queue_sevno, print_sevno;
235
236 ret = libdax_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
237 if (ret <= 0)
238 return 0;
239 ret = libdax_msgs__text_to_sev(print_severity, &print_sevno, 0);
240 if (ret <= 0)
241 return 0;
242 ret = libdax_msgs_set_severities(libdax_messenger, queue_sevno,
243 print_sevno, print_id, 0);
244 if (ret <= 0)
245 return 0;
246 return 1;
247 }
248
249
250 /* ts A60924 : ticket 74 */
251 #define BURM_MSGS_MESSAGE_LEN 4096
252
253 /** Obtain the oldest pending libburn message from the queue which has at
254 least the given minimum_severity. This message and any older message of
255 lower severity will get discarded from the queue and is then lost forever.
256 Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
257 "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
258 will discard the whole queue.
259 @param error_code Will become a unique error code as liste in
260 libburn/libdax_msgs.h
261 @param msg_text Must provide at least BURM_MSGS_MESSAGE_LEN bytes.
262 @param os_errno Will become the eventual errno related to the message
263 @param severity Will become the severity related to the message and
264 should provide at least 80 bytes.
265 @return 1 if a matching item was found, 0 if not, <0 for severe errors
266 */
burn_msgs_obtain(char * minimum_severity,int * error_code,char msg_text[],int * os_errno,char severity[])267 int burn_msgs_obtain(char *minimum_severity,
268 int *error_code, char msg_text[], int *os_errno,
269 char severity[])
270 {
271 int ret, minimum_sevno, sevno, priority;
272 char *textpt, *sev_name;
273 struct libdax_msgs_item *item = NULL;
274
275 ret = libdax_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
276 if (ret <= 0)
277 return 0;
278 if (libdax_messenger == NULL)
279 return 0;
280 ret = libdax_msgs_obtain(libdax_messenger, &item, minimum_sevno,
281 LIBDAX_MSGS_PRIO_ZERO, 0);
282 if (ret <= 0)
283 goto ex;
284 ret = libdax_msgs_item_get_msg(item, error_code, &textpt, os_errno, 0);
285 if (ret <= 0)
286 goto ex;
287 strncpy(msg_text, textpt, BURM_MSGS_MESSAGE_LEN-1);
288 if(strlen(textpt) >= BURM_MSGS_MESSAGE_LEN)
289 msg_text[BURM_MSGS_MESSAGE_LEN-1] = 0;
290
291 severity[0]= 0;
292 ret = libdax_msgs_item_get_rank(item, &sevno, &priority, 0);
293 if(ret <= 0)
294 goto ex;
295 ret = libdax_msgs__sev_to_text(sevno, &sev_name, 0);
296 if(ret <= 0)
297 goto ex;
298 strcpy(severity,sev_name);
299
300 ret = 1;
301 ex:
302 libdax_msgs_destroy_item(libdax_messenger, &item, 0);
303 return ret;
304 }
305
306
307 /* ts A70922 : API */
burn_msgs_submit(int error_code,char msg_text[],int os_errno,char severity[],struct burn_drive * d)308 int burn_msgs_submit(int error_code, char msg_text[], int os_errno,
309 char severity[], struct burn_drive *d)
310 {
311 int ret, sevno, global_index = -1;
312
313 ret = libdax_msgs__text_to_sev(severity, &sevno, 0);
314 if (ret <= 0)
315 sevno = LIBDAX_MSGS_SEV_ALL;
316 if (error_code <= 0) {
317 switch(sevno) {
318 case LIBDAX_MSGS_SEV_ABORT: error_code = 0x00040000;
319 break; case LIBDAX_MSGS_SEV_FATAL: error_code = 0x00040001;
320 break; case LIBDAX_MSGS_SEV_SORRY: error_code = 0x00040002;
321 break; case LIBDAX_MSGS_SEV_WARNING: error_code = 0x00040003;
322 break; case LIBDAX_MSGS_SEV_HINT: error_code = 0x00040004;
323 break; case LIBDAX_MSGS_SEV_NOTE: error_code = 0x00040005;
324 break; case LIBDAX_MSGS_SEV_UPDATE: error_code = 0x00040006;
325 break; case LIBDAX_MSGS_SEV_DEBUG: error_code = 0x00040007;
326 break; default: error_code = 0x00040008;
327 }
328 }
329 if (d != NULL)
330 global_index = d->global_index;
331 ret = libdax_msgs_submit(libdax_messenger, global_index, error_code,
332 sevno, LIBDAX_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
333 return ret;
334 }
335
336
337 /* ts A71016 API */
burn_text_to_sev(char * severity_name,int * sevno,int flag)338 int burn_text_to_sev(char *severity_name, int *sevno, int flag)
339 {
340 int ret;
341
342 ret = libdax_msgs__text_to_sev(severity_name, sevno, 0);
343 return ret;
344 }
345
346
347 /* ts A80202 API */
burn_sev_to_text(int severity_number,char ** severity_name,int flag)348 int burn_sev_to_text(int severity_number, char **severity_name, int flag)
349 {
350 int ret;
351
352 ret = libdax_msgs__sev_to_text(severity_number, severity_name, 0);
353 return ret;
354 }
355
356
357 /* ts B21214 API */
burn_list_sev_texts(int flag)358 char *burn_list_sev_texts(int flag)
359 {
360 char *sev_list;
361
362 libdax_msgs__sev_to_text(0, &sev_list, 1);
363 return sev_list;
364 }
365
366
367 /* ts B00224 */
burn_util_thread_id(pid_t pid,pthread_t tid,char text[80])368 char *burn_util_thread_id(pid_t pid, pthread_t tid, char text[80])
369 {
370 int i, l;
371
372 sprintf(text, "[%lu,", (unsigned long int) getpid());
373 l= strlen(text);
374 for(i= 0; i < ((int) sizeof(pthread_t)) && 2 * i < 80 - l - 3; i++)
375 sprintf(text + l + 2 * i,
376 "%2.2X", ((unsigned char *) &tid)[i]);
377
378 sprintf(text + l + 2 * i, "]");
379 return text;
380 }
381
382
383 /* ts B20122 */
384 /* @param value 0=return rather than exit(value)
385 */
burn_abort_exit(int value)386 int burn_abort_exit(int value)
387 {
388 burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
389 fprintf(stderr,
390 "\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
391 abort_message_prefix);
392 if (value)
393 exit(value);
394 burn_global_abort_level = -2;
395 return(1);
396 }
397
398
burn_builtin_abort_handler(void * handle,int signum,int flag)399 int burn_builtin_abort_handler(void *handle, int signum, int flag)
400 {
401
402 #define Libburn_new_thread_signal_handleR 1
403 /*
404 #define Libburn_signal_handler_verbouS 1
405 */
406
407 int ret;
408 struct burn_drive *d;
409
410 #ifdef Libburn_signal_handler_verbouS
411 char text[80];
412
413 fprintf(stderr, "libburn_ABORT: in = %s\n",
414 burn_util_thread_id(getpid(), pthread_self(), text));
415 fprintf(stderr, "libburn_ABORT: ctrl = %s\n",
416 burn_util_thread_id(abort_control_pid, abort_control_thread,
417 text));
418 if (burn_global_signal_handler == burn_builtin_abort_handler)
419 fprintf(stderr, "libburn_ABORT: signal action = %d\n",
420 burn_builtin_signal_action);
421
422 /* >>> find writing drives and report their tid
423 fprintf(stderr, "libburn_ABORT: wrt = %s\n",
424 burn_util_thread_id(0, burn_write_thread_id, text));
425 fprintf(stderr, "libburn_ABORT: sig= %d\n", signum);
426 */
427 #endif
428
429 burn_builtin_triggered_action = burn_builtin_signal_action;
430 burn_global_abort_level = -1;
431
432 if (burn_builtin_signal_action > 1) {
433 Cleanup_set_handlers(NULL, NULL, 2);
434 if (burn_builtin_signal_action == 4)
435 return -2;
436 fprintf(stderr,"%sABORT : Trying to shut down busy drives\n",
437 abort_message_prefix);
438 fprintf(stderr,
439 "%sABORT : Wait the normal burning time before any kill -9\n",
440 abort_message_prefix);
441 burn_abort_5(0, burn_abort_pacifier, abort_message_prefix,
442 0, 1);
443 libdax_msgs_submit(libdax_messenger, -1, 0x00020177,
444 LIBDAX_MSGS_SEV_ABORT, LIBDAX_MSGS_PRIO_HIGH,
445 "Urged drive worker threads to do emergency halt",
446 0, 0);
447 return -2;
448 }
449
450
451 /* ---- old deprecated stuck-in-abort-handler loop ---- */
452
453 /* ts A70928:
454 Must be quick. Allowed to coincide with other thread and to share
455 the increment with that one. It must not decrease, though, and
456 yield at least 1 if any thread calls this function.
457 */
458 burn_global_abort_level++;
459 burn_global_abort_signum= signum;
460
461 if(getpid() != abort_control_pid) {
462
463 #ifdef Libburn_new_thread_signal_handleR
464
465 ret = burn_drive_find_by_thread_pid(&d, getpid(),
466 pthread_self());
467 if (ret > 0 && d->busy == BURN_DRIVE_WRITING) {
468 /* This is an active writer thread */
469
470 #ifdef Libburn_signal_handler_verbouS
471 fprintf(stderr, "libburn_ABORT: pid %d found drive busy with writing, (level= %d)\n", (int) getpid(), burn_global_abort_level);
472 #endif
473
474 d->sync_cache(d);
475
476 /* >>> perform a more qualified end of burn process */;
477
478 d->busy = BURN_DRIVE_IDLE;
479
480 if (burn_global_abort_level > 0) {
481 /* control process did not show up yet */
482 #ifdef Libburn_signal_handler_verbouS
483 fprintf(stderr, "libburn_ABORT: pid %d sending signum %d to pid %d\n", (int) getpid(), (int) signum, (int) abort_control_pid);
484 #endif
485 kill(abort_control_pid, signum);
486 }
487
488 #ifdef Libburn_signal_handler_verbouS
489 fprintf(stderr, "libburn_ABORT: pid %d signum %d returning -2\n", (int) getpid(), (int) signum);
490 #endif
491
492 return -2;
493 } else {
494 usleep(1000000); /* calm down */
495 return -2;
496 }
497
498 #else
499 usleep(1000000); /* calm down */
500 return -2;
501 #endif /* ! Libburn_new_thread_signal_handleR */
502
503 }
504 burn_global_abort_level = -1;
505 Cleanup_set_handlers(NULL, NULL, 2);
506
507 fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
508 abort_message_prefix);
509 fprintf(stderr,
510 "%sABORT : Wait the normal burning time before any kill -9\n",
511 abort_message_prefix);
512 close(0); /* somehow stdin as input blocks abort until EOF */
513
514 burn_abort_exit(0);
515 return (1);
516 }
517
518
519 /* ts A61002 : API */
burn_set_signal_handling(void * handle,burn_abort_handler_t handler,int mode)520 void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
521 int mode)
522 {
523
524 /*
525 fprintf(stderr, "libburn_experimental: burn_set_signal_handling, handler==%lx mode=%d\n", (unsigned long) handler, mode);
526 */
527
528 if(handler == NULL) {
529 handler = burn_builtin_abort_handler;
530 /*
531 if ((mode & ~4) == 0)
532 fprintf(stderr, "libburn_experimental: activated burn_builtin_abort_handler() with handle '%s'\n",(handle==NULL ? "libburn : " : (char *) handle));
533 */
534
535 }
536 strcpy(abort_message_prefix, "libburn : ");
537 abort_message_prefix[0] = 0;
538 if(handle != NULL && handler == burn_builtin_abort_handler)
539 strncpy(abort_message_prefix, (char *) handle,
540 sizeof(abort_message_prefix)-1);
541 abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
542 abort_control_pid = getpid();
543 abort_control_thread = pthread_self();
544 burn_builtin_signal_action = (mode >> 4) & 15;
545 if((mode & 11) != 0)
546 burn_builtin_signal_action = 0;
547 if(burn_builtin_signal_action > 1)
548 burn_builtin_triggered_action = 0;
549 if(burn_builtin_signal_action == 0)
550 burn_builtin_signal_action = 1;
551 Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler,
552 (mode & 15) | 4 | (mode & 256));
553 burn_global_signal_handle = handle;
554 burn_global_signal_handler = handler;
555 }
556
557
558 /* ts B00304 : API */
burn_is_aborting(int flag)559 int burn_is_aborting(int flag)
560 {
561 return burn_builtin_triggered_action;
562 }
563
564
565 /* ts B00225 */
566 /* @return 0= no abort action 2 pending , 1= not control thread
567 */
burn_init_catch_on_abort(int flag)568 int burn_init_catch_on_abort(int flag)
569 {
570 if (burn_builtin_triggered_action != 2)
571 return 0;
572 if (abort_control_pid != getpid() ||
573 abort_control_thread != pthread_self())
574 return 1;
575 burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
576 fprintf(stderr,
577 "\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
578 abort_message_prefix);
579 exit(1);
580 }
581
582
583 /* B20122 */
584 /* Temporarily disable builtin actions 0,1,2 to avoid that burn_abort()
585 waits for its own thread to end grabbing.
586 */
burn_grab_prepare_sig_action(int * signal_action_mem,int flag)587 int burn_grab_prepare_sig_action(int *signal_action_mem, int flag)
588 {
589 *signal_action_mem = -1;
590 if (burn_global_signal_handler == burn_builtin_abort_handler &&
591 burn_builtin_signal_action >= 0 &&
592 burn_builtin_signal_action <= 2) {
593 *signal_action_mem = burn_builtin_signal_action;
594 burn_builtin_signal_action = 3;
595 }
596 return 1;
597 }
598
599
600 /* B20122 */
601 /* Re-enable builtin actions 0,1,2 and perform delayed signal reactions
602 */
burn_grab_restore_sig_action(int signal_action_mem,int flag)603 int burn_grab_restore_sig_action(int signal_action_mem, int flag)
604 {
605 if (signal_action_mem >= 0)
606 burn_builtin_signal_action = signal_action_mem;
607 if (burn_is_aborting(0) && signal_action_mem >= 0) {
608 if (signal_action_mem == 0 || signal_action_mem == 1) {
609 burn_abort_exit(1); /* Never comes back */
610 } else if (signal_action_mem == 2) {
611 burn_builtin_triggered_action = signal_action_mem;
612 }
613 }
614 return 1;
615 }
616
617
618 /* ts A70223 : API */
burn_allow_untested_profiles(int yes)619 void burn_allow_untested_profiles(int yes)
620 {
621 burn_support_untested_profiles = !!yes;
622 }
623
624
625 /* ts A70915 : API */
burn_set_messenger(void * messenger)626 int burn_set_messenger(void *messenger)
627 {
628 struct libdax_msgs *pt;
629
630 if (libdax_msgs_refer(&pt, messenger, 0) <= 0)
631 return 0;
632 libdax_msgs_destroy(&libdax_messenger, 0);
633 libdax_messenger = (struct libdax_msgs *) pt;
634 return 1;
635 }
636
637
638 /* ts A91111 API */
burn_set_scsi_logging(int flag)639 void burn_set_scsi_logging(int flag)
640 {
641 burn_sg_log_scsi = flag & 7;
642 }
643
644
645 /* ts B10312 API */
burn_allow_drive_role_4(int allowed)646 void burn_allow_drive_role_4(int allowed)
647 {
648 burn_drive_role_4_allowed = (allowed & 0xf);
649 }
650
651
652 /* ts B10606 */
burn_alloc_mem(size_t size,size_t count,int flag)653 void *burn_alloc_mem(size_t size, size_t count, int flag)
654 {
655 void *pt;
656
657 pt = calloc(count, size);
658 if(pt == NULL)
659 libdax_msgs_submit(libdax_messenger, -1, 0x00000003,
660 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
661 "Out of virtual memory", 0, 0);
662 return pt;
663 }
664
665