Exemple #1
0
/**
 * Generic send function for dsmesock messages
 * XXX: How should we handle sending failures?
 *
 * @param msg A pointer to the message to send
 */
static void mce_dsme_send(gpointer msg)
{
	if (dsme_disabled == TRUE)
		goto EXIT;

	if (dsme_conn == NULL) {
		mce_log(LL_CRIT,
			"Attempt to use dsme_conn uninitialised; aborting!");
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	if ((dsmesock_send(dsme_conn, msg)) == -1) {
		mce_log(LL_CRIT,
			"dsmesock_send error: %s",
			g_strerror(errno));
#ifdef MCE_DSME_ERROR_POLICY
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
#endif /* MCE_DSME_ERROR_POLICY */
	}

EXIT:
	return;
}
Exemple #2
0
/**
 * Signal handler
 *
 * @param signr Signal type
 */
static void signal_handler(const gint signr)
{
	switch (signr) {
	case SIGUSR1:
		/* We'll probably want some way to communicate with MCE */
		break;

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

	case SIGINT:
	case SIGQUIT:
	case SIGTERM:
		/* Just die if we somehow get here without having a mainloop */
		if( !mainloop ) {
			mce_exit_via_signal(signr);
		}

		/* Terminate mainloop */
		mce_quit_mainloop();
		break;

	case SIGPIPE:
		break;

	default:
		/* Should never happen */
		break;
	}
}
Exemple #3
0
/**
 * Create a new D-Bus method call reply, with proper error checking
 * will exit the mainloop if an error occurs
 *
 * @param message The DBusMessage to reply to
 * @return A new DBusMessage
 */
DBusMessage *dbus_new_method_reply(DBusMessage *const message)
{
	DBusMessage *msg;

	if ((msg = dbus_message_new_method_return(message)) == NULL) {
		mce_log(LL_CRIT, "No memory for new reply!");
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	return msg;
}
Exemple #4
0
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;
}
Exemple #5
0
/**
 * Create a new D-Bus signal, with proper error checking
 * will exit the mainloop if an error occurs
 *
 * @param path The signal path
 * @param interface The signal interface
 * @param name The name of the signal to send
 * @return A new DBusMessage
 */
DBusMessage *dbus_new_signal(const gchar *const path,
			     const gchar *const interface,
			     const gchar *const name)
{
	DBusMessage *msg;

	if ((msg = dbus_message_new_signal(path, interface, name)) == NULL) {
		mce_log(LL_CRIT, "No memory for new signal!");
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	return msg;
}
Exemple #6
0
/**
 * Create a new D-Bus error message, with proper error checking
 * will exit the mainloop if an error occurs
 *
 * @param message The DBusMessage that caused the error message to be sent
 * @param error The message to send
 * @return A new DBusMessage
 */
static DBusMessage *dbus_new_error(DBusMessage *const message,
				   const gchar *const error)
{
	DBusMessage *error_msg;

	if ((error_msg = dbus_message_new_error(message, error,
						NULL)) == NULL) {
		mce_log(LL_CRIT, "No memory for new D-Bus error message!");
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	return error_msg;
}
Exemple #7
0
static gboolean io_error_cb(GIOChannel *source,
			    GIOCondition condition,
			    gpointer data)
{
	/* Silence warnings */
	(void)source;
	(void)condition;
	(void)data;

	/* DSME socket closed/error */
	mce_log(LL_CRIT,
		"DSME socket closed/error, exiting...");
	// FIXME: this is not how one should exit from mainloop
	mce_quit_mainloop();
	exit(EXIT_FAILURE);
}
Exemple #8
0
/**
 * Create a new D-Bus method call, with proper error checking
 * will exit the mainloop if an error occurs
 *
 * @param service The method call service
 * @param path The method call path
 * @param interface The method call interface
 * @param name The name of the method to call
 * @return A new DBusMessage
 */
DBusMessage *dbus_new_method_call(const gchar *const service,
				  const gchar *const path,
				  const gchar *const interface,
				  const gchar *const name)
{
	DBusMessage *msg;

	if ((msg = dbus_message_new_method_call(service, path,
						interface, name)) == NULL) {
		mce_log(LL_CRIT,
			"Cannot allocate memory for D-Bus method call!");
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	return msg;
}
Exemple #9
0
/**
 * Signal handler
 *
 * @param signr Signal type
 */
static void signal_handler(const gint signr)
{
	switch (signr) {
	case SIGUSR1:
		/* 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);
		break;

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

	case SIGINT:
	case SIGQUIT:
	case SIGTERM:
		/* Just die if we somehow get here without having a mainloop */
		if( !mainloop ) {
			mce_exit_via_signal(signr);
		}

		/* Terminate mainloop */
		mce_quit_mainloop();
		break;

	case SIGPIPE:
		break;

	default:
		/* Should never happen */
		break;
	}
}
Exemple #10
0
/**
 * Callback for I/O errors
 *
 * @param source Unused
 * @param condition The GIOCondition for the error
 * @param data The iomon structure
 * @return Depending on error policy this function either exits
 *         or returns TRUE
 */
static gboolean io_error_cb(GIOChannel *source,
			    GIOCondition condition,
			    gpointer data)
{
	iomon_struct *iomon = data;
	gboolean exit_on_error = FALSE;
	loglevel_t loglevel;

	/* Silence warnings */
	(void)source;

	if (iomon == NULL) {
		mce_log(LL_CRIT, "iomon == NULL!");
		goto EXIT;
	}

	switch (iomon->error_policy) {
	case MCE_IO_ERROR_POLICY_EXIT:
		exit_on_error = TRUE;
		loglevel = LL_CRIT;
		break;

	case MCE_IO_ERROR_POLICY_WARN:
		loglevel = LL_WARN;
		break;

	case MCE_IO_ERROR_POLICY_IGNORE:
	default:
		/* No log message when ignoring errors */
		loglevel = LL_NONE;
		break;
	}

	/* We just got an I/O condition we've already reported
	 * since the last successful read; don't log
	 */
	if ((exit_on_error == FALSE) &&
	    ((iomon->latest_io_condition & condition) == condition)) {
		loglevel = LL_NONE;
	} else {
		iomon->latest_io_condition |= condition;
	}

	if (loglevel != LL_NONE) {
		mce_log(loglevel,
			"Error accessing %s (condition: %d). %s",
			iomon->file, condition,
			(exit_on_error == TRUE) ? "Exiting" : "Ignoring");
	}

EXIT:
	if ((iomon != NULL) && (exit_on_error == TRUE)) {
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	/* Call error callback if set */
	if (iomon->err_callback) {
		iomon->err_callback(iomon, condition);
	}

	return TRUE;
}
Exemple #11
0
/**
 * Callback for successful chunk I/O
 *
 * @param source The source of the activity
 * @param condition The I/O condition
 * @param data The iomon structure
 * @return Depending on error policy this function either exits
 *         or returns TRUE
 */
static gboolean io_chunk_cb(GIOChannel *source,
			    GIOCondition condition,
			    gpointer data)
{
	iomon_struct *iomon = data;
	gchar *buffer = NULL;
	gsize bytes_want = 4096;
	gsize bytes_read = 0;
	gsize chunks_read = 0;
	gsize chunks_done = 0;
	GIOStatus io_status;
	GError *error = NULL;
	gboolean status = TRUE;

	/* Silence warnings */
	(void)condition;

	if (iomon == NULL) {
		mce_log(LL_CRIT, "iomon == NULL!");
		status = FALSE;
		goto EXIT;
	}

	iomon->latest_io_condition = 0;

	/* Seek to the beginning of the file before reading if needed */
	if (iomon->rewind == TRUE) {
		g_io_channel_seek_position(source, 0, G_SEEK_SET, &error);
		if( error ) {
			mce_log(LL_ERR,	"%s: seek error: %s",
				iomon->file, error->message);
		}

		/* Reset errno,
		 * to avoid false positives down the line
		 */
		errno = 0;
		g_clear_error(&error);
	}

	if( iomon->chunk_size < bytes_want ) {
		bytes_want -= bytes_want % iomon->chunk_size;
	} else {
		bytes_want = iomon->chunk_size;
	}

	buffer = g_malloc(bytes_want);

#ifdef ENABLE_WAKELOCKS
	/* Since the locks on kernel side are released once all
	 * events are read, we must obtain the userspace lock
	 * before reading the available data */
	wakelock_lock("mce_input_handler", -1);
#endif

	io_status = g_io_channel_read_chars(source, buffer,
					    bytes_want, &bytes_read, &error);


	/* If the read was interrupted, ignore */
	if (io_status == G_IO_STATUS_AGAIN) {
		g_clear_error(&error);
	}

	if( bytes_read % iomon->chunk_size ) {
		mce_log(LL_WARN, "Incomplete chunks read from: %s", iomon->file);
	}

	/* Process the data, and optionally ignore some of it */
	if( (chunks_read = bytes_read / iomon->chunk_size) ) {
		gchar *chunk = buffer;
		for( ; chunks_done < chunks_read ; chunk += iomon->chunk_size ) {
			++chunks_done;
			if (iomon->callback(chunk, iomon->chunk_size) != TRUE) {
				continue;
			}
			/* if possible, seek to the end of file */
			if (iomon->seekable) {
				g_io_channel_seek_position(iomon->iochan, 0,
							   G_SEEK_END, &error);
			}
			/* in any case ignore rest of the data already read */
			break;
		}
	}

	mce_log(LL_INFO, "%s: status=%s, data=%d/%d=%d+%d, skipped=%d",
		iomon->file, io_status_name(io_status),
		bytes_read, (int)iomon->chunk_size, chunks_read,
		bytes_read % (int)iomon->chunk_size, chunks_read - chunks_done);

#ifdef ENABLE_WAKELOCKS
	/* Release the lock after we're done with processing it */
	wakelock_unlock("mce_input_handler");
#endif


	g_free(buffer);

	/* Were there any errors? */
	if (error != NULL) {
		mce_log(LL_ERR,
			"Error when reading from %s: %s",
			iomon->file, error->message);

		if ((error->code == G_IO_CHANNEL_ERROR_FAILED) &&
		    (errno == ENODEV) &&
		    (iomon->seekable)) {
			errno = 0;
			g_clear_error(&error);
			g_io_channel_seek_position(iomon->iochan, 0,
						   G_SEEK_END, &error);
			if( error ) {
				mce_log(LL_ERR,	"%s: seek error: %s",
					iomon->file, error->message);
			}
		} else {
			status = FALSE;
		}

		/* Reset errno,
		 * to avoid false positives down the line
		 */
		errno = 0;
		g_clear_error(&error);
	} else if ((bytes_read == 0) &&
		   (io_status != G_IO_STATUS_EOF) &&
		   (io_status != G_IO_STATUS_AGAIN)) {
		mce_log(LL_ERR,
			"Empty read from %s",
			iomon->file);
	}

EXIT:
	if ((status == FALSE) &&
	    (iomon != NULL) &&
	    (iomon->error_policy == MCE_IO_ERROR_POLICY_EXIT)) {
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	return TRUE;
}
Exemple #12
0
/**
 * Callback for successful string I/O
 *
 * @param source The source of the activity
 * @param condition The I/O condition
 * @param data The iomon structure
 * @return Depending on error policy this function either exits
 *         or returns TRUE
 */
static gboolean io_string_cb(GIOChannel *source,
			     GIOCondition condition,
			     gpointer data)
{
	iomon_struct *iomon = data;
	gchar *str = NULL;
	gsize bytes_read;
	GError *error = NULL;
	gboolean status = TRUE;

	/* Silence warnings */
	(void)condition;

	if (iomon == NULL) {
		mce_log(LL_CRIT, "iomon == NULL!");
		status = FALSE;
		goto EXIT;
	}

	iomon->latest_io_condition = 0;

	/* Seek to the beginning of the file before reading if needed */
	if (iomon->rewind == TRUE) {
		g_io_channel_seek_position(source, 0, G_SEEK_SET, &error);

		if( error ) {
			mce_log(LL_ERR,	"%s: seek error: %s",
				iomon->file, error->message);
		}
		/* Reset errno,
		 * to avoid false positives down the line
		 */
		errno = 0;
		g_clear_error(&error);
	}

	g_io_channel_read_line(source, &str, &bytes_read, NULL, &error);

	/* Errors and empty reads are nasty */
	if (error != NULL) {
		mce_log(LL_ERR,
			"Error when reading from %s: %s",
			iomon->file, error->message);
		status = FALSE;
	} else if ((bytes_read == 0) || (str == NULL) || (strlen(str) == 0)) {
		mce_log(LL_ERR,
			"Empty read from %s",
			iomon->file);
	} else {
		(void)iomon->callback(str, bytes_read);
	}

	g_free(str);

	/* Reset errno,
	 * to avoid false positives down the line
	 */
	errno = 0;
	g_clear_error(&error);

EXIT:
	if ((status == FALSE) &&
	    (iomon != NULL) &&
	    (iomon->error_policy == MCE_IO_ERROR_POLICY_EXIT)) {
		// FIXME: this is not how one should exit from mainloop
		mce_quit_mainloop();
		exit(EXIT_FAILURE);
	}

	return TRUE;
}
Exemple #13
0
/**
 * Callback for pending I/O from dsmesock
 *
 * XXX: is the error policy reasonable?
 *
 * @param source Unused
 * @param condition Unused
 * @param data Unused
 * @return TRUE on success, FALSE on failure
 */
static gboolean io_data_ready_cb(GIOChannel *source,
				 GIOCondition condition,
				 gpointer data)
{
	dsmemsg_generic_t *msg;
	DSM_MSGTYPE_STATE_CHANGE_IND *msg2;
	system_state_t oldstate = datapipe_get_gint(system_state_pipe);
	system_state_t newstate = MCE_STATE_UNDEF;

	(void)source;
	(void)condition;
	(void)data;

	if (dsme_disabled == TRUE)
		goto EXIT;

	if ((msg = (dsmemsg_generic_t *)dsmesock_receive(dsme_conn)) == NULL)
		goto EXIT;

        if (DSMEMSG_CAST(DSM_MSGTYPE_CLOSE, msg)) {
		/* DSME socket closed: try once to reopen;
		 * if that fails, exit
		 */
		mce_log(LL_ERR,
			"DSME socket closed; trying to reopen");

		if ((init_dsmesock()) == FALSE) {
			// FIXME: this is not how one should exit from mainloop
			mce_quit_mainloop();
			exit(EXIT_FAILURE);
		}
        } else if (DSMEMSG_CAST(DSM_MSGTYPE_PROCESSWD_PING, msg)) {
		dsme_send_pong();
        } else if ((msg2 = DSMEMSG_CAST(DSM_MSGTYPE_STATE_CHANGE_IND, msg))) {
		newstate = normalise_dsme_state(msg2->state);
		mce_log(LL_DEBUG,
			"DSME device state change: %d",
			newstate);

		/* If we're changing to a different state,
		 * add the transition flag, UNLESS the old state
		 * was MCE_STATE_UNDEF
		 */
		if ((oldstate != newstate) && (oldstate != MCE_STATE_UNDEF))
			mce_add_submode_int32(MCE_TRANSITION_SUBMODE);

		switch (newstate) {
		case MCE_STATE_USER:
			execute_datapipe_output_triggers(&led_pattern_activate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA);
			break;

		case MCE_STATE_ACTDEAD:
		case MCE_STATE_BOOT:
		case MCE_STATE_UNDEF:
			break;

		case MCE_STATE_SHUTDOWN:
		case MCE_STATE_REBOOT:
			execute_datapipe_output_triggers(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_DEVICE_ON, USE_INDATA);
			break;

		default:
			break;
		}

		execute_datapipe(&system_state_pipe,
				 GINT_TO_POINTER(newstate),
				 USE_INDATA, CACHE_INDATA);
        } else {
		mce_log(LL_DEBUG,
			"Unknown message type (%x) received from DSME!",
			msg->type_); /* <- unholy access of a private member */
	}

	free(msg);

EXIT:
	return TRUE;
}