diff options
Diffstat (limited to 'sway/main.c')
-rw-r--r-- | sway/main.c | 226 |
1 files changed, 84 insertions, 142 deletions
diff --git a/sway/main.c b/sway/main.c index 0c219fb3..1c4939aa 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <getopt.h> | 1 | #include <getopt.h> |
3 | #include <pango/pangocairo.h> | 2 | #include <pango/pangocairo.h> |
4 | #include <signal.h> | 3 | #include <signal.h> |
@@ -6,12 +5,14 @@ | |||
6 | #include <stdio.h> | 5 | #include <stdio.h> |
7 | #include <stdlib.h> | 6 | #include <stdlib.h> |
8 | #include <string.h> | 7 | #include <string.h> |
8 | #include <sys/resource.h> | ||
9 | #include <sys/stat.h> | 9 | #include <sys/stat.h> |
10 | #include <sys/types.h> | 10 | #include <sys/types.h> |
11 | #include <sys/wait.h> | 11 | #include <sys/wait.h> |
12 | #include <sys/un.h> | 12 | #include <sys/un.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <wlr/util/log.h> | 14 | #include <wlr/util/log.h> |
15 | #include <wlr/version.h> | ||
15 | #include "sway/commands.h" | 16 | #include "sway/commands.h" |
16 | #include "sway/config.h" | 17 | #include "sway/config.h" |
17 | #include "sway/server.h" | 18 | #include "sway/server.h" |
@@ -26,6 +27,7 @@ | |||
26 | 27 | ||
27 | static bool terminate_request = false; | 28 | static bool terminate_request = false; |
28 | static int exit_value = 0; | 29 | static int exit_value = 0; |
30 | static struct rlimit original_nofile_rlimit = {0}; | ||
29 | struct sway_server server = {0}; | 31 | struct sway_server server = {0}; |
30 | struct sway_debug debug = {0}; | 32 | struct sway_debug debug = {0}; |
31 | 33 | ||
@@ -46,81 +48,6 @@ void sig_handler(int signal) { | |||
46 | sway_terminate(EXIT_SUCCESS); | 48 | sway_terminate(EXIT_SUCCESS); |
47 | } | 49 | } |
48 | 50 | ||
49 | void detect_raspi(void) { | ||
50 | bool raspi = false; | ||
51 | FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); | ||
52 | if (!f) { | ||
53 | return; | ||
54 | } | ||
55 | char *line = NULL; | ||
56 | size_t line_size = 0; | ||
57 | while (getline(&line, &line_size, f) != -1) { | ||
58 | if (strstr(line, "Raspberry Pi")) { | ||
59 | raspi = true; | ||
60 | break; | ||
61 | } | ||
62 | } | ||
63 | fclose(f); | ||
64 | FILE *g = fopen("/proc/modules", "r"); | ||
65 | if (!g) { | ||
66 | free(line); | ||
67 | return; | ||
68 | } | ||
69 | bool vc4 = false; | ||
70 | while (getline(&line, &line_size, g) != -1) { | ||
71 | if (strstr(line, "vc4")) { | ||
72 | vc4 = true; | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | free(line); | ||
77 | fclose(g); | ||
78 | if (!vc4 && raspi) { | ||
79 | fprintf(stderr, "\x1B[1;31mWarning: You have a " | ||
80 | "Raspberry Pi, but the vc4 Module is " | ||
81 | "not loaded! Set 'dtoverlay=vc4-kms-v3d'" | ||
82 | "in /boot/config.txt and reboot.\x1B[0m\n"); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | void detect_proprietary(int allow_unsupported_gpu) { | ||
87 | FILE *f = fopen("/proc/modules", "r"); | ||
88 | if (!f) { | ||
89 | return; | ||
90 | } | ||
91 | char *line = NULL; | ||
92 | size_t line_size = 0; | ||
93 | while (getline(&line, &line_size, f) != -1) { | ||
94 | if (strncmp(line, "nvidia ", 7) == 0) { | ||
95 | if (allow_unsupported_gpu) { | ||
96 | sway_log(SWAY_ERROR, | ||
97 | "!!! Proprietary Nvidia drivers are in use !!!"); | ||
98 | } else { | ||
99 | sway_log(SWAY_ERROR, | ||
100 | "Proprietary Nvidia drivers are NOT supported. " | ||
101 | "Use Nouveau. To launch sway anyway, launch with " | ||
102 | "--my-next-gpu-wont-be-nvidia and DO NOT report issues."); | ||
103 | exit(EXIT_FAILURE); | ||
104 | } | ||
105 | break; | ||
106 | } | ||
107 | if (strstr(line, "fglrx")) { | ||
108 | if (allow_unsupported_gpu) { | ||
109 | sway_log(SWAY_ERROR, | ||
110 | "!!! Proprietary AMD drivers are in use !!!"); | ||
111 | } else { | ||
112 | sway_log(SWAY_ERROR, "Proprietary AMD drivers do NOT support " | ||
113 | "Wayland. Use radeon. To try anyway, launch sway with " | ||
114 | "--unsupported-gpu and DO NOT report issues."); | ||
115 | exit(EXIT_FAILURE); | ||
116 | } | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | free(line); | ||
121 | fclose(f); | ||
122 | } | ||
123 | |||
124 | void run_as_ipc_client(char *command, char *socket_path) { | 51 | void run_as_ipc_client(char *command, char *socket_path) { |
125 | int socketfd = ipc_open_socket(socket_path); | 52 | int socketfd = ipc_open_socket(socket_path); |
126 | uint32_t len = strlen(command); | 53 | uint32_t len = strlen(command); |
@@ -184,33 +111,49 @@ static void log_kernel(void) { | |||
184 | pclose(f); | 111 | pclose(f); |
185 | } | 112 | } |
186 | 113 | ||
187 | 114 | static bool detect_suid(void) { | |
188 | static bool drop_permissions(void) { | 115 | if (geteuid() != 0 && getegid() != 0) { |
189 | if (getuid() != geteuid() || getgid() != getegid()) { | 116 | return false; |
190 | // Set the gid and uid in the correct order. | ||
191 | if (setgid(getgid()) != 0) { | ||
192 | sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start"); | ||
193 | return false; | ||
194 | } | ||
195 | if (setuid(getuid()) != 0) { | ||
196 | sway_log(SWAY_ERROR, "Unable to drop root user, refusing to start"); | ||
197 | return false; | ||
198 | } | ||
199 | } | 117 | } |
200 | if (setgid(0) != -1 || setuid(0) != -1) { | 118 | |
201 | sway_log(SWAY_ERROR, "Unable to drop root (we shouldn't be able to " | 119 | if (getuid() == geteuid() && getgid() == getegid()) { |
202 | "restore it after setuid), refusing to start"); | ||
203 | return false; | 120 | return false; |
204 | } | 121 | } |
122 | |||
123 | sway_log(SWAY_ERROR, "SUID operation is no longer supported, refusing to start. " | ||
124 | "This check will be removed in a future release."); | ||
205 | return true; | 125 | return true; |
206 | } | 126 | } |
207 | 127 | ||
128 | static void increase_nofile_limit(void) { | ||
129 | if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { | ||
130 | sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " | ||
131 | "getrlimit(NOFILE) failed"); | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | struct rlimit new_rlimit = original_nofile_rlimit; | ||
136 | new_rlimit.rlim_cur = new_rlimit.rlim_max; | ||
137 | if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) { | ||
138 | sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " | ||
139 | "setrlimit(NOFILE) failed"); | ||
140 | sway_log(SWAY_INFO, "Running with %d max open files", | ||
141 | (int)original_nofile_rlimit.rlim_cur); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void restore_nofile_limit(void) { | ||
146 | if (original_nofile_rlimit.rlim_cur == 0) { | ||
147 | return; | ||
148 | } | ||
149 | if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { | ||
150 | sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: " | ||
151 | "setrlimit(NOFILE) failed"); | ||
152 | } | ||
153 | } | ||
154 | |||
208 | void enable_debug_flag(const char *flag) { | 155 | void enable_debug_flag(const char *flag) { |
209 | if (strcmp(flag, "damage=highlight") == 0) { | 156 | if (strcmp(flag, "noatomic") == 0) { |
210 | debug.damage = DAMAGE_HIGHLIGHT; | ||
211 | } else if (strcmp(flag, "damage=rerender") == 0) { | ||
212 | debug.damage = DAMAGE_RERENDER; | ||
213 | } else if (strcmp(flag, "noatomic") == 0) { | ||
214 | debug.noatomic = true; | 157 | debug.noatomic = true; |
215 | } else if (strcmp(flag, "txn-wait") == 0) { | 158 | } else if (strcmp(flag, "txn-wait") == 0) { |
216 | debug.txn_wait = true; | 159 | debug.txn_wait = true; |
@@ -218,6 +161,8 @@ void enable_debug_flag(const char *flag) { | |||
218 | debug.txn_timings = true; | 161 | debug.txn_timings = true; |
219 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { | 162 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { |
220 | server.txn_timeout_ms = atoi(&flag[12]); | 163 | server.txn_timeout_ms = atoi(&flag[12]); |
164 | } else if (strcmp(flag, "legacy-wl-drm") == 0) { | ||
165 | debug.legacy_wl_drm = true; | ||
221 | } else { | 166 | } else { |
222 | sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); | 167 | sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); |
223 | } | 168 | } |
@@ -242,36 +187,35 @@ static void handle_wlr_log(enum wlr_log_importance importance, | |||
242 | _sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args); | 187 | _sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args); |
243 | } | 188 | } |
244 | 189 | ||
190 | static const struct option long_options[] = { | ||
191 | {"help", no_argument, NULL, 'h'}, | ||
192 | {"config", required_argument, NULL, 'c'}, | ||
193 | {"validate", no_argument, NULL, 'C'}, | ||
194 | {"debug", no_argument, NULL, 'd'}, | ||
195 | {"version", no_argument, NULL, 'v'}, | ||
196 | {"verbose", no_argument, NULL, 'V'}, | ||
197 | {"get-socketpath", no_argument, NULL, 'p'}, | ||
198 | {"unsupported-gpu", no_argument, NULL, 'u'}, | ||
199 | {0, 0, 0, 0} | ||
200 | }; | ||
201 | |||
202 | static const char usage[] = | ||
203 | "Usage: sway [options] [command]\n" | ||
204 | "\n" | ||
205 | " -h, --help Show help message and quit.\n" | ||
206 | " -c, --config <config> Specify a config file.\n" | ||
207 | " -C, --validate Check the validity of the config file, then exit.\n" | ||
208 | " -d, --debug Enables full logging, including debug information.\n" | ||
209 | " -v, --version Show the version number and quit.\n" | ||
210 | " -V, --verbose Enables more verbose logging.\n" | ||
211 | " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" | ||
212 | "\n"; | ||
213 | |||
245 | int main(int argc, char **argv) { | 214 | int main(int argc, char **argv) { |
246 | static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0; | 215 | static bool verbose = false, debug = false, validate = false; |
247 | |||
248 | static struct option long_options[] = { | ||
249 | {"help", no_argument, NULL, 'h'}, | ||
250 | {"config", required_argument, NULL, 'c'}, | ||
251 | {"validate", no_argument, NULL, 'C'}, | ||
252 | {"debug", no_argument, NULL, 'd'}, | ||
253 | {"version", no_argument, NULL, 'v'}, | ||
254 | {"verbose", no_argument, NULL, 'V'}, | ||
255 | {"get-socketpath", no_argument, NULL, 'p'}, | ||
256 | {"unsupported-gpu", no_argument, NULL, 'u'}, | ||
257 | {"my-next-gpu-wont-be-nvidia", no_argument, NULL, 'u'}, | ||
258 | {0, 0, 0, 0} | ||
259 | }; | ||
260 | 216 | ||
261 | char *config_path = NULL; | 217 | char *config_path = NULL; |
262 | 218 | ||
263 | const char* usage = | ||
264 | "Usage: sway [options] [command]\n" | ||
265 | "\n" | ||
266 | " -h, --help Show help message and quit.\n" | ||
267 | " -c, --config <config> Specify a config file.\n" | ||
268 | " -C, --validate Check the validity of the config file, then exit.\n" | ||
269 | " -d, --debug Enables full logging, including debug information.\n" | ||
270 | " -v, --version Show the version number and quit.\n" | ||
271 | " -V, --verbose Enables more verbose logging.\n" | ||
272 | " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" | ||
273 | "\n"; | ||
274 | |||
275 | int c; | 219 | int c; |
276 | while (1) { | 220 | while (1) { |
277 | int option_index = 0; | 221 | int option_index = 0; |
@@ -289,25 +233,25 @@ int main(int argc, char **argv) { | |||
289 | config_path = strdup(optarg); | 233 | config_path = strdup(optarg); |
290 | break; | 234 | break; |
291 | case 'C': // validate | 235 | case 'C': // validate |
292 | validate = 1; | 236 | validate = true; |
293 | break; | 237 | break; |
294 | case 'd': // debug | 238 | case 'd': // debug |
295 | debug = 1; | 239 | debug = true; |
296 | break; | 240 | break; |
297 | case 'D': // extended debug options | 241 | case 'D': // extended debug options |
298 | enable_debug_flag(optarg); | 242 | enable_debug_flag(optarg); |
299 | break; | 243 | break; |
300 | case 'u': | 244 | case 'u': |
301 | allow_unsupported_gpu = 1; | 245 | allow_unsupported_gpu = true; |
302 | break; | 246 | break; |
303 | case 'v': // version | 247 | case 'v': // version |
304 | printf("sway version " SWAY_VERSION "\n"); | 248 | printf("sway version " SWAY_VERSION "\n"); |
305 | exit(EXIT_SUCCESS); | 249 | exit(EXIT_SUCCESS); |
306 | break; | 250 | break; |
307 | case 'V': // verbose | 251 | case 'V': // verbose |
308 | verbose = 1; | 252 | verbose = true; |
309 | break; | 253 | break; |
310 | case 'p': ; // --get-socketpath | 254 | case 'p': // --get-socketpath |
311 | if (getenv("SWAYSOCK")) { | 255 | if (getenv("SWAYSOCK")) { |
312 | printf("%s\n", getenv("SWAYSOCK")); | 256 | printf("%s\n", getenv("SWAYSOCK")); |
313 | exit(EXIT_SUCCESS); | 257 | exit(EXIT_SUCCESS); |
@@ -322,6 +266,11 @@ int main(int argc, char **argv) { | |||
322 | } | 266 | } |
323 | } | 267 | } |
324 | 268 | ||
269 | // SUID operation is deprecated, so block it for now. | ||
270 | if (detect_suid()) { | ||
271 | exit(EXIT_FAILURE); | ||
272 | } | ||
273 | |||
325 | // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the | 274 | // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the |
326 | // clear error message (when not running as an IPC client). | 275 | // clear error message (when not running as an IPC client). |
327 | if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { | 276 | if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { |
@@ -344,11 +293,10 @@ int main(int argc, char **argv) { | |||
344 | } | 293 | } |
345 | 294 | ||
346 | sway_log(SWAY_INFO, "Sway version " SWAY_VERSION); | 295 | sway_log(SWAY_INFO, "Sway version " SWAY_VERSION); |
296 | sway_log(SWAY_INFO, "wlroots version " WLR_VERSION_STR); | ||
347 | log_kernel(); | 297 | log_kernel(); |
348 | log_distro(); | 298 | log_distro(); |
349 | log_env(); | 299 | log_env(); |
350 | detect_proprietary(allow_unsupported_gpu); | ||
351 | detect_raspi(); | ||
352 | 300 | ||
353 | if (optind < argc) { // Behave as IPC client | 301 | if (optind < argc) { // Behave as IPC client |
354 | if (optind != 1) { | 302 | if (optind != 1) { |
@@ -361,9 +309,6 @@ int main(int argc, char **argv) { | |||
361 | "`sway -d 2>sway.log`."); | 309 | "`sway -d 2>sway.log`."); |
362 | exit(EXIT_FAILURE); | 310 | exit(EXIT_FAILURE); |
363 | } | 311 | } |
364 | if (!drop_permissions()) { | ||
365 | exit(EXIT_FAILURE); | ||
366 | } | ||
367 | char *socket_path = getenv("SWAYSOCK"); | 312 | char *socket_path = getenv("SWAYSOCK"); |
368 | if (!socket_path) { | 313 | if (!socket_path) { |
369 | sway_log(SWAY_ERROR, "Unable to retrieve socket path"); | 314 | sway_log(SWAY_ERROR, "Unable to retrieve socket path"); |
@@ -375,14 +320,7 @@ int main(int argc, char **argv) { | |||
375 | return 0; | 320 | return 0; |
376 | } | 321 | } |
377 | 322 | ||
378 | if (!server_privileged_prepare(&server)) { | 323 | increase_nofile_limit(); |
379 | return 1; | ||
380 | } | ||
381 | |||
382 | if (!drop_permissions()) { | ||
383 | server_fini(&server); | ||
384 | exit(EXIT_FAILURE); | ||
385 | } | ||
386 | 324 | ||
387 | // handle SIGTERM signals | 325 | // handle SIGTERM signals |
388 | signal(SIGTERM, sig_handler); | 326 | signal(SIGTERM, sig_handler); |
@@ -393,12 +331,14 @@ int main(int argc, char **argv) { | |||
393 | 331 | ||
394 | sway_log(SWAY_INFO, "Starting sway version " SWAY_VERSION); | 332 | sway_log(SWAY_INFO, "Starting sway version " SWAY_VERSION); |
395 | 333 | ||
396 | root = root_create(); | ||
397 | |||
398 | if (!server_init(&server)) { | 334 | if (!server_init(&server)) { |
399 | return 1; | 335 | return 1; |
400 | } | 336 | } |
401 | 337 | ||
338 | if (server.linux_dmabuf_v1) { | ||
339 | wlr_scene_set_linux_dmabuf_v1(root->root_scene, server.linux_dmabuf_v1); | ||
340 | } | ||
341 | |||
402 | if (validate) { | 342 | if (validate) { |
403 | bool valid = load_main_config(config_path, false, true); | 343 | bool valid = load_main_config(config_path, false, true); |
404 | free(config_path); | 344 | free(config_path); |
@@ -413,6 +353,8 @@ int main(int argc, char **argv) { | |||
413 | goto shutdown; | 353 | goto shutdown; |
414 | } | 354 | } |
415 | 355 | ||
356 | set_rr_scheduling(); | ||
357 | |||
416 | if (!server_start(&server)) { | 358 | if (!server_start(&server)) { |
417 | sway_terminate(EXIT_FAILURE); | 359 | sway_terminate(EXIT_FAILURE); |
418 | goto shutdown; | 360 | goto shutdown; |