Completely reworked tX_engine.cc for suid root operation. Misc fixes including
authorterminatorX <>
Sun, 11 Aug 2002 22:48:05 +0000 (22:48 +0000)
committerterminatorX <>
Sun, 11 Aug 2002 22:48:05 +0000 (22:48 +0000)
the panel bar - Alex

terminatorX/src/main.cc
terminatorX/src/tX_engine.cc
terminatorX/src/tX_engine.h
terminatorX/src/tX_global.h
terminatorX/src/tX_mastergui.cc
terminatorX/src/tX_vtt.cc

index fd40f90cdff91dde681954d98ce359f0dcf0d791..c8e6b390cc4291a8efba4ef26618578f33c5d907 100644 (file)
@@ -64,6 +64,8 @@
 
 #include "tX_ladspa.h"
 
+#include "tX_engine.h"
+
 #ifdef CREATE_BENCHMARK 
 #include "tX_vtt.h"
 #endif
@@ -364,14 +366,10 @@ int main(int argc, char **argv)
        FILE *gtk_rc_file;
        
        fprintf(stderr, "%s - Copyright (C) 1999-2002 by Alexander K├Ânig\n", VERSIONSTRING);
-
-#ifdef WIN32
-        setenv ("CYGWIN", "binmode");
-#endif
-       
-
        fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
 
+       engine=new tX_engine();
+       
 #ifdef USE_3DNOW
        if (tx_mm_support()!=5)
        {
index 9a9d911c484745b46da6e6766417b42d5b5ffec9..f409df6042ae668f18347adb067773d5306c46bc 100644 (file)
 #include "tX_widget.h"
 #include <config.h>
 #include "tX_sequencer.h"
+#include <errno.h>
 
-#ifdef USE_SCHEDULER
 #include <sys/time.h>
 #include <sys/resource.h>
-#endif
-
-pthread_t engine_thread=0;
 
-pthread_mutex_t stat_lock=PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t thread_lock=PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t pos_lock=PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t run_lock=PTHREAD_MUTEX_INITIALIZER;
+tX_engine *engine=NULL;
 
 tx_mouse *mouse=new tx_mouse();
 tX_audiodevice *device=NULL;
 tx_tapedeck *tape=new tx_tapedeck();
 
-int engine_quit=0;
-
-int engine_status=ENG_STOPPED;
-
-int realpos=0;
-
-int do_grab_mouse=0;
-int new_grab_mouse=0;
-
-int want_recording=0;
-int is_recording=0;
-
-void grab_mouse(int newstate)
-{
-       new_grab_mouse=newstate;
+void tX_engine :: set_grab_request() {
+       grab_request=true;
 }
 
-int get_engine_status()
-{
-       int tmp;
-       pthread_mutex_lock(&stat_lock);
-       tmp=engine_status;
-       pthread_mutex_unlock(&stat_lock);
-       return(tmp);
-}
-
-void set_engine_status(int status)
-{
-       pthread_mutex_lock(&stat_lock);
-       engine_status=status;
-       pthread_mutex_unlock(&stat_lock);
-}
-
-void *engine(void *nil)
-{
-       int scratch=0;          
-       int stop_sense=globals.sense_cycles;
-       f_prec warp=1.0;
+void tX_engine :: loop() {
        int16_t *temp;
        int result;
        
-/*     want_recording=0;
-       is_recording=0; */
-
-/*
-#ifdef USE_SCHEDULER
-               setpriority(PRIO_PROCESS, getpid(), -20);
-#endif
-*/
-       
-#ifdef ENABLE_DEBUG_OUTPUT
-       fprintf(stderr, "[engine()] Engine thread up, PID: %i\n", getpid());
-#endif                 
-       pthread_mutex_lock(&run_lock);
-
-       set_engine_status(ENG_RUNNING);
-
-       /*render first block*/
-       sequencer.step();
-       temp=vtt_class::render_all_turntables();
+       while (!thread_terminate) {
+               /* Waiting for the trigger */
+               pthread_mutex_lock(&start);
+               loop_is_active=true;
+               pthread_mutex_unlock(&start);
 
-       while (!engine_quit)
-       {       
-               if (new_grab_mouse!=do_grab_mouse)
-               {
+               /* Render first block */
+               sequencer.step();
+               temp=vtt_class::render_all_turntables();
                
-                       do_grab_mouse=new_grab_mouse;
-                       
-                       if (do_grab_mouse) 
-                       {
-                               result=mouse->grab();
-                               if (result)
-                               {
-                                       fprintf(stderr, "tX_engine: quitting due to grab-error. (%i)\n", result);
-                                       do_grab_mouse=0;
+               while (!stop_flag) {
+                       /* Checking whether to grab or not  */
+                       if (grab_request!=grab_active) {
+                               if (grab_request) {
+                                       /* Activating grab... */
+                                       result=mouse->grab(); 
+                                       if (result!=0) {
+                                               tX_error("tX_engine::loop(): failed to grab mouse - error %i", result);
+                                               grab_active=false;
+                                               /* Reseting grab_request, too - doesn't help keeping it, does it ? ;) */
+                                               grab_request=false;
+                                               // mouse->ungrab() // do we need this?
+                                       } else {
+                                               grab_active=true;
+                                       }
+                               } else {
+                                       /* Deactivating grab... */
                                        mouse->ungrab();
-                                       engine_quit=1;
+                                       grab_active=false;
+                                       grab_off(); // for the mastergui this is...
                                }
                        }
-                       else
-                       {
-                               mouse->ungrab();
-                               grab_off();
+
+                       /* Handling input events... */
+                       if (grab_active) {
+                               if (mouse->check_event()) {
+                                       /* If we're here the user pressed ESC */
+                                       grab_request=false;
+                               }
                        }
-               }
                
-               if (do_grab_mouse)
-               if (mouse->check_event())
-               {
-                       new_grab_mouse=0;
+                       /* Playback the audio... */
+                       device->play(temp);
+               
+                       /* Record the audio if necessary... */
+                       if (is_recording()) tape->eat(temp);
+                       
+                       /* Forward the sequencer... */
+                       sequencer.step();
+                       
+                       /* Render the next block... */
+                       temp=vtt_class::render_all_turntables();                                        
                }
                
-               device->play(temp);
-               if (is_recording) tape->eat(temp);
-               sequencer.step();
-               temp=vtt_class::render_all_turntables();                                        
+               /* Stopping engine... */
+               loop_is_active=false;
        }
-       
-//     device->dev_close();
-
-       if (engine_quit==1) set_engine_status(ENG_STOPPED);
-       else set_engine_status(ENG_FINISHED);
+}
 
-       pthread_mutex_unlock(&run_lock);
+void *engine_thread_entry(void *engine_void) {
+       tX_engine *engine=(tX_engine*) engine_void;
+       int result;
+       
+       /* Dropping root privileges for the engine thread - if running suid. */
+       
+       if ((!geteuid()) && (getuid() != geteuid())) {
+               tX_debug("engine_thread_entry() - Running suid root - dropping privileges.");
+               
+               result=setuid(getuid());
                
-       pthread_exit(NULL);
+               if (result!=0) {
+                       tX_error("engine_thread_entry() - Failed to drop root privileges.");
+                       exit(2);
+               }
+       }
+       
+       engine->loop();
 }
 
-int run_engine()
-{
-#ifdef USE_SCHEDULER
-       pthread_attr_t pattr;
-       struct sched_param sparm;
-#endif
-       char buffer[PATH_MAX];
-       list <vtt_class *> :: iterator vtt;     
+tX_engine :: tX_engine() {
+       int result;
        
-       pthread_mutex_lock(&thread_lock);
+       pthread_mutex_init(&start, NULL);
+       pthread_mutex_lock(&start);
+       thread_terminate=false;
        
-       if (engine_thread)
-       {
-               pthread_mutex_unlock(&thread_lock);
-               return(TX_ENG_ERR_BUSY);
+       /* Creating the actual engine thread.. */
+       
+       if (!geteuid()) {
+               pthread_attr_t pattr;
+               struct sched_param sparm;
+               
+               tX_debug("tX_engine() - Have root privileges - using SCHED_FIFO.");
+               
+               pthread_attr_init(&pattr);
+               pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
+               pthread_attr_setschedpolicy(&pattr, SCHED_FIFO);
+       
+               sched_getparam(getpid(), &sparm);
+               sparm.sched_priority=sched_get_priority_max(SCHED_FIFO);
+       
+               pthread_attr_setschedparam(&pattr, &sparm);
+               pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
+               pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM);
+               
+               result=pthread_create(&thread, &pattr, engine_thread_entry, (void *) this);
+       } else {
+               tX_debug("tX_engine() - Lacking root privileges - no realtime scheduling!");
+               
+               result=pthread_create(&thread, NULL, engine_thread_entry, (void *) this);
        }
+       
+       if (result!=0) {
+               tX_error("tX_engine() - Failed to create engine thread. Errno is %i.", errno);
+               exit(1);
+       }
+       
+       /* Dropping root privileges for the main thread - if running suid. */
+       
+       if ((!geteuid()) && (getuid() != geteuid())) {
+               tX_debug("tX_engine() - Running suid root - dropping privileges.");
+               
+               result=setuid(getuid());
+               
+               if (result!=0) {
+                       tX_error("tX_engine() - Failed to drop root privileges.");
+                       exit(2);
+               }
+       }
+       
+       mouse=new tx_mouse();
+       tape=new tx_tapedeck();
+       device=NULL;
+       recording=false;
+       recording_request=false;
+       loop_is_active=false;
+       grab_request=false;
+       grab_active=false;
+}
 
-       pthread_mutex_lock(&run_lock);
+void tX_engine :: set_recording_request (bool recording) {
+       this->recording_request=recording;
+}
+
+tX_engine_error tX_engine :: run() {
+       list <vtt_class *> :: iterator vtt;
+       
+       if (loop_is_active) return ERROR_BUSY;
        
-       switch (globals.audiodevice_type)
-       {
+       switch (globals.audiodevice_type) {
 #ifdef USE_OSS 
                case TX_AUDIODEVICE_TYPE_OSS:
-                       device=new tX_audiodevice_oss();
-                       break;
+                       device=new tX_audiodevice_oss(); break;
 #endif                 
 
 #ifdef USE_ALSA                        
                case TX_AUDIODEVICE_TYPE_ALSA:
-                       device=new tX_audiodevice_alsa();
-                       break;
+                       device=new tX_audiodevice_alsa(); break;
 #endif
                
                default:
-                       device=NULL;
-                       pthread_mutex_unlock(&run_lock);
-                       pthread_mutex_unlock(&thread_lock);
-                       return TX_ENG_ERR_DEVICE;
+                       device=NULL; return ERROR_AUDIO;
        }
        
-       if (device->open())
-       {
+       if (device->open()) {
                device->close();
                delete device;
                device=NULL;            
-               pthread_mutex_unlock(&run_lock);
-               pthread_mutex_unlock(&thread_lock);
-               return TX_ENG_ERR_DEVICE;
-       }
-       
-       is_recording=0;
+               return ERROR_AUDIO;
+       }       
+
+       vtt_class::set_mix_buffer_size(device->get_buffersize()/2); //mixbuffer is mono
        
-       if (want_recording)
-       {
-               if (!tape->start_record(globals.record_filename, device->get_buffersize()*sizeof(int16_t)))
-                       is_recording=1;
-               else
-               {
+       if (recording_request) {
+               if (tape->start_record(globals.record_filename, device->get_buffersize()*sizeof(int16_t))) {
+                       recording=true;
                        device->close();
                        delete device;
                        device=NULL;                    
-                       pthread_mutex_unlock(&run_lock);
-                       pthread_mutex_unlock(&thread_lock);
-                       return TX_ENG_ERR_TAPE;                 
-               }
-       }
-
-       vtt_class::set_mix_buffer_size(device->get_buffersize()/2); //mixbuffer is mono
-       
-       engine_quit=0;
-#ifdef USE_SCHEDULER   
-        if (!geteuid())
-       {
-#ifdef ENABLE_DEBUG_OUTPUT
-               fprintf(stderr, "[run_engine()] enabling fifo scheduling.\n");
-#endif
-               pthread_attr_init(&pattr);
-               pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
-               pthread_attr_setschedpolicy(&pattr, SCHED_FIFO);
-       
-               sched_getparam(getpid(), &sparm);
-               sparm.sched_priority=sched_get_priority_max(SCHED_FIFO);
-       
-               pthread_attr_setschedparam(&pattr, &sparm);
-               pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
-               pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM);
-               
-               pthread_create(&engine_thread, &pattr, engine, NULL);
-       }
-       else
-       {
-#ifdef ENABLE_DEBUG_OUTPUT
-               fprintf(stderr, "[run_engine()] NO fifo scheduling.\n");
-#endif
-               pthread_create(&engine_thread, NULL, engine, NULL);             
+                       return ERROR_TAPE;                      
+               }               
        }
-#else
-       pthread_create(&engine_thread, NULL, engine, NULL);     
-#endif
        
-       if (!engine_thread)
-       {
-               device->close();
-               delete device;          
-               device=NULL;
-               pthread_mutex_unlock(&run_lock);
-               pthread_mutex_unlock(&thread_lock);
-               return(TX_ENG_ERR_THREAD);
-       }
-
-//     gtk_label_set(GTK_LABEL(GTK_BUTTON(action_btn)->child), "Stop");        
-
-       for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++)
-       {
+       for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
                if ((*vtt)->autotrigger) (*vtt)->trigger();
        }
        
        sequencer.forward_to_start_timestamp(1);        
-       
-       pthread_detach(engine_thread);
-
-       set_engine_status(ENG_INIT);
-       
-       pthread_mutex_unlock(&thread_lock);
-       
-       pthread_mutex_unlock(&run_lock);
-               
-       return (TX_ENG_OK);
+       stop_flag=false;
+       /* Trigger the engine thread... */
+       pthread_mutex_unlock(&start);
 }
 
-int stop_engine()
-{
+void tX_engine :: stop() {
        list <vtt_class *> :: iterator vtt;
-       void *ret;
-
-       pthread_mutex_lock(&thread_lock);       
-       if (!engine_thread)
-       {
-               pthread_mutex_unlock(&thread_lock);
-               return(1);
+       
+       if (!loop_is_active) {
+               tX_error("tX_engine::stop() - but loop's not running?");
        }
        
-       engine_quit=1;
+       pthread_mutex_lock(&start);
+       stop_flag=true;
        
-       pthread_join(engine_thread, &ret);
+       tX_debug("tX_engine::stop() - waiting for loop to stop.");
        
-       engine_thread=0;
+       while (loop_is_active) {
+               usleep(50);
+       }
        
-       pthread_mutex_unlock(&thread_lock);
+       tX_debug("tX_engine::stop() - loop has stopped.");
+
        device->close();
        delete device;
        device=NULL;
        
-       for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++)
-       {
+       for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
                (*vtt)->stop();
                (*vtt)->ec_clear_buffer();
        }
        
-       if (is_recording) tape->stop_record();
-       is_recording=0;
-       return (0);
+       if (is_recording()) tape->stop_record();
+       recording=false;
+}
+
+tX_engine :: ~tX_engine() {
+       
 }
index a7195a98c67893e34245fcda9bd6e2ee19cfc5ed..e0d60a1c9f29fe1a9ec7b1020526d0d9b9734004 100644 (file)
 #ifndef _TX_ENGINE_H_
 #define _TX_ENGINE_H_
 
-extern int run_engine();
-extern int stop_engine();
-
-extern void grab_mouse(int);
+#include "tX_tape.h"
+#include "tX_mouse.h"
+#include "tX_audiodevice.h"
 
 #define ENG_ERR 4
 
@@ -44,15 +43,47 @@ extern void grab_mouse(int);
 #define ENG_ERR_GRABKEY 10
 #define ENG_ERR_BUSY 11
 
-#define TX_ENG_OK 0
-#define TX_ENG_ERR_TAPE 1
-#define TX_ENG_ERR_DEVICE 2
-#define TX_ENG_ERR_THREAD 3
-#define TX_ENG_ERR_BUSY 4
+#include <pthread.h>
+enum tX_engine_error {
+       NO_ERROR,
+       ERROR_TAPE,
+       ERROR_AUDIO,
+       ERROR_BUSY      
+};
 
-extern int get_engine_status();
-extern void set_engine_status(int );
+enum tX_engine_status {
+       RUNNING,
+       STOPPED
+};
 
-extern int want_recording;
+class tX_engine {
+       private:
+       pthread_t thread;
+       pthread_mutex_t start;
+       bool thread_terminate;
+       tx_mouse *mouse;
+       tX_audiodevice *device;
+       tx_tapedeck *tape;
+       bool recording;
+       bool recording_request;
+       bool stop_flag;
+       bool loop_is_active;
+       bool grab_request;
+       bool grab_active;
+       
+       public:
+       tX_engine();
+       ~tX_engine();
+       
+       tX_engine_error run();
+       void stop();
+       void loop();
+       void set_recording_request(bool recording);
+       bool get_recording_request() { return recording_request; }
+       bool is_recording() { return recording; }
+       
+       void set_grab_request();
+};
 
+extern tX_engine *engine;
 #endif
index 0abbbb7d62a13401dc73041aeefe748e1550aea1..5f0cce272b0e5d243e3f607f21a2532ae8369ac1 100644 (file)
@@ -48,6 +48,18 @@ extern "C" {
 #define TX_AUDIODEVICE_TYPE_OSS 0
 #define TX_AUDIODEVICE_TYPE_ALSA 1
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+       
+#ifdef ENABLE_DEBUG_OUTPUT     
+#define tX_debug(fmt, args...); { fprintf(stderr, "- tX_debug: "); fprintf(stderr, fmt , ## args); fprintf(stderr, "\n"); }
+#else
+#define tX_debug(fmt, args...);
+#endif
+       
+#define tX_error(fmt, args...); { fprintf(stderr, "* tX_error: "); fprintf(stderr, fmt , ## args); fprintf(stderr, "\n"); }
+
 typedef struct {
        char    audio_device[PATH_MAX];
        
index 032d979e4070638d0f458980b677cfc01791e166..7f5e02d0b1bafaac980376e41717f9e30936081b 100644 (file)
@@ -530,32 +530,29 @@ GtkSignalFunc seq_stop(GtkWidget *w, void *);
 
 GtkSignalFunc audio_on(GtkWidget *w, void *d)
 {
-       int res;
+       tX_engine_error res;
        
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
        {               
                sequencer_ready=0;
                mg_enable_critical_buttons(0);
-               res=run_engine();
+               res=engine->run();
                sequencer_ready=1;
 
-               if (res!=TX_ENG_OK)
+               if (res!=NO_ERROR)
                {
                        mg_enable_critical_buttons(1);
                        switch(res)
                        {
-                               case TX_ENG_ERR_BUSY:
+                               case ERROR_BUSY:
                                tx_note("Error starting engine: engine is already running.");
                                break;
-                               case TX_ENG_ERR_DEVICE:
+                               case ERROR_AUDIO:
                                tx_note("Error starting engine: failed to access audiodevice.");
                                break;
-                               case TX_ENG_ERR_TAPE:
+                               case ERROR_TAPE:
                                tx_note("Error starting engine: failed to open the recording file.");
                                break;
-                               case TX_ENG_ERR_THREAD:
-                               tx_note("Error starting engine: failed to create the engine thread.");
-                               break;
                                default:tx_note("Error starting engine: Unknown error.");
                        }
                        return 0;
@@ -571,12 +568,11 @@ GtkSignalFunc audio_on(GtkWidget *w, void *d)
        {               
                if (!sequencer_ready) return NULL;
                gtk_widget_set_sensitive(grab_button, 0);
-               stop_engine();
+               engine->stop();
                stop_update=1;
                audioon=0;
-               if ((want_recording) && (!globals.autoname))
-               {
-                       want_recording=0;
+               if (engine->get_recording_request()) {
+                       engine->set_recording_request(false);
                        rec_dont_care=1;
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_btn), 0);
                        rec_dont_care=0;
@@ -604,7 +600,7 @@ void do_rec(GtkWidget *wid)
        if (strlen(buffer))
        {
                strcpy(globals.record_filename, buffer);                
-               want_recording=1;
+               engine->set_recording_request(true);
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_btn), 1);
        }
        
@@ -654,13 +650,15 @@ GtkSignalFunc tape_on(GtkWidget *w, void *d)
        }
        else
        {
-                       want_recording=0;
+                       engine->set_recording_request(false);
        }
 }
 
 void grab_on(GtkWidget *w, void *d)
 {
-       grab_mouse(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
+               engine->set_grab_request();
+       }
        grab_status=1;
 }
 
index dcab53fc35d853f47d1bc5ff26bca148f22bb651..308b130dd19fd4c950dbbdd16e371c7b14622d0b 100644 (file)
@@ -1484,18 +1484,28 @@ void vtt_class :: focus_next()
                return;
        }
        
-       for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++)
-       {
-               if ((*vtt)==focused_vtt)
-               {
+       for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++) {
+               if ((*vtt)==focused_vtt) {
+                       /* Ok, we found ourselves.. */
+                       
                        vtt++;
-                       if (vtt==main_list.end())
-                       {                       
-                               focused_vtt=(*main_list.begin());
-                               return;
+                       while ((vtt!=main_list.end()) && ((*vtt)->audio_hidden) ) {
+                               vtt++;
                        }
-                       else
-                       {
+                       
+                       if (vtt==main_list.end()) {
+                               /* No other "focusable" after this vtt so we're looking for the next */
+                               
+                               for (vtt=main_list.begin(); vtt!=main_list.end() ; vtt++) {
+                                       if (! (*vtt)->audio_hidden) {
+                                               focused_vtt=(*vtt);
+                                               return;
+                                       }
+                               }
+                               /* When we get here there's no "focusable" vtt at all... damn */
+                               focused_vtt=NULL;
+                               return;
+                       } else {
                                focused_vtt=(*vtt);
                                return;
                        }