Starten der Desktop Environment mittels forkpty - Programme hängen sich auf?!
-
Hallo
Mein erster Post und ich konfrontiere euch schon mit einem komischen/schwierigen ProblemDer 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?