118c2aff7Sartem /***************************************************************************
218c2aff7Sartem * CVSID: $Id$
318c2aff7Sartem *
418c2aff7Sartem * main.c - Main dbus interface of the hald runner
518c2aff7Sartem *
618c2aff7Sartem * Copyright (C) 2006 Sjoerd Simons, <sjoerd@luon.net>
7*3ab06c27SMilan Jurik * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor@codethink.co.uk>
818c2aff7Sartem *
918c2aff7Sartem * Licensed under the Academic Free License version 2.1
1018c2aff7Sartem *
1118c2aff7Sartem * This program is free software; you can redistribute it and/or modify
1218c2aff7Sartem * it under the terms of the GNU General Public License as published by
1318c2aff7Sartem * the Free Software Foundation; either version 2 of the License, or
1418c2aff7Sartem * (at your option) any later version.
1518c2aff7Sartem *
1618c2aff7Sartem * This program is distributed in the hope that it will be useful,
1718c2aff7Sartem * but WITHOUT ANY WARRANTY; without even the implied warranty of
1818c2aff7Sartem * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1918c2aff7Sartem * GNU General Public License for more details.
2018c2aff7Sartem *
2118c2aff7Sartem * You should have received a copy of the GNU General Public License
2218c2aff7Sartem * along with this program; if not, write to the Free Software
2318c2aff7Sartem * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2418c2aff7Sartem *
2518c2aff7Sartem **************************************************************************/
2618c2aff7Sartem #include <stdio.h>
2718c2aff7Sartem #include <stdlib.h>
2818c2aff7Sartem #define DBUS_API_SUBJECT_TO_CHANGE
2918c2aff7Sartem #include <dbus/dbus-glib-lowlevel.h>
3018c2aff7Sartem
3118c2aff7Sartem #include <glib.h>
3218c2aff7Sartem #include "utils.h"
3318c2aff7Sartem #include "runner.h"
3418c2aff7Sartem
35*3ab06c27SMilan Jurik #ifndef __GNUC__
36*3ab06c27SMilan Jurik #define __attribute__(x)
37*3ab06c27SMilan Jurik #endif
38*3ab06c27SMilan Jurik
3918c2aff7Sartem static gboolean
parse_udi(run_request * r,DBusMessage * msg,DBusMessageIter * iter)40*3ab06c27SMilan Jurik parse_udi (run_request *r, DBusMessage *msg, DBusMessageIter *iter)
4118c2aff7Sartem {
4218c2aff7Sartem char *tmpstr;
4318c2aff7Sartem
44*3ab06c27SMilan Jurik /* Should be the device UDI */
4518c2aff7Sartem if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
4618c2aff7Sartem goto malformed;
4718c2aff7Sartem dbus_message_iter_get_basic(iter, &tmpstr);
4818c2aff7Sartem r->udi = g_strdup(tmpstr);
4918c2aff7Sartem
50*3ab06c27SMilan Jurik if (!dbus_message_iter_next(iter))
51*3ab06c27SMilan Jurik goto malformed;
52*3ab06c27SMilan Jurik
53*3ab06c27SMilan Jurik return TRUE;
54*3ab06c27SMilan Jurik
55*3ab06c27SMilan Jurik malformed:
56*3ab06c27SMilan Jurik return FALSE;
57*3ab06c27SMilan Jurik }
58*3ab06c27SMilan Jurik
59*3ab06c27SMilan Jurik static gboolean
parse_environment(run_request * r,DBusMessage * msg,DBusMessageIter * iter)60*3ab06c27SMilan Jurik parse_environment(run_request *r, DBusMessage *msg, DBusMessageIter *iter)
61*3ab06c27SMilan Jurik {
62*3ab06c27SMilan Jurik DBusMessageIter sub_iter;
63*3ab06c27SMilan Jurik char *tmpstr;
64*3ab06c27SMilan Jurik
65*3ab06c27SMilan Jurik /* The environment array */
66*3ab06c27SMilan Jurik if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
6718c2aff7Sartem goto malformed;
6818c2aff7Sartem dbus_message_iter_recurse(iter, &sub_iter);
6918c2aff7Sartem /* Add default path for the programs we start */
70*3ab06c27SMilan Jurik #if defined(__FreeBSD__)
71*3ab06c27SMilan Jurik tmpstr = g_strdup_printf("PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/X11R6/sbin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:%s", getenv("PATH"));
72*3ab06c27SMilan Jurik #else
7318c2aff7Sartem tmpstr = g_strdup_printf("PATH=/sbin:/usr/sbin:/bin:/usr/bin:%s", getenv("PATH"));
74*3ab06c27SMilan Jurik #endif
7518c2aff7Sartem r->environment = get_string_array(&sub_iter, tmpstr);
7618c2aff7Sartem
7718c2aff7Sartem /* Then argv */
7818c2aff7Sartem if (!dbus_message_iter_next(iter) || dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
7918c2aff7Sartem goto malformed;
8018c2aff7Sartem dbus_message_iter_recurse(iter, &sub_iter);
8118c2aff7Sartem r->argv = get_string_array(&sub_iter, NULL);
8218c2aff7Sartem
8318c2aff7Sartem return TRUE;
8418c2aff7Sartem
8518c2aff7Sartem malformed:
8618c2aff7Sartem return FALSE;
8718c2aff7Sartem }
8818c2aff7Sartem
8918c2aff7Sartem static void
handle_run(DBusConnection * con,DBusMessage * msg)9018c2aff7Sartem handle_run(DBusConnection *con, DBusMessage *msg)
9118c2aff7Sartem {
9218c2aff7Sartem DBusMessage *reply;
9318c2aff7Sartem DBusMessageIter iter;
9418c2aff7Sartem run_request *r;
9518c2aff7Sartem char *tmpstr;
9618c2aff7Sartem
9718c2aff7Sartem r = new_run_request();
9818c2aff7Sartem g_assert(dbus_message_iter_init(msg, &iter));
9918c2aff7Sartem
100*3ab06c27SMilan Jurik if (!parse_udi(r, msg, &iter))
101*3ab06c27SMilan Jurik goto malformed;
102*3ab06c27SMilan Jurik
103*3ab06c27SMilan Jurik if (!parse_environment(r, msg, &iter))
10418c2aff7Sartem goto malformed;
10518c2aff7Sartem
10618c2aff7Sartem /* Next a string of what should be written to stdin */
10718c2aff7Sartem if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
10818c2aff7Sartem goto malformed;
10918c2aff7Sartem dbus_message_iter_get_basic(&iter, &tmpstr);
11018c2aff7Sartem r->input = g_strdup(tmpstr);
11118c2aff7Sartem
11218c2aff7Sartem /* Then an bool to indicate if we should grab stderr */
11318c2aff7Sartem if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
11418c2aff7Sartem goto malformed;
11518c2aff7Sartem dbus_message_iter_get_basic(&iter, &(r->error_on_stderr));
11618c2aff7Sartem
11718c2aff7Sartem /* Then an uint32 timeout for it */
11818c2aff7Sartem if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
11918c2aff7Sartem goto malformed;
12018c2aff7Sartem dbus_message_iter_get_basic(&iter, &(r->timeout));
12118c2aff7Sartem
12218c2aff7Sartem /* let run_request_run handle the reply */
12318c2aff7Sartem run_request_run(r, con, msg, NULL);
12418c2aff7Sartem return;
12518c2aff7Sartem
12618c2aff7Sartem malformed:
12718c2aff7Sartem del_run_request(r);
12818c2aff7Sartem reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed",
12918c2aff7Sartem "Malformed run request");
13018c2aff7Sartem dbus_connection_send(con, reply, NULL);
13118c2aff7Sartem dbus_message_unref(reply);
13218c2aff7Sartem }
13318c2aff7Sartem
13418c2aff7Sartem static void
handle_start(DBusConnection * con,DBusMessage * msg,gboolean is_singleton)135*3ab06c27SMilan Jurik handle_start(DBusConnection *con, DBusMessage *msg, gboolean is_singleton)
13618c2aff7Sartem {
13718c2aff7Sartem DBusMessage *reply;
13818c2aff7Sartem DBusMessageIter iter;
13918c2aff7Sartem run_request *r;
14018c2aff7Sartem GPid pid;
14118c2aff7Sartem
14218c2aff7Sartem r = new_run_request();
143*3ab06c27SMilan Jurik r->is_singleton = is_singleton;
144*3ab06c27SMilan Jurik
14518c2aff7Sartem g_assert(dbus_message_iter_init(msg, &iter));
14618c2aff7Sartem
147*3ab06c27SMilan Jurik if (!dbus_message_iter_init(msg, &iter))
14818c2aff7Sartem goto malformed;
14918c2aff7Sartem
150*3ab06c27SMilan Jurik if (!is_singleton && !parse_udi(r, msg, &iter)) {
151*3ab06c27SMilan Jurik fprintf(stderr, "error parsing udi");
152*3ab06c27SMilan Jurik goto malformed;
153*3ab06c27SMilan Jurik }
154*3ab06c27SMilan Jurik
155*3ab06c27SMilan Jurik if (!parse_environment(r, msg, &iter)) {
156*3ab06c27SMilan Jurik fprintf(stderr, "error parsing environment");
157*3ab06c27SMilan Jurik goto malformed;
158*3ab06c27SMilan Jurik }
159*3ab06c27SMilan Jurik
16018c2aff7Sartem if (run_request_run(r, con, NULL, &pid)) {
161*3ab06c27SMilan Jurik gint64 ppid = pid;
16218c2aff7Sartem reply = dbus_message_new_method_return(msg);
16318c2aff7Sartem dbus_message_append_args (reply,
164*3ab06c27SMilan Jurik DBUS_TYPE_INT64, &ppid,
16518c2aff7Sartem DBUS_TYPE_INVALID);
16618c2aff7Sartem
16718c2aff7Sartem } else {
16818c2aff7Sartem reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Failed",
16918c2aff7Sartem "Start request failed");
17018c2aff7Sartem }
17118c2aff7Sartem dbus_connection_send(con, reply, NULL);
17218c2aff7Sartem dbus_message_unref(reply);
17318c2aff7Sartem return ;
17418c2aff7Sartem malformed:
17518c2aff7Sartem del_run_request(r);
17618c2aff7Sartem reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed",
17718c2aff7Sartem "Malformed start request");
17818c2aff7Sartem dbus_connection_send(con, reply, NULL);
17918c2aff7Sartem dbus_message_unref(reply);
18018c2aff7Sartem }
18118c2aff7Sartem
18218c2aff7Sartem static void
handle_kill(DBusConnection * con,DBusMessage * msg)18318c2aff7Sartem handle_kill(DBusConnection *con, DBusMessage *msg)
18418c2aff7Sartem {
18518c2aff7Sartem DBusError error;
18618c2aff7Sartem DBusMessage *reply = NULL;
18718c2aff7Sartem char *udi;
18818c2aff7Sartem
18918c2aff7Sartem dbus_error_init (&error);
19018c2aff7Sartem if (!dbus_message_get_args(msg, &error,
19118c2aff7Sartem DBUS_TYPE_STRING, &udi,
19218c2aff7Sartem DBUS_TYPE_INVALID)) {
19318c2aff7Sartem reply = dbus_message_new_error (msg, "org.freedesktop.HalRunner.Malformed",
19418c2aff7Sartem "Malformed kill message");
19518c2aff7Sartem g_assert(reply);
19618c2aff7Sartem dbus_connection_send (con, reply, NULL);
19718c2aff7Sartem dbus_message_unref(reply);
19818c2aff7Sartem return;
19918c2aff7Sartem }
20018c2aff7Sartem run_kill_udi(udi);
20118c2aff7Sartem
20218c2aff7Sartem /* always successfull */
20318c2aff7Sartem reply = dbus_message_new_method_return(msg);
20418c2aff7Sartem dbus_connection_send(con, reply, NULL);
20518c2aff7Sartem dbus_message_unref(reply);
20618c2aff7Sartem }
20718c2aff7Sartem
20818c2aff7Sartem static DBusHandlerResult
filter(DBusConnection * con,DBusMessage * msg,void * user_data)20918c2aff7Sartem filter(DBusConnection *con, DBusMessage *msg, void *user_data)
21018c2aff7Sartem {
21118c2aff7Sartem DBusMessage *reply;
21218c2aff7Sartem
21318c2aff7Sartem if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Run")) {
21418c2aff7Sartem handle_run(con, msg);
21518c2aff7Sartem return DBUS_HANDLER_RESULT_HANDLED;
21618c2aff7Sartem } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Start")) {
217*3ab06c27SMilan Jurik handle_start(con, msg, FALSE);
218*3ab06c27SMilan Jurik return DBUS_HANDLER_RESULT_HANDLED;
219*3ab06c27SMilan Jurik } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "StartSingleton")) {
220*3ab06c27SMilan Jurik handle_start(con, msg, TRUE);
22118c2aff7Sartem return DBUS_HANDLER_RESULT_HANDLED;
22218c2aff7Sartem } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Kill")) {
22318c2aff7Sartem handle_kill(con, msg);
22418c2aff7Sartem return DBUS_HANDLER_RESULT_HANDLED;
225*3ab06c27SMilan Jurik } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Shutdown")) {
226*3ab06c27SMilan Jurik run_kill_all ();
227*3ab06c27SMilan Jurik exit (0);
228*3ab06c27SMilan Jurik return DBUS_HANDLER_RESULT_HANDLED;
22918c2aff7Sartem } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "KillAll")) {
23018c2aff7Sartem run_kill_all();
23118c2aff7Sartem /* alwasy successfull */
23218c2aff7Sartem reply = dbus_message_new_method_return(msg);
23318c2aff7Sartem dbus_connection_send(con, reply, NULL);
23418c2aff7Sartem dbus_message_unref(reply);
23518c2aff7Sartem return DBUS_HANDLER_RESULT_HANDLED;
23618c2aff7Sartem }
23718c2aff7Sartem return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
23818c2aff7Sartem }
23918c2aff7Sartem
24018c2aff7Sartem int
main(int argc,char ** argv)24118c2aff7Sartem main(int argc, char **argv)
24218c2aff7Sartem {
24318c2aff7Sartem DBusConnection *c;
24418c2aff7Sartem DBusError error;
24518c2aff7Sartem GMainLoop *loop;
24618c2aff7Sartem char *dbus_address;
24718c2aff7Sartem
24818c2aff7Sartem run_init();
24918c2aff7Sartem dbus_error_init(&error);
25018c2aff7Sartem dbus_address = getenv("HALD_RUNNER_DBUS_ADDRESS");
25118c2aff7Sartem g_assert(dbus_address != NULL);
25218c2aff7Sartem
25318c2aff7Sartem fprintf(stderr, "Runner started - allowed paths are '%s'\n", getenv("PATH"));
25418c2aff7Sartem
25518c2aff7Sartem c = dbus_connection_open(dbus_address, &error);
25618c2aff7Sartem if (c == NULL)
25718c2aff7Sartem goto error;
25818c2aff7Sartem
25918c2aff7Sartem loop = g_main_loop_new(NULL, FALSE);
26018c2aff7Sartem
26118c2aff7Sartem dbus_connection_setup_with_g_main(c, NULL);
26218c2aff7Sartem dbus_connection_set_exit_on_disconnect(c, TRUE);
26318c2aff7Sartem dbus_connection_add_filter(c, filter, NULL, NULL);
26418c2aff7Sartem
26518c2aff7Sartem g_main_loop_run(loop);
26618c2aff7Sartem
26718c2aff7Sartem error:
26818c2aff7Sartem fprintf(stderr,"An error has occured: %s\n", error.message);
26918c2aff7Sartem return -1;
27018c2aff7Sartem }
271