diff options
Diffstat (limited to 'sway/main.c')
-rw-r--r-- | sway/main.c | 225 |
1 files changed, 84 insertions, 141 deletions
diff --git a/sway/main.c b/sway/main.c index 0c219fb3..73254dc2 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -6,12 +6,14 @@ | |||
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include <sys/resource.h> | ||
9 | #include <sys/stat.h> | 10 | #include <sys/stat.h> |
10 | #include <sys/types.h> | 11 | #include <sys/types.h> |
11 | #include <sys/wait.h> | 12 | #include <sys/wait.h> |
12 | #include <sys/un.h> | 13 | #include <sys/un.h> |
13 | #include <unistd.h> | 14 | #include <unistd.h> |
14 | #include <wlr/util/log.h> | 15 | #include <wlr/util/log.h> |
16 | #include <wlr/version.h> | ||
15 | #include "sway/commands.h" | 17 | #include "sway/commands.h" |
16 | #include "sway/config.h" | 18 | #include "sway/config.h" |
17 | #include "sway/server.h" | 19 | #include "sway/server.h" |
@@ -26,6 +28,7 @@ | |||
26 | 28 | ||
27 | static bool terminate_request = false; | 29 | static bool terminate_request = false; |
28 | static int exit_value = 0; | 30 | static int exit_value = 0; |
31 | static struct rlimit original_nofile_rlimit = {0}; | ||
29 | struct sway_server server = {0}; | 32 | struct sway_server server = {0}; |
30 | struct sway_debug debug = {0}; | 33 | struct sway_debug debug = {0}; |
31 | 34 | ||
@@ -46,81 +49,6 @@ void sig_handler(int signal) { | |||
46 | sway_terminate(EXIT_SUCCESS); | 49 | sway_terminate(EXIT_SUCCESS); |
47 | } | 50 | } |
48 | 51 | ||
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) { | 52 | void run_as_ipc_client(char *command, char *socket_path) { |
125 | int socketfd = ipc_open_socket(socket_path); | 53 | int socketfd = ipc_open_socket(socket_path); |
126 | uint32_t len = strlen(command); | 54 | uint32_t len = strlen(command); |
@@ -184,33 +112,49 @@ static void log_kernel(void) { | |||
184 | pclose(f); | 112 | pclose(f); |
185 | } | 113 | } |
186 | 114 | ||
187 | 115 | static bool detect_suid(void) { | |
188 | static bool drop_permissions(void) { | 116 | if (geteuid() != 0 && getegid() != 0) { |
189 | if (getuid() != geteuid() || getgid() != getegid()) { | 117 | 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 | } | 118 | } |
200 | if (setgid(0) != -1 || setuid(0) != -1) { | 119 | |
201 | sway_log(SWAY_ERROR, "Unable to drop root (we shouldn't be able to " | 120 | if (getuid() == geteuid() && getgid() == getegid()) { |
202 | "restore it after setuid), refusing to start"); | ||
203 | return false; | 121 | return false; |
204 | } | 122 | } |
123 | |||
124 | sway_log(SWAY_ERROR, "SUID operation is no longer supported, refusing to start. " | ||
125 | "This check will be removed in a future release."); | ||
205 | return true; | 126 | return true; |
206 | } | 127 | } |
207 | 128 | ||
129 | static void increase_nofile_limit(void) { | ||
130 | if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { | ||
131 | sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " | ||
132 | "getrlimit(NOFILE) failed"); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | struct rlimit new_rlimit = original_nofile_rlimit; | ||
137 | new_rlimit.rlim_cur = new_rlimit.rlim_max; | ||
138 | if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) { | ||
139 | sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " | ||
140 | "setrlimit(NOFILE) failed"); | ||
141 | sway_log(SWAY_INFO, "Running with %d max open files", | ||
142 | (int)original_nofile_rlimit.rlim_cur); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | void restore_nofile_limit(void) { | ||
147 | if (original_nofile_rlimit.rlim_cur == 0) { | ||
148 | return; | ||
149 | } | ||
150 | if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { | ||
151 | sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: " | ||
152 | "setrlimit(NOFILE) failed"); | ||
153 | } | ||
154 | } | ||
155 | |||
208 | void enable_debug_flag(const char *flag) { | 156 | void enable_debug_flag(const char *flag) { |
209 | if (strcmp(flag, "damage=highlight") == 0) { | 157 | 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; | 158 | debug.noatomic = true; |
215 | } else if (strcmp(flag, "txn-wait") == 0) { | 159 | } else if (strcmp(flag, "txn-wait") == 0) { |
216 | debug.txn_wait = true; | 160 | debug.txn_wait = true; |
@@ -218,6 +162,8 @@ void enable_debug_flag(const char *flag) { | |||
218 | debug.txn_timings = true; | 162 | debug.txn_timings = true; |
219 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { | 163 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { |
220 | server.txn_timeout_ms = atoi(&flag[12]); | 164 | server.txn_timeout_ms = atoi(&flag[12]); |
165 | } else if (strcmp(flag, "legacy-wl-drm") == 0) { | ||
166 | debug.legacy_wl_drm = true; | ||
221 | } else { | 167 | } else { |
222 | sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); | 168 | sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); |
223 | } | 169 | } |
@@ -242,36 +188,35 @@ static void handle_wlr_log(enum wlr_log_importance importance, | |||
242 | _sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args); | 188 | _sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args); |
243 | } | 189 | } |
244 | 190 | ||
191 | static const struct option long_options[] = { | ||
192 | {"help", no_argument, NULL, 'h'}, | ||
193 | {"config", required_argument, NULL, 'c'}, | ||
194 | {"validate", no_argument, NULL, 'C'}, | ||
195 | {"debug", no_argument, NULL, 'd'}, | ||
196 | {"version", no_argument, NULL, 'v'}, | ||
197 | {"verbose", no_argument, NULL, 'V'}, | ||
198 | {"get-socketpath", no_argument, NULL, 'p'}, | ||
199 | {"unsupported-gpu", no_argument, NULL, 'u'}, | ||
200 | {0, 0, 0, 0} | ||
201 | }; | ||
202 | |||
203 | static const char usage[] = | ||
204 | "Usage: sway [options] [command]\n" | ||
205 | "\n" | ||
206 | " -h, --help Show help message and quit.\n" | ||
207 | " -c, --config <config> Specify a config file.\n" | ||
208 | " -C, --validate Check the validity of the config file, then exit.\n" | ||
209 | " -d, --debug Enables full logging, including debug information.\n" | ||
210 | " -v, --version Show the version number and quit.\n" | ||
211 | " -V, --verbose Enables more verbose logging.\n" | ||
212 | " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" | ||
213 | "\n"; | ||
214 | |||
245 | int main(int argc, char **argv) { | 215 | int main(int argc, char **argv) { |
246 | static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0; | 216 | 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 | 217 | ||
261 | char *config_path = NULL; | 218 | char *config_path = NULL; |
262 | 219 | ||
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; | 220 | int c; |
276 | while (1) { | 221 | while (1) { |
277 | int option_index = 0; | 222 | int option_index = 0; |
@@ -289,25 +234,25 @@ int main(int argc, char **argv) { | |||
289 | config_path = strdup(optarg); | 234 | config_path = strdup(optarg); |
290 | break; | 235 | break; |
291 | case 'C': // validate | 236 | case 'C': // validate |
292 | validate = 1; | 237 | validate = true; |
293 | break; | 238 | break; |
294 | case 'd': // debug | 239 | case 'd': // debug |
295 | debug = 1; | 240 | debug = true; |
296 | break; | 241 | break; |
297 | case 'D': // extended debug options | 242 | case 'D': // extended debug options |
298 | enable_debug_flag(optarg); | 243 | enable_debug_flag(optarg); |
299 | break; | 244 | break; |
300 | case 'u': | 245 | case 'u': |
301 | allow_unsupported_gpu = 1; | 246 | allow_unsupported_gpu = true; |
302 | break; | 247 | break; |
303 | case 'v': // version | 248 | case 'v': // version |
304 | printf("sway version " SWAY_VERSION "\n"); | 249 | printf("sway version " SWAY_VERSION "\n"); |
305 | exit(EXIT_SUCCESS); | 250 | exit(EXIT_SUCCESS); |
306 | break; | 251 | break; |
307 | case 'V': // verbose | 252 | case 'V': // verbose |
308 | verbose = 1; | 253 | verbose = true; |
309 | break; | 254 | break; |
310 | case 'p': ; // --get-socketpath | 255 | case 'p': // --get-socketpath |
311 | if (getenv("SWAYSOCK")) { | 256 | if (getenv("SWAYSOCK")) { |
312 | printf("%s\n", getenv("SWAYSOCK")); | 257 | printf("%s\n", getenv("SWAYSOCK")); |
313 | exit(EXIT_SUCCESS); | 258 | exit(EXIT_SUCCESS); |
@@ -322,6 +267,11 @@ int main(int argc, char **argv) { | |||
322 | } | 267 | } |
323 | } | 268 | } |
324 | 269 | ||
270 | // SUID operation is deprecated, so block it for now. | ||
271 | if (detect_suid()) { | ||
272 | exit(EXIT_FAILURE); | ||
273 | } | ||
274 | |||
325 | // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the | 275 | // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the |
326 | // clear error message (when not running as an IPC client). | 276 | // clear error message (when not running as an IPC client). |
327 | if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { | 277 | if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { |
@@ -344,11 +294,10 @@ int main(int argc, char **argv) { | |||
344 | } | 294 | } |
345 | 295 | ||
346 | sway_log(SWAY_INFO, "Sway version " SWAY_VERSION); | 296 | sway_log(SWAY_INFO, "Sway version " SWAY_VERSION); |
297 | sway_log(SWAY_INFO, "wlroots version " WLR_VERSION_STR); | ||
347 | log_kernel(); | 298 | log_kernel(); |
348 | log_distro(); | 299 | log_distro(); |
349 | log_env(); | 300 | log_env(); |
350 | detect_proprietary(allow_unsupported_gpu); | ||
351 | detect_raspi(); | ||
352 | 301 | ||
353 | if (optind < argc) { // Behave as IPC client | 302 | if (optind < argc) { // Behave as IPC client |
354 | if (optind != 1) { | 303 | if (optind != 1) { |
@@ -361,9 +310,6 @@ int main(int argc, char **argv) { | |||
361 | "`sway -d 2>sway.log`."); | 310 | "`sway -d 2>sway.log`."); |
362 | exit(EXIT_FAILURE); | 311 | exit(EXIT_FAILURE); |
363 | } | 312 | } |
364 | if (!drop_permissions()) { | ||
365 | exit(EXIT_FAILURE); | ||
366 | } | ||
367 | char *socket_path = getenv("SWAYSOCK"); | 313 | char *socket_path = getenv("SWAYSOCK"); |
368 | if (!socket_path) { | 314 | if (!socket_path) { |
369 | sway_log(SWAY_ERROR, "Unable to retrieve socket path"); | 315 | sway_log(SWAY_ERROR, "Unable to retrieve socket path"); |
@@ -375,14 +321,7 @@ int main(int argc, char **argv) { | |||
375 | return 0; | 321 | return 0; |
376 | } | 322 | } |
377 | 323 | ||
378 | if (!server_privileged_prepare(&server)) { | 324 | increase_nofile_limit(); |
379 | return 1; | ||
380 | } | ||
381 | |||
382 | if (!drop_permissions()) { | ||
383 | server_fini(&server); | ||
384 | exit(EXIT_FAILURE); | ||
385 | } | ||
386 | 325 | ||
387 | // handle SIGTERM signals | 326 | // handle SIGTERM signals |
388 | signal(SIGTERM, sig_handler); | 327 | signal(SIGTERM, sig_handler); |
@@ -393,12 +332,14 @@ int main(int argc, char **argv) { | |||
393 | 332 | ||
394 | sway_log(SWAY_INFO, "Starting sway version " SWAY_VERSION); | 333 | sway_log(SWAY_INFO, "Starting sway version " SWAY_VERSION); |
395 | 334 | ||
396 | root = root_create(); | ||
397 | |||
398 | if (!server_init(&server)) { | 335 | if (!server_init(&server)) { |
399 | return 1; | 336 | return 1; |
400 | } | 337 | } |
401 | 338 | ||
339 | if (server.linux_dmabuf_v1) { | ||
340 | wlr_scene_set_linux_dmabuf_v1(root->root_scene, server.linux_dmabuf_v1); | ||
341 | } | ||
342 | |||
402 | if (validate) { | 343 | if (validate) { |
403 | bool valid = load_main_config(config_path, false, true); | 344 | bool valid = load_main_config(config_path, false, true); |
404 | free(config_path); | 345 | free(config_path); |
@@ -413,6 +354,8 @@ int main(int argc, char **argv) { | |||
413 | goto shutdown; | 354 | goto shutdown; |
414 | } | 355 | } |
415 | 356 | ||
357 | set_rr_scheduling(); | ||
358 | |||
416 | if (!server_start(&server)) { | 359 | if (!server_start(&server)) { |
417 | sway_terminate(EXIT_FAILURE); | 360 | sway_terminate(EXIT_FAILURE); |
418 | goto shutdown; | 361 | goto shutdown; |