Example #1
0
File: wlc.c Project: UIKit0/wlc
WLC_API bool
wlc_init(const struct wlc_interface *interface, int argc, char *argv[])
{
   assert(interface);

   if (!interface)
      die("no wlc_interface was given");

   if (wlc.display)
      return true;

   memset(&wlc, 0, sizeof(wlc));

   wl_log_set_handler_server(wl_cb_log);

   for (int i = 1; i < argc; ++i) {
      if (chck_cstreq(argv[i], "--log")) {
         if (i + 1 >= argc)
            die("--log takes an argument (filename)");
         wlc_set_log_file(fopen(argv[++i], "a"));
      }
   }

   unsetenv("TERM");
   const char *x11display = getenv("DISPLAY");
   bool privilidged = false;
   const bool has_logind  = wlc_logind_available();

   if (getuid() != geteuid() || getgid() != getegid()) {
      wlc_log(WLC_LOG_INFO, "Doing work on SUID/SGID side and dropping permissions");
      privilidged = true;
   } else if (getuid() == 0) {
      die("Do not run wlc compositor as root");
   } else if (!x11display && !has_logind && access("/dev/input/event0", R_OK | W_OK) != 0) {
      die("Not running from X11 and no access to /dev/input/event0 or logind available");
   }

#ifndef NDEBUG
   {
      struct sigaction action = {
         .sa_handler = backtrace
      };
      sigaction(SIGABRT, &action, NULL);
      sigaction(SIGSEGV, &action, NULL);

      // XXX: Some weird sigfpes seems to come when running
      // wlc compositor inside wlc compositor (X11 backend).
      // Seems to be caused by resolution changes and mouse clicks.
      // Gather more information about this later and see what's going on.
      if (!getenv("WAYLAND_DISPLAY"))
         fpesetup(&action);
   }
#endif

   int vt = 0;

#ifdef HAS_LOGIND
   // Init logind if we are not running as SUID.
   // We need event loop for logind to work, and thus we won't allow it on SUID process.
   if (!privilidged && !x11display && has_logind) {
      if (!(wlc.display = wl_display_create()))
         die("Failed to create wayland display");
      if (!(vt = wlc_logind_init("seat0")))
         die("Failed to init logind");
   }
#else
   (void)privilidged;
#endif

   if (!x11display)
      wlc_tty_init(vt);

   // -- we open tty before dropping permissions
   //    so the fd process can also handle cleanup in case of crash
   //    if logind initialized correctly, fd process does nothing but handle crash.

   {
      struct wl_display *display = wlc.display;
      wlc.display = NULL;
      wlc_fd_init(argc, argv, (vt != 0));
      wlc.display = display;
   }


   // -- permissions are now dropped

   wl_signal_init(&wlc.signals.terminate);
   wl_signal_init(&wlc.signals.activate);
   wl_signal_init(&wlc.signals.compositor);
   wl_signal_init(&wlc.signals.focus);
   wl_signal_init(&wlc.signals.surface);
   wl_signal_init(&wlc.signals.input);
   wl_signal_init(&wlc.signals.output);
   wl_signal_init(&wlc.signals.render);
   wl_signal_init(&wlc.signals.xwayland);
   wl_signal_add(&wlc.signals.compositor, &compositor_listener);

   if (!wlc_resources_init())
      die("Failed to init resource manager");

   if (!wlc.display && !(wlc.display = wl_display_create()))
      die("Failed to create wayland display");

   const char *socket_name;
   if (!(socket_name = wl_display_add_socket_auto(wlc.display)))
      die("Failed to add socket to wayland display");

   if (socket_name) // shut up static analyze
      setenv("WAYLAND_DISPLAY", socket_name, true);

   if (wl_display_init_shm(wlc.display) != 0)
      die("Failed to init shm");

   if (!wlc_udev_init())
      die("Failed to init udev");

   const char *libinput = getenv("WLC_LIBINPUT");
   if (!x11display || (libinput && !chck_cstreq(libinput, "0"))) {
      if (!wlc_input_init())
         die("Failed to init input");
   }

   memcpy(&wlc.interface, interface, sizeof(wlc.interface));

   if (!wlc_compositor(&wlc.compositor))
      die("Failed to init compositor");

   const char *xwayland = getenv("WLC_XWAYLAND");
   if (!xwayland || !chck_cstreq(xwayland, "0")) {
      if (!(wlc_xwayland_init()))
         die("Failed to init xwayland");
   } else {
      wlc.set_ready_on_run = true;
   }

   wlc_set_active(true);
   return wlc_compositor_is_good(&wlc.compositor);
}
Example #2
0
int
main(void)
{
   // TEST: Basic source and handle creation
   {
      assert(wlc_resources_init());

      struct wlc_source source;
      assert(wlc_source(&source, "test", constructor, destructor, 1, sizeof(struct wlc_resource)));

      struct wlc_resource *ptr;
      assert(!constructor_called);
      assert((ptr = wlc_handle_create(&source)));
      assert(constructor_called);
      assert(source.pool.items.count == 1);

      wlc_handle handle;
#pragma GCC diagnostic ignored "-Wpointer-arith"
      assert(!convert_to_wlc_handle(NULL));
#pragma GCC diagnostic warning "-Wpointer-arith"
      assert((handle = convert_to_wlc_handle(ptr)));
      assert(!convert_from_wlc_handle(handle, "invalid"));
      assert(convert_from_wlc_handle(handle, "test") == ptr);

      const char *test = "foobar";
      wlc_handle_set_user_data(handle, test);
      assert(wlc_handle_get_user_data(handle) == test);

      assert(!destructor_called);
      wlc_handle_release(handle);
      assert(destructor_called);
      assert(!convert_from_wlc_handle(handle, "invalid"));
      assert(!convert_from_wlc_handle(handle, "test"));
      assert(!wlc_handle_get_user_data(handle));
      assert(source.pool.items.count == 0);

      wlc_source_release(&source);
      wlc_resources_terminate();
   }

   // TEST: Handle invalidation on source release
   {
      assert(wlc_resources_init());

      struct wlc_source source;
      assert(wlc_source(&source, "test", constructor, destructor, 1, sizeof(struct wlc_resource)));

      struct wlc_resource *ptr;
      assert((ptr = wlc_handle_create(&source)));
      assert(source.pool.items.count == 1);

      wlc_handle handle;
      assert((handle = convert_to_wlc_handle(ptr)));

      assert(!(destructor_called = false));
      wlc_source_release(&source);
      assert(destructor_called);

      assert(source.pool.items.count == 0);
      assert(!convert_from_wlc_handle(handle, "test"));

      wlc_resources_terminate();
   }

   // TEST: Handle invalidation on resources termination
   {
      assert(wlc_resources_init());

      struct wlc_source source;
      assert(wlc_source(&source, "test", constructor, destructor, 1, sizeof(struct wlc_resource)));

      struct wlc_resource *ptr;
      assert((ptr = wlc_handle_create(&source)));
      assert(source.pool.items.count == 1);

      wlc_handle handle;
      assert((handle = convert_to_wlc_handle(ptr)));

      assert(!(destructor_called = false));
      wlc_resources_terminate();
      assert(destructor_called);

      assert(!convert_from_wlc_handle(handle, "test"));
      wlc_source_release(&source);
   }

   // TEST: Relocation of source inside container of handle, when the handle's source changes location
   {
      assert(wlc_resources_init());

      struct wlc_source source;
      assert(wlc_source(&source, "test", constructor2, destructor2, 1, sizeof(struct contains_source)));

      struct contains_source *ptr;
      assert((ptr = wlc_handle_create(&source)));
      assert(source.pool.items.count == 1);
      void *original_source = &ptr->source;

      wlc_handle handle;
      assert((handle = convert_to_wlc_handle(ptr)));

      struct wlc_resource *ptr2;
      assert((ptr2 = wlc_handle_create(&ptr->source)));

      wlc_handle handle2;
      assert((handle2 = convert_to_wlc_handle(ptr2)));
      assert(convert_from_wlc_handle(handle2, "test2") == ptr2);

      // Play with heap until realloc does not return linear memory anymore
      {
         void *original = source.pool.items.buffer;
         do {
            void *garbage;
            assert((garbage = malloc(1024)));
            assert(wlc_handle_create(&source));
            free(garbage);
         } while (original == source.pool.items.buffer);
      }

      // So this should be true
      assert(ptr = convert_from_wlc_handle(handle, "test"));
      assert(original_source != &ptr->source);

      wlc_resources_terminate();

      assert(!convert_from_wlc_handle(handle2, "test2"));
      wlc_source_release(&source);
   }

   // TEST: Benchmark (many insertions, and removal expanding from center)
   {
      assert(wlc_resources_init());

      struct container {
         wlc_handle self;
      };

      struct wlc_source source;
      assert(wlc_source(&source, "test", constructor, destructor, 1024, sizeof(struct container)));

      wlc_handle first = 0;
      const uint32_t iters = 0xFFFFF;
      for (uint32_t i = 0; i < iters; ++i) {
         struct container *ptr = wlc_handle_create(&source);
         ptr->self = convert_to_wlc_handle(ptr);
         if (!first) first = ptr->self;
         assert(convert_from_wlc_handle(first, "test"));
      }
      assert(source.pool.items.count == iters);

      for (uint32_t i = iters / 2, d = iters / 2; i < iters; ++i, --d) {
         assert(((struct container*)convert_from_wlc_handle(i + 1, "test"))->self == i + 1);
         assert(((struct container*)convert_from_wlc_handle(d + 1, "test"))->self == d + 1);
         wlc_handle_release(i + 1);
         wlc_handle_release(d + 1);
      }
      assert(source.pool.items.count == 0);

      assert(!convert_from_wlc_handle(first, "test"));
      wlc_source_release(&source);
      wlc_resources_terminate();
   }

   // TODO: Needs test for wlc_resource.
   //       For this we need to start compositor and some clients, or dummy the wl_resource struct.
   //       (Latter probably better)

   return EXIT_SUCCESS;
}
Example #3
0
WLC_API bool
wlc_init(const struct wlc_interface *interface, int argc, char *argv[])
{
   assert(interface);

   if (!interface)
      die("no wlc_interface was given");

   if (wlc.display)
      return true;

   // reset wlc state, but keep log function
   void *log_fun = wlc.log_fun;
   memset(&wlc, 0, sizeof(wlc));
   wlc.log_fun = log_fun;

   wl_log_set_handler_server(wl_cb_log);

   unsetenv("TERM");
   const char *x11display = getenv("DISPLAY");
   bool privileged = false;
   const bool has_logind = wlc_logind_available();

   if (getuid() != geteuid() || getgid() != getegid()) {
      wlc_log(WLC_LOG_INFO, "Doing work on SUID/SGID side and dropping permissions");
      privileged = true;
   } else if (getuid() == 0) {
      die("Do not run wlc compositor as root");
   } else if (!x11display && !has_logind && access("/dev/input/event0", R_OK | W_OK) != 0) {
      die("Not running from X11 and no access to /dev/input/event0 or logind available");
   }

   int vt = 0;

#ifdef HAS_LOGIND
   // Init logind if we are not running as SUID.
   // We need event loop for logind to work, and thus we won't allow it on SUID process.
   if (!privileged && !x11display && has_logind) {
      if (!(wlc.display = wl_display_create()))
         die("Failed to create wayland display");
      if (!(vt = wlc_logind_init("seat0")))
         die("Failed to init logind");
   }
#else
   (void)privileged;
#endif

   if (!x11display)
      wlc_tty_init(vt);

   // -- we open tty before dropping permissions
   //    so the fd process can also handle cleanup in case of crash
   //    if logind initialized correctly, fd process does nothing but handle crash.

   {
      struct wl_display *display = wlc.display;
      wlc.display = NULL;
      wlc_fd_init(argc, argv, (vt != 0));
      wlc.display = display;
   }

   // -- permissions are now dropped

   wl_signal_init(&wlc.signals.terminate);
   wl_signal_init(&wlc.signals.activate);
   wl_signal_init(&wlc.signals.compositor);
   wl_signal_init(&wlc.signals.focus);
   wl_signal_init(&wlc.signals.surface);
   wl_signal_init(&wlc.signals.input);
   wl_signal_init(&wlc.signals.output);
   wl_signal_init(&wlc.signals.render);
   wl_signal_init(&wlc.signals.xwayland);
   wl_signal_add(&wlc.signals.compositor, &compositor_listener);

   if (!wlc_resources_init())
      die("Failed to init resource manager");

   if (!wlc.display && !(wlc.display = wl_display_create()))
      die("Failed to create wayland display");

   const char *socket_name;
   if (!(socket_name = wl_display_add_socket_auto(wlc.display)))
      die("Failed to add socket to wayland display");

   if (socket_name) // shut up static analyze
      setenv("WAYLAND_DISPLAY", socket_name, true);

   if (wl_display_init_shm(wlc.display) != 0)
      die("Failed to init shm");

   if (!wlc_udev_init())
      die("Failed to init udev");

   const char *libinput = getenv("WLC_LIBINPUT");
   if (!x11display || (libinput && !chck_cstreq(libinput, "0"))) {
      if (!wlc_input_init())
         die("Failed to init input");
   }

   if (!wlc_compositor(&wlc.compositor))
      die("Failed to init compositor");

   memcpy(&wlc.interface, interface, sizeof(wlc.interface));
   return true;
}