Untitled
unknown
plain_text
10 months ago
15 kB
4
Indexable
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <getopt.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayfire/debug.hpp>
#include "main.hpp"
#include <wayland-server.h>
#include "wayfire/config-backend.hpp"
#include "core/plugin-loader.hpp"
#include "core/core-impl.hpp"
#include <wlr/render/gbm.h>
#include <wlr/render/renderer.h>
static void print_version()
{
std::cout << WAYFIRE_VERSION << "-" << wf::version::git_commit <<
" (" __DATE__ ") branch " << wf::version::git_branch <<
" wlroots-" << WLR_VERSION_STR << std::endl;
exit(0);
}
static void print_help()
{
std::cout << "Wayfire " << WAYFIRE_VERSION << std::endl;
std::cout << "Usage: wayfire [OPTION]...\n" << std::endl;
std::cout << " -c, --config specify config file to use " <<
"(overrides WAYFIRE_CONFIG_FILE from the environment)" << std::endl;
std::cout << " -B, --config-backend specify config backend to use" <<
std::endl;
std::cout << " -h, --help print this help" << std::endl;
std::cout << " -d, --debug enable debug logging" << std::endl;
std::cout <<
" -D, --damage-debug enable additional debug for damaged regions" <<
std::endl;
std::cout << " -R, --damage-rerender rerender damaged regions" << std::endl;
std::cout << " -l, --legacy-wl-drm use legacy drm for wayland clients" << std::endl;
std::cout << " -v, --version print version and exit" << std::endl;
exit(0);
}
static bool drop_permissions(void)
{
if ((getuid() != geteuid()) || (getgid() != getegid()))
{
// Set the gid and uid in the correct order.
if ((setgid(getgid()) != 0) || (setuid(getuid()) != 0))
{
LOGE("Unable to drop root, refusing to start");
return false;
}
}
if ((setgid(0) != -1) || (setuid(0) != -1))
{
LOGE("Unable to drop root (we shouldn't be able to "
"restore it after setuid), refusing to start");
return false;
}
return true;
}
static wf::log::color_mode_t detect_color_mode()
{
return isatty(STDOUT_FILENO) ?
wf::log::LOG_COLOR_MODE_ON : wf::log::LOG_COLOR_MODE_OFF;
}
static void wlr_log_handler(wlr_log_importance level,
const char *fmt, va_list args)
{
const int bufsize = 4 * 1024;
char buffer[bufsize];
vsnprintf(buffer, bufsize, fmt, args);
wf::log::log_level_t wlevel;
switch (level)
{
case WLR_ERROR:
wlevel = wf::log::LOG_LEVEL_ERROR;
break;
case WLR_INFO:
wlevel = wf::log::LOG_LEVEL_INFO;
break;
case WLR_DEBUG:
wlevel = wf::log::LOG_LEVEL_DEBUG;
break;
default:
return;
}
bool enabled =
wf::log::enabled_categories.test((int)wf::log::logging_category::WLR);
if ((wlevel == wf::log::LOG_LEVEL_DEBUG) && !enabled)
{
return;
}
wf::log::log_plain(wlevel, buffer);
}
static std::optional<int> exit_because_signal;
static void signal_handler(int signal)
{
std::string error;
switch (signal)
{
case SIGSEGV:
error = "Segmentation fault";
break;
case SIGFPE:
error = "Floating-point exception";
break;
case SIGABRT:
error = "Fatal error(SIGABRT)";
break;
case SIGINT:
exit_because_signal = SIGINT;
wf::get_core().shutdown();
return;
case SIGTERM:
exit_because_signal = SIGTERM;
wf::get_core().shutdown();
return;
default:
error = "Unknown";
}
LOGE("Fatal error: ", error);
wf::print_trace(false);
std::_Exit(-1);
}
static std::optional<std::string> choose_socket(wl_display *display)
{
for (int i = 1; i <= 32; i++)
{
auto name = "wayland-" + std::to_string(i);
if (wl_display_add_socket(display, name.c_str()) >= 0)
{
return name;
}
}
return {};
}
static wf::config_backend_t *load_backend(const std::string& backend)
{
std::string config_plugin(backend);
if (backend.size())
{
std::vector<std::string> plugin_prefixes = wf::get_plugin_paths();
config_plugin =
wf::get_plugin_path_for_name(plugin_prefixes, backend).value_or("");
}
auto [_, init_ptr] = wf::get_new_instance_handle(config_plugin);
if (!init_ptr)
{
return nullptr;
}
using backend_init_t = wf::config_backend_t * (*)();
auto init = wf::union_cast<void*, backend_init_t>(init_ptr);
return init();
}
void parse_extended_debugging(const std::vector<std::string>& categories)
{
for (const auto& cat : categories)
{
if (cat == "txn")
{
LOGD("Enabling extended debugging for transactions");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::TXN, 1);
} else if (cat == "txni")
{
LOGD("Enabling extended debugging for transaction objects");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::TXNI, 1);
} else if (cat == "views")
{
LOGD("Enabling extended debugging for views");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::VIEWS, 1);
} else if (cat == "wlroots")
{
LOGD("Enabling extended debugging for wlroots");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::WLR, 1);
} else if (cat == "scanout")
{
LOGD("Enabling extended debugging for direct scanout");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::SCANOUT, 1);
} else if (cat == "pointer")
{
LOGD("Enabling extended debugging for pointer events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::POINTER, 1);
} else if (cat == "wset")
{
LOGD("Enabling extended debugging for workspace set events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::WSET, 1);
} else if (cat == "kbd")
{
LOGD("Enabling extended debugging for keyboard events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::KBD, 1);
} else if (cat == "xwayland")
{
LOGD("Enabling extended debugging for xwayland events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::XWL, 1);
} else if (cat == "layer-shell")
{
LOGD("Enabling extended debugging for layer-shell events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::LSHELL, 1);
} else if (cat == "im")
{
LOGD("Enabling extended debugging for input method events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::IM, 1);
} else if (cat == "render")
{
LOGD("Enabling extended debugging for render events");
wf::log::enabled_categories.set((size_t)wf::log::logging_category::RENDER, 1);
} else
{
LOGE("Unrecognized debugging category \"", cat, "\"");
}
}
}
// Override assert() handler to be more useful and print a trace.
// extern "C" {
// void __assert_fail(const char* expr, const char *filename, unsigned int line, const char *assert_func)
// {
// LOGE("Assertion failed: ", expr, " at ", filename, ":", line, " in ", assert_func);
// wf::print_trace(false);
// std::_Exit(-1);
// }
// }
// Override exception handling to be more useful and print a trace.
// extern "C" {
// void __cxa_throw(void *ex, void *info, void (*dest)(void*))
// {
// wf::print_trace(false);
// std::_Exit(-1);
// }
// }
//
int main(int argc, char *argv[])
{
wf::log::log_level_t log_level = wf::log::LOG_LEVEL_INFO;
struct option opts[] = {
{
"config", required_argument, NULL, 'c'
},
{
"config-backend", required_argument, NULL, 'B'
},
{"debug", optional_argument, NULL, 'd'},
{"damage-debug", no_argument, NULL, 'D'},
{"damage-rerender", no_argument, NULL, 'R'},
{"legacy-wl-drm", no_argument, NULL, 'l'},
{"with-great-power-comes-great-responsibility", no_argument, NULL, 'r'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{0, 0, NULL, 0}
};
std::string config_file;
std::string config_backend = WF_DEFAULT_CONFIG_BACKEND;
std::vector<std::string> extended_debug_categories;
bool allow_root = false;
int c, i;
while ((c = getopt_long(argc, argv, "c:B:d::DhRlrv", opts, &i)) != -1)
{
switch (c)
{
case 'c':
config_file = optarg;
break;
case 'B':
config_backend = optarg;
break;
case 'D':
runtime_config.damage_debug = true;
break;
case 'R':
runtime_config.no_damage_track = true;
break;
case 'l':
runtime_config.legacy_wl_drm = true;
break;
case 'r':
allow_root = true;
break;
case 'h':
print_help();
break;
case 'd':
log_level = wf::log::LOG_LEVEL_DEBUG;
// Make sure to parse things like `-d txn`, which getopt does not.
// According to documentation, for optional arguments, optarg will
// be NULL so we need to manually check.
if (!optarg && (NULL != argv[optind]) &&
('-' != argv[optind][0]))
{
optarg = argv[optind];
++optind;
}
if (optarg)
{
extended_debug_categories.push_back(optarg);
}
break;
case 'v':
print_version();
break;
default:
std::cerr << "Unrecognized command line argument " << optarg << "\n" <<
std::endl;
}
}
/* Don't crash on SIGPIPE, e.g., when doing IPC to a client whose fd has been closed. */
signal(SIGPIPE, SIG_IGN);
wf::log::initialize_logging(std::cout, log_level, detect_color_mode());
parse_extended_debugging(extended_debug_categories);
wlr_log_init(WLR_DEBUG, wlr_log_handler);
#ifdef PRINT_TRACE
/* In case of crash, print the stacktrace for debugging.
* However, if ASAN is enabled, we'll get better stacktrace from there. */
signal(SIGSEGV, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGABRT, signal_handler);
#endif
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
std::set_terminate([] ()
{
std::cout << "Unhandled exception" << std::endl;
wf::print_trace(false);
std::abort();
});
LOGI("Starting wayfire version ", WAYFIRE_VERSION);
/* First create display and initialize safe-list's event loop, so that
* wf objects (which depend on safe-list) can work */
auto display = wl_display_create();
auto& core = wf::compositor_core_impl_t::allocate_core();
core.argc = argc;
core.argv = argv;
/** TODO: move this to core_impl constructor */
core.display = display;
core.ev_loop = wl_display_get_event_loop(core.display);
core.backend = wlr_backend_autocreate(core.ev_loop, &core.session);
if (getenv("WLR_RDP"))
{
wayfire_rdp_init(&core);
}
int drm_fd = -1;
char *drm_device = getenv("WLR_RENDER_DRM_DEVICE");
if (drm_device)
{
drm_fd = open(drm_device, O_RDWR | O_CLOEXEC);
} else
{
drm_fd = wlr_backend_get_drm_fd(core.backend);
}
/*
if (drm_fd < 0)
{
LOGW("Failed to open DRM render device, consider specifying WLR_RENDER_DRM_DEVICE."
"Trying SW rendering instead.");
}
core.renderer = wlr_gles2_renderer_create_with_drm_fd(drm_fd);
if (!core.renderer)
{
LOGE("Failed to create renderer");
wl_display_destroy_clients(core.display);
wl_display_destroy(core.display);
return EXIT_FAILURE;
}
*/
// In main.cpp
core.renderer = nullptr;
// Try multiple renderer creation methods
if (drm_fd >= 0) {
core.renderer = wlr_gles2_renderer_create_with_drm_fd(drm_fd);
}
// Fallback methods
if (!core.renderer) {
core.renderer = wlr_renderer_autocreate(core.backend);
}
// If still no renderer, try manual GBM renderer creation
if (!core.renderer) {
struct gbm_device *gbm_dev = gbm_create_device(drm_fd);
if (gbm_dev) {
core.renderer = wlr_renderer_create_with_gbm_device(core.backend, gbm_dev);
}
}
if (!core.renderer)
{
LOGE("Failed to create renderer");
wl_display_destroy_clients(core.display);
wl_display_destroy(core.display);
return EXIT_FAILURE;
}
core.allocator = wlr_allocator_autocreate(core.backend, core.renderer);
assert(core.allocator);
core.egl = wlr_gles2_renderer_get_egl(core.renderer);
assert(core.egl);
if (!allow_root && !drop_permissions())
{
wl_display_destroy_clients(core.display);
wl_display_destroy(core.display);
return EXIT_FAILURE;
}
auto backend = load_backend(config_backend);
if (!backend)
{
LOGE("Failed to load configuration backend!");
wl_display_destroy_clients(core.display);
wl_display_destroy(core.display);
return EXIT_FAILURE;
}
LOGD("Using configuration backend: ", config_backend);
core.config_backend = std::unique_ptr<wf::config_backend_t>(backend);
core.config_backend->init(display, core.config, config_file);
core.init();
auto socket = choose_socket(core.display);
if (!socket)
{
LOGE("Failed to create wayland socket, exiting.");
return -1;
}
core.wayland_display = socket.value();
LOGI("Using socket name ", core.wayland_display);
if (!wlr_backend_start(core.backend))
{
LOGE("Failed to initialize backend, exiting");
wlr_backend_destroy(core.backend);
wl_display_destroy(core.display);
return -1;
}
setenv("WAYLAND_DISPLAY", core.wayland_display.c_str(), 1);
core.post_init();
wl_display_run(core.display);
if (exit_because_signal == SIGINT)
{
LOGI("Got SIGINT, shutting down");
} else if (exit_because_signal == SIGTERM)
{
LOGI("Got SIGTERM, shutting down");
}
wf::compositor_core_impl_t::deallocate_core();
LOGI("Shutdown successful!");
return EXIT_SUCCESS;
}
Editor is loading...
Leave a Comment