Starten der Desktop Environment mittels forkpty - Programme hängen sich auf?!



  • Hallo
    Mein erster Post und ich konfrontiere euch schon mit einem komischen/schwierigen Problem 😉

    Der X Server läuft bereits mit Root Rechten auf einem Linux System. Dann wird ein neuer Prozess in einem Pseudo Terminal geöffnet mittels forkpty und es wird in diesem Prozess zu Benutzer Rechten gewechselt. Danach wird xinit ausgeführt und die DE wird gestartet. Alles funktioniert einwandfrei, außer dass nach 20-40min laufende Programme in dieser DE und somit im Pseudo Terminal sich aufhängen. Weitere gestartete Programme nach diesem Auftreten, hängen sich dann meistens sofort auf. Wenn ich jedoch versuche die Programme in einem Terminal zu starten, dass ja eine neues Pseudo Terminal öffnet, dann funktioniert dies meistens. Jedoch hängen sich diese dann auch wiederum nach einer gewissen Zeit auf. Was mache ich Falsch? Wie machen das Terminal Emulators? Ich habe mir den Source von Einigen angeschaut und alle benutzen PTYs!
    Wenn ich das forkpty durch ein normales fork ersetzte, dann treten keine Probelem auf! Aber ich benötige ein PTY, dass in einem neuen Prozess gestartet wird, da sich sonst Prozesse selbstständig machen und ich diese nicht mehr killen kann nach der Schließung von der DE.

    Dieses Problem mit dem Aufhängen der laufenden Programme ist auf mehreren PCs getestet worden. Die Systeme waren Arch Linux und Manjaro Linux(Arch Linux basierend).

    Hier mein Code:

    bool Core::LoginUser(QString Username, QString Session) {
        // Create a new Process within a pseudo terminal, so child processes get also killed.
        int masterfd;
    
        pid_t pid = forkpty(&masterfd, 0, 0, 0);
    
        if(pid < 0)
          return false;
    
        if(pid == 0)
        {
            // TODO: QObject::tr() -> cerr
            // TODO: Hide the Cursor
    
            struct passwd *pw = getpwnam(Username.toAscii());
            endpwent();
    
            if(pw == 0)
                _exit(1);
            if (pw->pw_shell[0] == '\0') {
                setusershell();
                strcpy(pw->pw_shell, getusershell());
                endusershell();
            }
    
            // Fill the Environment Variable
            const int Num_Of_Variables = 9; // Number of env. variables + 1
            char** child_env = static_cast<char**>(malloc(sizeof(char*)*Num_Of_Variables));
            int n = 0;
            char* term = getenv("TERM");
            if(term) child_env[n++]=StrConcat("TERM=", term);
            child_env[n++]=StrConcat("HOME=", pw->pw_dir);
            child_env[n++]=StrConcat("SHELL=", pw->pw_shell);
            child_env[n++]=StrConcat("USER=", pw->pw_name);
            child_env[n++]=StrConcat("LOGNAME=", pw->pw_name);
            // TODO: Get this from the config
            child_env[n++]=StrConcat("PATH=", "PATH=/bin:/usr/bin:/usr/local/bin");
            child_env[n++]=StrConcat("DISPLAY=", MainXServer::DisplayName.toAscii());
            child_env[n++]=StrConcat("XAUTHORITY=", QString(QString(pw->pw_dir) + "/.Xauthority").toAscii());
            child_env[n++]=0;
    
            if((initgroups(pw->pw_name, pw->pw_gid) != 0) || (setgid(pw->pw_gid) != 0) || (setuid(pw->pw_uid) != 0)) {
                cerr << "could not switch user id" << endl;
                _exit(1);
            }
    
            // Run the session login script
            if (!RunScript("/etc/mldm.d/session_login.sh", child_env))
                cerr << QObject::tr("Failed to exec session_login.sh script!").toAscii().data() << endl;
    
            // Change Session and Username Variable
            DBus::registerSession(MainXServer::DisplayNum, MainXServer::VTNum, Session, Username);
    
            // Set the XServer command
            // TODO: get the loginCommand from the config
            // TODO: Start xinit scripts in /etc/X11/xinit.d.....
            QString LoginCommand = "/login.sh"; //"exec /bin/bash -login ~/.xinitrc %session";
            LoginCommand.replace("%session", Session);
    
            // Change current directory of current process
            if (chdir(pw->pw_dir) < 0) {
                cerr << "Failed to change directory to users home folder!" << endl;
                _exit(1);
            }
    
            // Execute command
            execle(pw->pw_shell, pw->pw_shell, "-c", LoginCommand.toAscii().data(), NULL, child_env);
    
            // TODO: Display error on gui
            cerr << "could not execute login command" << endl;
    
            _exit(1);
        }
    
        // Wait until user is logging out (login process terminates)
        int status;
    
        // TODO: Change to pid
        waitpid(pid, &status, 0);
    
        // Close the pseudo terminal
        close(masterfd);
    
        // Change Session and Username Variable
        DBus::registerSession(MainXServer::DisplayNum, MainXServer::VTNum, "MLDM");
    
        // Check the return status of the process
        if (WIFEXITED(status) && WEXITSTATUS(status)) {
            // TODO: show this in gui
            // Failed to execute login command
            return false;
        } else {
            // TODO:
            // Run Stop Script
    
            return true;
        }
    
    }
    

    Hoffe ihr könnt mir helfen. Bin schon am verzweifeln. 😉

    MFG

    Roland Singer



  • Was heisst "haengt sich auf"? Schau mal, was das Programm beim Aufhaengen macht. strace and gdb sollten das zeigen.



  • Gute Idee. Ich werde ein paar Daten sammeln. 😉



  • K. Tint2 hat sich sofort aufgehängt(Nachdem es wieder angefangen hat -> 40min), indem ich mit der Maus drauf geklickt habe. Hier die letzten Ausgaben von strace:

    Komplette Ausgabe: http://pastebin.com/KmxWgyGR

    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    poll([{fd=3, events=POLLIN|POLLOUT}], 1, -1) = 1 ([{fd=3, revents=POLLOUT}])
    writev(3, [{"6\0\2\0k\0`\0035 \4\0s\0`\3Z\1\0\0\240\5\34\0>\0\7\0\t\0`\3"..., 220}, {NULL, 0}, {"", 0}], 3) = 220
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 49450})  = 1 (in [3], left {0, 44318})
    read(3, "\16\0'\2s\0`\3\0\0>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 224
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 44124})  = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 1 (in [3], left {0, 895305})
    read(3, "\226\0-\2\4\0\240\3\4\0\240\3\0\0\0\0\0\0\25\0\240\5S\3\0\0\0\0\0\0\0\0", 4096) = 32
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 895069}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=157, ...}) = 0
    poll([{fd=3, events=POLLIN|POLLOUT}], 1, -1) = 1 ([{fd=3, revents=POLLOUT}])
    writev(3, [{"6\0\2\0s\0`\0035 \4\0t\0`\3Z\1\0\0\240\5\34\0>\0\7\0\t\0`\3"..., 424}, {NULL, 0}, {"", 0}], 3) = 424
    read(3, "\16\0000\2t\0`\3\0\0>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 256
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 999170}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999995}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    open("/sys/class/power_supply/BAT1/status", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "Unknown\n", 4096)              = 8
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    open("/sys/class/power_supply/BAT1/charge_now", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "6000000\n", 4096)              = 8
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    open("/sys/class/power_supply/BAT1/charge_full", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "6000000\n", 4096)              = 8
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    open("/sys/class/power_supply/BAT1/current_now", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "0\n", 4096)                    = 2
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999995}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999997}) = 1 (in [3], left {0, 559164})
    read(3, "\34\0A\2Z\1\0\0\263\1\0\0\345\3707\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096) = 32
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 558897}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 1 (in [3], left {0, 868220})
    read(3, "\34\0A\2Z\1\0\0\263\1\0\0\202\3777\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096) = 32
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 867943}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999995}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 1 (in [3], left {0, 621587})
    read(3, "\34\0A\2Z\1\0\0\263\1\0\0\35\0208\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096) = 32
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 621318}) = 1 (in [3], left {0, 621114})
    read(3, "\34\0A\2\4\0\240\3c\1\0\0\36\0208\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096) = 32
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    select(4, [3], NULL, NULL, {0, 620959}) = 0 (Timeout)
    select(4, [3], NULL, NULL, {0, 999996}) = 0 (Timeout)
    open("/sys/class/power_supply/BAT1/status", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "Unknown\n", 4096)              = 8
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    open("/sys/class/power_supply/BAT1/charge_now", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "6000000\n", 4096)              = 8
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    open("/sys/class/power_supply/BAT1/charge_full", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "6000000\n", 4096)              = 8
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    open("/sys/class/power_supply/BAT1/current_now", O_RDONLY) = 4
    fstat(4, {st_mode=S_IFREG|0444, st_size=4096, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74fc061000
    read(4, "0\n", 4096)                    = 2
    close(4)                                = 0
    munmap(0x7f74fc061000, 4096)            = 0
    select(4, [3], NULL, NULL, {0, 999996}) = 1 (in [3], left {0, 488655})
    read(3, "\34\0A\2\4\0\240\3c\1\0\0\312\0308\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096) = 32
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0x163cdf4, 4096)                = -1 EAGAIN (Resource temporarily unavailable)
    

    Sehr komisch. Weitere Anwendungen hängen sich gerade nach der Reihe auf.

    Edit: Wenn ich tint2 mit F2 oder in einem Terminal starte, hängt es sich auf. Wenn ich es jedoch mit gdb starte, scheint es zu funktionieren. Leider hat sich gerade meine gesamte DE aufgehängt und ich kann nicht mehr Infos zu gdb geben. So ein Mist aber auch.



  • Der Prozess wartet auf Daten vom X-Server. Die Frage ist nun, warum da nichts mehr kommt. War das ein Prozess, der Events bekommen sollte?



  • Hmm. Der X Server wurde mit Root Rechten in einem vfork gestartet. Ich habe die Signals angepasst. Ich habe da eine Idee.

    Das hier habe ich gerade in den VTE libs gefunden:

    /* Reset the handlers for all known signals to their defaults.  The parent
     * (or one of the libraries it links to) may have changed one to be ignored. */
    static void
    _vte_pty_reset_signal_handlers(void)
    {
    #ifdef SIGHUP
    	signal(SIGHUP,  SIG_DFL);
    #endif
    	signal(SIGINT,  SIG_DFL);
    	signal(SIGILL,  SIG_DFL);
    	signal(SIGABRT, SIG_DFL);
    	signal(SIGFPE,  SIG_DFL);
    #ifdef SIGKILL
    	signal(SIGKILL, SIG_DFL);
    #endif
    	signal(SIGSEGV, SIG_DFL);
    #ifdef SIGPIPE
    	signal(SIGPIPE, SIG_DFL);
    #endif
    #ifdef SIGALRM
    	signal(SIGALRM, SIG_DFL);
    #endif
    	signal(SIGTERM, SIG_DFL);
    #ifdef SIGCHLD
    	signal(SIGCHLD, SIG_DFL);
    #endif
    #ifdef SIGCONT
    	signal(SIGCONT, SIG_DFL);
    #endif
    #ifdef SIGSTOP
    	signal(SIGSTOP, SIG_DFL);
    #endif
    #ifdef SIGTSTP
    	signal(SIGTSTP, SIG_DFL);
    #endif
    #ifdef SIGTTIN
    	signal(SIGTTIN, SIG_DFL);
    #endif
    #ifdef SIGTTOU
    	signal(SIGTTOU, SIG_DFL);
    #endif
    #ifdef SIGBUS
    	signal(SIGBUS,  SIG_DFL);
    #endif
    #ifdef SIGPOLL
    	signal(SIGPOLL, SIG_DFL);
    #endif
    #ifdef SIGPROF
    	signal(SIGPROF, SIG_DFL);
    #endif
    #ifdef SIGSYS
    	signal(SIGSYS,  SIG_DFL);
    #endif
    #ifdef SIGTRAP
    	signal(SIGTRAP, SIG_DFL);
    #endif
    #ifdef SIGURG
    	signal(SIGURG,  SIG_DFL);
    #endif
    #ifdef SIGVTALARM
    	signal(SIGVTALARM, SIG_DFL);
    #endif
    #ifdef SIGXCPU
    	signal(SIGXCPU, SIG_DFL);
    #endif
    #ifdef SIGXFSZ
    	signal(SIGXFSZ, SIG_DFL);
    #endif
    #ifdef SIGIOT
    	signal(SIGIOT,  SIG_DFL);
    #endif
    #ifdef SIGEMT
    	signal(SIGEMT,  SIG_DFL);
    #endif
    #ifdef SIGSTKFLT
    	signal(SIGSTKFLT, SIG_DFL);
    #endif
    #ifdef SIGIO
    	signal(SIGIO,   SIG_DFL);
    #endif
    #ifdef SIGCLD
    	signal(SIGCLD,  SIG_DFL);
    #endif
    #ifdef SIGPWR
    	signal(SIGPWR,  SIG_DFL);
    #endif
    #ifdef SIGINFO
    	signal(SIGINFO, SIG_DFL);
    #endif
    #ifdef SIGLOST
    	signal(SIGLOST, SIG_DFL);
    #endif
    #ifdef SIGWINCH
    	signal(SIGWINCH, SIG_DFL);
    #endif
    #ifdef SIGUNUSED
    	signal(SIGUNUSED, SIG_DFL);
    #endif
    }
    

    Ich baue das gerade eben mal ein und werde diese Funktion im PTY Childprozess aufrufen.



  • Hmm. Scheint nichts zu ändern. Würde es vllt helfen, wenn man anstatt forkpty, selber ein pty über open öffnet und dann forked...? Könnte mir da jemand helfen einen Code zusammen zu basteln?


Anmelden zum Antworten