1N/A/***************************************************************************
1N/A * CVSID: $Id$
1N/A *
1N/A * main.c - Main dbus interface of the hald runner
1N/A *
1N/A * Copyright (C) 2006 Sjoerd Simons, <sjoerd@luon.net>
1N/A *
1N/A * Licensed under the Academic Free License version 2.1
1N/A *
1N/A * This program is free software; you can redistribute it and/or modify
1N/A * it under the terms of the GNU General Public License as published by
1N/A * the Free Software Foundation; either version 2 of the License, or
1N/A * (at your option) any later version.
1N/A *
1N/A * This program is distributed in the hope that it will be useful,
1N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A * GNU General Public License for more details.
1N/A *
1N/A * You should have received a copy of the GNU General Public License
1N/A * along with this program; if not, write to the Free Software
1N/A * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1N/A *
1N/A **************************************************************************/
1N/A#include <stdio.h>
1N/A#include <stdlib.h>
1N/A#define DBUS_API_SUBJECT_TO_CHANGE
1N/A#include <dbus/dbus-glib-lowlevel.h>
1N/A
1N/A#include <glib.h>
1N/A#include "utils.h"
1N/A#include "runner.h"
1N/A
1N/Astatic gboolean
1N/Aparse_first_part(run_request *r, DBusMessage *msg, DBusMessageIter *iter)
1N/A{
1N/A DBusMessageIter sub_iter;
1N/A char *tmpstr;
1N/A
1N/A /* First should be the device UDI */
1N/A if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
1N/A goto malformed;
1N/A dbus_message_iter_get_basic(iter, &tmpstr);
1N/A r->udi = g_strdup(tmpstr);
1N/A
1N/A /* Then the environment array */
1N/A if (!dbus_message_iter_next(iter) || dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
1N/A goto malformed;
1N/A dbus_message_iter_recurse(iter, &sub_iter);
1N/A /* Add default path for the programs we start */
1N/A tmpstr = g_strdup_printf("PATH=/sbin:/usr/sbin:/bin:/usr/bin:%s", getenv("PATH"));
1N/A r->environment = get_string_array(&sub_iter, tmpstr);
1N/A
1N/A /* Then argv */
1N/A if (!dbus_message_iter_next(iter) || dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
1N/A goto malformed;
1N/A dbus_message_iter_recurse(iter, &sub_iter);
1N/A r->argv = get_string_array(&sub_iter, NULL);
1N/A
1N/A return TRUE;
1N/A
1N/Amalformed:
1N/A return FALSE;
1N/A}
1N/A
1N/Astatic void
1N/Ahandle_run(DBusConnection *con, DBusMessage *msg)
1N/A{
1N/A DBusMessage *reply;
1N/A DBusMessageIter iter;
1N/A run_request *r;
1N/A char *tmpstr;
1N/A
1N/A r = new_run_request();
1N/A g_assert(dbus_message_iter_init(msg, &iter));
1N/A
1N/A if (!parse_first_part(r, msg, &iter))
1N/A goto malformed;
1N/A
1N/A /* Next a string of what should be written to stdin */
1N/A if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1N/A goto malformed;
1N/A dbus_message_iter_get_basic(&iter, &tmpstr);
1N/A r->input = g_strdup(tmpstr);
1N/A
1N/A /* Then an bool to indicate if we should grab stderr */
1N/A if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
1N/A goto malformed;
1N/A dbus_message_iter_get_basic(&iter, &(r->error_on_stderr));
1N/A
1N/A /* Then an uint32 timeout for it */
1N/A if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
1N/A goto malformed;
1N/A dbus_message_iter_get_basic(&iter, &(r->timeout));
1N/A
1N/A /* let run_request_run handle the reply */
1N/A run_request_run(r, con, msg, NULL);
1N/A return;
1N/A
1N/Amalformed:
1N/A del_run_request(r);
1N/A reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed",
1N/A "Malformed run request");
1N/A dbus_connection_send(con, reply, NULL);
1N/A dbus_message_unref(reply);
1N/A}
1N/A
1N/Astatic void
1N/Ahandle_start(DBusConnection *con, DBusMessage *msg)
1N/A{
1N/A DBusMessage *reply;
1N/A DBusMessageIter iter;
1N/A run_request *r;
1N/A GPid pid;
1N/A dbus_int64_t pid64;
1N/A
1N/A r = new_run_request();
1N/A g_assert(dbus_message_iter_init(msg, &iter));
1N/A
1N/A if (!dbus_message_iter_init(msg, &iter) || !parse_first_part(r, msg, &iter))
1N/A goto malformed;
1N/A
1N/A if (run_request_run(r, con, NULL, &pid)) {
1N/A pid64 = pid;
1N/A reply = dbus_message_new_method_return(msg);
1N/A dbus_message_append_args (reply,
1N/A DBUS_TYPE_INT64, &pid64,
1N/A DBUS_TYPE_INVALID);
1N/A
1N/A } else {
1N/A reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Failed",
1N/A "Start request failed");
1N/A }
1N/A dbus_connection_send(con, reply, NULL);
1N/A dbus_message_unref(reply);
1N/A return ;
1N/Amalformed:
1N/A del_run_request(r);
1N/A reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed",
1N/A "Malformed start request");
1N/A dbus_connection_send(con, reply, NULL);
1N/A dbus_message_unref(reply);
1N/A}
1N/A
1N/Astatic void
1N/Ahandle_kill(DBusConnection *con, DBusMessage *msg)
1N/A{
1N/A DBusError error;
1N/A DBusMessage *reply = NULL;
1N/A char *udi;
1N/A
1N/A dbus_error_init (&error);
1N/A if (!dbus_message_get_args(msg, &error,
1N/A DBUS_TYPE_STRING, &udi,
1N/A DBUS_TYPE_INVALID)) {
1N/A reply = dbus_message_new_error (msg, "org.freedesktop.HalRunner.Malformed",
1N/A "Malformed kill message");
1N/A g_assert(reply);
1N/A dbus_connection_send (con, reply, NULL);
1N/A dbus_message_unref(reply);
1N/A return;
1N/A }
1N/A run_kill_udi(udi);
1N/A
1N/A /* always successfull */
1N/A reply = dbus_message_new_method_return(msg);
1N/A dbus_connection_send(con, reply, NULL);
1N/A dbus_message_unref(reply);
1N/A}
1N/A
1N/Astatic DBusHandlerResult
1N/Afilter(DBusConnection *con, DBusMessage *msg, void *user_data)
1N/A{
1N/A DBusMessage *reply;
1N/A
1N/A if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Run")) {
1N/A handle_run(con, msg);
1N/A return DBUS_HANDLER_RESULT_HANDLED;
1N/A } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Start")) {
1N/A handle_start(con, msg);
1N/A return DBUS_HANDLER_RESULT_HANDLED;
1N/A } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Kill")) {
1N/A handle_kill(con, msg);
1N/A return DBUS_HANDLER_RESULT_HANDLED;
1N/A } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "KillAll")) {
1N/A run_kill_all();
1N/A /* alwasy successfull */
1N/A reply = dbus_message_new_method_return(msg);
1N/A dbus_connection_send(con, reply, NULL);
1N/A dbus_message_unref(reply);
1N/A return DBUS_HANDLER_RESULT_HANDLED;
1N/A }
1N/A return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1N/A}
1N/A
1N/Aint
1N/Amain(int argc, char **argv)
1N/A{
1N/A DBusConnection *c;
1N/A DBusError error;
1N/A GMainLoop *loop;
1N/A char *dbus_address;
1N/A
1N/A run_init();
1N/A dbus_error_init(&error);
1N/A dbus_address = getenv("HALD_RUNNER_DBUS_ADDRESS");
1N/A g_assert(dbus_address != NULL);
1N/A
1N/A fprintf(stderr, "Runner started - allowed paths are '%s'\n", getenv("PATH"));
1N/A
1N/A c = dbus_connection_open(dbus_address, &error);
1N/A if (c == NULL)
1N/A goto error;
1N/A
1N/A loop = g_main_loop_new(NULL, FALSE);
1N/A
1N/A dbus_connection_setup_with_g_main(c, NULL);
1N/A dbus_connection_set_exit_on_disconnect(c, TRUE);
1N/A dbus_connection_add_filter(c, filter, NULL, NULL);
1N/A
1N/A g_main_loop_run(loop);
1N/A
1N/Aerror:
1N/A fprintf(stderr,"An error has occured: %s\n", error.message);
1N/A return -1;
1N/A}