1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
/*
* Copyright © 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Ted Gould <ted.gould@canonical.com>
*/
#define _POSIX_C_SOURCE 200112L
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
int
main (int argc, char * argv[])
{
const gchar * mir_name = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
const gchar * mir_socket = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLE_PATH");
if (mir_socket == NULL || mir_socket[0] == '\0') {
g_error("Unable to find Mir path for service");
return -1;
}
if (mir_name == NULL || mir_name[0] == '\0') {
g_error("Unable to find Mir name for service");
return -1;
}
g_debug("Mir socket connection to %s:%s", mir_name, mir_socket);
GError * error = NULL;
GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
if (error != NULL) {
g_error("Unable to get session bus: %s", error->message);
g_error_free(error);
return -1;
}
GVariant * retval;
GUnixFDList * fdlist;
retval = g_dbus_connection_call_with_unix_fd_list_sync(
bus,
mir_name,
mir_socket,
"com.canonical.UbuntuAppLaunch.SocketDemangler",
"GetMirSocket",
NULL,
G_VARIANT_TYPE("(h)"),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
-1, /* timeout */
NULL, /* fd list in */
&fdlist,
NULL, /* cancelable */
&error);
g_clear_object(&bus);
if (error != NULL) {
g_error("Unable to get Mir socket over dbus: %s", error->message);
g_error_free(error);
return -1;
}
GVariant * outhandle = g_variant_get_child_value(retval, 0);
if (outhandle == NULL) {
g_error("Unable to get data from function");
return -1;
}
gint32 handle = g_variant_get_handle(outhandle);
g_variant_unref(outhandle);
g_variant_unref(retval);
if (handle >= g_unix_fd_list_get_length(fdlist)) {
g_error("Handle is %d but the FD list only has %d entries", handle, g_unix_fd_list_get_length(fdlist));
g_clear_object(&fdlist);
return -1;
}
gint32 fd = g_unix_fd_list_get(fdlist, handle, &error);
g_clear_object(&fdlist);
if (error != NULL) {
g_error("Unable to Unix FD: %s", error->message);
g_error_free(error);
return -1;
}
errno = 0;
fcntl(fd, F_GETFD);
if (errno != 0) {
perror("File descriptor is invalid");
return -1;
}
/* Make sure the FD doesn't close on exec */
fcntl(fd, F_SETFD, 0);
gchar * mirsocketbuf = g_strdup_printf("fd://%d", fd);
setenv("MIR_SOCKET", mirsocketbuf, 1);
g_debug("MIR_SOCKET=%s", mirsocketbuf);
g_free(mirsocketbuf);
return execvp(argv[1], argv + 1);
}
|