init.c 15.4 KB
Newer Older
Mario Danic's avatar
Mario Danic committed
1 2
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */

3 4 5 6 7
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
   Copyright (c) 2006 - 2010 Thomas Schmitt <scdbackup@gmx.net>
   Provided under GPL version 2 or later.
*/

8 9 10 11
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif

12

Mario Danic's avatar
Mario Danic committed
13
#include <unistd.h>
14 15 16 17

/* ts A61007 */
/* #include <a ssert.h> */

Mario Danic's avatar
Mario Danic committed
18 19
#include <stdio.h>
#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
Mario Danic's avatar
Mario Danic committed
25
#include "init.h"
26 27 28
*/


Mario Danic's avatar
Mario Danic committed
29 30 31 32
#include "sg.h"
#include "error.h"
#include "libburn.h"
#include "drive.h"
33
#include "transport.h"
Mario Danic's avatar
Mario Danic committed
34

35 36 37 38
/* ts A60825 : The storage location for back_hacks.h variables. */
#define BURN_BACK_HACKS_INIT 1
#include "back_hacks.h"

39 40
/* ts A60924 : a new message handling facility */
#include "libdax_msgs.h"
41
struct libdax_msgs *libdax_messenger= NULL;
42 43


Mario Danic's avatar
Mario Danic committed
44 45
int burn_running = 0;

46 47 48
/* ts A60813 : GNU/Linux: whether to use O_EXCL on open() of device files
   ts B00212 : FreeBSD:   whether to use flock(LOCK_EX) after open()
*/
49 50
int burn_sg_open_o_excl = 1;

51
/* ts A70403 : GNU/Linux: wether to use fcntl(,F_SETLK,)
52 53 54
                      after open() of device files  */
int burn_sg_fcntl_f_setlk = 1;

55
/* ts A70314 : GNU/Linux: what device family to use :
56 57 58 59 60 61 62 63
    0= default family
    1= sr
    2= scd
   (3= st)
    4= sg
*/
int burn_sg_use_family = 0;

64 65 66 67 68 69 70 71 72 73 74
/* O_NONBLOCK was hardcoded in enumerate_ata() which i hardly use.
   For enumerate_sg() it seems ok.
   So it should stay default mode until enumerate_ata() without O_NONBLOCK
   has been thoroughly tested. */
int burn_sg_open_o_nonblock = 1;

/* wether to take a busy drive as an error */
/* Caution: this is implemented by a rough hack and eventually leads
	    to unconditional abort of the process  */
int burn_sg_open_abort_busy = 0;

75

76
/* The message returned from sg_id_string() and/or sg_initialize()
77
*/
78
static char sg_initialize_msg[1024] = {""};
79 80


81 82 83 84 85 86 87
/* ts A61002 */

#include "cleanup.h"

/* Parameters for builtin abort handler */
static char abort_message_prefix[81] = {"libburn : "};
static pid_t abort_control_pid= 0;
88
static pthread_t abort_control_thread;
89 90 91 92
volatile int burn_global_abort_level= 0;
int burn_global_abort_signum= 0;
void *burn_global_signal_handle = NULL;
burn_abort_handler_t burn_global_signal_handler = NULL;
93 94
int burn_builtin_signal_action = 0;            /* burn_set_signal_handling() */
volatile int burn_builtin_triggered_action = 0;       /*  burn_is_aborting() */
95 96


97 98 99
/* ts A70223 : wether implemented untested profiles are supported */
int burn_support_untested_profiles = 0;

100 101 102 103 104 105 106
/* ts A91111 :
   whether to log SCSI commands (to be implemented in sg-*.c)
   bit0= log in /tmp/libburn_sg_command_log
   bit1= log to stderr
   bit2= flush every line
*/
int burn_sg_log_scsi = 0;
107

108 109 110 111 112 113
/* ts A60925 : ticket 74 */
/** Create the messenger object for libburn. */
int burn_msgs_initialize(void)
{
	int ret;

114
	if(libdax_messenger == NULL) {
115
		ret = libdax_msgs_new(&libdax_messenger,0);
116 117 118
		if (ret <= 0)
			return 0;
	}
119 120 121 122 123
	libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
				   LIBDAX_MSGS_SEV_FATAL, "libburn: ", 0);
	return 1;
}

124
/* ts A60924 : ticket 74 : Added use of global libdax_messenger */
Mario Danic's avatar
Mario Danic committed
125 126
int burn_initialize(void)
{
127 128
	int ret;

Mario Danic's avatar
Mario Danic committed
129 130
	if (burn_running)
		return 1;
131
	burn_support_untested_profiles = 0;
132
	ret = burn_msgs_initialize();
133 134
	if (ret <= 0)
		return 0;
135 136 137 138 139 140 141 142
	ret = sg_initialize(sg_initialize_msg, 0);
	if (ret <= 0) {
                libdax_msgs_submit(libdax_messenger, -1,
                        0x00020175,
                        LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
                        sg_initialize_msg, 0, 0);
		return 0;
	}
Mario Danic's avatar
Mario Danic committed
143 144 145 146 147 148
	burn_running = 1;
	return 1;
}

void burn_finish(void)
{
149 150 151 152
	/* ts A61007 : assume no messageing system */
	/* a ssert(burn_running); */
	if (!burn_running)
		return;
Mario Danic's avatar
Mario Danic committed
153

154 155
	/* ts A61007 */
	/* burn_wait_all(); */
156
	if (!burn_drives_are_clear(0)) {
157
		libdax_msgs_submit(libdax_messenger, -1, 0x00020107,
158 159 160 161
			LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
			"A drive is still busy on shutdown of library", 0, 0);
		usleep(1000001);
		burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
162
	}
Mario Danic's avatar
Mario Danic committed
163

164 165
	/* ts A60904 : ticket 62, contribution by elmom : name addon "_all" */
	burn_drive_free_all();
Mario Danic's avatar
Mario Danic committed
166

167 168 169
	/* ts A60924 : ticket 74 */
	libdax_msgs_destroy(&libdax_messenger,0);

170 171
	sg_shutdown(0);

Mario Danic's avatar
Mario Danic committed
172 173
	burn_running = 0;
}
174

175 176

/* ts A91226 */
177 178 179
/** API function. See libburn.h */
char *burn_scsi_transport_id(int flag)
{
180 181
	if (!burn_running)
		sg_id_string(sg_initialize_msg, 0);
182 183 184
	return sg_initialize_msg;
}

185 186

/* ts A60813 */
187
/** API function. See libburn.h */
188 189
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
{
190 191 192 193
	/* ts A61007 */
	/* a ssert(burn_running); */
	if (!burn_running)
		return;	
194 195
	burn_sg_open_o_excl = exclusive & 3;
	burn_sg_fcntl_f_setlk = !!(exclusive & 32);
196
	burn_sg_use_family = (exclusive >> 2) & 7;
197 198
	burn_sg_open_o_nonblock = !blocking;
	burn_sg_open_abort_busy = !!abort_on_busy;
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

/* ts A60924 : ticket 74 */
/** Control queueing and stderr printing of messages from libburn.
    Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
    "NOTE", "UPDATE", "DEBUG", "ALL".
    @param queue_severity Gives the minimum limit for messages to be queued.
                          Default: "NEVER". If you queue messages then you
                          must consume them by burn_msgs_obtain().
    @param print_severity Does the same for messages to be printed directly
                          to stderr.
    @param print_id       A text prefix to be printed before the message.
    @return               >0 for success, <=0 for error

*/
int burn_msgs_set_severities(char *queue_severity,
                             char *print_severity, char *print_id)
{
	int ret, queue_sevno, print_sevno;

	ret = libdax_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
	if (ret <= 0)
		return 0;
	ret = libdax_msgs__text_to_sev(print_severity, &print_sevno, 0);
	if (ret <= 0)
		return 0;
	ret = libdax_msgs_set_severities(libdax_messenger, queue_sevno,
					 print_sevno, print_id, 0);
	if (ret <= 0)
		return 0;
	return 1;
}


/* ts A60924 : ticket 74 */
#define BURM_MSGS_MESSAGE_LEN 4096

/** Obtain the oldest pending libburn message from the queue which has at
    least the given minimum_severity. This message and any older message of
    lower severity will get discarded from the queue and is then lost forever.
    Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
    "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
    will discard the whole queue.
    @param error_code Will become a unique error code as liste in 
                      libburn/libdax_msgs.h
    @param msg_text   Must provide at least BURM_MSGS_MESSAGE_LEN bytes.
    @param os_errno   Will become the eventual errno related to the message
    @param severity   Will become the severity related to the message and
                      should provide at least 80 bytes.
    @return 1 if a matching item was found, 0 if not, <0 for severe errors
*/
int burn_msgs_obtain(char *minimum_severity,
                     int *error_code, char msg_text[], int *os_errno,
                     char severity[])
{
	int ret, minimum_sevno, sevno, priority;
	char *textpt, *sev_name;
	struct libdax_msgs_item *item = NULL;

	ret = libdax_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
	if (ret <= 0)
		return 0;
262 263
	if (libdax_messenger == NULL)
		return 0;
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
	ret = libdax_msgs_obtain(libdax_messenger, &item, minimum_sevno,
				LIBDAX_MSGS_PRIO_ZERO, 0);
	if (ret <= 0)
		goto ex;
	ret = libdax_msgs_item_get_msg(item, error_code, &textpt, os_errno, 0);
	if (ret <= 0)
		goto ex;
	strncpy(msg_text, textpt, BURM_MSGS_MESSAGE_LEN-1);
	if(strlen(textpt) >= BURM_MSGS_MESSAGE_LEN)
		msg_text[BURM_MSGS_MESSAGE_LEN-1] = 0;

	severity[0]= 0;
	ret = libdax_msgs_item_get_rank(item, &sevno, &priority, 0);
	if(ret <= 0)
		goto ex;
	ret = libdax_msgs__sev_to_text(sevno, &sev_name, 0);
	if(ret <= 0)
		goto ex;
	strcpy(severity,sev_name);

	ret = 1;
ex:
	libdax_msgs_destroy_item(libdax_messenger, &item, 0);
	return ret;
}

290 291 292 293 294 295 296 297 298

/* ts A70922 : API */
int burn_msgs_submit(int error_code, char msg_text[], int os_errno,
			char severity[], struct burn_drive *d)
{
	int ret, sevno, global_index = -1;

	ret = libdax_msgs__text_to_sev(severity, &sevno, 0);
	if (ret <= 0)
299
		sevno = LIBDAX_MSGS_SEV_ALL;
300 301 302 303 304 305 306 307 308 309
	if (error_code <= 0) {
		switch(sevno) {
		       case LIBDAX_MSGS_SEV_ABORT:   error_code = 0x00040000;
		break; case LIBDAX_MSGS_SEV_FATAL:   error_code = 0x00040001;
		break; case LIBDAX_MSGS_SEV_SORRY:   error_code = 0x00040002;
		break; case LIBDAX_MSGS_SEV_WARNING: error_code = 0x00040003;
		break; case LIBDAX_MSGS_SEV_HINT:    error_code = 0x00040004;
		break; case LIBDAX_MSGS_SEV_NOTE:    error_code = 0x00040005;
		break; case LIBDAX_MSGS_SEV_UPDATE:  error_code = 0x00040006;
		break; case LIBDAX_MSGS_SEV_DEBUG:   error_code = 0x00040007;
310
		break; default:                      error_code = 0x00040008;
311 312 313 314 315 316 317 318 319 320
		}
	}
	if (d != NULL)
		global_index = d->global_index;
	ret = libdax_msgs_submit(libdax_messenger, global_index, error_code,
			sevno, LIBDAX_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
	return ret;
}


321 322 323 324 325 326 327 328 329 330
/* ts A71016 API */
int burn_text_to_sev(char *severity_name, int *sevno, int flag)
{
	int ret;

	ret = libdax_msgs__text_to_sev(severity_name, sevno, 0);
	return ret;
}


331 332 333 334 335 336 337 338 339
/* ts A80202 API */
int burn_sev_to_text(int severity_number, char **severity_name, int flag)
{
	int ret;

	ret = libdax_msgs__sev_to_text(severity_number, severity_name, 0);
	return ret;
}

340 341 342 343 344
/* ts B00224 */
char *burn_util_thread_id(pid_t pid, pthread_t tid, char text[80])
{
	int i, l;

345
	sprintf(text, "[%lu,", (unsigned long int) getpid());
346 347 348 349 350 351 352 353
	l= strlen(text);
	for(i= 0; i < sizeof(pthread_t) && 2 * i < 80 - l - 3; i++)
		sprintf(text + l + 2 * i,
			 "%2.2X", ((unsigned char *) &tid)[i]);

	sprintf(text + l + 2 * i, "]");
	return text;
}
354

355 356
int burn_builtin_abort_handler(void *handle, int signum, int flag)
{
357

358
#define Libburn_new_thread_signal_handleR 1
359
/*
360
#define Libburn_signal_handler_verbouS 1
361
*/
362

363 364
	int ret;
	struct burn_drive *d;
365

366
#ifdef Libburn_signal_handler_verbouS
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
	char text[80];

	fprintf(stderr, "libburn_ABORT: in = %s\n",
		burn_util_thread_id(getpid(), pthread_self(), text));
	fprintf(stderr, "libburn_ABORT: ctrl = %s\n",
		burn_util_thread_id(abort_control_pid, abort_control_thread,
					text));
	if (burn_global_signal_handler == burn_builtin_abort_handler)
		fprintf(stderr, "libburn_ABORT: signal action = %d\n",
				burn_builtin_signal_action);

	/* >>> find writing drives and report their tid
	fprintf(stderr, "libburn_ABORT: wrt = %s\n",
		burn_util_thread_id(0, burn_write_thread_id, text));
	fprintf(stderr, "libburn_ABORT: sig= %d\n", signum);
	*/
383
#endif
384

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
	burn_builtin_triggered_action = burn_builtin_signal_action;
	burn_global_abort_level = -1;

	if (burn_builtin_signal_action > 1) {
		Cleanup_set_handlers(NULL, NULL, 2);
		if (burn_builtin_signal_action == 4)
			return -2;
		fprintf(stderr,"%sABORT : Trying to shut down busy drives\n",
			abort_message_prefix);
		fprintf(stderr,
		 "%sABORT : Wait the normal burning time before any kill -9\n",
		 	abort_message_prefix);
		burn_abort_5(0, burn_abort_pacifier, abort_message_prefix,
				0, 1);
		libdax_msgs_submit(libdax_messenger, -1, 0x00020177,
			LIBDAX_MSGS_SEV_ABORT, LIBDAX_MSGS_PRIO_HIGH,
			"Urged drive worker threads to do emergency halt",
			0, 0);
		return -2;
	}


	/* ---- old deprecated stuck-in-abort-handler loop ---- */

409 410 411 412 413 414 415
	/* ts A70928:
	Must be quick. Allowed to coincide with other thread and to share
	the increment with that one. It must not decrease, though, and
	yield at least 1 if any thread calls this function.
	*/
	burn_global_abort_level++;
	burn_global_abort_signum= signum;
416

417
	if(getpid() != abort_control_pid) {
418

419
#ifdef Libburn_new_thread_signal_handleR
420

421 422
		ret = burn_drive_find_by_thread_pid(&d, getpid(),
							pthread_self());
423 424
		if (ret > 0 && d->busy == BURN_DRIVE_WRITING) {
					/* This is an active writer thread */
425 426

#ifdef Libburn_signal_handler_verbouS
427
			fprintf(stderr, "libburn_ABORT: pid %d found drive busy with writing, (level= %d)\n", (int) getpid(), burn_global_abort_level);
428
#endif
429 430

			d->sync_cache(d);
431

432
			/* >>> perform a more qualified end of burn process */;
433

434 435 436 437
			d->busy = BURN_DRIVE_IDLE;

			if (burn_global_abort_level > 0) {
				/* control process did not show up yet */
438
#ifdef Libburn_signal_handler_verbouS
439
					fprintf(stderr, "libburn_ABORT: pid %d sending signum %d to pid %d\n", (int) getpid(), (int) signum, (int) abort_control_pid);
440
#endif
441 442
					kill(abort_control_pid, signum);
			}
443 444 445 446 447

#ifdef Libburn_signal_handler_verbouS
					fprintf(stderr, "libburn_ABORT: pid %d signum %d returning -2\n", (int) getpid(), (int) signum);
#endif

448
			return -2;
449 450 451
		} else {
			usleep(1000000); /* calm down */
			return -2;
452
		}
453 454 455

#else
		usleep(1000000); /* calm down */
456
		return -2;
457
#endif /* ! Libburn_new_thread_signal_handleR */
458 459

	}
460
	burn_global_abort_level = -1;
461
	Cleanup_set_handlers(NULL, NULL, 2);
462

463 464 465 466 467 468 469
	fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
		abort_message_prefix);
	fprintf(stderr,
		"%sABORT : Wait the normal burning time before any kill -9\n",
		abort_message_prefix);
	close(0); /* somehow stdin as input blocks abort until EOF */
	burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
470

471 472 473
	fprintf(stderr,
	"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
		abort_message_prefix);
474
	burn_global_abort_level = -2;
475 476 477
	return(1);
}

478 479

/* ts A61002 : API */
480
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
481
				int mode)
482
{
483 484 485 486 487 488

/*
	fprintf(stderr, "libburn_experimental: burn_set_signal_handling, handler==%lx  mode=%d\n", (unsigned long) handler, mode);
*/

	if(handler == NULL) {
489 490
		handler = burn_builtin_abort_handler;
/*
491 492
		if ((mode & ~4) == 0)
			fprintf(stderr, "libburn_experimental: activated burn_builtin_abort_handler() with handle '%s'\n",(handle==NULL ? "libburn : " : (char *) handle));
493 494 495 496
*/

	}
	strcpy(abort_message_prefix, "libburn : ");
497 498
	abort_message_prefix[0] = 0;
	if(handle != NULL && handler == burn_builtin_abort_handler)
499 500 501
		strncpy(abort_message_prefix, (char *) handle,
			sizeof(abort_message_prefix)-1);
	abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
502
	abort_control_pid = getpid();
503 504 505 506 507 508 509 510 511 512
	abort_control_thread = pthread_self();
	burn_builtin_signal_action = (mode >> 4) & 15;
	if((mode & 11) != 0)
		burn_builtin_signal_action = 0;
	if(burn_builtin_signal_action > 1)
		burn_builtin_triggered_action = 0;
	if(burn_builtin_signal_action == 0)
		burn_builtin_signal_action = 1;
	Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler,
				 (mode & 15) | 4);
513 514
	burn_global_signal_handle = handle;
	burn_global_signal_handler = handler;
515 516
}

517

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
/* ts B00304 : API */
int burn_is_aborting(int flag)
{
	return burn_builtin_triggered_action;
}


/* ts B00225 */
/* @return 0= no abort action 2 pending , 1= not control thread
*/
int burn_init_catch_on_abort(int flag)
{
	if (burn_builtin_triggered_action != 2)
		return 0;
	if (abort_control_pid != getpid() ||
		abort_control_thread != pthread_self())
		return 1;
	burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
	fprintf(stderr,
	"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
		abort_message_prefix);
	exit(1);
}


543 544 545 546 547 548
/* ts A70223 : API */
void burn_allow_untested_profiles(int yes)
{
	burn_support_untested_profiles = !!yes;
}

549 550 551 552

/* ts A70915 : API */
int burn_set_messenger(void *messenger)
{
553 554 555 556 557 558
	struct libdax_msgs *pt;

	if (libdax_msgs_refer(&pt, messenger, 0) <= 0)
		return 0;
	libdax_msgs_destroy(&libdax_messenger, 0);
	libdax_messenger = (struct libdax_msgs *) pt;
559 560 561
	return 1;
}

562 563 564 565 566 567

/* ts A91111 API */
void burn_set_scsi_logging(int flag)
{
	burn_sg_log_scsi = flag & 7;
}