tbm_drm_helper_server: Set tbm drm server thread name
[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         pthread_t thread;
47
48         char *device_name;
49         uint32_t fd;
50         uint32_t flags;
51 };
52
53 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
54
55 struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv;
56
57 static int tbm_drm_master_fd = -1;
58
59 /* LCOV_EXCL_START */
60 static void
61 _send_server_auth_info(struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv,
62                        struct wl_resource *resource)
63 {
64         int fd = -1;
65         uint32_t capabilities;
66         char *device_name = NULL;
67         drm_magic_t magic = 0;
68
69         fd = open(tbm_drm_auth_srv->device_name, O_RDWR | O_CLOEXEC);
70         if (fd == -1 && errno == EINVAL) {
71                 fd = open(tbm_drm_auth_srv->device_name, O_RDWR);
72                 if (fd != -1) {
73                         if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) == -1) {
74                                 TBM_ERR("failed to set fd\n");
75                                 goto fini;
76                         }
77                 }
78         }
79
80         if (fd < 0) {
81                 TBM_ERR("failed to open drm : device_name, %s (%m)\n", tbm_drm_auth_srv->device_name);
82
83                 wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
84                                        "authenicate failed::open_drm");
85                 goto fini;
86         }
87
88         if (drmGetMagic(fd, &magic) < 0) {
89                 if (errno != EACCES) {
90                         TBM_ERR("failed to get magic\n");
91
92                         wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
93                                                "authenicate failed::get_magic");
94                         goto fini;
95                 }
96         }
97
98         if (drmAuthMagic(tbm_drm_auth_srv->fd, magic) < 0) {
99                 TBM_ERR("failed to authenticate magic\n");
100
101                 wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
102                                        "authenicate failed::auth_magic");
103                 goto fini;
104         }
105
106         capabilities = tbm_drm_auth_srv->flags;
107         device_name = tbm_drm_auth_srv->device_name;
108
109         /* send */
110         wl_tbm_drm_auth_send_authentication_info(resource, device_name, capabilities, fd);
111
112         TBM_INFO("Send tbm drm auth info fd:%d device_name:%s capabilities:%x",
113                         fd, device_name, capabilities);
114
115 fini:
116         if (fd >= 0)
117                 close(fd);
118
119         if (device_name && device_name != tbm_drm_auth_srv->device_name)
120                 free(device_name);
121
122 }
123
124 static void
125 _wayland_tbm_drm_auth_server_impl_get_authentication_info(struct wl_client *client,
126                 struct wl_resource *resource)
127 {
128         struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv = wl_resource_get_user_data(resource);
129
130         /* if display server is the client of the host display server, for embedded server */
131         _send_server_auth_info(tbm_drm_auth_srv, resource);
132 }
133
134
135 static const struct wl_tbm_drm_auth_interface _wayland_tbm_drm_auth_server_implementation = {
136         _wayland_tbm_drm_auth_server_impl_get_authentication_info,
137 };
138
139 static void
140 _wayland_tbm_drm_auth_server_bind_cb(struct wl_client *client, void *data,
141                             uint32_t version,
142                             uint32_t id)
143 {
144         struct wl_resource *resource;
145
146         resource = wl_resource_create(client, &wl_tbm_drm_auth_interface, MIN(version, 1), id);
147         if (!resource) {
148                 wl_client_post_no_memory(client);
149                 return;
150         }
151
152         wl_resource_set_implementation(resource,
153                                        &_wayland_tbm_drm_auth_server_implementation,
154                                        data,
155                                        NULL);
156 }
157
158 static int
159 _tbm_getgrnam_r(const char *name)
160 {
161         struct group *grp = NULL;
162         struct group *grp_res = NULL;
163         char* buf = NULL;
164         size_t buf_len;
165         int ret;
166         int id;
167
168         buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
169         if (buf_len == -1)
170                 buf_len = 2048;
171
172         buf = calloc(1, buf_len * sizeof(char));
173         if (!buf) {
174                 TBM_ERR("creating buffer failed\n");
175                 goto failed;
176         }
177
178         grp = calloc(1, sizeof(struct group));
179         if (!grp) {
180                 TBM_ERR("creating group failed\n");
181                 goto failed;
182         }
183
184         ret = getgrnam_r(name, grp, buf, buf_len, &grp_res);
185         if (ret < 0) {
186                 TBM_ERR("getgrnam_r failed errno:%d(%m)\n", ret);
187                 goto failed;
188         }
189
190         if (grp_res == NULL) {
191                 TBM_ERR("finding name:%s group failed\n", name);
192                 goto failed;
193         }
194
195         id = grp->gr_gid;
196         free(buf);
197         free(grp);
198
199         return id;
200
201 failed:
202         if (buf)
203                 free(buf);
204         if (grp)
205                 free(grp);
206
207         return -1;
208 }
209
210 static void
211 _tbm_drm_auth_socket_init(struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv)
212 {
213         const char *dir = NULL;
214         char socket_path[128];
215         int ret = -1;
216         uid_t uid;
217         gid_t gid;
218
219         dir = getenv("XDG_RUNTIME_DIR");
220         if (!dir) {
221                 TBM_WRN("getting XDG_RUNTIME_DIR failed\n");
222                 return;
223         }
224
225         snprintf(socket_path, sizeof(socket_path), "%s/%s", dir, "tbm-drm-auth");
226
227         ret = chmod(socket_path, 509);
228         if (ret < 0) {
229                 TBM_WRN("changing modes of socket file failed:%s (%m)\n", socket_path);
230                 return;
231         }
232
233         ret = _tbm_getgrnam_r("root");
234         if (ret < 0) {
235                 TBM_WRN("getting uid failed\n");
236                 return;
237         }
238         uid = ret;
239
240         ret = _tbm_getgrnam_r("display");
241         if (ret < 0) {
242                 TBM_WRN("getting gid failed\n");
243                 return;
244         }
245         gid = ret;
246
247         ret = chown(socket_path, uid, gid);
248         if (ret < 0) {
249                 TBM_WRN("changing owner of socket file failed:%s (%m)\n", socket_path);
250                 return;
251         }
252 }
253
254 static void *
255 _tbm_drm_auth_main(void *data)
256 {
257         wl_display_run(tbm_drm_auth_srv->display);
258         pthread_exit(NULL);
259 }
260
261 int
262 tbm_drm_helper_wl_auth_server_init(void *wl_display, int fd, const char *device_name, uint32_t flags)
263 {
264         int ret;
265
266         if (tbm_drm_auth_srv) return 1;
267
268         tbm_drm_auth_srv = calloc(1, sizeof(struct wayland_tbm_drm_auth_server));
269         TBM_RETURN_VAL_IF_FAIL(tbm_drm_auth_srv != NULL, 0);
270
271         tbm_drm_auth_srv->display = wl_display_create();
272         if (!tbm_drm_auth_srv->display) {
273                 TBM_ERR("fail to create wl_display");
274                 goto fail;
275         }
276
277         if (!device_name) {
278                 tbm_drm_auth_srv->device_name = drmGetDeviceNameFromFd(fd);
279                 if (!tbm_drm_auth_srv->device_name) {
280                         TBM_ERR("fail to get device name");
281                         goto fail;
282                 }
283         } else {
284                 tbm_drm_auth_srv->device_name = strdup(device_name);
285         }
286
287         tbm_drm_auth_srv->fd = fd;
288         tbm_drm_auth_srv->flags = flags;
289
290         if (wl_display_add_socket(tbm_drm_auth_srv->display, "tbm-drm-auth")) {
291                 TBM_ERR("[TBM_DRM] fail to add socket");
292                 goto fail;
293         }
294
295         _tbm_drm_auth_socket_init(tbm_drm_auth_srv);
296
297         /* init the client resource list */
298         tbm_drm_auth_srv->wl_tbm_drm_auth_global = wl_global_create(tbm_drm_auth_srv->display, &wl_tbm_drm_auth_interface, 1,
299                                         tbm_drm_auth_srv, _wayland_tbm_drm_auth_server_bind_cb);
300
301         ret = pthread_create(&tbm_drm_auth_srv->thread, NULL, _tbm_drm_auth_main, NULL);
302         if (ret != 0) {
303                 TBM_ERR("fail to create auth thread err:%d", ret);
304                 goto fail;
305         }
306
307         pthread_setname_np(tbm_drm_auth_srv->thread, "tbm_drm_auth");
308
309         return 1;
310
311 fail:
312         if (tbm_drm_auth_srv->display)
313                 wl_display_destroy(tbm_drm_auth_srv->display);
314
315         if (tbm_drm_auth_srv->device_name)
316                 free(tbm_drm_auth_srv->device_name);
317
318         free(tbm_drm_auth_srv);
319         tbm_drm_auth_srv = NULL;
320
321         return 0;
322 }
323
324 void
325 tbm_drm_helper_wl_auth_server_deinit(void)
326 {
327         if (!tbm_drm_auth_srv) return;
328
329         wl_display_terminate(tbm_drm_auth_srv->display);
330         pthread_join(tbm_drm_auth_srv->thread, NULL);
331
332         wl_global_destroy(tbm_drm_auth_srv->wl_tbm_drm_auth_global);
333
334         wl_display_destroy(tbm_drm_auth_srv->display);
335
336         if (tbm_drm_auth_srv->device_name)
337                 free(tbm_drm_auth_srv->device_name);
338
339         free(tbm_drm_auth_srv);
340         tbm_drm_auth_srv = NULL;
341 }
342
343 int
344 tbm_drm_helper_get_master_fd(void)
345 {
346         int new_fd, flags, fd = -1;
347
348         fd = tbm_drm_master_fd;
349         if (fd == -1) {
350                 TBM_INFO("no presetted TBM DRM MASTER FD");
351                 return -1;
352         }
353
354         TBM_INFO("TBM DRM MASTER FD: %d\n", fd);
355
356         flags = fcntl(fd, F_GETFD);
357         if (flags == -1) {
358                 TBM_ERR("fcntl failed: %m");
359                 return -1;
360         }
361
362         new_fd = dup(fd);
363         if (new_fd < 0) {
364                 TBM_ERR("dup failed: %m");
365                 return -1;
366         }
367
368         if (fcntl(new_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
369                 TBM_ERR("failed to set fd\n");
370                 close(new_fd);
371                 return -1;
372         }
373
374         TBM_INFO("Return MASTER_FD: %d\n", new_fd);
375
376         return new_fd;
377 }
378
379 void
380 tbm_drm_helper_set_tbm_master_fd(int fd)
381 {
382         int fd_max = tbm_bufmgr_get_fd_limit();
383
384         if (tbm_drm_master_fd == fd)
385                 return;
386
387         if (fd < 0 || fd > fd_max) {
388                 TBM_ERR("%d out of fd range\n", fd);
389                 return;
390         }
391
392         if (tbm_drm_master_fd != -1)
393                 TBM_WRN("already has TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
394
395         tbm_drm_master_fd = fd;
396
397         TBM_INFO("TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
398 }
399
400 void
401 tbm_drm_helper_unset_tbm_master_fd(void)
402 {
403         tbm_drm_master_fd = -1;
404         TBM_INFO("TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
405 }
406
407 int
408 tbm_drm_helper_is_render_node(int fd)
409 {
410         if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER)
411                 return 1;
412
413         return 0;
414 }
415 /* LCOV_EXCL_STOP */