File indexing completed on 2024-11-10 04:56:46
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2020 <davidedmundson@kde.org> 0006 SPDX-FileCopyrightText: 2008 Kristian Høgsberg 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #define _DEFAULT_SOURCE 0012 #include <assert.h> 0013 #include <errno.h> 0014 #include <fcntl.h> 0015 #include <stdio.h> 0016 #include <stdlib.h> 0017 #include <string.h> 0018 #include <sys/file.h> 0019 #include <sys/socket.h> 0020 #include <sys/stat.h> 0021 #include <sys/un.h> 0022 #include <unistd.h> 0023 0024 /* This is the size of the char array in struct sock_addr_un. 0025 * No Wayland socket can be created with a path longer than this, 0026 * including the null terminator. 0027 */ 0028 #ifndef UNIX_PATH_MAX 0029 #define UNIX_PATH_MAX 108 0030 #endif 0031 0032 #define LOCK_SUFFIX ".lock" 0033 #define LOCK_SUFFIXLEN 5 0034 0035 struct wl_socket { 0036 int fd; 0037 int fd_lock; 0038 struct sockaddr_un addr; 0039 char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN]; 0040 char display_name[20]; 0041 }; 0042 0043 static struct wl_socket *wl_socket_alloc(void) 0044 { 0045 struct wl_socket *s; 0046 0047 s = malloc(sizeof *s); 0048 if (!s) 0049 return NULL; 0050 0051 s->fd = -1; 0052 s->fd_lock = -1; 0053 0054 return s; 0055 } 0056 0057 static int wl_socket_lock(struct wl_socket *socket) 0058 { 0059 struct stat socket_stat; 0060 0061 snprintf(socket->lock_addr, sizeof socket->lock_addr, "%s%s", socket->addr.sun_path, LOCK_SUFFIX); 0062 0063 socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC | O_RDWR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); 0064 0065 if (socket->fd_lock < 0) { 0066 printf("unable to open lockfile %s check permissions\n", socket->lock_addr); 0067 goto err; 0068 } 0069 0070 if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) { 0071 printf("unable to lock lockfile %s, maybe another compositor is running\n", socket->lock_addr); 0072 goto err_fd; 0073 } 0074 0075 if (lstat(socket->addr.sun_path, &socket_stat) < 0) { 0076 if (errno != ENOENT) { 0077 printf("did not manage to stat file %s\n", socket->addr.sun_path); 0078 goto err_fd; 0079 } 0080 } else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) { 0081 unlink(socket->addr.sun_path); 0082 } 0083 0084 return 0; 0085 err_fd: 0086 close(socket->fd_lock); 0087 socket->fd_lock = -1; 0088 err: 0089 *socket->lock_addr = 0; 0090 /* we did not set this value here, but without lock the 0091 * socket won't be created anyway. This prevents the 0092 * wl_socket_destroy from unlinking already existing socket 0093 * created by other compositor */ 0094 *socket->addr.sun_path = 0; 0095 0096 return -1; 0097 } 0098 0099 void wl_socket_destroy(struct wl_socket *s) 0100 { 0101 if (s->addr.sun_path[0]) 0102 unlink(s->addr.sun_path); 0103 if (s->fd >= 0) 0104 close(s->fd); 0105 if (s->lock_addr[0]) 0106 unlink(s->lock_addr); 0107 if (s->fd_lock >= 0) 0108 close(s->fd_lock); 0109 0110 free(s); 0111 } 0112 0113 const char *wl_socket_get_display_name(struct wl_socket *s) 0114 { 0115 return s->display_name; 0116 } 0117 0118 int wl_socket_get_fd(struct wl_socket *s) 0119 { 0120 return s->fd; 0121 } 0122 0123 struct wl_socket *wl_socket_create() 0124 { 0125 struct wl_socket *s; 0126 int displayno = 0; 0127 int name_size; 0128 0129 /* A reasonable number of maximum default sockets. If 0130 * you need more than this, use the explicit add_socket API. */ 0131 const int MAX_DISPLAYNO = 32; 0132 const char *runtime_dir = getenv("XDG_RUNTIME_DIR"); 0133 if (!runtime_dir) { 0134 printf("XDG_RUNTIME_DIR not set"); 0135 return NULL; 0136 } 0137 0138 s = wl_socket_alloc(); 0139 if (s == NULL) 0140 return NULL; 0141 0142 do { 0143 snprintf(s->display_name, sizeof s->display_name, "wayland-%d", displayno); 0144 s->addr.sun_family = AF_LOCAL; 0145 name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path, "%s/%s", runtime_dir, s->display_name) + 1; 0146 assert(name_size > 0); 0147 0148 if (name_size > (int)sizeof s->addr.sun_path) { 0149 goto fail; 0150 } 0151 0152 if (wl_socket_lock(s) < 0) 0153 continue; 0154 0155 s->fd = socket(PF_LOCAL, SOCK_STREAM, 0); 0156 0157 int size = SUN_LEN(&s->addr); 0158 int ret = bind(s->fd, (struct sockaddr*)&s->addr, size); 0159 if (ret < 0) { 0160 goto fail; 0161 } 0162 ret = listen(s->fd, 128); 0163 if (ret < 0) { 0164 goto fail; 0165 } 0166 return s; 0167 } while (displayno++ < MAX_DISPLAYNO); 0168 0169 fail: 0170 wl_socket_destroy(s); 0171 return NULL; 0172 }