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
parse_udi(run_request * r,DBusMessage * msg,DBusMessageIter * iter)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
parse_environment(run_request * r,DBusMessage * msg,DBusMessageIter * iter)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
handle_run(DBusConnection * con,DBusMessage * msg)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
handle_start(DBusConnection * con,DBusMessage * msg,gboolean is_singleton)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
handle_kill(DBusConnection * con,DBusMessage * msg)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
filter(DBusConnection * con,DBusMessage * msg,void * user_data)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
main(int argc,char ** argv)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