tbm_module: free bo when it is not from hal_surface.
[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                 if (!device_name) {
261                         tbm_drm_auth_srv->device_name = drmGetDeviceNameFromFd(fd);
262                         if (!tbm_drm_auth_srv->device_name) {
263                                         TBM_ERR("fail to get device name!\n");
264                                         return 0;
265                         }
266                 } else {
267                         tbm_drm_auth_srv->device_name = strdup(device_name);
268                 }
269                 tbm_drm_auth_srv->fd = fd;
270                 tbm_drm_auth_srv->flags = flags;
271
272                 if (wl_display_add_socket(tbm_drm_auth_srv->display, "tbm-drm-auth")) {
273                         TBM_ERR("[TBM_DRM] fail to add socket\n");
274
275                         if (tbm_drm_auth_srv->device_name)
276                                 free(tbm_drm_auth_srv->device_name);
277
278                         free(tbm_drm_auth_srv);
279                         tbm_drm_auth_srv = NULL;
280
281                         return 0;
282                 }
283
284                 _tbm_drm_auth_socket_init(tbm_drm_auth_srv);
285
286                 /* init the client resource list */
287                 tbm_drm_auth_srv->wl_tbm_drm_auth_global = wl_global_create(tbm_drm_auth_srv->display, &wl_tbm_drm_auth_interface, 1,
288                                          tbm_drm_auth_srv, _wayland_tbm_drm_auth_server_bind_cb);
289         }
290
291         return 1;
292 }
293
294 void
295 tbm_drm_helper_wl_auth_server_deinit(void)
296 {
297         if (tbm_drm_auth_srv) {
298                 wl_global_destroy(tbm_drm_auth_srv->wl_tbm_drm_auth_global);
299
300                 if (tbm_drm_auth_srv->device_name)
301                         free(tbm_drm_auth_srv->device_name);
302
303                 free(tbm_drm_auth_srv);
304                 tbm_drm_auth_srv = NULL;
305         }
306 }
307
308 int
309 tbm_drm_helper_get_master_fd(void)
310 {
311         int new_fd, flags, fd = -1;
312
313         fd = tbm_drm_master_fd;
314         if (fd == -1) {
315                 TBM_INFO("no presetted TBM DRM MASTER FD");
316                 return -1;
317         }
318
319         TBM_INFO("TBM DRM MASTER FD: %d\n", fd);
320
321         flags = fcntl(fd, F_GETFD);
322         if (flags == -1) {
323                 TBM_ERR("fcntl failed: %m");
324                 return -1;
325         }
326
327         new_fd = dup(fd);
328         if (new_fd < 0) {
329                 TBM_ERR("dup failed: %m");
330                 return -1;
331         }
332
333         if (fcntl(new_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
334                 TBM_ERR("failed to set fd\n");
335                 close(new_fd);
336                 return -1;
337         }
338
339         TBM_INFO("Return MASTER_FD: %d\n", new_fd);
340
341         return new_fd;
342 }
343
344 void
345 tbm_drm_helper_set_tbm_master_fd(int fd)
346 {
347         int fd_max = tbm_bufmgr_get_fd_limit();
348
349         if (tbm_drm_master_fd == fd)
350                 return;
351
352         if (fd < 0 || fd > fd_max) {
353                 TBM_ERR("%d out of fd range\n", fd);
354                 return;
355         }
356
357         if (tbm_drm_master_fd != -1)
358                 TBM_WRN("already has TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
359
360         tbm_drm_master_fd = fd;
361
362         TBM_INFO("TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
363 }
364
365 void
366 tbm_drm_helper_unset_tbm_master_fd(void)
367 {
368         tbm_drm_master_fd = -1;
369         TBM_INFO("TBM DRM MASTER FD: %d\n", tbm_drm_master_fd);
370 }
371 /* LCOV_EXCL_STOP */
372