Merge lp:~ted/ubuntu-app-launch/xmir-support into lp:ubuntu-app-launch/15.04

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/ubuntu-app-launch/xmir-support
Merge into: lp:ubuntu-app-launch/15.04
Diff against target: 1717 lines (+1193/-77) (has conflicts)
29 files modified
CMakeLists.txt (+22/-2)
cmake/UseGdbusCodegen.cmake (+21/-20)
data/com.canonical.UbuntuAppLaunch.SocketDemangler.xml (+8/-0)
debian/changelog (+22/-0)
debian/control (+2/-1)
debian/libubuntu-app-launch2.symbols (+2/-0)
exec-line-exec-trace.tp (+6/-0)
exec-line-exec.c (+14/-0)
libubuntu-app-launch/CMakeLists.txt (+11/-3)
libubuntu-app-launch/click-exec.c (+8/-0)
libubuntu-app-launch/desktop-exec.c (+8/-0)
libubuntu-app-launch/ubuntu-app-launch.c (+363/-6)
libubuntu-app-launch/ubuntu-app-launch.h (+43/-1)
libubuntu-app-launch/ubuntu-app-launch.pc.in (+1/-1)
socket-demangler.c (+124/-0)
tests/CMakeLists.txt (+15/-1)
tests/libual-test.cc (+197/-27)
tests/mir-mock.cpp (+106/-0)
tests/mir-mock.h (+12/-0)
tests/socket-tool.c (+28/-0)
tests/xmir-helper-exec.sh (+3/-0)
tests/xmir-helper-test.in (+25/-0)
tests/xmir-mock.sh (+27/-0)
ubuntu-app-test/CMakeLists.txt (+0/-8)
ubuntu-app-test/ubuntu-app-test (+0/-6)
upstart-jobs/application-click.conf.in (+3/-0)
upstart-jobs/application-legacy.conf.in (+3/-0)
xmir-helper.c (+118/-0)
zg-report-app.c (+1/-1)
Text conflict in debian/changelog
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/xmir-support
Reviewer Review Type Date Requested Status
Indicator Applet Developers Pending
Review via email: mp+257139@code.launchpad.net

This proposal has been superseded by a proposal from 2015-07-01.

To post a comment you must log in.
124. By Ted Gould

Updating to trunk

125. By Ted Gould

Refactor to make things all pipey

126. By Ted Gould

Putting the basics together for a helper test

127. By Ted Gould

Remove trailing returns

128. By Ted Gould

Linking into CMake

129. By Ted Gould

Getting the value out of the code page

130. By Ted Gould

Add in a sig child handler to handle the Xserver dying and not sending info on the socket

131. By Ted Gould

Adding in an evil test

132. By Ted Gould

Adding in rootless

133. By Ted Gould

Desktop tests for setting the xmir values

134. By Ted Gould

Adding a click test, with all the joy that brings

135. By Ted Gould

Remove the -rootless flag

136. By Ted Gould

Refactor test into a helper function

137. By Ted Gould

Porting some more cases

138. By Ted Gould

Changing the click mir tests over

139. By Ted Gould

Mention varargs

140. By Ted Gould

Remove std=c11

141. By Ted Gould

Don't set a default value for XMIR_ENABLE

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-03-05 02:59:41 +0000
3+++ CMakeLists.txt 2015-07-01 01:16:06 +0000
4@@ -36,7 +36,8 @@
5 )
6 set(ubuntu_app_launch_arch "${UBUNTU_APP_LAUNCH_ARCH}")
7
8-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-error=unused-function -std=c99")
9+# Deprecated needed for g_atexit() in libual
10+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-error=unused-function -Wno-error=deprecated-declarations -std=c99")
11
12 enable_testing()
13
14@@ -46,7 +47,7 @@
15 pkg_check_modules(GOBJECT2 REQUIRED gobject-2.0)
16 include_directories(${GOBJECT2_INCLUDE_DIRS})
17
18-pkg_check_modules(GIO2 REQUIRED gio-2.0)
19+pkg_check_modules(GIO2 REQUIRED gio-2.0 gio-unix-2.0)
20 include_directories(${GIO2_INCLUDE_DIRS})
21
22 pkg_check_modules(JSONGLIB REQUIRED json-glib-1.0)
23@@ -80,6 +81,8 @@
24
25 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -fPIC")
26
27+add_definitions( -DXMIR_HELPER="${pkglibexecdir}/xmir-helper" )
28+
29 ####################
30 # Helpers
31 ####################
32@@ -135,6 +138,14 @@
33 install(TARGETS application-failed RUNTIME DESTINATION "${pkglibexecdir}")
34
35 ####################
36+# xmir-helper
37+####################
38+
39+add_executable(xmir-helper xmir-helper.c)
40+set_target_properties(xmir-helper PROPERTIES OUTPUT_NAME "xmir-helper")
41+install(TARGETS xmir-helper RUNTIME DESTINATION "${pkglibexecdir}")
42+
43+####################
44 # untrusted-helper-type-end
45 ####################
46
47@@ -161,6 +172,15 @@
48 install(TARGETS oom-adjust-setuid-helper RUNTIME DESTINATION "${pkglibexecdir}")
49
50 ####################
51+# socket-demangler
52+####################
53+
54+add_executable(socket-demangler-helper socket-demangler.c)
55+set_target_properties(socket-demangler-helper PROPERTIES OUTPUT_NAME "socket-demangler")
56+target_link_libraries(socket-demangler-helper ${GIO2_LIBRARIES})
57+install(TARGETS socket-demangler-helper RUNTIME DESTINATION "${pkglibexecdir}")
58+
59+####################
60 # ubuntu-app-launch-desktop.click-hook
61 ####################
62
63
64=== modified file 'cmake/UseGdbusCodegen.cmake'
65--- cmake/UseGdbusCodegen.cmake 2013-07-24 21:13:19 +0000
66+++ cmake/UseGdbusCodegen.cmake 2015-07-01 01:16:06 +0000
67@@ -8,28 +8,29 @@
68 message(FATAL_ERROR "Excutable gdbus-codegen not found")
69 endif()
70
71-function(add_gdbus_codegen)
72- set(_one_value OUTFILES NAME PREFIX NAMESPACE SERVICE_XML)
73- set(_multi_value DEPENDS)
74- cmake_parse_arguments (arg "" "${_one_value}" "${_multi_value}" ${ARGN})
75+macro(add_gdbus_codegen outfiles name prefix service_xml)
76+ add_custom_command(
77+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
78+ COMMAND "${GDBUS_CODEGEN}"
79+ --interface-prefix "${prefix}"
80+ --generate-c-code "${name}"
81+ "${service_xml}"
82+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
83+ DEPENDS ${ARGN} "${service_xml}"
84+ )
85+ list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
86+endmacro(add_gdbus_codegen)
87
88- if(arg_PREFIX)
89- set(PREFIX --interface-prefix ${arg_PREFIX})
90- endif()
91-
92- if(arg_NAMESPACE)
93- set(NAMESPACE --c-namespace ${arg_NAMESPACE})
94- endif()
95-
96+macro(add_gdbus_codegen_with_namespace outfiles name prefix namespace service_xml)
97 add_custom_command(
98- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.h" "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.c"
99+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
100 COMMAND "${GDBUS_CODEGEN}"
101- --generate-c-code "${arg_NAME}"
102- ${PREFIX}
103- ${NAMESPACE}
104- "${arg_SERVICE_XML}"
105+ --interface-prefix "${prefix}"
106+ --generate-c-code "${name}"
107+ --c-namespace "${namespace}"
108+ "${service_xml}"
109 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
110- DEPENDS ${arg_DEPENDS} "${arg_SERVICE_XML}"
111+ DEPENDS ${ARGN} "${service_xml}"
112 )
113- set(${arg_OUTFILES} ${${arg_OUTFILES}} "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.c" PARENT_SCOPE)
114-endfunction(add_gdbus_codegen)
115+ list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
116+endmacro(add_gdbus_codegen_with_namespace)
117
118=== added file 'data/com.canonical.UbuntuAppLaunch.SocketDemangler.xml'
119--- data/com.canonical.UbuntuAppLaunch.SocketDemangler.xml 1970-01-01 00:00:00 +0000
120+++ data/com.canonical.UbuntuAppLaunch.SocketDemangler.xml 2015-07-01 01:16:06 +0000
121@@ -0,0 +1,8 @@
122+<?xml version="1.0" encoding="UTF-8"?>
123+<node>
124+ <interface name="com.canonical.UbuntuAppLaunch.SocketDemangler">
125+ <method name="GetMirSocket">
126+ <arg type="h" name="handle" direction="out" />
127+ </method>
128+ </interface>
129+</node>
130
131=== modified file 'debian/changelog'
132--- debian/changelog 2015-06-03 21:20:42 +0000
133+++ debian/changelog 2015-07-01 01:16:06 +0000
134@@ -1,3 +1,4 @@
135+<<<<<<< TREE
136 ubuntu-app-launch (0.4+15.04.20150603-0ubuntu1) vivid; urgency=medium
137
138 [ Ted Gould ]
139@@ -5,6 +6,27 @@
140
141 -- CI Train Bot <ci-train-bot@canonical.com> Wed, 03 Jun 2015 21:20:42 +0000
142
143+=======
144+ubuntu-app-launch (0.5+15.10.20150605-0ubuntu1) wily; urgency=medium
145+
146+ [ Ted Gould ]
147+ * Don't error on ZG failure (LP: #1452178)
148+ * Fallback to looking for the AppID tag if the source is missing (LP:
149+ #1461138)
150+
151+ -- CI Train Bot <ci-train-bot@canonical.com> Fri, 05 Jun 2015 19:49:48 +0000
152+
153+ubuntu-app-launch (0.5+15.10.20150604-0ubuntu1) wily; urgency=medium
154+
155+ [ Ted Gould ]
156+ * Add an untrusted helper that works with Mir trusted prompt sessions.
157+
158+ [ CI Train Bot ]
159+ * debian/libubuntu-app-launch2.symbols: update to released version.
160+
161+ -- CI Train Bot <ci-train-bot@canonical.com> Thu, 04 Jun 2015 20:35:57 +0000
162+
163+>>>>>>> MERGE-SOURCE
164 ubuntu-app-launch (0.4+15.04.20150410-0ubuntu1) vivid; urgency=medium
165
166 [ Ted Gould ]
167
168=== modified file 'debian/control'
169--- debian/control 2015-03-05 03:04:41 +0000
170+++ debian/control 2015-07-01 01:16:06 +0000
171@@ -16,7 +16,7 @@
172 libgtest-dev,
173 libjson-glib-dev,
174 liblttng-ust-dev,
175- libmirclient-dev (>= 0.5) [!powerpc !ppc64el],
176+ libmirclient-dev (>= 0.5),
177 libnih-dbus-dev,
178 libnih-dev,
179 libupstart-dev,
180@@ -78,6 +78,7 @@
181 Depends: ${misc:Depends},
182 ${shlibs:Depends},
183 libglib2.0-dev,
184+ libmirclient-dev (>= 0.5),
185 libubuntu-app-launch2 (= ${binary:Version}),
186 Pre-Depends: ${misc:Pre-Depends},
187 Multi-Arch: same
188
189=== modified file 'debian/libubuntu-app-launch2.symbols'
190--- debian/libubuntu-app-launch2.symbols 2015-03-05 14:36:33 +0000
191+++ debian/libubuntu-app-launch2.symbols 2015-07-01 01:16:06 +0000
192@@ -2,6 +2,7 @@
193 ubuntu_app_launch_app_id_parse@Base 0.4
194 ubuntu_app_launch_application_log_path@Base 0.4
195 ubuntu_app_launch_get_primary_pid@Base 0.4
196+ ubuntu_app_launch_helper_set_exec@Base 0.5+15.10.20150604
197 ubuntu_app_launch_list_helper_instances@Base 0.4
198 ubuntu_app_launch_list_helpers@Base 0.4
199 ubuntu_app_launch_list_running_apps@Base 0.4
200@@ -32,6 +33,7 @@
201 ubuntu_app_launch_start_application_test@Base 0.4
202 ubuntu_app_launch_start_helper@Base 0.4
203 ubuntu_app_launch_start_multiple_helper@Base 0.4
204+ ubuntu_app_launch_start_session_helper@Base 0.5+15.10.20150604
205 ubuntu_app_launch_stop_application@Base 0.4
206 ubuntu_app_launch_stop_helper@Base 0.4
207 ubuntu_app_launch_stop_multiple_helper@Base 0.4
208
209=== modified file 'exec-line-exec-trace.tp'
210--- exec-line-exec-trace.tp 2014-08-11 17:19:57 +0000
211+++ exec-line-exec-trace.tp 2015-07-01 01:16:06 +0000
212@@ -5,6 +5,12 @@
213 ctf_string(appid, appid)
214 )
215 )
216+TRACEPOINT_EVENT(ubuntu_app_launch, exec_parse_complete,
217+ TP_ARGS(const char *, appid),
218+ TP_FIELDS(
219+ ctf_string(appid, appid)
220+ )
221+)
222 TRACEPOINT_EVENT(ubuntu_app_launch, exec_pre_exec,
223 TP_ARGS(const char *, appid),
224 TP_FIELDS(
225
226=== modified file 'exec-line-exec.c'
227--- exec-line-exec.c 2014-08-11 17:19:57 +0000
228+++ exec-line-exec.c 2015-07-01 01:16:06 +0000
229@@ -139,6 +139,20 @@
230 return 1;
231 }
232
233+ ual_tracepoint(exec_parse_complete, app_id);
234+
235+ if (g_getenv("MIR_SOCKET") != NULL && g_strcmp0(g_getenv("APP_XMIR_ENABLE"), "1") == 0) {
236+ g_debug("XMir Helper being used");
237+
238+ /* xmir-helper $(APP_ID) $(COMMAND) */
239+ const gchar * appid = g_getenv("APP_ID");
240+ g_array_prepend_val(newargv, appid);
241+
242+ /* Pulling into the heap instead of the code page */
243+ char * xmir_helper = g_strdup(XMIR_HELPER);
244+ g_array_prepend_val(newargv, xmir_helper);
245+ }
246+
247 /* Now exec */
248 gchar ** nargv = (gchar**)g_array_free(newargv, FALSE);
249
250
251=== modified file 'libubuntu-app-launch/CMakeLists.txt'
252--- libubuntu-app-launch/CMakeLists.txt 2014-11-21 21:17:09 +0000
253+++ libubuntu-app-launch/CMakeLists.txt 2015-07-01 01:16:06 +0000
254@@ -17,7 +17,7 @@
255 add_lttng_gen_tp(NAME ubuntu-app-launch-trace)
256
257 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
258-add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" )
259+add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" -DDEMANGLER_PATH="${pkglibexecdir}/socket-demangler" )
260
261 set(LAUNCHER_HEADERS
262 ubuntu-app-launch.h
263@@ -31,7 +31,13 @@
264 ubuntu-app-launch-trace.c
265 )
266
267-add_library(ubuntu-launcher SHARED ${LAUNCHER_SOURCES})
268+set(LAUNCHER_GEN_SOURCES
269+)
270+
271+add_gdbus_codegen_with_namespace(LAUNCHER_GEN_SOURCES proxy-socket-demangler com.canonical.UbuntuAppLaunch. proxy ${CMAKE_SOURCE_DIR}/data/com.canonical.UbuntuAppLaunch.SocketDemangler.xml)
272+
273+
274+add_library(ubuntu-launcher SHARED ${LAUNCHER_SOURCES} ${LAUNCHER_GEN_SOURCES})
275
276 set_target_properties(ubuntu-launcher PROPERTIES
277 VERSION ${ABI_VERSION}.0.0
278@@ -50,6 +56,7 @@
279 ${JSONGLIB_LIBRARIES}
280 ${CLICK_LIBRARIES}
281 ${ZEITGEIST_LIBRARIES}
282+ ${MIR_LIBRARIES}
283 helpers
284 -Wl,--no-undefined
285 )
286@@ -91,7 +98,8 @@
287 set(UbuntuAppLaunch_2_gir_INCLUDES GObject-2.0)
288
289 gir_get_cflags(_cflags)
290-set(UbuntuAppLaunch_2_gir_CFLAGS ${c_flags})
291+list_prefix(MIR_C_INCLUDES MIR_INCLUDE_DIRS "-I")
292+set(UbuntuAppLaunch_2_gir_CFLAGS ${c_flags} ${MIR_C_INCLUDES})
293 set(UbuntuAppLaunch_2_gir_LIBS ubuntu-app-launch)
294
295 list_make_absolute(_abs_introspection_files _introspection_files "${CMAKE_CURRENT_SOURCE_DIR}/")
296
297=== modified file 'libubuntu-app-launch/click-exec.c'
298--- libubuntu-app-launch/click-exec.c 2014-08-22 21:04:13 +0000
299+++ libubuntu-app-launch/click-exec.c 2015-07-01 01:16:06 +0000
300@@ -136,6 +136,14 @@
301 return FALSE;
302 }
303
304+ if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-XMir-Enable", NULL)) {
305+ if (g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-XMir-Enable", NULL)) {
306+ env_handle_add(handle, "APP_XMIR_ENABLE", "1");
307+ } else {
308+ env_handle_add(handle, "APP_XMIR_ENABLE", "0");
309+ }
310+ }
311+
312 /* This string is quoted using desktop file quoting:
313 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables */
314 gchar * exec = desktop_to_exec(keyfile, desktopfile);
315
316=== modified file 'libubuntu-app-launch/desktop-exec.c'
317--- libubuntu-app-launch/desktop-exec.c 2014-08-22 21:06:00 +0000
318+++ libubuntu-app-launch/desktop-exec.c 2015-07-01 01:16:06 +0000
319@@ -118,6 +118,14 @@
320 env_handle_add(handle, "APP_EXEC_POLICY", "unconfined");
321 }
322
323+ if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-XMir-Enable", NULL)) {
324+ if (g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-XMir-Enable", NULL)) {
325+ env_handle_add(handle, "APP_XMIR_ENABLE", "1");
326+ } else {
327+ env_handle_add(handle, "APP_XMIR_ENABLE", "0");
328+ }
329+ }
330+
331 /* This string is quoted using desktop file quoting:
332 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables */
333 gchar * execline = desktop_to_exec(keyfile, app_id);
334
335=== modified file 'libubuntu-app-launch/ubuntu-app-launch.c'
336--- libubuntu-app-launch/ubuntu-app-launch.c 2015-04-10 16:58:27 +0000
337+++ libubuntu-app-launch/ubuntu-app-launch.c 2015-07-01 01:16:06 +0000
338@@ -22,6 +22,7 @@
339 #include <click.h>
340 #include <upstart.h>
341 #include <gio/gio.h>
342+#include <gio/gunixfdlist.h>
343 #include <string.h>
344 #include <fcntl.h>
345 #include <errno.h>
346@@ -33,11 +34,17 @@
347 #include "ual-tracepoint.h"
348 #include "click-exec.h"
349 #include "desktop-exec.h"
350+#include "recoverable-problem.h"
351+#include "proxy-socket-demangler.h"
352
353 static void apps_for_job (GDBusConnection * con, const gchar * name, GArray * apps, gboolean truncate_legacy);
354 static void free_helper (gpointer value);
355 static GList * pids_for_appid (const gchar * appid);
356 int kill (pid_t pid, int signal);
357+static gchar * escape_dbus_string (const gchar * input);
358+
359+G_DEFINE_QUARK(UBUNTU_APP_LAUNCH_PROXY_PATH, proxy_path);
360+G_DEFINE_QUARK(UBUNTU_APP_LAUNCH_MIR_FD, mir_fd);
361
362 /* Function to take the urls and escape them so that they can be
363 parsed on the other side correctly. */
364@@ -1754,7 +1761,7 @@
365 to define the instance. In the end there's only one job with
366 an array of instances. */
367 static gboolean
368-start_helper_core (const gchar * type, const gchar * appid, const gchar * const * uris, const gchar * instance)
369+start_helper_core (const gchar * type, const gchar * appid, const gchar * const * uris, const gchar * instance, const gchar * mirsocketpath)
370 {
371 GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
372 g_return_val_if_fail(con != NULL, FALSE);
373@@ -1778,6 +1785,11 @@
374 g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instance)));
375 }
376
377+ if (mirsocketpath != NULL) {
378+ g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("UBUNTU_APP_LAUNCH_DEMANGLE_PATH=%s", mirsocketpath)));
379+ g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("UBUNTU_APP_LAUNCH_DEMANGLE_NAME=%s", g_dbus_connection_get_unique_name(con))));
380+ }
381+
382 g_variant_builder_close(&builder);
383 g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
384
385@@ -1807,7 +1819,7 @@
386 g_return_val_if_fail(appid != NULL, FALSE);
387 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, FALSE);
388
389- return start_helper_core(type, appid, uris, NULL);
390+ return start_helper_core(type, appid, uris, NULL, NULL);
391 }
392
393 gchar *
394@@ -1819,10 +1831,254 @@
395
396 gchar * instanceid = g_strdup_printf("%" G_GUINT64_FORMAT, g_get_real_time());
397
398- if (start_helper_core(type, appid, uris, instanceid)) {
399- return instanceid;
400- }
401-
402+ if (start_helper_core(type, appid, uris, instanceid, NULL)) {
403+ return instanceid;
404+ }
405+
406+ g_free(instanceid);
407+ return NULL;
408+}
409+
410+/* Transfer from Mir's data structure to ours */
411+static void
412+get_mir_session_fd_helper (MirPromptSession * session, size_t count, int const * fdin, void * user_data)
413+{
414+ if (count != 1) {
415+ g_warning("Mir trusted session returned %d FDs instead of one", (int)count);
416+ return;
417+ }
418+
419+ int * retfd = (int *)user_data;
420+ *retfd = fdin[0];
421+}
422+
423+/* Setup to get the FD from Mir, blocking */
424+static int
425+get_mir_session_fd (MirPromptSession * session)
426+{
427+ int retfd = 0;
428+ MirWaitHandle * wait = mir_prompt_session_new_fds_for_prompt_providers(session,
429+ 1,
430+ get_mir_session_fd_helper,
431+ &retfd);
432+
433+ mir_wait_for(wait);
434+
435+ return retfd;
436+}
437+
438+static GList * open_proxies = NULL;
439+
440+static gint
441+remove_socket_path_find (gconstpointer a, gconstpointer b)
442+{
443+ GObject * obj = (GObject *)a;
444+ const gchar * path = (const gchar *)b;
445+
446+ gchar * objpath = g_object_get_qdata(obj, proxy_path_quark());
447+
448+ return g_strcmp0(objpath, path);
449+}
450+
451+/* Cleans up if we need to early */
452+static gboolean
453+remove_socket_path (const gchar * path)
454+{
455+ GList * thisproxy = g_list_find_custom(open_proxies, path, remove_socket_path_find);
456+ if (thisproxy == NULL)
457+ return FALSE;
458+
459+ g_debug("Removing Mir Socket Proxy: %s", path);
460+
461+ GObject * obj = G_OBJECT(thisproxy->data);
462+ open_proxies = g_list_delete_link(open_proxies, thisproxy);
463+
464+ /* Remove ourselves from DBus if we weren't already */
465+ g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(obj));
466+
467+ /* If we still have FD, close it */
468+ int mirfd = GPOINTER_TO_INT(g_object_get_qdata(obj, mir_fd_quark()));
469+ if (mirfd != 0) {
470+ close(mirfd);
471+
472+ /* This is actually an error, we should expect not to find
473+ this here to do anything with it. */
474+ const gchar * props[3] = {
475+ "UbuntuAppLaunchProxyDbusPath",
476+ NULL,
477+ NULL
478+ };
479+ props[1] = path;
480+ report_recoverable_problem("ubuntu-app-launch-mir-fd-proxy", 0, TRUE, props);
481+ }
482+
483+ g_object_unref(obj);
484+
485+ return TRUE;
486+}
487+
488+/* Small timeout function that shouldn't, in most cases, ever do anything.
489+ But we need it here to ensure we don't leave things on the bus */
490+static gboolean
491+proxy_timeout (gpointer user_data)
492+{
493+ const gchar * path = (const gchar *)user_data;
494+ remove_socket_path(path);
495+ return G_SOURCE_REMOVE;
496+}
497+
498+/* Removes the whole list of proxies if they are there */
499+static void
500+proxy_cleanup_list (void)
501+{
502+ while (open_proxies) {
503+ GObject * obj = G_OBJECT(open_proxies->data);
504+ gchar * path = g_object_get_qdata(obj, proxy_path_quark());
505+ remove_socket_path(path);
506+ }
507+}
508+
509+static gboolean
510+proxy_mir_socket (GObject * obj, GDBusMethodInvocation * invocation, gpointer user_data)
511+{
512+ g_debug("Called to give Mir socket");
513+ int fd = GPOINTER_TO_INT(user_data);
514+
515+ if (fd == 0) {
516+ g_critical("No FDs to give!");
517+ return FALSE;
518+ }
519+
520+ /* Index into fds */
521+ GVariant* handle = g_variant_new_handle(0);
522+ GVariant* tuple = g_variant_new_tuple(&handle, 1);
523+
524+ GError* error = NULL;
525+ GUnixFDList* list = g_unix_fd_list_new();
526+ g_unix_fd_list_append(list, fd, &error);
527+
528+ if (error == NULL) {
529+ g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, tuple, list);
530+ } else {
531+ g_variant_ref_sink(tuple);
532+ g_variant_unref(tuple);
533+ }
534+
535+ g_object_unref(list);
536+
537+ if (error != NULL) {
538+ g_critical("Unable to pass FD %d: %s", fd, error->message);
539+ g_error_free(error);
540+ return FALSE;
541+ }
542+
543+ g_object_set_qdata(obj, mir_fd_quark(), GINT_TO_POINTER(0));
544+
545+ return TRUE;
546+}
547+
548+/* Sets up the DBus proxy to send to the demangler */
549+static gchar *
550+build_proxy_socket_path (const gchar * appid, int mirfd)
551+{
552+ static gboolean final_cleanup = FALSE;
553+ if (!final_cleanup) {
554+ g_atexit(proxy_cleanup_list);
555+ final_cleanup = TRUE;
556+ }
557+
558+ GError * error = NULL;
559+ GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
560+ if (error != NULL) {
561+ g_warning("Unable to get session bus: %s", error->message);
562+ g_error_free(error);
563+ return NULL;
564+ }
565+
566+ /* Export an Object on DBus */
567+ proxySocketDemangler * skel = proxy_socket_demangler_skeleton_new();
568+ g_signal_connect(G_OBJECT(skel), "handle-get-mir-socket", G_CALLBACK(proxy_mir_socket), GINT_TO_POINTER(mirfd));
569+
570+ gchar * encoded_appid = escape_dbus_string(appid);
571+ gchar * socket_name = NULL;
572+ /* Loop until we fine an object path that isn't taken (probably only once) */
573+ while (socket_name == NULL) {
574+ gchar* tryname = g_strdup_printf("/com/canonical/UbuntuAppLaunch/%s/%X", encoded_appid, g_random_int());
575+ g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skel),
576+ session,
577+ tryname,
578+ &error);
579+
580+ if (error == NULL) {
581+ socket_name = tryname;
582+ g_debug("Exporting Mir socket on path: %s", socket_name);
583+ } else {
584+ /* Always print the error, but if the object path is in use let's
585+ not exit the loop. Let's just try again. */
586+ bool exitnow = (error->domain != G_DBUS_ERROR || error->code != G_DBUS_ERROR_OBJECT_PATH_IN_USE);
587+ g_critical("Unable to export trusted session object: %s", error->message);
588+
589+ g_clear_error(&error);
590+ g_free(tryname);
591+
592+ if (exitnow) {
593+ break;
594+ }
595+ }
596+ }
597+ g_free(encoded_appid);
598+
599+ /* If we didn't get a socket name, we should just exit. And
600+ make sure to clean up the socket. */
601+ if (socket_name == NULL) {
602+ g_object_unref(skel);
603+ g_object_unref(session);
604+ g_critical("Unable to export object to any name");
605+ return NULL;
606+ }
607+
608+ g_object_set_qdata_full(G_OBJECT(skel), proxy_path_quark(), g_strdup(socket_name), g_free);
609+ g_object_set_qdata(G_OBJECT(skel), mir_fd_quark(), GINT_TO_POINTER(mirfd));
610+ open_proxies = g_list_prepend(open_proxies, skel);
611+
612+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
613+ 2,
614+ proxy_timeout,
615+ g_strdup(socket_name),
616+ g_free);
617+
618+ g_object_unref(session);
619+
620+ return socket_name;
621+}
622+
623+gchar *
624+ubuntu_app_launch_start_session_helper (const gchar * type, MirPromptSession * session, const gchar * appid, const gchar * const * uris)
625+{
626+ g_return_val_if_fail(type != NULL, NULL);
627+ g_return_val_if_fail(session != NULL, NULL);
628+ g_return_val_if_fail(appid != NULL, NULL);
629+ g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, NULL);
630+
631+ int mirfd = get_mir_session_fd(session);
632+ if (mirfd == 0)
633+ return NULL;
634+
635+ gchar * socket_path = build_proxy_socket_path(appid, mirfd);
636+ if (socket_path == NULL) {
637+ close(mirfd);
638+ return NULL;
639+ }
640+
641+ gchar * instanceid = g_strdup_printf("%" G_GUINT64_FORMAT, g_get_real_time());
642+
643+ if (start_helper_core(type, appid, uris, instanceid, socket_path)) {
644+ return instanceid;
645+ }
646+
647+ remove_socket_path(socket_path);
648+ g_free(socket_path);
649+ close(mirfd);
650 g_free(instanceid);
651 return NULL;
652 }
653@@ -2203,3 +2459,104 @@
654 return delete_helper_generic(observer, helper_type, user_data, &helper_stopped_obs);
655 }
656
657+/* Sets an environment variable in Upstart */
658+static void
659+set_var (GDBusConnection * bus, const gchar * job_name, const gchar * instance_name, const gchar * envvar)
660+{
661+ GVariantBuilder builder; /* Target: (assb) */
662+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
663+
664+ /* Setup the job properties */
665+ g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
666+ g_variant_builder_add_value(&builder, g_variant_new_string(job_name));
667+ if (instance_name != NULL)
668+ g_variant_builder_add_value(&builder, g_variant_new_string(instance_name));
669+ g_variant_builder_close(&builder);
670+
671+ g_variant_builder_add_value(&builder, g_variant_new_string(envvar));
672+
673+ /* Do we want to replace? Yes, we do! */
674+ g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
675+
676+ g_dbus_connection_call(bus,
677+ "com.ubuntu.Upstart",
678+ "/com/ubuntu/Upstart",
679+ "com.ubuntu.Upstart0_6",
680+ "SetEnv",
681+ g_variant_builder_end(&builder),
682+ NULL, /* reply */
683+ G_DBUS_CALL_FLAGS_NONE,
684+ -1, /* timeout */
685+ NULL, /* cancelable */
686+ NULL, NULL); /* callback */
687+}
688+
689+gboolean
690+ubuntu_app_launch_helper_set_exec (const gchar * execline, const gchar * directory)
691+{
692+ g_return_val_if_fail(execline != NULL, FALSE);
693+ g_return_val_if_fail(execline[0] != '\0', FALSE);
694+
695+ /* Check to see if we can get the job environment */
696+ const gchar * job_name = g_getenv("UPSTART_JOB");
697+ const gchar * instance_name = g_getenv("UPSTART_INSTANCE");
698+ const gchar * demangler = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
699+ g_return_if_fail(job_name != NULL);
700+
701+ GError * error = NULL;
702+ GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
703+
704+ if (error != NULL) {
705+ g_warning("Unable to get session bus: %s", error->message);
706+ g_error_free(error);
707+ return FALSE;
708+ }
709+
710+ /* The exec value */
711+ gchar * envstr = NULL;
712+ if (demangler) {
713+ envstr = g_strdup_printf("APP_EXEC=" DEMANGLER_PATH " %s", execline);
714+ } else {
715+ envstr = g_strdup_printf("APP_EXEC=%s", execline);
716+ }
717+
718+ set_var(bus, job_name, instance_name, envstr);
719+ g_free(envstr);
720+
721+ /* The directory value */
722+ if (directory != NULL) {
723+ gchar * direnv = g_strdup_printf("APP_DIR=%s", directory);
724+ set_var(bus, job_name, instance_name, direnv);
725+ g_free(direnv);
726+ }
727+
728+ g_object_unref(bus);
729+
730+ return TRUE;
731+}
732+
733+
734+/* ensure that all characters are valid in the dbus output string */
735+static gchar *
736+escape_dbus_string (const gchar * input)
737+{
738+ static const gchar *xdigits = "0123456789abcdef";
739+ GString *escaped;
740+ gchar c;
741+
742+ g_return_val_if_fail (input != NULL, NULL);
743+
744+ escaped = g_string_new (NULL);
745+ while ((c = *input++)) {
746+ if (g_ascii_isalnum (c)) {
747+ g_string_append_c (escaped, c);
748+ } else {
749+ g_string_append_c (escaped, '_');
750+ g_string_append_c (escaped, xdigits[c >> 4]);
751+ g_string_append_c (escaped, xdigits[c & 0xf]);
752+ }
753+ }
754+
755+ return g_string_free (escaped, FALSE);
756+}
757+
758
759=== modified file 'libubuntu-app-launch/ubuntu-app-launch.h'
760--- libubuntu-app-launch/ubuntu-app-launch.h 2015-02-25 22:20:14 +0000
761+++ libubuntu-app-launch/ubuntu-app-launch.h 2015-07-01 01:16:06 +0000
762@@ -18,6 +18,7 @@
763 */
764
765 #include <glib.h>
766+#include <mir_toolkit/mir_prompt_session.h>
767
768 #ifndef __UBUNTU_APP_LAUNCH_H__
769 #define __UBUNTU_APP_LAUNCH_H__ 1
770@@ -450,7 +451,7 @@
771 * @appid: App ID of the helper
772 * @uris: (allow-none) (array zero-terminated=1) (element-type utf8) (transfer none): A NULL terminated list of URIs to send to the helper
773 *
774- * Start an untrusted helper for a specific @type on a given
775+ * Start an untrusted helper for a specific @type of a given
776 * @appid. We don't know how that is done specifically, as Upstart
777 * will call a helper for that type. And then execute it under the
778 * Apparmor profile for that helper type. This function is different
779@@ -465,6 +466,29 @@
780 const gchar * const * uris);
781
782 /**
783+ * ubuntu_app_launch_start_session_helper:
784+ * @type: Type of helper
785+ * @session: Mir Trusted Prompt Session to run the helper under
786+ * @appid: App ID of the helper
787+ * @uris: (allow-none) (array zero-terminated=1) (element-type utf8) (transfer none): A NULL terminated list of URIs to send to the helper
788+ *
789+ * Start an untrusted helper for a specific @type of a given
790+ * @appid running under a Mir Trusted Prompt Session @session. The
791+ * helper's MIR_SOCKET environment variable will be set appropriately
792+ * so that the helper will draw on the correct surfaces. Otherwise this
793+ * is the same as #ubuntu_app_launch_start_multiple_helper.
794+ *
795+ * It is important that all exec tools for @type call the function
796+ * #ubuntu_app_launch_helper_set_exec to set the exec line.
797+ *
798+ * Return value: The generated instance ID or NULL on failure
799+ */
800+gchar * ubuntu_app_launch_start_session_helper (const gchar * type,
801+ MirPromptSession * session,
802+ const gchar * appid,
803+ const gchar * const * uris);
804+
805+/**
806 * ubuntu_app_launch_stop_helper:
807 * @type: Type of helper
808 * @appid: App ID of the helper
809@@ -574,6 +598,24 @@
810 const gchar * helper_type,
811 gpointer user_data);
812
813+/**
814+ * ubuntu_app_launch_helper_set_exec:
815+ * @execline: Exec line to be executed, in Desktop file format
816+ * @directory: (allow-none): The directory that the exec line should
817+ * be executed in.
818+ *
819+ * A function to be called by an untrusted helper exec
820+ * tool to set the exec line. The exec tool should determine
821+ * what should be executed from some sort of configuration
822+ * based on its type (usually a configuration file from a click
823+ * package). Once it determines the exec line it can set it
824+ * with this function and exit.
825+ *
826+ * Return Value: Whether we were able to set the exec line
827+ */
828+gboolean ubuntu_app_launch_helper_set_exec (const gchar * execline,
829+ const gchar * directory);
830+
831 #ifdef __cplusplus
832 }
833 #endif
834
835=== modified file 'libubuntu-app-launch/ubuntu-app-launch.pc.in'
836--- libubuntu-app-launch/ubuntu-app-launch.pc.in 2014-04-30 15:45:23 +0000
837+++ libubuntu-app-launch/ubuntu-app-launch.pc.in 2015-07-01 01:16:06 +0000
838@@ -2,7 +2,7 @@
839 includedir=@includedir@
840
841 Cflags: -I${includedir}/libubuntu-app-launch-@apiversion@
842-Requires: glib-2.0
843+Requires: glib-2.0 mirclient
844 Libs: -L${libdir} -lubuntu-app-launch
845
846 Name: libubuntu-app-launch
847
848=== added file 'socket-demangler.c'
849--- socket-demangler.c 1970-01-01 00:00:00 +0000
850+++ socket-demangler.c 2015-07-01 01:16:06 +0000
851@@ -0,0 +1,124 @@
852+/*
853+ * Copyright © 2014 Canonical Ltd.
854+ *
855+ * This program is free software: you can redistribute it and/or modify it
856+ * under the terms of the GNU General Public License version 3, as published
857+ * by the Free Software Foundation.
858+ *
859+ * This program is distributed in the hope that it will be useful, but
860+ * WITHOUT ANY WARRANTY; without even the implied warranties of
861+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
862+ * PURPOSE. See the GNU General Public License for more details.
863+ *
864+ * You should have received a copy of the GNU General Public License along
865+ * with this program. If not, see <http://www.gnu.org/licenses/>.
866+ *
867+ * Authors:
868+ * Ted Gould <ted.gould@canonical.com>
869+ */
870+
871+#define _POSIX_C_SOURCE 200112L
872+
873+#include <gio/gio.h>
874+#include <gio/gunixfdlist.h>
875+
876+#include <stdio.h>
877+#include <stdlib.h>
878+#include <errno.h>
879+#include <fcntl.h>
880+
881+int
882+main (int argc, char * argv[])
883+{
884+ const gchar * mir_name = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
885+ const gchar * mir_socket = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLE_PATH");
886+ if (mir_socket == NULL || mir_socket[0] == '\0') {
887+ g_error("Unable to find Mir path for service");
888+ return -1;
889+ }
890+ if (mir_name == NULL || mir_name[0] == '\0') {
891+ g_error("Unable to find Mir name for service");
892+ return -1;
893+ }
894+
895+ g_debug("Mir socket connection to %s:%s", mir_name, mir_socket);
896+
897+ GError * error = NULL;
898+ GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
899+
900+ if (error != NULL) {
901+ g_error("Unable to get session bus: %s", error->message);
902+ g_error_free(error);
903+ return -1;
904+ }
905+
906+ GVariant * retval;
907+ GUnixFDList * fdlist;
908+
909+ retval = g_dbus_connection_call_with_unix_fd_list_sync(
910+ bus,
911+ mir_name,
912+ mir_socket,
913+ "com.canonical.UbuntuAppLaunch.SocketDemangler",
914+ "GetMirSocket",
915+ NULL,
916+ G_VARIANT_TYPE("(h)"),
917+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
918+ -1, /* timeout */
919+ NULL, /* fd list in */
920+ &fdlist,
921+ NULL, /* cancelable */
922+ &error);
923+
924+ g_clear_object(&bus);
925+
926+ if (error != NULL) {
927+ g_error("Unable to get Mir socket over dbus: %s", error->message);
928+ g_error_free(error);
929+ return -1;
930+ }
931+
932+ GVariant * outhandle = g_variant_get_child_value(retval, 0);
933+
934+ if (outhandle == NULL) {
935+ g_error("Unable to get data from function");
936+ return -1;
937+ }
938+
939+ gint32 handle = g_variant_get_handle(outhandle);
940+ g_variant_unref(outhandle);
941+ g_variant_unref(retval);
942+
943+ if (handle >= g_unix_fd_list_get_length(fdlist)) {
944+ g_error("Handle is %d but the FD list only has %d entries", handle, g_unix_fd_list_get_length(fdlist));
945+ g_clear_object(&fdlist);
946+ return -1;
947+ }
948+
949+ gint32 fd = g_unix_fd_list_get(fdlist, handle, &error);
950+ g_clear_object(&fdlist);
951+
952+ if (error != NULL) {
953+ g_error("Unable to Unix FD: %s", error->message);
954+ g_error_free(error);
955+ return -1;
956+ }
957+
958+ errno = 0;
959+ fcntl(fd, F_GETFD);
960+ if (errno != 0) {
961+ perror("File descriptor is invalid");
962+ return -1;
963+ }
964+
965+ /* Make sure the FD doesn't close on exec */
966+ fcntl(fd, F_SETFD, 0);
967+
968+ gchar * mirsocketbuf = g_strdup_printf("fd://%d", fd);
969+ setenv("MIR_SOCKET", mirsocketbuf, 1);
970+ g_debug("MIR_SOCKET=%s", mirsocketbuf);
971+
972+ g_free(mirsocketbuf);
973+
974+ return execvp(argv[1], argv + 1);
975+}
976
977=== modified file 'tests/CMakeLists.txt'
978--- tests/CMakeLists.txt 2015-04-06 21:28:13 +0000
979+++ tests/CMakeLists.txt 2015-07-01 01:16:06 +0000
980@@ -32,15 +32,23 @@
981
982 include_directories("${CMAKE_SOURCE_DIR}/libubuntu-app-launch")
983 add_definitions ( -DSPEW_UTILITY="${CMAKE_CURRENT_BINARY_DIR}/data-spew" )
984+add_definitions ( -DSESSION_TEMP_FILE="${CMAKE_CURRENT_BINARY_DIR}/libual-test-session-start-temp" )
985+add_definitions ( -DSOCKET_DEMANGLER="${CMAKE_BINARY_DIR}/socket-demangler" )
986+add_definitions ( -DSOCKET_DEMANGLER_INSTALL="${pkglibexecdir}/socket-demangler" )
987+add_definitions ( -DSOCKET_TOOL="${CMAKE_CURRENT_BINARY_DIR}/socket-tool" )
988
989 add_executable (libual-test
990- libual-test.cc)
991+ libual-test.cc
992+ mir-mock.cpp)
993 target_link_libraries (libual-test gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher)
994
995 add_executable (data-spew
996 data-spew.c)
997 target_link_libraries (data-spew ${GLIB2_LIBRARIES})
998
999+add_executable (socket-tool
1000+ socket-tool.c)
1001+
1002 add_test (NAME libual-test COMMAND libual-test)
1003
1004 # Failure Test
1005@@ -87,3 +95,9 @@
1006 configure_file ("click-desktop-hook-db/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-desktop-hook-db/test.conf" @ONLY)
1007 configure_file ("desktop-hook-test.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/desktop-hook-test.sh" @ONLY)
1008 add_test (desktop-hook-test desktop-hook-test.sh)
1009+
1010+# XMir helper Test
1011+
1012+configure_file ("xmir-helper-test.in" "${CMAKE_CURRENT_BINARY_DIR}/xmir-helper-test" @ONLY)
1013+add_test (xmir-helper-test xmir-helper-test)
1014+
1015
1016=== modified file 'tests/libual-test.cc'
1017--- tests/libual-test.cc 2015-03-02 19:59:44 +0000
1018+++ tests/libual-test.cc 2015-07-01 01:16:06 +0000
1019@@ -17,13 +17,18 @@
1020 * Ted Gould <ted.gould@canonical.com>
1021 */
1022
1023+#include <future>
1024+#include <thread>
1025+
1026 #include <gtest/gtest.h>
1027 #include <gio/gio.h>
1028 #include <zeitgeist.h>
1029+#include "mir-mock.h"
1030
1031 extern "C" {
1032 #include "ubuntu-app-launch.h"
1033 #include "libdbustest/dbus-test.h"
1034+#include <fcntl.h>
1035 }
1036
1037 class LibUAL : public ::testing::Test
1038@@ -108,6 +113,13 @@
1039 " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n",
1040 NULL);
1041
1042+ dbus_test_dbus_mock_object_add_method(mock, obj,
1043+ "SetEnv",
1044+ G_VARIANT_TYPE("(assb)"),
1045+ NULL,
1046+ "",
1047+ NULL);
1048+
1049 /* Click App */
1050 DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
1051
1052@@ -266,50 +278,64 @@
1053 }
1054 ASSERT_EQ(nullptr, bus);
1055 }
1056-
1057- bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {
1058- GVariantIter iter;
1059- g_variant_iter_init(&iter, env_array);
1060+
1061+ GVariant * find_env (GVariant * env_array, const gchar * var) {
1062+ int i;
1063 gchar * envvar = NULL;
1064- bool found = false;
1065-
1066- while (g_variant_iter_loop(&iter, "s", &envvar)) {
1067+ GVariant * retval = nullptr;
1068+
1069+ for (i = 0; i < g_variant_n_children(env_array); i++) {
1070+ GVariant * child = g_variant_get_child_value(env_array, i);
1071+ const gchar * envvar = g_variant_get_string(child, nullptr);
1072+
1073 if (g_str_has_prefix(envvar, var)) {
1074- if (found) {
1075+ if (retval != nullptr) {
1076 g_warning("Found the env var more than once!");
1077- return false;
1078+ g_variant_unref(retval);
1079+ return nullptr;
1080 }
1081
1082- if (value != NULL) {
1083- gchar * combined = g_strdup_printf("%s=%s", var, value);
1084- if (g_strcmp0(envvar, combined) == 0) {
1085- found = true;
1086- }
1087- g_free(combined);
1088- } else {
1089- found = true;
1090- }
1091+ retval = child;
1092+ } else {
1093+ g_variant_unref(child);
1094 }
1095 }
1096
1097- if (!found) {
1098+ if (!retval) {
1099 gchar * envstr = g_variant_print(env_array, FALSE);
1100- g_warning("Unable to find '%s' with value '%s' in '%s'", var, value, envstr);
1101+ g_warning("Unable to find '%s' in '%s'", var, envstr);
1102 g_free(envstr);
1103 }
1104
1105+ return retval;
1106+ }
1107+
1108+ bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {
1109+ bool found = false;
1110+ GVariant * val = find_env(env_array, var);
1111+ if (val == nullptr)
1112+ return false;
1113+
1114+ const gchar * envvar = g_variant_get_string(val, nullptr);
1115+
1116+ gchar * combined = g_strdup_printf("%s=%s", var, value);
1117+ if (g_strcmp0(envvar, combined) == 0) {
1118+ found = true;
1119+ }
1120+
1121+ g_variant_unref(val);
1122+
1123 return found;
1124 }
1125
1126- static gboolean pause_helper (gpointer pmainloop) {
1127- g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
1128- return G_SOURCE_REMOVE;
1129- }
1130-
1131- void pause (guint time) {
1132+ void pause (guint time = 0) {
1133 if (time > 0) {
1134 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
1135- g_timeout_add(time, pause_helper, mainloop);
1136+
1137+ g_timeout_add(time, [](gpointer pmainloop) -> gboolean {
1138+ g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
1139+ return G_SOURCE_REMOVE;
1140+ }, mainloop);
1141
1142 g_main_loop_run(mainloop);
1143
1144@@ -1446,3 +1472,147 @@
1145
1146 g_free(oomadjfile);
1147 }
1148+
1149+TEST_F(LibUAL, StartSessionHelper)
1150+{
1151+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
1152+ MirConnection * conn = mir_connect_sync("libual-test", "start-session-helper"); // Mocked, doesn't need cleaning up
1153+ MirPromptSession * msession = mir_connection_create_prompt_session_sync(conn, 5, nullptr, nullptr);
1154+
1155+ /* Building a temporary file and making an FD for it */
1156+ const char * filedata = "This is some data that we should get on the other side\n";
1157+ ASSERT_TRUE(g_file_set_contents(SESSION_TEMP_FILE, filedata, strlen(filedata), nullptr) == TRUE);
1158+ int mirfd = open(SESSION_TEMP_FILE, 0);
1159+ mir_mock_set_trusted_fd(mirfd);
1160+
1161+ /* Basic make sure we can send the event */
1162+ gchar * instance_id = ubuntu_app_launch_start_session_helper("untrusted-type", msession, "com.test.multiple_first_1.2.3", NULL);
1163+ ASSERT_NE(nullptr, instance_id);
1164+
1165+ guint len = 0;
1166+ const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
1167+ EXPECT_NE(nullptr, calls);
1168+ EXPECT_EQ(1, len);
1169+
1170+ EXPECT_STREQ("Start", calls->name);
1171+ EXPECT_EQ(2, g_variant_n_children(calls->params));
1172+
1173+ GVariant * block = g_variant_get_child_value(calls->params, 1);
1174+ EXPECT_TRUE(g_variant_get_boolean(block));
1175+ g_variant_unref(block);
1176+
1177+ /* Check the environment */
1178+ GVariant * env = g_variant_get_child_value(calls->params, 0);
1179+ EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
1180+ EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
1181+ EXPECT_TRUE(check_env(env, "INSTANCE_ID", instance_id));
1182+
1183+ GVariant * mnamev = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
1184+ ASSERT_NE(nullptr, mnamev); /* Have to assert because, eh, GVariant */
1185+ EXPECT_STREQ(g_dbus_connection_get_unique_name(bus), g_variant_get_string(mnamev, nullptr) + strlen("UBUNTU_APP_LAUNCH_DEMANGLE_NAME="));
1186+ GVariant * mpathv = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_PATH");
1187+ ASSERT_NE(nullptr, mpathv); /* Have to assert because, eh, GVariant */
1188+
1189+ g_variant_unref(env);
1190+
1191+ /* Setup environment for call */
1192+ const gchar * mname = g_variant_get_string(mnamev, nullptr);
1193+ mname += strlen("UBUNTU_APP_LAUNCH_DEMANGLE_NAME=");
1194+ g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", mname, TRUE);
1195+ g_variant_unref(mnamev);
1196+
1197+ const gchar * mpath = g_variant_get_string(mpathv, nullptr);
1198+ mpath += strlen("UBUNTU_APP_LAUNCH_DEMANGLE_PATH=");
1199+ g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_PATH", mpath, TRUE);
1200+ g_variant_unref(mpathv);
1201+
1202+ /* Exec our tool */
1203+ std::promise<std::string> outputpromise;
1204+ std::thread t([&outputpromise]() {
1205+ gchar * socketstdout = nullptr;
1206+ GError * error = nullptr;
1207+ g_unsetenv("G_MESSAGES_DEBUG");
1208+
1209+ g_spawn_command_line_sync(
1210+ SOCKET_DEMANGLER " " SOCKET_TOOL,
1211+ &socketstdout,
1212+ nullptr,
1213+ nullptr,
1214+ &error);
1215+
1216+ if (error != nullptr) {
1217+ fprintf(stderr, "Unable to spawn '" SOCKET_DEMANGLER " " SOCKET_TOOL "': %s\n", error->message);
1218+ g_error_free(error);
1219+ outputpromise.set_value(std::string(""));
1220+ } else {
1221+ outputpromise.set_value(std::string(socketstdout));
1222+ g_free(socketstdout);
1223+ }
1224+ });
1225+ t.detach();
1226+
1227+ auto outputfuture = outputpromise.get_future();
1228+ while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready) {
1229+ pause();
1230+ }
1231+
1232+ ASSERT_STREQ(filedata, outputfuture.get().c_str());
1233+
1234+ ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1235+
1236+ return;
1237+}
1238+
1239+TEST_F(LibUAL, SetExec)
1240+{
1241+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
1242+
1243+ const char * exec = "lets exec this";
1244+
1245+ g_setenv("UPSTART_JOB", "fubar", TRUE);
1246+ g_unsetenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
1247+ EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, NULL));
1248+
1249+ guint len = 0;
1250+ const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
1251+ ASSERT_NE(nullptr, calls);
1252+ EXPECT_EQ(1, len);
1253+
1254+ gchar * appexecstr = g_strdup_printf("APP_EXEC=%s", exec);
1255+ GVariant * appexecenv = g_variant_get_child_value(calls[0].params, 1);
1256+ EXPECT_STREQ(appexecstr, g_variant_get_string(appexecenv, nullptr));
1257+ g_variant_unref(appexecenv);
1258+ g_free(appexecstr);
1259+
1260+ ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1261+
1262+ /* Now check for the demangler */
1263+ g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", g_dbus_connection_get_unique_name(bus), TRUE);
1264+ EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, NULL));
1265+
1266+ calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
1267+ ASSERT_NE(nullptr, calls);
1268+ EXPECT_EQ(1, len);
1269+
1270+ gchar * demangleexecstr = g_strdup_printf("APP_EXEC=%s %s", SOCKET_DEMANGLER_INSTALL, exec);
1271+ appexecenv = g_variant_get_child_value(calls[0].params, 1);
1272+ EXPECT_STREQ(demangleexecstr, g_variant_get_string(appexecenv, nullptr));
1273+ g_variant_unref(appexecenv);
1274+ g_free(demangleexecstr);
1275+
1276+ ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1277+
1278+ /* Now check for the directory */
1279+ g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", g_dbus_connection_get_unique_name(bus), TRUE);
1280+ EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, "/not/a/real/directory"));
1281+
1282+ calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
1283+ ASSERT_NE(nullptr, calls);
1284+ EXPECT_EQ(2, len);
1285+
1286+ appexecenv = g_variant_get_child_value(calls[1].params, 1);
1287+ EXPECT_STREQ("APP_DIR=/not/a/real/directory", g_variant_get_string(appexecenv, nullptr));
1288+ g_variant_unref(appexecenv);
1289+
1290+ ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1291+}
1292
1293=== added file 'tests/mir-mock.cpp'
1294--- tests/mir-mock.cpp 1970-01-01 00:00:00 +0000
1295+++ tests/mir-mock.cpp 2015-07-01 01:16:06 +0000
1296@@ -0,0 +1,106 @@
1297+
1298+#include "mir-mock.h"
1299+
1300+#include <iostream>
1301+#include <thread>
1302+
1303+#include <mir_toolkit/mir_connection.h>
1304+#include <mir_toolkit/mir_prompt_session.h>
1305+
1306+static const char * valid_trust_session = "In the circle of trust";
1307+static bool valid_trust_connection = true;
1308+static pid_t last_trust_pid = 0;
1309+static int trusted_fd = 1234;
1310+
1311+MirPromptSession *
1312+mir_connection_create_prompt_session_sync(MirConnection * connection, pid_t pid, void (*)(MirPromptSession *, MirPromptSessionState, void*data), void * context) {
1313+ last_trust_pid = pid;
1314+
1315+ if (valid_trust_connection) {
1316+ return (MirPromptSession *)valid_trust_session;
1317+ } else {
1318+ return nullptr;
1319+ }
1320+}
1321+
1322+void
1323+mir_prompt_session_release_sync (MirPromptSession * session)
1324+{
1325+ if (reinterpret_cast<char *>(session) != valid_trust_session) {
1326+ std::cerr << "Releasing a Mir Trusted Prompt that isn't valid" << std::endl;
1327+ exit(1);
1328+ }
1329+}
1330+
1331+MirWaitHandle *
1332+mir_prompt_session_new_fds_for_prompt_providers (MirPromptSession * session, unsigned int numfds, mir_client_fd_callback cb, void * data) {
1333+ if (reinterpret_cast<char *>(session) != valid_trust_session) {
1334+ std::cerr << "Releasing a Mir Trusted Prompt that isn't valid" << std::endl;
1335+ exit(1);
1336+ }
1337+
1338+ /* TODO: Put in another thread to be more mir like */
1339+ std::thread * thread = new std::thread([session, numfds, cb, data]() {
1340+ int fdlist[numfds];
1341+
1342+ for (int i = 0; i < numfds; i++)
1343+ fdlist[i] = trusted_fd;
1344+
1345+ cb(session, numfds, fdlist, data);
1346+ });
1347+
1348+ return reinterpret_cast<MirWaitHandle *>(thread);
1349+}
1350+
1351+void
1352+mir_wait_for (MirWaitHandle * wait)
1353+{
1354+ auto thread = reinterpret_cast<std::thread *>(wait);
1355+
1356+ if (thread->joinable())
1357+ thread->join();
1358+
1359+ delete thread;
1360+}
1361+
1362+static const char * valid_connection_str = "Valid Mir Connection";
1363+static std::pair<std::string, std::string> last_connection;
1364+static bool valid_connection = true;
1365+
1366+void
1367+mir_mock_connect_return_valid (bool valid)
1368+{
1369+ valid_connection = valid;
1370+}
1371+
1372+std::pair<std::string, std::string>
1373+mir_mock_connect_last_connect (void)
1374+{
1375+ return last_connection;
1376+}
1377+
1378+MirConnection *
1379+mir_connect_sync (char const * server, char const * appname)
1380+{
1381+ last_connection = std::pair<std::string, std::string>(server, appname);
1382+
1383+ if (valid_connection) {
1384+ return (MirConnection *)(valid_connection_str);
1385+ } else {
1386+ return nullptr;
1387+ }
1388+}
1389+
1390+void
1391+mir_connection_release (MirConnection * con)
1392+{
1393+ if (reinterpret_cast<char *>(con) != valid_connection_str) {
1394+ std::cerr << "Releasing a Mir Connection that isn't valid" << std::endl;
1395+ exit(1);
1396+ }
1397+}
1398+
1399+void mir_mock_set_trusted_fd (int fd)
1400+{
1401+ trusted_fd = fd;
1402+}
1403
1404=== added file 'tests/mir-mock.h'
1405--- tests/mir-mock.h 1970-01-01 00:00:00 +0000
1406+++ tests/mir-mock.h 2015-07-01 01:16:06 +0000
1407@@ -0,0 +1,12 @@
1408+
1409+#ifndef MIR_MOCK_H
1410+#define MIR_MOCK_H 1
1411+
1412+#include <string>
1413+#include <utility>
1414+
1415+void mir_mock_connect_return_valid (bool valid);
1416+std::pair<std::string, std::string> mir_mock_connect_last_connect (void);
1417+void mir_mock_set_trusted_fd (int fd);
1418+
1419+#endif // MIR_MOCK_H
1420
1421=== added file 'tests/socket-tool.c'
1422--- tests/socket-tool.c 1970-01-01 00:00:00 +0000
1423+++ tests/socket-tool.c 2015-07-01 01:16:06 +0000
1424@@ -0,0 +1,28 @@
1425+
1426+#include <stdlib.h>
1427+#include <stdio.h>
1428+#include <unistd.h>
1429+
1430+int
1431+main (int argc, char * argv[])
1432+{
1433+ const char * fdstr = getenv("MIR_SOCKET");
1434+ if (!fdstr) {
1435+ fprintf(stderr, "No MIR_SOCKET defined\n");
1436+ return 1;
1437+ }
1438+
1439+ int fdnum = 0;
1440+ sscanf(fdstr, "fd://%d", &fdnum);
1441+ if (fdnum == 0) {
1442+ fprintf(stderr, "Unable to get FD number\n");
1443+ return 1;
1444+ }
1445+
1446+ char inchar;
1447+ while (read(fdnum, &inchar, 1) == 1)
1448+ fwrite(&inchar, 1, 1, stdout);
1449+
1450+ close(fdnum);
1451+ return 0;
1452+}
1453
1454=== added file 'tests/xmir-helper-exec.sh'
1455--- tests/xmir-helper-exec.sh 1970-01-01 00:00:00 +0000
1456+++ tests/xmir-helper-exec.sh 2015-07-01 01:16:06 +0000
1457@@ -0,0 +1,3 @@
1458+#!/bin/bash
1459+
1460+echo $DISPLAY
1461
1462=== added file 'tests/xmir-helper-test.in'
1463--- tests/xmir-helper-test.in 1970-01-01 00:00:00 +0000
1464+++ tests/xmir-helper-test.in 2015-07-01 01:16:06 +0000
1465@@ -0,0 +1,25 @@
1466+#!/bin/bash
1467+
1468+echo -n "Testing XMir Helper… "
1469+
1470+export UBUNTU_APP_LAUNCH_XMIR_PATH="@CMAKE_CURRENT_SOURCE_DIR@/xmir-mock.sh"
1471+
1472+TESTVALUE=`@CMAKE_BINARY_DIR@/xmir-helper com.mir.test_mirtest_1.2.3 @CMAKE_CURRENT_SOURCE_DIR@/xmir-helper-exec.sh`
1473+
1474+if [ $TESTVALUE == ":42" ]; then
1475+ echo "PASSED"
1476+else
1477+ echo "FAILED"
1478+ exit 1
1479+fi
1480+
1481+echo -n "Testing an evil XMir helper… "
1482+
1483+export UBUNTU_APP_LAUNCH_XMIR_PATH="@CMAKE_CURRENT_SOURCE_DIR@/xmir-mock-evil.sh"
1484+
1485+if @CMAKE_BINARY_DIR@/xmir-helper com.mir.test_mirtest_1.2.3 @CMAKE_CURRENT_SOURCE_DIR@/xmir-helper-exec.sh ; then
1486+ echo "FAILED"
1487+ exit 1
1488+else
1489+ echo "PASSED"
1490+fi
1491
1492=== added file 'tests/xmir-mock.sh'
1493--- tests/xmir-mock.sh 1970-01-01 00:00:00 +0000
1494+++ tests/xmir-mock.sh 2015-07-01 01:16:06 +0000
1495@@ -0,0 +1,27 @@
1496+#!/bin/bash
1497+
1498+if [ $1 != "-rootless" ]; then
1499+ echo "-rootless missing"
1500+ exit 1
1501+fi
1502+
1503+if [ $2 != "-displayfd" ]; then
1504+ echo "-displayfd missing"
1505+ exit 1
1506+fi
1507+
1508+if [ $4 != "-mir" ]; then
1509+ echo "-mir missing"
1510+ exit 1
1511+fi
1512+
1513+if [ $5 != "com.mir.test_mirtest_1.2.3" ]; then
1514+ echo "AppID wrong"
1515+ exit 1
1516+fi
1517+
1518+echo "42" >&$3
1519+
1520+# Ensure that our "XMir" runs longer than
1521+# the test, if it exits first that's a failure
1522+sleep 1
1523
1524=== modified file 'ubuntu-app-test/CMakeLists.txt'
1525--- ubuntu-app-test/CMakeLists.txt 2015-03-05 14:35:26 +0000
1526+++ ubuntu-app-test/CMakeLists.txt 2015-07-01 01:16:06 +0000
1527@@ -1,6 +1,4 @@
1528 add_subdirectory(data)
1529-
1530-if (${MIR_FOUND})
1531 add_subdirectory(src)
1532
1533 # testing & coverage
1534@@ -8,9 +6,3 @@
1535 add_subdirectory(tests)
1536 endif ()
1537
1538-else ()
1539-
1540-install(PROGRAMS ubuntu-app-test DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}/app-test")
1541-
1542-endif ()
1543-
1544
1545=== removed file 'ubuntu-app-test/ubuntu-app-test'
1546--- ubuntu-app-test/ubuntu-app-test 2015-03-05 14:35:26 +0000
1547+++ ubuntu-app-test/ubuntu-app-test 1970-01-01 00:00:00 +0000
1548@@ -1,6 +0,0 @@
1549-#!/bin/sh
1550-
1551-# Used for Architectures that don't have Mir, otherwise we build the executable
1552-
1553-echo "ubuntu-app-test doesn't work on this architecture, sorry"
1554-exit 1
1555
1556=== modified file 'upstart-jobs/application-click.conf.in'
1557--- upstart-jobs/application-click.conf.in 2015-01-23 18:12:29 +0000
1558+++ upstart-jobs/application-click.conf.in 2015-07-01 01:16:06 +0000
1559@@ -12,6 +12,9 @@
1560 env APP_DIR
1561 env APP_DESKTOP_FILE_PATH
1562
1563+env APP_XMIR_ENABLE=0
1564+export APP_XMIR_ENABLE
1565+
1566 env UBUNTU_APP_LAUNCH_ARCH="@ubuntu_app_launch_arch@"
1567 export UBUNTU_APP_LAUNCH_ARCH
1568
1569
1570=== modified file 'upstart-jobs/application-legacy.conf.in'
1571--- upstart-jobs/application-legacy.conf.in 2015-01-23 18:12:29 +0000
1572+++ upstart-jobs/application-legacy.conf.in 2015-07-01 01:16:06 +0000
1573@@ -12,6 +12,9 @@
1574 env APP_URIS
1575 env APP_DESKTOP_FILE_PATH
1576
1577+env APP_XMIR_ENABLE=1
1578+export APP_XMIR_ENABLE
1579+
1580 # This will be set to "unconfined" by desktop-exec if there is no confinement defined
1581 apparmor switch $APP_EXEC_POLICY
1582 cgroup freezer
1583
1584=== added file 'xmir-helper.c'
1585--- xmir-helper.c 1970-01-01 00:00:00 +0000
1586+++ xmir-helper.c 2015-07-01 01:16:06 +0000
1587@@ -0,0 +1,118 @@
1588+/*
1589+ * Copyright © 2014 Canonical Ltd.
1590+ *
1591+ * This program is free software: you can redistribute it and/or modify it
1592+ * under the terms of the GNU General Public License version 3, as published
1593+ * by the Free Software Foundation.
1594+ *
1595+ * This program is distributed in the hope that it will be useful, but
1596+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1597+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1598+ * PURPOSE. See the GNU General Public License for more details.
1599+ *
1600+ * You should have received a copy of the GNU General Public License along
1601+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1602+ *
1603+ * Authors:
1604+ * Ted Gould <ted.gould@canonical.com>
1605+ */
1606+
1607+#define _POSIX_C_SOURCE 200212L
1608+
1609+#include <unistd.h>
1610+#include <stdio.h>
1611+#include <stdlib.h>
1612+#include <sys/types.h>
1613+#include <sys/socket.h>
1614+#include <signal.h>
1615+
1616+void
1617+sigchild_handler (int signal)
1618+{
1619+ fprintf(stderr, "XMir has closed unexpectedly\n");
1620+ exit(1);
1621+}
1622+
1623+struct sigaction sigchild_action = {
1624+ .sa_handler = sigchild_handler,
1625+ .sa_flags = SA_NOCLDWAIT
1626+};
1627+
1628+int
1629+main (int argc, char * argv[])
1630+{
1631+ if (argc < 3) {
1632+ fprintf(stderr, "xmir-helper needs more arguments: xmir-helper $(appid) $(thing to exec)\n");
1633+ return 1;
1634+ }
1635+
1636+ /* Make nice variables for the things we need */
1637+ char * appid = argv[1];
1638+ char * xmir = getenv("UBUNTU_APP_LAUNCH_XMIR_PATH");
1639+ if (xmir == NULL) {
1640+ xmir = "/usr/bin/Xmir";
1641+ }
1642+
1643+ /* Build a socket pair to get the connection back from XMir */
1644+ int sockets[2];
1645+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) != 0) {
1646+ fprintf(stderr, "Unable to create socketpair for communicating with XMir\n");
1647+ return 1;
1648+ }
1649+
1650+ /* Give them nice names, the compiler will optimize out */
1651+ int xmirsocket = sockets[0];
1652+ int helpersocket = sockets[1];
1653+
1654+ /* Watch for the child dying */
1655+ if (sigaction(SIGCHLD, &sigchild_action, NULL) != 0) {
1656+ fprintf(stderr, "Unable to setup child signal handler\n");
1657+ return 1;
1658+ }
1659+
1660+ /* Start XMir */
1661+ if (fork() == 0) {
1662+ /* XMir start here */
1663+ /* GOAL: XMir -displayfd ${xmirsocket} -mir ${appid} */
1664+ char socketbuf[16] = {0};
1665+ snprintf(socketbuf, 16, "%d", xmirsocket);
1666+
1667+ char * xmirexec[7] = {
1668+ xmir,
1669+ "-rootless",
1670+ "-displayfd",
1671+ socketbuf,
1672+ "-mir",
1673+ appid,
1674+ NULL
1675+ };
1676+
1677+ return execv(xmir, xmirexec);
1678+ }
1679+
1680+ /* Wait to get the display number from XMir */
1681+ char readbuf[16] = {0};
1682+ if (read(helpersocket, readbuf, 16) == 0) {
1683+ fprintf(stderr, "Not reading anything from XMir\n");
1684+ return 1;
1685+ }
1686+
1687+ int i;
1688+ for (i = 0; i < sizeof(readbuf); i++) {
1689+ if (readbuf[i] == '\n') {
1690+ readbuf[i] = '\0';
1691+ break;
1692+ }
1693+ }
1694+
1695+ char displaynumber[16] = {0};
1696+ snprintf(displaynumber, 16, ":%s", readbuf);
1697+
1698+ /* Set up the display variable */
1699+ setenv("DISPLAY", displaynumber, 1);
1700+
1701+ /* Now that we have everything setup, we can execute */
1702+ char ** nargv = &argv[2];
1703+ int execret = execvp(nargv[0], nargv);
1704+ return execret;
1705+}
1706
1707=== modified file 'zg-report-app.c'
1708--- zg-report-app.c 2014-09-10 14:54:01 +0000
1709+++ zg-report-app.c 2015-07-01 01:16:06 +0000
1710@@ -39,7 +39,7 @@
1711 result = zeitgeist_log_insert_event_finish(ZEITGEIST_LOG(obj), res, &error);
1712
1713 if (error != NULL) {
1714- g_error("Unable to submit Zeitgeist Event: %s", error->message);
1715+ g_warning("Unable to submit Zeitgeist Event: %s", error->message);
1716 g_error_free(error);
1717 }
1718

Subscribers

People subscribed via source and target branches