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 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 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 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 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 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 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 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