/* * 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 . * * Authors: * Ted Gould */ #define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include 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); }