9182fa5279d11ccc3af99375c1b292ab391f2d0e
[platform/core/uifw/libtbm.git] / src / tbm_drm_helper_server.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #define WL_HIDE_DEPRECATED
33
34 #include "config.h"
35
36 #include <xf86drm.h>
37 #include <grp.h>
38
39 #include "tbm_bufmgr_int.h"
40
41 #include "wayland-tbm-drm-auth-server-protocol.h"
42
43 struct wayland_tbm_drm_auth_server {
44         struct wl_display *display;
45         struct wl_global *wl_tbm_drm_auth_global;
46
47         char *device_name;
48         uint32_t fd;
49         uint32_t flags;
50 };
51
52 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
53
54 struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv;
55
56 static int tbm_drm_master_fd = -1;
57
58 /* LCOV_EXCL_START */
59 static void
60 _send_server_auth_info(struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv,
61                        struct wl_resource *resource)
62 {
63         int fd = -1;
64         uint32_t capabilities;
65         char *device_name = NULL;
66         drm_magic_t magic = 0;
67
68         fd = open(tbm_drm_auth_srv->device_name, O_RDWR | O_CLOEXEC);
69         if (fd == -1 && errno == EINVAL) {
70                 fd = open(tbm_drm_auth_srv->device_name, O_RDWR);
71                 if (fd != -1) {
72                         if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) == -1) {
73                                 TBM_ERR("failed to set fd\n");
74                                 goto fini;
75                         }
76                 }
77         }
78
79         if (fd < 0) {
80                 TBM_ERR("failed to open drm : device_name, %s\n", tbm_drm_auth_srv->device_name);
81
82                 wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
83                                        "authenicate failed::open_drm");
84                 goto fini;
85         }
86
87         if (drmGetMagic(fd, &magic) < 0) {
88                 if (errno != EACCES) {
89                         TBM_ERR("failed to get magic\n");
90
91                         wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
92                                                "authenicate failed::get_magic");
93                         goto fini;
94                 }
95         }
96
97         if (drmAuthMagic(tbm_drm_auth_srv->fd, magic) < 0) {
98                 TBM_ERR("failed to authenticate magic\n");
99
100                 wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
101                                        "authenicate failed::auth_magic");
102                 goto fini;
103         }
104
105         capabilities = tbm_drm_auth_srv->flags;
106         device_name = tbm_drm_auth_srv->device_name;
107
108         /* send */
109         wl_tbm_drm_auth_send_authentication_info(resource, device_name, capabilities, fd);
110
111 fini:
112         if (fd >= 0)
113                 close(fd);
114
115         if (device_name && device_name != tbm_drm_auth_srv->device_name)
116                 free(device_name);
117
118 }
119
120 static void
121 _wayland_tbm_drm_auth_server_impl_get_authentication_info(struct wl_client *client,
122                 struct wl_resource *resource)
123 {
124         struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv = wl_resource_get_user_data(resource);
125
126         /* if display server is the client of the host display server, for embedded server */
127         _send_server_auth_info(tbm_drm_auth_srv, resource);
128 }
129
130
131 static const struct wl_tbm_drm_auth_interface _wayland_tbm_drm_auth_server_implementation = {
132         _wayland_tbm_drm_auth_server_impl_get_authentication_info,
133 };
134
135 static void
136 _wayland_tbm_drm_auth_server_bind_cb(struct wl_client *client, void *data,
137                             uint32_t version,
138                             uint32_t id)
139 {
140         struct wl_resource *resource;
141
142         resource = wl_resource_create(client, &wl_tbm_drm_auth_interface, MIN(version, 1), id);
143         if (!resource) {
144                 wl_client_post_no_memory(client);
145                 return;
146         }
147
148         wl_resource_set_implementation(resource,
149                                        &_wayland_tbm_drm_auth_server_implementation,
150                                        data,
151                                        NULL);
152 }
153
154 static int
155 _tbm_getgrnam_r(const char *name)
156 {
157         struct group *grp = NULL;
158         struct group *grp_res = NULL;
159         char* buf = NULL;
160         size_t buf_len;
161         int ret;
162         int id;
163
164         buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
165         if (buf_len == -1)
166                 buf_len = 2048;
167
168         buf = calloc(1, buf_len * sizeof(char));
169         if (!buf) {
170                 TBM_ERR("creating buffer failed\n");
171                 goto failed;
172         }
173
174         grp = calloc(1, sizeof(struct group));
175         if (!grp) {
176                 TBM_ERR("creating group failed\n");
177                 goto failed;
178         }
179
180         ret = getgrnam_r(name, grp, buf, buf_len, &grp_res);
181         if (ret < 0) {
182                 TBM_ERR("getgrnam_r failed errno:%d(%m)\n", ret);
183                 goto failed;
184         }
185
186         if (grp_res == NULL) {
187                 TBM_ERR("finding name:%s group failed\n", name);
188                 goto failed;
189         }
190
191         id = grp->gr_gid;
192         free(buf);
193         free(grp);
194
195         return id;
196
197 failed:
198         if (buf)
199                 free(buf);
200         if (grp)
201                 free(grp);
202
203         return -1;
204 }
205
206 static void
207 _tbm_drm_auth_socket_init(struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv)
208 {
209         const char *dir = NULL;
210         char socket_path[128];
211         int ret = -1;
212         uid_t uid;
213         gid_t gid;
214
215         dir = getenv("XDG_RUNTIME_DIR");
216         if (!dir) {
217                 TBM_WRN("getting XDG_RUNTIME_DIR failed\n");
218                 return;
219         }
220
221         snprintf(socket_path, sizeof(socket_path), "%s/%s", dir, "tbm-drm-auth");
222
223         ret = chmod(socket_path, 509);
224         if (ret < 0) {
225                 TBM_WRN("changing modes of socket file failed:%s (%m)\n", socket_path);
226                 return;
227         }
228
229         ret = _tbm_getgrnam_r("root");
230         if (ret < 0) {
231                 TBM_WRN("getting uid failed\n");
232                 return;
233         }
234         uid = ret;
235
236         ret = _tbm_getgrnam_r("display");
237         if (ret < 0) {
238                 TBM_WRN("getting gid failed\n");
239                 return;
240         }
241         gid = ret;
242
243         ret = chown(socket_path, uid, gid);
244         if (ret < 0) {
245                 TBM_WRN("changing owner of socket file failed:%s (%m)\n", socket_path);
246                 return;
247         }
248 }
249
250 int
251 tbm_drm_helper_wl_auth_server_init(void *wl_display,   int fd, const char *device_name, uint32_t flags)
252 {
253         if (!tbm_drm_auth_srv) {
254                 TBM_RETURN_VAL_IF_FAIL(wl_display != NULL, 0);
255
256                 tbm_drm_auth_srv = calloc(1, sizeof(struct wayland_tbm_drm_auth_server));
257                 TBM_RETURN_VAL_IF_FAIL(tbm_drm_auth_srv != NULL, 0);
258
259                 tbm_drm_auth_srv->display = (struct wl_display *)wl_display;
260                 tbm_drm_auth_srv->device_name = strdup(device_name);
261                 tbm_drm_auth_srv->fd = fd;
262                 tbm_drm_auth_srv->flags = flags;
263
264                 if (wl_display_add_socket(tbm_drm_auth_srv->display, "tbm-drm-auth")) {
265                         TBM_ERR("[TBM_DRM] fail to add socket\n");
266
267                         if (tbm_drm_auth_srv->device_name)
268                                 free(tbm_drm_auth_srv->device_name);
269
270                         free(tbm_drm_auth_srv);
271                         tbm_drm_auth_srv = NULL;
272
273                         return 0;
274                 }
275
276                 _tbm_drm_auth_socket_init(tbm_drm_auth_srv);
277
278                 /* init the client resource list */
279                 tbm_drm_auth_srv->wl_tbm_drm_auth_global = wl_global_create(tbm_drm_auth_srv->display, &wl_tbm_drm_auth_interface, 1,
280                                          tbm_drm_auth_srv, _wayland_tbm_drm_auth_server_bind_cb);
281         }
282
283         return 1;
284 }
285
286 void
287 tbm_drm_helper_wl_auth_server_deinit(void)
288 {
289         if (tbm_drm_auth_srv) {
290                 wl_global_destroy(tbm_drm_auth_srv->wl_tbm_drm_auth_global);
291
292                 if (tbm_drm_auth_srv->device_name)
293                         free(tbm_drm_auth_srv->device_name);
294
295                 free(tbm_drm_auth_srv);
296                 tbm_drm_auth_srv = NULL;
297         }
298 }
299
300 int
301 tbm_drm_helper_get_master_fd(void)
302 {
303         int new_fd, flags, fd = -1;
304
305 #if 1  /* TODO: can't remove below at this time. This code SHOULD be removed later  */
306         const char *value = (const char*)getenv("TDM_DRM_MASTER_FD");
307         if (value) {
308                 char *end;
309                 const long int sl = strtol(value, &end, 10);
310
311                 if (end == value) {
312                         TBM_ERR("%s: not a decimal number\n", value);
313                         return -1;
314                 } else if (*end != '\0') {
315                         TBM_ERR("%s: extra characters at end of input: %s\n", value, end);
316                         return -1;
317                 } else if ((sl == LONG_MIN || sl == LONG_MAX) && errno == ERANGE) {
318                         TBM_ERR("%s out of range of type long\n", value);
319                         return -1;
320                 } else if (sl >= INT_MAX) {
321                         TBM_ERR("%ld greater than INT_MAX\n", sl);
322                         return -1;
323                 } else if (sl <= INT_MIN) {
324                         TBM_ERR("%ld less than INT_MIN\n", sl);
325                         return -1;
326                 } else {
327                         int fd_max = tbm_bufmgr_get_fd_limit();
328                         fd = (int)sl;
329                         if (fd < 0 || fd > fd_max) {
330                                 TBM_ERR("%d out of fd range\n", fd);
331                                 return -1;
332                         }
333                 }
334         } else
335 #endif
336         fd = tbm_drm_master_fd;
337
338         if (fd == -1) {
339                 TBM_INFO("no presetted TBM DRM MASTER FD");
340                 return -1;
341         }
342
343         TBM_INFO("TBM DRM MASTER FD: %d\n", fd);
344
345         flags = fcntl(fd, F_GETFD);
346         if (flags == -1) {
347                 TBM_ERR("fcntl failed: %m");
348                 return -1;
349         }
350
351         new_fd = dup(fd);
352         if (new_fd < 0) {
353                 TBM_ERR("dup failed: %m");
354                 return -1;
355         }
356
357         if (fcntl(new_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
358                 TBM_ERR("failed to set fd\n");
359                 close(new_fd);
360                 return -1;
361         }
362
363         TBM_INFO("Return MASTER_FD: %d\n", new_fd);
364
365         return new_fd;
366 }
367
368 void
369 tbm_drm_helper_set_tbm_master_fd(int fd)
370 {
371         int fd_max = tbm_bufmgr_get_fd_limit();
372
373         if (tbm_drm_master_fd == fd)
374                 return;
375
376         if (fd < 0 || fd > fd_max) {
377                 TBM_ERR("%d out of fd range\n", fd);
378                 return;
379         }
380
381         if (tbm_drm_master_fd != -1)
382                 TBM_WRN("already has TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
383
384         tbm_drm_master_fd = fd;
385
386         TBM_INFO("TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
387 }
388
389 void
390 tbm_drm_helper_unset_tbm_master_fd(void)
391 {
392         tbm_drm_master_fd = -1;
393         TBM_INFO("TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
394 }
395 /* LCOV_EXCL_STOP */
396