diff options
Diffstat (limited to 'sway/main.c')
-rw-r--r-- | sway/main.c | 254 |
1 files changed, 93 insertions, 161 deletions
diff --git a/sway/main.c b/sway/main.c index cc9147b8..efb674b6 100644 --- a/sway/main.c +++ b/sway/main.c @@ -1,58 +1,46 @@ #define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 200112L -#include <stdio.h> -#include <stdlib.h> +#include <getopt.h> +#include <signal.h> #include <stdbool.h> -#include <wlc/wlc.h> -#include <sys/wait.h> -#include <sys/types.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> #include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> #include <sys/un.h> -#include <signal.h> #include <unistd.h> -#include <getopt.h> #ifdef __linux__ #include <sys/capability.h> #include <sys/prctl.h> #endif -#include "sway/extensions.h" -#include "sway/layout.h" +#include <wlr/util/log.h> #include "sway/config.h" -#include "sway/security.h" -#include "sway/handlers.h" -#include "sway/input.h" +#include "sway/debug.h" +#include "sway/server.h" +#include "sway/tree/layout.h" #include "sway/ipc-server.h" #include "ipc-client.h" #include "readline.h" #include "stringop.h" -#include "sway.h" -#include "log.h" #include "util.h" static bool terminate_request = false; static int exit_value = 0; +struct sway_server server; void sway_terminate(int exit_code) { terminate_request = true; exit_value = exit_code; - wlc_terminate(); + wl_display_terminate(server.wl_display); } void sig_handler(int signal) { - close_views(&root_container); + //close_views(&root_container); sway_terminate(EXIT_SUCCESS); } -static void wlc_log_handler(enum wlc_log_type type, const char *str) { - if (type == WLC_LOG_ERROR) { - sway_log(L_ERROR, "[wlc] %s", str); - } else if (type == WLC_LOG_WARN) { - sway_log(L_INFO, "[wlc] %s", str); - } else { - sway_log(L_DEBUG, "[wlc] %s", str); - } -} - void detect_raspi() { bool raspi = false; FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); @@ -98,23 +86,16 @@ void detect_proprietary() { if (!f) { return; } - bool nvidia = false, nvidia_modeset = false, nvidia_uvm = false, nvidia_drm = false; while (!feof(f)) { char *line; if (!(line = read_line(f))) { break; } if (strstr(line, "nvidia")) { - nvidia = true; - } - if (strstr(line, "nvidia_modeset")) { - nvidia_modeset = true; - } - if (strstr(line, "nvidia_uvm")) { - nvidia_uvm = true; - } - if (strstr(line, "nvidia_drm")) { - nvidia_drm = true; + fprintf(stderr, "\x1B[1;31mWarning: Proprietary Nvidia drivers are " + "NOT supported. Use Nouveau.\x1B[0m\n"); + free(line); + break; } if (strstr(line, "fglrx")) { fprintf(stderr, "\x1B[1;31mWarning: Proprietary AMD drivers do " @@ -125,52 +106,6 @@ void detect_proprietary() { free(line); } fclose(f); - if (nvidia) { - fprintf(stderr, "\x1B[1;31mWarning: Proprietary nvidia driver support " - "is considered experimental. Nouveau is strongly recommended." - "\x1B[0m\n"); - if (!nvidia_modeset || !nvidia_uvm || !nvidia_drm) { - fprintf(stderr, "\x1B[1;31mWarning: You do not have all of the " - "necessary kernel modules loaded for nvidia support. " - "You need nvidia, nvidia_modeset, nvidia_uvm, and nvidia_drm." - "\x1B[0m\n"); - } -#ifdef __linux__ - f = fopen("/sys/module/nvidia_drm/parameters/modeset", "r"); - if (f) { - char *line = read_line(f); - if (line && strstr(line, "Y")) { - // nvidia-drm.modeset is set to 0 - fprintf(stderr, "\x1B[1;31mWarning: You must load " - "nvidia-drm with the modeset option on to use " - "the proprietary driver. Consider adding " - "nvidia-drm.modeset=1 to your kernel command line " - "parameters.\x1B[0m\n"); - } - fclose(f); - free(line); - } else { - // nvidia-drm.modeset is not set - fprintf(stderr, "\x1B[1;31mWarning: You must load " - "nvidia-drm with the modeset option on to use " - "the proprietary driver. Consider adding " - "nvidia-drm.modeset=1 to your kernel command line " - "parameters.\x1B[0m\n"); - } -#else - f = fopen("/proc/cmdline", "r"); - if (f) { - char *line = read_line(f); - if (line && !strstr(line, "nvidia-drm.modeset=1")) { - fprintf(stderr, "\x1B[1;31mWarning: You must add " - "nvidia-drm.modeset=1 to your kernel command line to use " - "the proprietary driver.\x1B[0m\n"); - } - fclose(f); - free(line); - } -#endif - } } void run_as_ipc_client(char *command, char *socket_path) { @@ -184,27 +119,15 @@ void run_as_ipc_client(char *command, char *socket_path) { static void log_env() { const char *log_vars[] = { "PATH", - "LD_LOAD_PATH", + "LD_LIBRARY_PATH", "LD_PRELOAD_PATH", "LD_LIBRARY_PATH", "SWAY_CURSOR_THEME", "SWAY_CURSOR_SIZE", - "SWAYSOCK", - "WLC_DRM_DEVICE", - "WLC_SHM", - "WLC_OUTPUTS", - "WLC_XWAYLAND", - "WLC_LIBINPUT", - "WLC_REPEAT_DELAY", - "WLC_REPEAT_RATE", - "XKB_DEFAULT_RULES", - "XKB_DEFAULT_MODEL", - "XKB_DEFAULT_LAYOUT", - "XKB_DEFAULT_VARIANT", - "XKB_DEFAULT_OPTIONS", + "SWAYSOCK" }; for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { - sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); + wlr_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); } } @@ -219,14 +142,14 @@ static void log_distro() { for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) { FILE *f = fopen(paths[i], "r"); if (f) { - sway_log(L_INFO, "Contents of %s:", paths[i]); + wlr_log(L_INFO, "Contents of %s:", paths[i]); while (!feof(f)) { char *line; if (!(line = read_line(f))) { break; } if (*line) { - sway_log(L_INFO, "%s", line); + wlr_log(L_INFO, "%s", line); } free(line); } @@ -236,9 +159,10 @@ static void log_distro() { } static void log_kernel() { + return; FILE *f = popen("uname -a", "r"); if (!f) { - sway_log(L_INFO, "Unable to determine kernel version"); + wlr_log(L_INFO, "Unable to determine kernel version"); return; } while (!feof(f)) { @@ -247,7 +171,7 @@ static void log_kernel() { break; } if (*line) { - sway_log(L_INFO, "%s", line); + wlr_log(L_INFO, "%s", line); } free(line); } @@ -258,14 +182,14 @@ static void security_sanity_check() { // TODO: Notify users visually if this has issues struct stat s; if (stat("/proc", &s)) { - sway_log(L_ERROR, + wlr_log(L_ERROR, "!! DANGER !! /proc is not available - sway CANNOT enforce security rules!"); } #ifdef __linux__ cap_flag_value_t v; cap_t cap = cap_get_proc(); if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) { - sway_log(L_ERROR, + wlr_log(L_ERROR, "!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users."); } if (cap) { @@ -281,13 +205,13 @@ static void executable_sanity_check() { stat(exe, &sb); // We assume that cap_get_file returning NULL implies ENODATA if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) { - sway_log(L_ERROR, + wlr_log(L_ERROR, "sway executable has both the s(g)uid bit AND file caps set."); - sway_log(L_ERROR, + wlr_log(L_ERROR, "This is strongly discouraged (and completely broken)."); - sway_log(L_ERROR, + wlr_log(L_ERROR, "Please clear one of them (either the suid bit, or the file caps)."); - sway_log(L_ERROR, + wlr_log(L_ERROR, "If unsure, strip the file caps."); exit(EXIT_FAILURE); } @@ -295,6 +219,37 @@ static void executable_sanity_check() { #endif } +static void drop_permissions(bool keep_caps) { + if (getuid() != geteuid() || getgid() != getegid()) { + if (setgid(getgid()) != 0) { + wlr_log(L_ERROR, "Unable to drop root"); + exit(EXIT_FAILURE); + } + if (setuid(getuid()) != 0) { + wlr_log(L_ERROR, "Unable to drop root"); + exit(EXIT_FAILURE); + } + } + if (setuid(0) != -1) { + wlr_log(L_ERROR, "Root privileges can be restored."); + exit(EXIT_FAILURE); + } +#ifdef __linux__ + if (keep_caps) { + // Drop every cap except CAP_SYS_PTRACE + cap_t caps = cap_init(); + cap_value_t keep = CAP_SYS_PTRACE; + wlr_log(L_INFO, "Dropping extra capabilities"); + if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || + cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || + cap_set_proc(caps)) { + wlr_log(L_ERROR, "Failed to drop extra capabilities"); + exit(EXIT_FAILURE); + } + } +#endif +} + int main(int argc, char **argv) { static int verbose = 0, debug = 0, validate = 0; @@ -334,7 +289,7 @@ int main(int argc, char **argv) { int c; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "hCdvVc:", long_options, &option_index); + c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index); if (c == -1) { break; } @@ -352,6 +307,9 @@ int main(int argc, char **argv) { case 'd': // debug debug = 1; break; + case 'D': // extended debug options + enable_debug_tree = true; + break; case 'v': // version fprintf(stdout, "sway version " SWAY_VERSION "\n"); exit(EXIT_SUCCESS); @@ -374,37 +332,24 @@ int main(int argc, char **argv) { } } - // we need to setup logging before wlc_init in case it fails. + // TODO: switch logging over to wlroots? if (debug) { - init_log(L_DEBUG); + wlr_log_init(L_DEBUG, NULL); } else if (verbose || validate) { - init_log(L_INFO); + wlr_log_init(L_INFO, NULL); } else { - init_log(L_ERROR); + wlr_log_init(L_ERROR, NULL); } if (optind < argc) { // Behave as IPC client if(optind != 1) { - sway_log(L_ERROR, "Don't use options with the IPC client"); - exit(EXIT_FAILURE); - } - if (getuid() != geteuid() || getgid() != getegid()) { - if (setgid(getgid()) != 0) { - sway_log(L_ERROR, "Unable to drop root"); - exit(EXIT_FAILURE); - } - if (setuid(getuid()) != 0) { - sway_log(L_ERROR, "Unable to drop root"); - exit(EXIT_FAILURE); - } - } - if (setuid(0) != -1) { - sway_log(L_ERROR, "Root privileges can be restored."); + wlr_log(L_ERROR, "Don't use options with the IPC client"); exit(EXIT_FAILURE); } + drop_permissions(false); char *socket_path = getenv("SWAYSOCK"); if (!socket_path) { - sway_log(L_ERROR, "Unable to retrieve socket path"); + wlr_log(L_ERROR, "Unable to retrieve socket path"); exit(EXIT_FAILURE); } char *command = join_args(argv + optind, argc - optind); @@ -413,49 +358,25 @@ int main(int argc, char **argv) { } executable_sanity_check(); -#ifdef __linux__ bool suid = false; +#ifdef __linux__ if (getuid() != geteuid() || getgid() != getegid()) { // Retain capabilities after setuid() if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { - sway_log(L_ERROR, "Cannot keep caps after setuid()"); + wlr_log(L_ERROR, "Cannot keep caps after setuid()"); exit(EXIT_FAILURE); } suid = true; } #endif - wlc_log_set_handler(wlc_log_handler); log_kernel(); log_distro(); - log_env(); detect_proprietary(); detect_raspi(); - input_devices = create_list(); - - /* Changing code earlier than this point requires detailed review */ - /* (That code runs as root on systems without logind, and wlc_init drops to - * another user.) */ - register_wlc_handlers(); - if (!wlc_init()) { - return 1; - } - register_extensions(); - #ifdef __linux__ - if (suid) { - // Drop every cap except CAP_SYS_PTRACE - cap_t caps = cap_init(); - cap_value_t keep = CAP_SYS_PTRACE; - sway_log(L_INFO, "Dropping extra capabilities"); - if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || - cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || - cap_set_proc(caps)) { - sway_log(L_ERROR, "Failed to drop extra capabilities"); - exit(EXIT_FAILURE); - } - } + drop_permissions(suid); #endif // handle SIGTERM signals signal(SIGTERM, sig_handler); @@ -463,11 +384,16 @@ int main(int argc, char **argv) { // prevent ipc from crashing sway signal(SIGPIPE, SIG_IGN); - sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n"); + wlr_log(L_INFO, "Starting sway version " SWAY_VERSION); + + layout_init(); - init_layout(); + if (!server_init(&server)) { + return 1; + } - ipc_init(); + ipc_init(&server); + log_env(); if (validate) { bool valid = load_main_config(config_path, false); @@ -484,11 +410,17 @@ int main(int argc, char **argv) { security_sanity_check(); + // TODO: wait for server to be ready + // TODO: consume config->cmd_queue + config->active = true; + if (!terminate_request) { - wlc_run(); + server_run(&server); } - list_free(input_devices); + wlr_log(L_INFO, "Shutting down sway"); + + server_fini(&server); ipc_terminate(); |