1 /*************************************************************************** 2 * CVSID: $Id$ 3 * 4 * main.c - Main dbus interface of the hald runner 5 * 6 * Copyright (C) 2006 Sjoerd Simons, <sjoerd@luon.net> 7 * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor@codethink.co.uk> 8 * 9 * Licensed under the Academic Free License version 2.1 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 * 25 **************************************************************************/ 26 #include <stdio.h> 27 #include <stdlib.h> 28 #define DBUS_API_SUBJECT_TO_CHANGE 29 #include <dbus/dbus-glib-lowlevel.h> 30 31 #include <glib.h> 32 #include "utils.h" 33 #include "runner.h" 34 35 #ifndef __GNUC__ 36 #define __attribute__(x) 37 #endif 38 39 static gboolean 40 parse_udi (run_request *r, DBusMessage *msg, DBusMessageIter *iter) 41 { 42 char *tmpstr; 43 44 /* Should be the device UDI */ 45 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) 46 goto malformed; 47 dbus_message_iter_get_basic(iter, &tmpstr); 48 r->udi = g_strdup(tmpstr); 49 50 if (!dbus_message_iter_next(iter)) 51 goto malformed; 52 53 return TRUE; 54 55 malformed: 56 return FALSE; 57 } 58 59 static gboolean 60 parse_environment(run_request *r, DBusMessage *msg, DBusMessageIter *iter) 61 { 62 DBusMessageIter sub_iter; 63 char *tmpstr; 64 65 /* The environment array */ 66 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) 67 goto malformed; 68 dbus_message_iter_recurse(iter, &sub_iter); 69 /* Add default path for the programs we start */ 70 #if defined(__FreeBSD__) 71 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 #else 73 tmpstr = g_strdup_printf("PATH=/sbin:/usr/sbin:/bin:/usr/bin:%s", getenv("PATH")); 74 #endif 75 r->environment = get_string_array(&sub_iter, tmpstr); 76 77 /* Then argv */ 78 if (!dbus_message_iter_next(iter) || dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) 79 goto malformed; 80 dbus_message_iter_recurse(iter, &sub_iter); 81 r->argv = get_string_array(&sub_iter, NULL); 82 83 return TRUE; 84 85 malformed: 86 return FALSE; 87 } 88 89 static void 90 handle_run(DBusConnection *con, DBusMessage *msg) 91 { 92 DBusMessage *reply; 93 DBusMessageIter iter; 94 run_request *r; 95 char *tmpstr; 96 97 r = new_run_request(); 98 g_assert(dbus_message_iter_init(msg, &iter)); 99 100 if (!parse_udi(r, msg, &iter)) 101 goto malformed; 102 103 if (!parse_environment(r, msg, &iter)) 104 goto malformed; 105 106 /* Next a string of what should be written to stdin */ 107 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) 108 goto malformed; 109 dbus_message_iter_get_basic(&iter, &tmpstr); 110 r->input = g_strdup(tmpstr); 111 112 /* Then an bool to indicate if we should grab stderr */ 113 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) 114 goto malformed; 115 dbus_message_iter_get_basic(&iter, &(r->error_on_stderr)); 116 117 /* Then an uint32 timeout for it */ 118 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) 119 goto malformed; 120 dbus_message_iter_get_basic(&iter, &(r->timeout)); 121 122 /* let run_request_run handle the reply */ 123 run_request_run(r, con, msg, NULL); 124 return; 125 126 malformed: 127 del_run_request(r); 128 reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed", 129 "Malformed run request"); 130 dbus_connection_send(con, reply, NULL); 131 dbus_message_unref(reply); 132 } 133 134 static void 135 handle_start(DBusConnection *con, DBusMessage *msg, gboolean is_singleton) 136 { 137 DBusMessage *reply; 138 DBusMessageIter iter; 139 run_request *r; 140 GPid pid; 141 142 r = new_run_request(); 143 r->is_singleton = is_singleton; 144 145 g_assert(dbus_message_iter_init(msg, &iter)); 146 147 if (!dbus_message_iter_init(msg, &iter)) 148 goto malformed; 149 150 if (!is_singleton && !parse_udi(r, msg, &iter)) { 151 fprintf(stderr, "error parsing udi"); 152 goto malformed; 153 } 154 155 if (!parse_environment(r, msg, &iter)) { 156 fprintf(stderr, "error parsing environment"); 157 goto malformed; 158 } 159 160 if (run_request_run(r, con, NULL, &pid)) { 161 gint64 ppid = pid; 162 reply = dbus_message_new_method_return(msg); 163 dbus_message_append_args (reply, 164 DBUS_TYPE_INT64, &ppid, 165 DBUS_TYPE_INVALID); 166 167 } else { 168 reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Failed", 169 "Start request failed"); 170 } 171 dbus_connection_send(con, reply, NULL); 172 dbus_message_unref(reply); 173 return ; 174 malformed: 175 del_run_request(r); 176 reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed", 177 "Malformed start request"); 178 dbus_connection_send(con, reply, NULL); 179 dbus_message_unref(reply); 180 } 181 182 static void 183 handle_kill(DBusConnection *con, DBusMessage *msg) 184 { 185 DBusError error; 186 DBusMessage *reply = NULL; 187 char *udi; 188 189 dbus_error_init (&error); 190 if (!dbus_message_get_args(msg, &error, 191 DBUS_TYPE_STRING, &udi, 192 DBUS_TYPE_INVALID)) { 193 reply = dbus_message_new_error (msg, "org.freedesktop.HalRunner.Malformed", 194 "Malformed kill message"); 195 g_assert(reply); 196 dbus_connection_send (con, reply, NULL); 197 dbus_message_unref(reply); 198 return; 199 } 200 run_kill_udi(udi); 201 202 /* always successfull */ 203 reply = dbus_message_new_method_return(msg); 204 dbus_connection_send(con, reply, NULL); 205 dbus_message_unref(reply); 206 } 207 208 static DBusHandlerResult 209 filter(DBusConnection *con, DBusMessage *msg, void *user_data) 210 { 211 DBusMessage *reply; 212 213 if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Run")) { 214 handle_run(con, msg); 215 return DBUS_HANDLER_RESULT_HANDLED; 216 } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Start")) { 217 handle_start(con, msg, FALSE); 218 return DBUS_HANDLER_RESULT_HANDLED; 219 } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "StartSingleton")) { 220 handle_start(con, msg, TRUE); 221 return DBUS_HANDLER_RESULT_HANDLED; 222 } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Kill")) { 223 handle_kill(con, msg); 224 return DBUS_HANDLER_RESULT_HANDLED; 225 } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "Shutdown")) { 226 run_kill_all (); 227 exit (0); 228 return DBUS_HANDLER_RESULT_HANDLED; 229 } else if (dbus_message_is_method_call(msg, "org.freedesktop.HalRunner", "KillAll")) { 230 run_kill_all(); 231 /* alwasy successfull */ 232 reply = dbus_message_new_method_return(msg); 233 dbus_connection_send(con, reply, NULL); 234 dbus_message_unref(reply); 235 return DBUS_HANDLER_RESULT_HANDLED; 236 } 237 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 238 } 239 240 int 241 main(int argc, char **argv) 242 { 243 DBusConnection *c; 244 DBusError error; 245 GMainLoop *loop; 246 char *dbus_address; 247 248 run_init(); 249 dbus_error_init(&error); 250 dbus_address = getenv("HALD_RUNNER_DBUS_ADDRESS"); 251 g_assert(dbus_address != NULL); 252 253 fprintf(stderr, "Runner started - allowed paths are '%s'\n", getenv("PATH")); 254 255 c = dbus_connection_open(dbus_address, &error); 256 if (c == NULL) 257 goto error; 258 259 loop = g_main_loop_new(NULL, FALSE); 260 261 dbus_connection_setup_with_g_main(c, NULL); 262 dbus_connection_set_exit_on_disconnect(c, TRUE); 263 dbus_connection_add_filter(c, filter, NULL, NULL); 264 265 g_main_loop_run(loop); 266 267 error: 268 fprintf(stderr,"An error has occured: %s\n", error.message); 269 return -1; 270 } 271