aboutsummaryrefslogtreecommitdiffstats
path: root/sway/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/main.c')
-rw-r--r--sway/main.c83
1 files changed, 53 insertions, 30 deletions
diff --git a/sway/main.c b/sway/main.c
index a325dc3a..a20f1dac 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -1,6 +1,7 @@
1#define _XOPEN_SOURCE 700 1#define _XOPEN_SOURCE 700
2#define _POSIX_C_SOURCE 200112L 2#define _POSIX_C_SOURCE 200112L
3#include <getopt.h> 3#include <getopt.h>
4#include <pango/pangocairo.h>
4#include <signal.h> 5#include <signal.h>
5#include <stdbool.h> 6#include <stdbool.h>
6#include <stdlib.h> 7#include <stdlib.h>
@@ -19,6 +20,7 @@
19#include "sway/commands.h" 20#include "sway/commands.h"
20#include "sway/config.h" 21#include "sway/config.h"
21#include "sway/debug.h" 22#include "sway/debug.h"
23#include "sway/desktop/transaction.h"
22#include "sway/server.h" 24#include "sway/server.h"
23#include "sway/tree/layout.h" 25#include "sway/tree/layout.h"
24#include "sway/ipc-server.h" 26#include "sway/ipc-server.h"
@@ -128,7 +130,7 @@ static void log_env() {
128 "SWAYSOCK" 130 "SWAYSOCK"
129 }; 131 };
130 for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { 132 for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
131 wlr_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); 133 wlr_log(WLR_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
132 } 134 }
133} 135}
134 136
@@ -143,14 +145,14 @@ static void log_distro() {
143 for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) { 145 for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) {
144 FILE *f = fopen(paths[i], "r"); 146 FILE *f = fopen(paths[i], "r");
145 if (f) { 147 if (f) {
146 wlr_log(L_INFO, "Contents of %s:", paths[i]); 148 wlr_log(WLR_INFO, "Contents of %s:", paths[i]);
147 while (!feof(f)) { 149 while (!feof(f)) {
148 char *line; 150 char *line;
149 if (!(line = read_line(f))) { 151 if (!(line = read_line(f))) {
150 break; 152 break;
151 } 153 }
152 if (*line) { 154 if (*line) {
153 wlr_log(L_INFO, "%s", line); 155 wlr_log(WLR_INFO, "%s", line);
154 } 156 }
155 free(line); 157 free(line);
156 } 158 }
@@ -162,7 +164,7 @@ static void log_distro() {
162static void log_kernel() { 164static void log_kernel() {
163 FILE *f = popen("uname -a", "r"); 165 FILE *f = popen("uname -a", "r");
164 if (!f) { 166 if (!f) {
165 wlr_log(L_INFO, "Unable to determine kernel version"); 167 wlr_log(WLR_INFO, "Unable to determine kernel version");
166 return; 168 return;
167 } 169 }
168 while (!feof(f)) { 170 while (!feof(f)) {
@@ -171,25 +173,25 @@ static void log_kernel() {
171 break; 173 break;
172 } 174 }
173 if (*line) { 175 if (*line) {
174 wlr_log(L_INFO, "%s", line); 176 wlr_log(WLR_INFO, "%s", line);
175 } 177 }
176 free(line); 178 free(line);
177 } 179 }
178 fclose(f); 180 pclose(f);
179} 181}
180 182
181static void security_sanity_check() { 183static void security_sanity_check() {
182 // TODO: Notify users visually if this has issues 184 // TODO: Notify users visually if this has issues
183 struct stat s; 185 struct stat s;
184 if (stat("/proc", &s)) { 186 if (stat("/proc", &s)) {
185 wlr_log(L_ERROR, 187 wlr_log(WLR_ERROR,
186 "!! DANGER !! /proc is not available - sway CANNOT enforce security rules!"); 188 "!! DANGER !! /proc is not available - sway CANNOT enforce security rules!");
187 } 189 }
188#ifdef __linux__ 190#ifdef __linux__
189 cap_flag_value_t v; 191 cap_flag_value_t v;
190 cap_t cap = cap_get_proc(); 192 cap_t cap = cap_get_proc();
191 if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) { 193 if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) {
192 wlr_log(L_ERROR, 194 wlr_log(WLR_ERROR,
193 "!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users."); 195 "!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users.");
194 } 196 }
195 if (cap) { 197 if (cap) {
@@ -205,13 +207,13 @@ static void executable_sanity_check() {
205 stat(exe, &sb); 207 stat(exe, &sb);
206 // We assume that cap_get_file returning NULL implies ENODATA 208 // We assume that cap_get_file returning NULL implies ENODATA
207 if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) { 209 if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) {
208 wlr_log(L_ERROR, 210 wlr_log(WLR_ERROR,
209 "sway executable has both the s(g)uid bit AND file caps set."); 211 "sway executable has both the s(g)uid bit AND file caps set.");
210 wlr_log(L_ERROR, 212 wlr_log(WLR_ERROR,
211 "This is strongly discouraged (and completely broken)."); 213 "This is strongly discouraged (and completely broken).");
212 wlr_log(L_ERROR, 214 wlr_log(WLR_ERROR,
213 "Please clear one of them (either the suid bit, or the file caps)."); 215 "Please clear one of them (either the suid bit, or the file caps).");
214 wlr_log(L_ERROR, 216 wlr_log(WLR_ERROR,
215 "If unsure, strip the file caps."); 217 "If unsure, strip the file caps.");
216 exit(EXIT_FAILURE); 218 exit(EXIT_FAILURE);
217 } 219 }
@@ -222,16 +224,16 @@ static void executable_sanity_check() {
222static void drop_permissions(bool keep_caps) { 224static void drop_permissions(bool keep_caps) {
223 if (getuid() != geteuid() || getgid() != getegid()) { 225 if (getuid() != geteuid() || getgid() != getegid()) {
224 if (setgid(getgid()) != 0) { 226 if (setgid(getgid()) != 0) {
225 wlr_log(L_ERROR, "Unable to drop root"); 227 wlr_log(WLR_ERROR, "Unable to drop root");
226 exit(EXIT_FAILURE); 228 exit(EXIT_FAILURE);
227 } 229 }
228 if (setuid(getuid()) != 0) { 230 if (setuid(getuid()) != 0) {
229 wlr_log(L_ERROR, "Unable to drop root"); 231 wlr_log(WLR_ERROR, "Unable to drop root");
230 exit(EXIT_FAILURE); 232 exit(EXIT_FAILURE);
231 } 233 }
232 } 234 }
233 if (setuid(0) != -1) { 235 if (setuid(0) != -1) {
234 wlr_log(L_ERROR, "Root privileges can be restored."); 236 wlr_log(WLR_ERROR, "Root privileges can be restored.");
235 exit(EXIT_FAILURE); 237 exit(EXIT_FAILURE);
236 } 238 }
237#ifdef __linux__ 239#ifdef __linux__
@@ -239,17 +241,29 @@ static void drop_permissions(bool keep_caps) {
239 // Drop every cap except CAP_SYS_PTRACE 241 // Drop every cap except CAP_SYS_PTRACE
240 cap_t caps = cap_init(); 242 cap_t caps = cap_init();
241 cap_value_t keep = CAP_SYS_PTRACE; 243 cap_value_t keep = CAP_SYS_PTRACE;
242 wlr_log(L_INFO, "Dropping extra capabilities"); 244 wlr_log(WLR_INFO, "Dropping extra capabilities");
243 if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || 245 if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
244 cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || 246 cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
245 cap_set_proc(caps)) { 247 cap_set_proc(caps)) {
246 wlr_log(L_ERROR, "Failed to drop extra capabilities"); 248 wlr_log(WLR_ERROR, "Failed to drop extra capabilities");
247 exit(EXIT_FAILURE); 249 exit(EXIT_FAILURE);
248 } 250 }
249 } 251 }
250#endif 252#endif
251} 253}
252 254
255void enable_debug_flag(const char *flag) {
256 if (strcmp(flag, "render-tree") == 0) {
257 enable_debug_tree = true;
258 } else if (strncmp(flag, "damage=", 7) == 0) {
259 damage_debug = &flag[7];
260 } else if (strcmp(flag, "txn-debug") == 0) {
261 txn_debug = true;
262 } else if (strncmp(flag, "txn-timeout=", 12) == 0) {
263 txn_timeout_ms = atoi(&flag[12]);
264 }
265}
266
253int main(int argc, char **argv) { 267int main(int argc, char **argv) {
254 static int verbose = 0, debug = 0, validate = 0; 268 static int verbose = 0, debug = 0, validate = 0;
255 269
@@ -289,7 +303,7 @@ int main(int argc, char **argv) {
289 int c; 303 int c;
290 while (1) { 304 while (1) {
291 int option_index = 0; 305 int option_index = 0;
292 c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index); 306 c = getopt_long(argc, argv, "hCdD:vVc:", long_options, &option_index);
293 if (c == -1) { 307 if (c == -1) {
294 break; 308 break;
295 } 309 }
@@ -308,7 +322,7 @@ int main(int argc, char **argv) {
308 debug = 1; 322 debug = 1;
309 break; 323 break;
310 case 'D': // extended debug options 324 case 'D': // extended debug options
311 enable_debug_tree = true; 325 enable_debug_flag(optarg);
312 break; 326 break;
313 case 'v': // version 327 case 'v': // version
314 fprintf(stdout, "sway version " SWAY_VERSION "\n"); 328 fprintf(stdout, "sway version " SWAY_VERSION "\n");
@@ -334,22 +348,22 @@ int main(int argc, char **argv) {
334 348
335 // TODO: switch logging over to wlroots? 349 // TODO: switch logging over to wlroots?
336 if (debug) { 350 if (debug) {
337 wlr_log_init(L_DEBUG, NULL); 351 wlr_log_init(WLR_DEBUG, NULL);
338 } else if (verbose || validate) { 352 } else if (verbose || validate) {
339 wlr_log_init(L_INFO, NULL); 353 wlr_log_init(WLR_INFO, NULL);
340 } else { 354 } else {
341 wlr_log_init(L_ERROR, NULL); 355 wlr_log_init(WLR_ERROR, NULL);
342 } 356 }
343 357
344 if (optind < argc) { // Behave as IPC client 358 if (optind < argc) { // Behave as IPC client
345 if(optind != 1) { 359 if(optind != 1) {
346 wlr_log(L_ERROR, "Don't use options with the IPC client"); 360 wlr_log(WLR_ERROR, "Don't use options with the IPC client");
347 exit(EXIT_FAILURE); 361 exit(EXIT_FAILURE);
348 } 362 }
349 drop_permissions(false); 363 drop_permissions(false);
350 char *socket_path = getenv("SWAYSOCK"); 364 char *socket_path = getenv("SWAYSOCK");
351 if (!socket_path) { 365 if (!socket_path) {
352 wlr_log(L_ERROR, "Unable to retrieve socket path"); 366 wlr_log(WLR_ERROR, "Unable to retrieve socket path");
353 exit(EXIT_FAILURE); 367 exit(EXIT_FAILURE);
354 } 368 }
355 char *command = join_args(argv + optind, argc - optind); 369 char *command = join_args(argv + optind, argc - optind);
@@ -368,7 +382,7 @@ int main(int argc, char **argv) {
368 if (getuid() != geteuid() || getgid() != getegid()) { 382 if (getuid() != geteuid() || getgid() != getegid()) {
369 // Retain capabilities after setuid() 383 // Retain capabilities after setuid()
370 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { 384 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
371 wlr_log(L_ERROR, "Cannot keep caps after setuid()"); 385 wlr_log(WLR_ERROR, "Cannot keep caps after setuid()");
372 exit(EXIT_FAILURE); 386 exit(EXIT_FAILURE);
373 } 387 }
374 suid = true; 388 suid = true;
@@ -389,7 +403,7 @@ int main(int argc, char **argv) {
389 // prevent ipc from crashing sway 403 // prevent ipc from crashing sway
390 signal(SIGPIPE, SIG_IGN); 404 signal(SIGPIPE, SIG_IGN);
391 405
392 wlr_log(L_INFO, "Starting sway version " SWAY_VERSION); 406 wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION);
393 407
394 layout_init(); 408 layout_init();
395 409
@@ -415,32 +429,41 @@ int main(int argc, char **argv) {
415 429
416 security_sanity_check(); 430 security_sanity_check();
417 431
432 setenv("WAYLAND_DISPLAY", server.socket, true);
433 if (!terminate_request) {
434 if (!server_start_backend(&server)) {
435 sway_terminate(EXIT_FAILURE);
436 }
437 }
438
418 config->active = true; 439 config->active = true;
419 // Execute commands until there are none left 440 // Execute commands until there are none left
441 wlr_log(WLR_DEBUG, "Running deferred commands");
420 while (config->cmd_queue->length) { 442 while (config->cmd_queue->length) {
421 char *line = config->cmd_queue->items[0]; 443 char *line = config->cmd_queue->items[0];
422 struct cmd_results *res = execute_command(line, NULL); 444 struct cmd_results *res = execute_command(line, NULL);
423 if (res->status != CMD_SUCCESS) { 445 if (res->status != CMD_SUCCESS) {
424 wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error); 446 wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
425 } 447 }
426 free_cmd_results(res); 448 free_cmd_results(res);
427 free(line); 449 free(line);
428 list_del(config->cmd_queue, 0); 450 list_del(config->cmd_queue, 0);
429 } 451 }
452 transaction_commit_dirty();
430 453
431 if (!terminate_request) { 454 if (!terminate_request) {
432 server_run(&server); 455 server_run(&server);
433 } 456 }
434 457
435 wlr_log(L_INFO, "Shutting down sway"); 458 wlr_log(WLR_INFO, "Shutting down sway");
436 459
437 server_fini(&server); 460 server_fini(&server);
438 461
439 ipc_terminate();
440
441 if (config) { 462 if (config) {
442 free_config(config); 463 free_config(config);
443 } 464 }
444 465
466 pango_cairo_font_map_set_default(NULL);
467
445 return exit_value; 468 return exit_value;
446} 469}