Open '/dev/input/mice' early before dropping root privileges.
authorAlexander Koenig <alex@lisas.de>
Wed, 11 May 2016 21:59:00 +0000 (23:59 +0200)
committerAlexander Koenig <alex@lisas.de>
Wed, 11 May 2016 21:59:00 +0000 (23:59 +0200)
src/main.cc
src/tX_mouse.cc
src/tX_mouse.h

index 118d3db1b91d1e4293636be32ae924a4c4faf6cf..a30fc4ba14bf2f650368de2a989f914f607ca527 100644 (file)
@@ -175,30 +175,43 @@ void checkenv(const char *name)
 
 int main(int argc, char **argv)
 {
-       fprintf(stderr, "%s - Copyright (C) 1999-2014 by Alexander König\n", VERSIONSTRING);
-       fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
+       bool keep_caps_failed = false;
+       bool root_dropped = false;
 
 #ifdef USE_CAPABILITIES        
        if (!geteuid()) {
                if (prctl(PR_SET_KEEPCAPS, 1, -1, -1, -1)) {
-                       tX_error("failed to keep capabilities.");
+                       keep_caps_failed = true;
                }
                set_nice_capability(CAP_PERMITTED);
        }
 #endif
 
+       GError *mouse_error = mouse.open_channel();
+
        if ((!geteuid()) && (getuid() != geteuid())) {
-               tX_msg("runnig suid-root - dropping root privileges.");
-               
                int result=setuid(getuid());
+               root_dropped = true;
                
                if (result) {
-                       tX_error("main() Panic: can't drop root privileges.");
+                       tX_error("main() panic: can't drop root privileges.");
                        exit(2);
                }
        }
        
        /* No suidroot below this comment. */
+
+       fprintf(stderr, "%s - Copyright (C) 1999-2016 by Alexander König\n", VERSIONSTRING);
+       fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
+
+       if (keep_caps_failed) {
+               tX_error("failed to keep capabilities.");
+       }
+
+       if (root_dropped) {
+               tX_msg("started suid-root - root privileges dropped.");
+       }
+
        
 #ifdef USE_CAPABILITIES                
        set_nice_capability(CAP_EFFECTIVE);     
@@ -253,7 +266,7 @@ int main(int argc, char **argv)
        jack_check();
 #endif
        display_mastergui();
-               
+       
        if (globals.startup_set) {
                while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); 
                tX_cursor::set_cursor(tX_cursor::WAIT_CURSOR);
@@ -265,6 +278,22 @@ int main(int argc, char **argv)
 #endif         
        }
 
+       if (mouse_error) {
+               char buffer[4096];
+               const char *errorFmt = "<span size=\"larger\" weight=\"bold\">Failed to access input hardware</span>\n\n"
+                       "terminatorX failed to get direct access to the Linux input interface and "
+                       "will now fallback to the standard \"pointer warp\" mode, which will result in "
+                       "<span weight=\"bold\">significantly reduced scratching precision</span>.\n\nTo achieve "
+                       "high precision scratching either\n - <span style=\"italic\">install terminatorX suid-root</span>, or\n"
+                       " - <span style=\"italic\">add the users running terminatorX to a group that can access the special "
+                       "file \"/dev/input/mice\"</span>\nand restart terminatorX.\n\n"
+                       "The reported error was: <span weight=\"bold\">%s</span>";
+
+               snprintf(buffer, 4096, errorFmt, mouse_error->message);
+               tx_note(buffer, true, NULL);
+               g_error_free(mouse_error);
+       }
+               
 #ifdef USE_STARTUP_NOTIFICATION
        gdk_notify_startup_complete();
 #endif 
@@ -274,6 +303,8 @@ int main(int argc, char **argv)
 
        store_globals();
 
+       mouse.close_channel();
+
        delete engine;
        
        fprintf(stderr, "Have a nice life.\n");
index 01cf0bbfa01b79cd840f7bc7814df1ec838c2525..bdba74e0d92c5b20ff605751073f18ff531c4f03 100644 (file)
@@ -47,6 +47,7 @@ tx_mouse :: tx_mouse()
 {
        pointer = NULL;
        keyboard = NULL;
+       linux_input_channel = NULL;
        grab_mode = LINUX_INPUT;
        
        grabbed=0;
@@ -108,7 +109,6 @@ int tx_mouse :: grab()
        
        gdk_device_warp(pointer, screen, x_abs, y_abs);
 
-
        if (grab_status != GDK_GRAB_SUCCESS) {
                return(-1);
        }       
@@ -178,33 +178,46 @@ void tx_mouse :: ungrab()
        grabbed=0;
 }
 
-int tx_mouse::grab_linux_input() {
+GError *tx_mouse::open_channel() {
        GError *error = NULL;
-       
+
        linux_input_channel = g_io_channel_new_file("/dev/input/mice", "r", &error);
-       
        if (linux_input_channel) {
-               //GIOFlags flags = g_io_channel_get_flags(linux_input_channel);
                g_io_channel_set_flags(linux_input_channel, G_IO_FLAG_NONBLOCK, NULL);
+               return 0;
+       } else {
+               return error;
+       }
+       
+       return NULL;
+}
+
+void tx_mouse::close_channel() {
+    if (linux_input_channel) {
+           g_io_channel_shutdown(linux_input_channel, false, NULL);
+           g_io_channel_unref(linux_input_channel);
+           linux_input_channel = NULL;
+    }
+}
+
+int tx_mouse::grab_linux_input() {
+       
+       if (linux_input_channel) {
                linux_input_watch = g_io_add_watch_full(linux_input_channel, G_PRIORITY_HIGH, G_IO_IN, tx_mouse::linux_input_wrap, this, NULL);
        } else {
-               tX_msg("Failed to open /dev/input/mice: %s", error->message)
-               g_error_free(error);
-               tx_note("Failed to open input device.", true, GTK_WINDOW(main_window));         
+               tX_msg("Linux input channel not available, falling back to pointer warping.");
                return 0;
        }
        return 1;
-       
 }
 
 void tx_mouse::ungrab_linux_input() {
        if (grab_mode == LINUX_INPUT) {
+               // only remove the watch, we keep the channel as we dropped root and might fail to re-open it
                g_source_remove(linux_input_watch);
-               g_io_channel_shutdown(linux_input_channel, false, NULL);
-               g_io_channel_unref(linux_input_channel);
-               linux_input_channel = NULL;
        }
 }
+
 #define vtt vtt_class::focused_vtt
 
 void tx_mouse::motion_notify(GtkWidget *widget, GdkEventMotion *eventMotion) {
@@ -213,6 +226,9 @@ void tx_mouse::motion_notify(GtkWidget *widget, GdkEventMotion *eventMotion) {
                gdouble d_y = eventMotion->y_root - y_abs;
                
                if ((d_x != 0.0) || (d_y != 0.0)) {
+                       gdouble xnow, ynow;
+                       //gdk_device_get_position_double(pointer, NULL, &xnow, &ynow);
+                       //printf("%lf -> %lf, %lf -> %lf\n", eventMotion->x_root, xnow, eventMotion->y_root, ynow);
                        gdk_device_warp(pointer, screen, x_abs, y_abs);
                        
                        if (warp_override) {
index e0146300ef792d3f1069d012c8304e48ebec26a7..14bcd379546a5737d4c6f24bbd9a5774d3e84b1e 100644 (file)
@@ -128,7 +128,9 @@ class tx_mouse
        void ungrab();
        void ungrab_linux_input();
        tx_mouse();
-       
+       GError *open_channel();
+       void close_channel();
+
        void motion_notify(GtkWidget *widget, GdkEventMotion *eventMotion);
        void button_press(GtkWidget *widget, GdkEventButton *eventButton);
        void button_release(GtkWidget *widget, GdkEventButton *eventButton);