mce.c 25.6 KB
Newer Older
1 2 3 4
/**
 * @file mce.c
 * Mode Control Entity - main file
 * <p>
Santtu Lakkala's avatar
Santtu Lakkala committed
5
 * Copyright © 2004-2011 Nokia Corporation and/or its subsidiary(-ies).
6
 * Copyright (C) 2012-2017 Jolla Ltd.
7 8
 * <p>
 * @author David Weinehall <david.weinehall@nokia.com>
9 10 11
 * @author Tapio Rantala <ext-tapio.rantala@nokia.com>
 * @author Santtu Lakkala <ext-santtu.1.lakkala@nokia.com>
 * @author Simo Piiroinen <simo.piiroinen@jollamobile.com>
12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * mce is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * mce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with mce.  If not, see <http://www.gnu.org/licenses/>.
 */

26
#include "mce.h"
27
#include "mce-io.h"
28
#include "mce-log.h"
29
#include "mce-common.h"
30
#include "mce-conf.h"
31
#include "mce-fbdev.h"
32
#include "mce-hbtimer.h"
33
#include "mce-wltimer.h"
34
#include "mce-setting.h"
35 36 37 38
#include "mce-dbus.h"
#include "mce-dsme.h"
#include "mce-modules.h"
#include "mce-command-line.h"
39
#include "mce-sensorfw.h"
40
#include "mce-wakelock.h"
41
#include "mce-worker.h"
42 43 44 45 46 47 48 49
#include "tklock.h"
#include "powerkey.h"
#include "event-input.h"
#include "event-switches.h"
#include "modetransition.h"
#ifdef ENABLE_WAKELOCKS
# include "libwakelock.h"
#endif
50

51 52 53 54 55 56 57 58
#include <sys/stat.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
59

60 61
#include <systemd/sd-daemon.h>

62 63 64 65 66 67 68
/** Path to the lockfile */
#define MCE_LOCKFILE			"/var/run/mce.pid"
/** Name shown by --help etc. */
#define PRG_NAME			"mce"

static const gchar *progname;	/**< Used to store the name of the program */

69 70 71
/** The GMainLoop used by MCE */
static GMainLoop *mainloop = 0;

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
/** Wrapper for write() for use when we do not care if it works or not
 *
 * Main purpose is to stop static analyzers from nagging us when
 * we really do not care whether the data gets written or not
 *
 * @param fd   file descriptor to write to
 * @param data data to write
 * @param size amount of data to write
 */
static void no_error_check_write(int fd, const void *data, size_t size)
{
	// do the write, then ...
	ssize_t rc = TEMP_FAILURE_RETRY(write(fd, data, size));
	// try to silence static analyzers by doing /something/ with rc
	if( rc == -1 )
		rc = rc;
}

90 91
void mce_quit_mainloop(void)
{
92
#ifdef ENABLE_WAKELOCKS
93 94
	/* We are on exit path -> block suspend for good */
	wakelock_block_suspend_until_exit();
95
#endif
96 97 98

	/* Exit immediately if there is no mainloop to terminate */
	if( !mainloop ) {
spiiroin's avatar
spiiroin committed
99
		exit(EXIT_FAILURE);
100 101 102 103 104 105
	}

	/* Terminate mainloop */
	g_main_loop_quit(mainloop);
}

106 107 108 109 110 111 112 113
#ifdef ENABLE_WAKELOCKS
/** Disable automatic suspend and remove wakelocks mce might hold
 *
 * This function should be called just before mce process terminates
 * so that we do not leave the system in a non-functioning state
 */
static void mce_cleanup_wakelocks(void)
{
114 115 116
	/* We are on exit path -> block suspend for good */
	wakelock_block_suspend_until_exit();

117 118
	wakelock_unlock("mce_display_on");
	wakelock_unlock("mce_input_handler");
119
	wakelock_unlock("mce_cpu_keepalive");
120
	wakelock_unlock("mce_display_stm");
121
	wakelock_unlock("mce_powerkey_stm");
122
	wakelock_unlock("mce_proximity_stm");
123
	wakelock_unlock("mce_bluez_wait");
124
	wakelock_unlock("mce_led_breathing");
125
	wakelock_unlock("mce_lpm_off");
126
	wakelock_unlock("mce_tklock_notify");
127
	wakelock_unlock("mce_hbtimer_dispatch");
128
	wakelock_unlock("mce_inactivity_notify");
129 130 131 132 133 134 135 136 137 138
}
#endif // ENABLE_WAKELOCKS

/** Disable autosuspend then exit via default signal handler
 *
 * @param signr the signal to exit through
 */
static void mce_exit_via_signal(int signr) __attribute__((noreturn));
static void mce_exit_via_signal(int signr)
{
spiiroin's avatar
spiiroin committed
139 140 141 142 143
	sigset_t ss;

	sigemptyset(&ss);
	sigaddset(&ss, SIGALRM);

144 145 146
	/* Give us N seconds to exit */
	signal(SIGALRM, SIG_DFL);
	alarm(3);
spiiroin's avatar
spiiroin committed
147
	sigprocmask(SIG_UNBLOCK, &ss, 0);
148

spiiroin's avatar
spiiroin committed
149 150 151
#ifdef ENABLE_WAKELOCKS
	/* Cancel auto suspend */
	mce_cleanup_wakelocks();
152
	mce_wakelock_abort();
spiiroin's avatar
spiiroin committed
153 154
#endif
	/* Try to exit via default handler */
155
	signal(signr, SIG_DFL);
spiiroin's avatar
spiiroin committed
156 157
	sigaddset(&ss, signr);
	sigprocmask(SIG_UNBLOCK, &ss, 0);
158
	raise(signr);
spiiroin's avatar
spiiroin committed
159 160

	/* Or just abort as the last resort*/
161 162 163 164 165 166 167 168 169 170
	abort();
}

/** Suspend safe replacement for _exit(1), abort() etc
 */
void mce_abort(void)
{
	mce_exit_via_signal(SIGABRT);
}

171 172
static void mce_tx_signal_cb(int sig);

173 174 175 176 177 178 179 180 181
/**
 * Signal handler
 *
 * @param signr Signal type
 */
static void signal_handler(const gint signr)
{
	switch (signr) {
	case SIGUSR1:
182 183 184 185 186 187 188 189 190 191
		/* switch to debug verbosity */
		mce_log_set_verbosity(LL_DEBUG);
		mce_log(LL_DEBUG, "switching to DEBUG verbosity level");
		break;

	case SIGUSR2:
		/* switch to normal verbosity */
		mce_log_set_verbosity(LL_DEBUG);
		mce_log(LL_DEBUG, "switching to WARNING verbosity level");
		mce_log_set_verbosity(LL_WARN);
192 193 194 195 196 197
		break;

	case SIGHUP:
		/* Possibly for re-reading configuration? */
		break;

198 199
	case SIGINT:
	case SIGQUIT:
200
	case SIGTERM:
201 202 203 204 205 206
		/* Just die if we somehow get here without having a mainloop */
		if( !mainloop ) {
			mce_exit_via_signal(signr);
		}

		/* Terminate mainloop */
207
		mce_quit_mainloop();
208 209 210 211
		break;

	default:
		/* Should never happen */
212
		mce_log(LL_WARN, "stray signal %d received in mainloop", signr);
213 214 215 216
		break;
	}
}

217 218
/** Array of signals that should be ignored */
static const int mce_signals_to_ignore[] =
219
{
220 221
	/* We want error return from write() & co, not a signal */
	SIGPIPE,
222

223 224 225 226 227 228
	/* Ignore tty signals even if mce is run from terminal */
	SIGTSTP,
	SIGTTOU,
	SIGTTIN,
	-1
};
229

230 231 232
/** Array of signals that should terminate mce */
static const int mce_signals_to_exit_on[] =
{
233
#ifdef ENABLE_WAKELOCKS
234 235 236 237 238 239 240
	SIGABRT,
	SIGILL,
	SIGFPE,
	SIGSEGV,
	SIGALRM,
	SIGBUS,
	SIGTSTP,
241
#endif
242 243
	-1
};
244

245 246 247 248 249 250 251 252 253
/** Array of signals that should be trapped */
static const int mce_signals_to_trap[] =
{
	SIGUSR1,
	SIGUSR2,
	SIGHUP,
	SIGINT,
	SIGQUIT,
	SIGTERM,
254 255 256 257 258 259 260
	-1
};

/** Install handlers for signals we need to trap
 */
static void mce_signal_handlers_install(void)
{
261 262 263 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
	struct sigaction sa;

	/* Signals that are completely ignored */
	for( size_t i = 0; mce_signals_to_ignore[i] != -1; ++i )
		signal(mce_signals_to_ignore[i], SIG_IGN);

	/* Unrecoverable situations that require immediate exit,
	 * but we should still attempt to disable autosuspend
	 * and clean up wakelocks: Reset default behavior when
	 * triggered and do not block while attempting to handle.
	 */

	memset(&sa, 0, sizeof sa);
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = mce_tx_signal_cb;
	sa.sa_flags   = SA_RESETHAND | SA_NODEFER;

	for( size_t i = 0; mce_signals_to_exit_on[i] != -1; ++i )
		sigaction(mce_signals_to_exit_on[i], &sa, 0);

	/* Signals that should be ok to handle via mainloop */

	memset(&sa, 0, sizeof sa);
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = mce_tx_signal_cb;
	sa.sa_flags   = SA_RESTART;

	for( size_t i = 0; mce_signals_to_trap[i] != -1; ++i )
		sigaction(mce_signals_to_trap[i], &sa, 0);
290
}
291

292 293 294 295
/** Restore default handlers for trapped signals
 */
void mce_signal_handlers_remove(void)
{
296 297 298 299 300 301 302
	for( size_t i = 0; mce_signals_to_ignore[i] != -1; ++i )
		signal(mce_signals_to_ignore[i], SIG_DFL);

	for( size_t i = 0; mce_signals_to_exit_on[i] != -1; ++i )
		signal(mce_signals_to_exit_on[i], SIG_DFL);

	for( size_t i = 0; mce_signals_to_trap[i] != -1; ++i )
303
		signal(mce_signals_to_trap[i], SIG_DFL);
304 305 306 307 308
}

/** Pipe used for transferring signals out of signal handler context */
static int signal_pipe[2] = {-1, -1};

309 310 311
/** I/O watch id for signal_pipe */
static guint signal_pipe_id = 0;

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
/** GIO callback for reading signals from pipe
 *
 * @param channel   io channel for signal pipe
 * @param condition call reason
 * @param data      user data
 *
 * @return TRUE (or aborts on error)
 */
static gboolean mce_rx_signal_cb(GIOChannel *channel,
				 GIOCondition condition, gpointer data)
{
	// we just want the cb ...
	(void)channel; (void)condition; (void)data;

	int sig = 0;
	int got = TEMP_FAILURE_RETRY(read(signal_pipe[0], &sig, sizeof sig));

	if( got != sizeof sig ) {
		mce_abort();
	}

	/* handle the signal */
	signal_handler(sig);

	/* keep the io watch */
	return TRUE;
}

/** Signal handler callback for writing signals to pipe
 *
 * @param sig the signal number to pass to mainloop via pipe
 */
static void mce_tx_signal_cb(int sig)
{
	/* NOTE: this function must be kept async-signal-safe! */

	static volatile int exit_tries = 0;

	static const char msg[] = "\n*** BREAK ***\n";
spiiroin's avatar
spiiroin committed
351
	static const char die[] = "\n*** UNRECOVERABLE FAILURE ***\n";
352 353 354

	switch( sig )
	{
355 356 357 358 359 360
	case SIGUSR1:
	case SIGUSR2:
	case SIGHUP:
		/* Just pass to mainloop */
		break;

361 362 363
	case SIGINT:
	case SIGQUIT:
	case SIGTERM:
spiiroin's avatar
spiiroin committed
364 365 366 367
		/* Make sure that a stuck or non-existing mainloop does
		 * not stop us from handling at least repeated terminating
		 signals ... */

368
#ifdef ENABLE_WAKELOCKS
369 370
		/* We are on exit path -> block suspend for good */
		wakelock_block_suspend_until_exit();
371
#endif
372

373 374 375 376 377 378
		no_error_check_write(STDERR_FILENO, msg, sizeof msg - 1);

		if( !mainloop || ++exit_tries >= 2 ) {
			mce_abort();
		}
		break;
spiiroin's avatar
spiiroin committed
379

380 381 382 383
	default:
		/* Assume unrecoverable failure that can't be handled in
		 * the mainloop - disable autosuspend and then terminate
		 * via default signal handler. */
spiiroin's avatar
spiiroin committed
384 385 386
		no_error_check_write(STDERR_FILENO, die, sizeof die - 1);
		mce_exit_via_signal(sig);
		break;
387 388 389 390 391 392 393 394 395 396
	}

	/* transfer the signal to mainloop via pipe */
	int did = TEMP_FAILURE_RETRY(write(signal_pipe[1], &sig, sizeof sig));

	if( did != (int)sizeof sig ) {
		mce_abort();
	}
}

397 398 399 400 401 402 403 404 405 406 407 408 409 410
/** Remove pipe and io watch for handling signals
 */
static void mce_quit_signal_pipe(void)
{
	if( signal_pipe_id )
		g_source_remove(signal_pipe_id), signal_pipe_id = 0;

	if( signal_pipe[0] != -1 )
		close(signal_pipe[0]), signal_pipe[0] = -1;

	if( signal_pipe[1] != -1 )
		close(signal_pipe[1]), signal_pipe[1] = -1;
}

411 412 413 414 415 416 417 418 419 420 421 422 423
/** Create a pipe and io watch for handling signal from glib mainloop
 */
static gboolean mce_init_signal_pipe(void)
{
	int         result  = FALSE;
	GIOChannel *channel = 0;

	if( pipe(signal_pipe) == -1 )
		goto EXIT;

	if( (channel = g_io_channel_unix_new(signal_pipe[0])) == 0 )
		goto EXIT;

424 425 426 427 428
	signal_pipe_id =
		g_io_add_watch(channel,
			       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
			       mce_rx_signal_cb, 0);
	if( !signal_pipe_id )
429 430 431 432 433 434 435 436 437 438
		goto EXIT;

	result = TRUE;

EXIT:
	if( channel != 0 ) g_io_channel_unref(channel);

	return result;
}

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
/**
 * Daemonize the program
 *
 * @return TRUE if MCE is started during boot, FALSE otherwise
 */
static gboolean daemonize(void)
{
	gint retries = 0;
	gint i = 0;
	gchar str[10];

	if (getppid() == 1)
		goto EXIT;	/* Already daemonized */

	/* Detach from process group */
	switch (fork()) {
	case -1:
456
		/* Parent - Failure */
457 458 459 460 461 462 463 464 465
		mce_log(LL_CRIT, "daemonize: fork failed: %s",
			g_strerror(errno));
		exit(EXIT_FAILURE);

	case 0:
		/* Child */
		break;

	default:
466 467 468 469 470
		/* Parent -- Success */

		/* One main() one exit() - in this case the parent
		 * must not call atexit handlers etc */
		_exit(EXIT_SUCCESS);
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
	}

	/* Detach TTY */
	setsid();

	/* Close all file descriptors and redirect stdio to /dev/null */
	if ((i = getdtablesize()) == -1)
		i = 256;

	while (--i >= 0) {
		if (close(i) == -1) {
			if (retries > 10) {
				mce_log(LL_CRIT,
					"close() was interrupted more than "
					"10 times. Exiting.");
				exit(EXIT_FAILURE);
			}

			if (errno == EINTR) {
				mce_log(LL_INFO,
					"close() was interrupted; retrying.");
				errno = 0;
				i++;
				retries++;
			} else if (errno == EBADF) {
Santtu Lakkala's avatar
Santtu Lakkala committed
496
				/* Ignore invalid file descriptors */
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 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 543 544 545 546 547 548 549 550 551 552 553 554 555
				errno = 0;
			} else {
				mce_log(LL_CRIT,
					"Failed to close() fd %d; %s. "
					"Exiting.",
					i + 1, g_strerror(errno));
				exit(EXIT_FAILURE);
			}
		} else {
			retries = 0;
		}
	}

	if ((i = open("/dev/null", O_RDWR)) == -1) {
		mce_log(LL_CRIT,
			"Cannot open `/dev/null'; %s. Exiting.",
			g_strerror(errno));
		exit(EXIT_FAILURE);
	}

	if ((dup(i) == -1)) {
		mce_log(LL_CRIT,
			"Failed to dup() `/dev/null'; %s. Exiting.",
			g_strerror(errno));
		exit(EXIT_FAILURE);
	}

	if ((dup(i) == -1)) {
		mce_log(LL_CRIT,
			"Failed to dup() `/dev/null'; %s. Exiting.",
			g_strerror(errno));
		exit(EXIT_FAILURE);
	}

	/* Set umask */
	umask(022);

	/* Set working directory */
	if ((chdir("/tmp") == -1)) {
		mce_log(LL_CRIT,
			"Failed to chdir() to `/tmp'; %s. Exiting.",
			g_strerror(errno));
		exit(EXIT_FAILURE);
	}

	/* Single instance */
	if ((i = open(MCE_LOCKFILE, O_RDWR | O_CREAT, 0640)) == -1) {
		mce_log(LL_CRIT,
			"Cannot open lockfile; %s. Exiting.",
			g_strerror(errno));
		exit(EXIT_FAILURE);
	}

	if (lockf(i, F_TLOCK, 0) == -1) {
		mce_log(LL_CRIT, "Already running. Exiting.");
		exit(EXIT_FAILURE);
	}

	sprintf(str, "%d\n", getpid());
556
	no_error_check_write(i, str, strlen(str));
557 558 559 560 561 562 563 564 565 566 567 568 569 570
	close(i);

	/* Ignore TTY signals */
	signal(SIGTSTP, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);

	/* Ignore child terminate signal */
	signal(SIGCHLD, SIG_IGN);

EXIT:
	return 0;
}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
/** Helper for determining how long common prefix two strings have
 *
 * @param str1 non null string
 * @param str2 non null string
 *
 * @return length of common prefix strings share
 */
static size_t common_length(const char *str1, const char *str2)
{
	size_t i;
	for( i = 0; str1[i] && str1[i] == str2[i]; ++i ) {}
	return i;
}

/** Handle --trace=flags options
 *
 * @param flags comma separated list of trace domains
 *
 * @return TRUE on success, FALSE if unknown domains used
 */
static gboolean mce_enable_trace(const char *flags)
{
	static const struct {
		const char *domain;
		void (*callback)(void);
	} lut[] = {
#ifdef ENABLE_WAKELOCKS
		{ "wakelocks", lwl_enable_logging },
#endif
		{ NULL, NULL }
	};

	gboolean  res = TRUE;
	gchar    *tmp = g_strdup(flags);

	gchar    *now, *zen;
	size_t    bi, bn;

	for( now = tmp; now; now = zen ) {
		if( (zen = strchr(now, ',')) )
			*zen++ = 0;

		// initialize to: no match
		bi = bn = 0;

		for( size_t ti = 0; lut[ti].domain; ++ti ) {
			size_t tn = common_length(lut[ti].domain, now);

			// all of flag mathed?
			if( now[tn] )
				continue;

			// better or equal as the previous best?
			if( bn <= tn )
				bi = ti, bn = tn;

			// full match found?
			if( !lut[ti].domain[tn] )
				break;
		}

		// did we find a match?
		if( !bn ) {
			fprintf(stderr, "unknown trace domain: '%s'\n", now);
			res = FALSE;
		}
		else {
			// report if non-full match was used
			if( lut[bi].domain[bn] )
				fprintf(stderr, "trace: %s\n", lut[bi].domain);
			lut[bi].callback();
		}
	}

	g_free(tmp);
	return res;
}

649 650 651 652 653 654 655 656 657 658 659 660
/* ========================================================================= *
 * COMMAND LINE OPTIONS
 * ========================================================================= */

static struct
{
	bool daemonflag;
	int  logtype;
	int  verbosity;
	bool systembus;
	bool show_module_info;
	bool systemd_notify;
661
	bool valgrind_mode;
662
	bool sensortest_mode;
663
	int  auto_exit;
664 665 666 667 668 669 670 671
} mce_args =
{
	.daemonflag       = false,
	.logtype          = MCE_LOG_SYSLOG,
	.verbosity        = LL_DEFAULT,
	.systembus        = true,
	.show_module_info = false,
	.systemd_notify   = false,
672
	.valgrind_mode    = false,
673
	.sensortest_mode  = false,
674
	.auto_exit        = -1,
675 676
};

677 678 679 680 681
bool mce_in_valgrind_mode(void)
{
	return mce_args.valgrind_mode;
}

682 683 684 685 686
bool mce_in_sensortest_mode(void)
{
	return mce_args.sensortest_mode;
}

687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
static bool mce_do_help(const char *arg);
static bool mce_do_version(const char *arg);

static bool mce_do_daemonize(const char *arg)
{
	(void)arg;
	mce_args.daemonflag = true;
	return true;
}

static bool mce_do_force_stderr(const char *arg)
{
	(void)arg;
	mce_args.logtype = MCE_LOG_STDERR;
	return true;
}

static bool mce_do_force_syslog(const char *arg)
{
	(void)arg;
	mce_args.logtype = MCE_LOG_SYSLOG;
	return true;
}

711 712 713 714 715
static bool mce_do_auto_exit(const char *arg)
{
	mce_args.auto_exit = arg ? strtol(arg, 0, 0) : 5;
	return true;
}
716 717 718 719 720 721
static bool mce_do_valgrind_mode(const char *arg)
{
	(void)arg;
	mce_args.valgrind_mode = true;
	return true;
}
722 723 724 725 726 727
static bool mce_do_sensortest_mode(const char *arg)
{
	(void)arg;
	mce_args.sensortest_mode = true;
	return true;
}
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
static bool mce_do_log_function(const char *arg)
{
	mce_log_add_pattern(arg);
	return true;
}

static bool mce_do_verbose(const char *arg)
{
	(void)arg;
	if( mce_args.verbosity < LL_DEBUG )
		mce_args.verbosity++;
	return true;
}

static bool mce_do_quiet(const char *arg)
{
	(void)arg;
	if( mce_args.verbosity > LL_NONE )
		mce_args.verbosity--;
	return true;
}

static bool mce_do_session_bus(const char *arg)
{
	(void)arg;
	mce_args.systembus = false;
	return true;
}

static bool mce_do_show_module_info(const char *arg)
{
	(void)arg;
	mce_args.show_module_info = true;
	return true;
}

static bool mce_do_systemd(const char *arg)
{
	(void)arg;
	mce_args.systemd_notify = true;
	return true;
}

static bool mce_do_trace(const char *arg)
{
	return mce_enable_trace(arg);
}

static const mce_opt_t options[] =
{

	{
		.name        = "help",
		.flag        = 'h',
		.with_arg    = mce_do_help,
		.without_arg = mce_do_help,
		.values      = "option|\"all\"",
		.usage       =
			"Show usage information\n"
			"\n"
			"If the optional argument is given, more detailed information is\n"
			"given about matching options. Using \"all\" lists all options\n"
	},
	{
		.name        = "version",
		.flag        = 'V',
		.without_arg = mce_do_version,
		.usage       =
			"Output version information and exit\n"

	},

	{
		.name        = "verbose",
		.flag        = 'v',
		.without_arg = mce_do_verbose,
		.usage       =
			"Increase debug message verbosity\n"

	},
	{
		.name        = "quiet",
		.flag        = 'q',
		.without_arg = mce_do_quiet,
		.usage       =
			"Decrease debug message verbosity\n"

	},
	{
		.name        = "systemd",
		.flag        = 'n',
		.without_arg = mce_do_systemd,
		.usage       =
			"Notify systemd when started up\n"

	},
	{
		.name        = "daemonflag",
		.flag        = 'd',
		.without_arg = mce_do_daemonize,
		.usage       =
			"Run MCE as a daemon\n"

	},
	{
		.name        = "force-syslog",
		.flag        = 's',
		.without_arg = mce_do_force_syslog,
		.usage       =
			"Log to syslog even when not daemonized\n"

	},
	{
		.name        = "force-stderr",
		.flag        = 'T',
		.without_arg = mce_do_force_stderr,
		.usage       =
			"Log to stderr even when daemonized\n"

	},
	{
		.name        = "session",
		.flag        = 'S',
		.without_arg = mce_do_session_bus,
		.usage       =
			"Use the session bus instead of the system bus for D-Bus\n"
	},
	{
		.name        = "show-module-info",
		.flag        = 'M',
		.without_arg = mce_do_show_module_info,
		.usage       =
			"Show information about loaded modules\n"
	},
	{
		.name        = "trace",
		.flag        = 't',
		.with_arg    = mce_do_trace,
		.values      = "what",
		.usage       =
			"enable domain specific debug logging; supported values:\n"
			"  wakelocks\n"
	},
	{
		.name        = "log-function",
		.flag        = 'l',
		.with_arg    = mce_do_log_function,
		.values      = "file:func",
		.usage       =
			"Add function logging override"
	},
879 880 881 882 883 884 885 886 887 888
	{
		.name        = "auto-exit",
		.values      = "seconds",
		.with_arg    = mce_do_auto_exit,
		.without_arg = mce_do_auto_exit,
		.usage       =
			"Exit after mainloop gets idle\n"
			"\n"
			"This is usefult for mce startup debugging only.\n"
	},
889 890 891 892 893 894
	{
		.name        = "valgrind-mode",
		.without_arg = mce_do_valgrind_mode,
		.usage       =
			"Enable run-under valgrind mode\n"
	},
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
	{
		.name        = "sensortest-mode",
		.without_arg = mce_do_sensortest_mode,
		.usage       =
			"Enable track-all-sensors mode\n"
			"\n"
			"Intents to provide a quick way to check whether\n"
			"sensor adaptation is in a state where all sensors\n"
			"that are supposedly supported actually report\n"
			"changes via sensorfwd interfaces.\n"
			"\n"
			"This is mainly useful when porting to new devices.\n"
			"\n"
			"Suggested usage is to manually execute mce in a way\n"
			"where it is otherwise quiet, but debug logging for\n"
			"sensor related activity is enabled, for example:\n"
			"\n"
			"   mce --sensortest-mode -Tqqq -lmce-sensorfw.c:*\n"
	},
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
	// sentinel
	{
		.name = 0
	}
};

static bool mce_do_version(const char *arg)
{
	(void)arg;

	static const char vers[] = G_STRINGIFY(PRG_VERSION);
	static const char info[] =
		"Written by David Weinehall.\n"
		"\n"
		"Copyright (C) 2004-2010 Nokia Corporation.  "
		"All rights reserved.\n";

	fprintf(stdout,	"%s v%s\n%s", progname, vers, info);
	exit(EXIT_SUCCESS);
}

static bool mce_do_help(const char *arg)
{
	fprintf(stdout,
		"Mode Control Entity\n"
		"\n"
		"USAGE\n"
		"\tmce [OPTION] ...\n"
		"\n"
		"OPTIONS\n");

	mce_command_line_usage(options, arg);

	if( !arg )
		goto EXIT;

	fprintf(stdout,
		"REPORTING BUGS\n"
		"\tSend e-mail to: <simo.piiroinen@jollamobile.com>\n");

EXIT:
	exit(EXIT_SUCCESS);
}

958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
static gboolean mce_auto_exit_cb(gpointer aptr)
{
	(void)aptr;

	if( mce_args.auto_exit <= 0 ) {
		mce_log(LL_WARN, "exit");
		mce_quit_mainloop();
	}
	else {
		mce_log(LL_WARN, "idle");
		g_timeout_add_seconds(mce_args.auto_exit, mce_auto_exit_cb, 0);
		mce_args.auto_exit = 0;
	}
	return FALSE;
}

974 975 976 977
/* ========================================================================= *
 * MAIN ENTRY POINT
 * ========================================================================= */

978 979 980 981 982 983 984 985 986
/**
 * Main
 *
 * @param argc Number of command line arguments
 * @param argv Array with command line arguments
 * @return 0 on success, non-zero on failure
 */
int main(int argc, char **argv)
{
987
	int status = EXIT_FAILURE;
988

989 990
	/* Set the program-name */
	progname = PRG_NAME;
991 992

	/* Parse the command-line options */
993 994
	if( !mce_command_line_parse(options, argc, argv) )
		goto EXIT;
995 996 997

	/* We don't take any non-flag arguments */
	if ((argc - optind) > 0) {
998 999
		fprintf(stderr, "%s: Too many arguments\n"
			"Try: `%s --help' for more information.\n",
1000
			progname, progname);
1001
		exit(EXIT_FAILURE);
1002 1003
	}

1004 1005
	mce_log_open(PRG_NAME, LOG_DAEMON, mce_args.logtype);
	mce_log_set_verbosity(mce_args.verbosity);
1006

1007 1008 1009 1010
#ifdef ENABLE_WAKELOCKS
	/* Since mce enables automatic suspend, we must try to
	 * disable it when mce process exits */
	atexit(mce_cleanup_wakelocks);
1011 1012 1013

	/* Allow acquiring of multiplexed wakelock */
	mce_wakelock_init();
1014 1015
#endif

1016 1017 1018
	/* Identify mce version & flavor on start up */
	mce_log(LL_WARN, "MCE %s (%s) starting up",
		G_STRINGIFY(PRG_VERSION),
spiiroin's avatar
spiiroin committed
1019
		(LL_DEVEL == LL_EXTRA) ? "devel" : "release");
1020

1021
	/* Daemonize if requested */
1022
	if( mce_args.daemonflag )
1023 1024 1025 1026 1027
		daemonize();

	/* Register a mainloop */
	mainloop = g_main_loop_new(NULL, FALSE);

1028 1029 1030 1031 1032
	/* Signal handlers can be installed once we have a mainloop */
	if( !mce_init_signal_pipe() ) {
		mce_log(LL_CRIT, "Failed to initialise signal pipe");
		exit(EXIT_FAILURE);
	}
1033
	mce_signal_handlers_install();
1034

1035 1036 1037
	/* Initialise subsystems */

	/* Get configuration options */
1038 1039 1040 1041 1042
	if( !mce_conf_init() ) {
		mce_log(LL_CRIT,
			"Failed to initialise configuration options");
		exit(EXIT_FAILURE);
	}
1043

1044 1045 1046 1047 1048 1049 1050
	/* Open fbdev as early as possible */
	mce_fbdev_init();

	/* Start worker thread */
	if( !mce_worker_init() )
		goto EXIT;

1051
	/* Initialise D-Bus */
1052
	if( !mce_dbus_init(mce_args.systembus) ) {
1053 1054 1055 1056 1057 1058 1059 1060
		mce_log(LL_CRIT,
			"Failed to initialise D-Bus");
		exit(EXIT_FAILURE);
	}

	/* Initialise GConf
	 * pre-requisite: g_type_init()
	 */
1061
	if (mce_setting_init() == FALSE) {
1062 1063 1064 1065 1066 1067
		mce_log(LL_CRIT,
			"Cannot connect to default GConf engine");
		exit(EXIT_FAILURE);
	}

	/* Setup all datapipes */
1068 1069
	mce_datapipe_init();

1070 1071 1072
	/* Allow registering of suspend proof timers */
	mce_hbtimer_init();

1073 1074 1075
	/* Allow registering of suspend blocking timers */
	mce_wltimer_init();

1076
	/* Initialise mode management
1077
	 * pre-requisite: mce_setting_init()
1078 1079 1080 1081 1082 1083 1084
	 * pre-requisite: mce_dbus_init()
	 */
	if (mce_mode_init() == FALSE) {
		goto EXIT;
	}

	/* Initialise DSME
1085
	 * pre-requisite: mce_setting_init()
1086 1087 1088
	 * pre-requisite: mce_dbus_init()
	 * pre-requisite: mce_mce_init()
	 */
1089 1090
	if( !mce_dsme_init() )
		goto EXIT;
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113

	/* Initialise powerkey driver */
	if (mce_powerkey_init() == FALSE) {
		goto EXIT;
	}

	/* Initialise /dev/input driver
	 * pre-requisite: g_type_init()
	 */
	if (mce_input_init() == FALSE) {
		goto EXIT;
	}

	/* Initialise switch driver */
	if (mce_switches_init() == FALSE) {
		goto EXIT;
	}

	/* Initialise tklock driver */
	if (mce_tklock_init() == FALSE) {
		goto EXIT;
	}

1114 1115 1116 1117
	if( !mce_sensorfw_init() ) {
		goto EXIT;
	}

1118 1119 1120
	if( !mce_common_init() )
		goto EXIT;

1121 1122 1123 1124 1125
	/* Load all modules */
	if (mce_modules_init() == FALSE) {
		goto EXIT;
	}

1126
	if( mce_args.show_module_info ) {
1127 1128 1129 1130
		mce_modules_dump_info();
		goto EXIT;
	}

1131 1132 1133
	/* MCE startup succeeded */
	status = EXIT_SUCCESS;

1134
	/* Tell systemd that we have started up */
1135
	if( mce_args.systemd_notify ) {
1136 1137 1138
		mce_log(LL_NOTICE, "notifying systemd");
		sd_notify(0, "READY=1");
	}
1139 1140 1141 1142 1143
	/* Debug feature: exit after startup is finished */
	if( mce_args.auto_exit >= 0 ) {
		mce_log(LL_WARN, "auto-exit scheduled");
		g_idle_add(mce_auto_exit_cb, 0);
	}
1144

1145 1146 1147
	/* Use timerfd to detect resume from suspend */
	mce_io_init_resume_timer();

1148 1149 1150 1151 1152 1153 1154
	/* Run the main loop */
	g_main_loop_run(mainloop);

	/* If we get here, the main loop has terminated;
	 * either because we requested or because of an error
	 */
EXIT:
1155 1156
	mce_io_quit_resume_timer();

1157 1158 1159
	/* Unload all modules */
	mce_modules_exit();

1160 1161
	mce_common_quit();

1162
	/* Call the exit function for all components */
1163
	mce_sensorfw_quit();
1164 1165 1166 1167 1168 1169
	mce_tklock_exit();
	mce_switches_exit();
	mce_input_exit();
	mce_powerkey_exit();
	mce_dsme_exit();
	mce_mode_exit();
1170
	mce_wltimer_quit();
1171
	mce_hbtimer_quit();
1172 1173

	/* Free all datapipes */
1174
	mce_datapipe_quit();
1175 1176

	/* Call the exit function for all subsystems */
1177
	mce_setting_exit();
1178 1179
	mce_dbus_exit();
	mce_conf_exit();
1180
	mce_worker_quit();
1181
	mce_fbdev_quit();
1182 1183

	/* If the mainloop is initialised, unreference it */
1184
	if (mainloop != NULL) {
1185
		g_main_loop_unref(mainloop);
1186 1187
		mainloop = 0;
	}
1188

1189 1190 1191
	/* Close signal pipe & remove io watch for it */
	mce_quit_signal_pipe();

1192 1193 1194
	/* Release multiplexed wakelock */
	mce_wakelock_quit();

1195 1196
	/* Log a farewell message and close the log */
	mce_log(LL_INFO, "Exiting...");
1197

1198 1199
	/* No more logging expected */
	mce_log_close();
1200 1201 1202

	return status;
}