1/* swc: libswc/launch.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "launch.h"
25#include "event.h"
26#include "internal.h"
27#include "launch/protocol.h"
28#include "util.h"
29
30#include <fcntl.h>
31#include <sys/uio.h>
32#include <unistd.h>
33#include <wayland-server.h>
34
35static struct {
36 int socket;
37 struct wl_event_source *source;
38 uint32_t next_serial;
39} launch;
40
41static bool
42handle_event(struct swc_launch_event *event)
43{
44 switch (event->type) {
45 case SWC_LAUNCH_EVENT_ACTIVATE:
46 swc_activate();
47 break;
48 case SWC_LAUNCH_EVENT_DEACTIVATE:
49 swc_deactivate();
50 break;
51 default:
52 return false;
53 }
54
55 return true;
56}
57
58static int
59handle_data(int fd, uint32_t mask, void *data)
60{
61 struct swc_launch_event event;
62 struct iovec iov[1] = {
63 {.iov_base = &event, .iov_len = sizeof(event)},
64 };
65
66 if (receive_fd(fd, NULL, iov, 1) != -1) {
67 handle_event(&event);
68 }
69 return 1;
70}
71
72bool
73launch_initialize(void)
74{
75 char *socket_string, *end;
76
77 if (!(socket_string = getenv(SWC_LAUNCH_SOCKET_ENV))) {
78 return false;
79 }
80
81 launch.socket = strtol(socket_string, &end, 10);
82 if (*end != '\0') {
83 return false;
84 }
85
86 unsetenv(SWC_LAUNCH_SOCKET_ENV);
87 if (fcntl(launch.socket, F_SETFD, FD_CLOEXEC) < 0) {
88 return false;
89 }
90
91 launch.source = wl_event_loop_add_fd(swc.event_loop, launch.socket,
92 WL_EVENT_READABLE, &handle_data, NULL);
93 if (!launch.source) {
94 return false;
95 }
96
97 return true;
98}
99
100void
101launch_finalize(void)
102{
103 wl_event_source_remove(launch.source);
104 close(launch.socket);
105}
106
107static bool
108send_request(struct swc_launch_request *request, const void *data, size_t size,
109 struct swc_launch_event *event, int out_fd, int *in_fd)
110{
111 struct iovec request_iov[2] = {
112 {.iov_base = request, .iov_len = sizeof(*request)},
113 {.iov_base = (void *)data, .iov_len = size},
114 };
115 struct iovec response_iov[1] = {
116 {.iov_base = event, .iov_len = sizeof(*event)},
117 };
118
119 request->serial = ++launch.next_serial;
120
121 if (send_fd(launch.socket, out_fd, request_iov, 1 + (size > 0)) == -1) {
122 return false;
123 }
124
125 while (receive_fd(launch.socket, in_fd, response_iov, 1) != -1) {
126 if (event->type == SWC_LAUNCH_EVENT_RESPONSE &&
127 event->serial == request->serial) {
128 return true;
129 }
130 handle_event(event);
131 }
132
133 return false;
134}
135
136int
137launch_open_device(const char *path, int flags)
138{
139 struct swc_launch_request request;
140 struct swc_launch_event response;
141 int fd;
142
143 request.type = SWC_LAUNCH_REQUEST_OPEN_DEVICE;
144 request.flags = flags;
145
146 if (!send_request(&request, path, strlen(path) + 1, &response, -1, &fd)) {
147 return -1;
148 }
149
150 return fd;
151}
152
153bool
154launch_activate_vt(unsigned vt)
155{
156 struct swc_launch_request request;
157 struct swc_launch_event response;
158
159 request.type = SWC_LAUNCH_REQUEST_ACTIVATE_VT;
160 request.vt = vt;
161
162 if (!send_request(&request, NULL, 0, &response, -1, NULL)) {
163 return false;
164 }
165
166 return response.success;
167}