xref: /illumos-gate/usr/src/cmd/hal/hald-runner/main.c (revision 69a119caa6570c7077699161b7c28b6ee9f8b0f4)
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