Merge lp:~ted/ubuntu-app-launch/xmir-support into lp:ubuntu-app-launch/15.04
- xmir-support
- Merge into trunk.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 |
Related bugs: |
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.
Commit message
Description of the change
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 |