diff --git a/kdm/backend/dm.c b/kdm/backend/dm.c index e0f1366..5a5f8a7 100644 --- a/kdm/backend/dm.c +++ b/kdm/backend/dm.c @@ -1347,54 +1347,207 @@ getBusyVTs(void) return activeVTs; } +static int +get_active_vt (void) +{ + int console_fd; + struct vt_stat console_state = { 0 }; + console_fd = open ("/dev/tty0", O_RDONLY | O_NOCTTY); + if (console_fd < 0) { + return 0; + } + ioctl (console_fd, VT_GETSTATE, &console_state); + + close (console_fd); + return console_state.v_active; +} + +static int +plymouth_is_running (void) +{ + static int running = -1; + if (running == 0) + return 0; + + int status; + status = system ("/usr/bin/plymouth --ping"); + + running = WIFEXITED (status) && WEXITSTATUS (status) == 0; + logWarn ("plymouth is %srunning\n", running?"":"NOT "); + return running; +} + +static int +plymouth_has_active_vt (void) +{ + int status; + status = system ("/usr/bin/plymouth --has-active-vt"); + + return WIFEXITED (status) && WEXITSTATUS (status) == 0; +} + +static int +plymouth_prepare_for_transition (void) +{ + int status; + status = system ("/usr/bin/plymouth deactivate"); + + return WIFEXITED (status) && WEXITSTATUS (status) == 0; +} + +int +plymouth_quit_with_transition (void) +{ + int status; + status = system ("/usr/bin/plymouth --wait quit --retain-splash"); + + return WIFEXITED (status) && WEXITSTATUS (status) == 0; +} + +int +plymouth_quit_without_transition (void) +{ + int status; + status = system ("/usr/bin/plymouth --wait quit"); + + return WIFEXITED (status) && WEXITSTATUS (status) == 0; +} + +static int +triggered_to_force_display_on_active_vt (void) +{ + int should_force_display_on_active_vt; + should_force_display_on_active_vt=open("/var/spool/gdm/force-display-on-active-vt", O_RDONLY); + if ( should_force_display_on_active_vt >= 0 ) + close(should_force_display_on_active_vt); + unlink("/var/spool/gdm/force-display-on-active-vt"); + return should_force_display_on_active_vt; +} + static void allocateVT(struct display *d) { struct display *cd; - int i, tvt, volun; + int i, tvt; if ((d->displayType & d_location) == dLocal && d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0) { + /* Try to find the correct VT. + * If ServerVT is specified in the config, use it (if the admin used the + * same VT for multiple display, it is his/her own fault, no checks done). + * Otherwise, walk the list of specified VTs. Positive numbers are used + * even if the VT is already in use by a tty. Negative numbers and + * unspecified numbers (up to #15) are used if not already in use. + * VTs already in use (cd->serverVT) or requested (cd->reqSrvVT) + * by any display are skipped. + */ + + /* some special handling is needed for Plymouth: + * if no VT is requested, use the active VT from plymouth for the first + * started display. + * If the display takes over the VT from plymouth, deactivate plymouth + */ + + char allowedVTs[16] = { 0 }; if (d->reqSrvVT && d->reqSrvVT < 16) { - d->serverVT = d->reqSrvVT; + allowedVTs[d->reqSrvVT] = 1; } else { - for (i = tvt = 0;;) { - if (serverVTs[i]) { - tvt = atoi(serverVTs[i++]); - volun = False; - if (tvt < 0) { - tvt = -tvt; - volun = True; - } - if (!tvt || tvt >= 16) - continue; - } else { - if (++tvt >= 16) - break; - volun = True; + for (i = 0; serverVTs[i]; i++) { + tvt = atoi(serverVTs[i]); + if ((tvt >= 0) && (tvt < 16)) { + allowedVTs[tvt] = 1; + } else if (tvt > -16) { + allowedVTs[-tvt] = 2; } - for (cd = displays; cd; cd = cd->next) { - if (cd->reqSrvVT == tvt && /* protect from lusers */ - (cd->status != zombie || cd->zstatus != DS_REMOVE)) - goto next; - if (cd->serverVT == tvt) { - if (cd->status != zombie || cd->zstatus == DS_REMOTE) - goto next; - if (!cd->follower) { - d->serverVT = -1; - cd->follower = d; - return; - } - } + } + + for (tvt = 15; allowedVTs[tvt] == 0; tvt--) { + allowedVTs[tvt] = 2; + } + + for (cd = displays; cd; cd = cd->next) { + if (cd->status != zombie) { + if (cd->reqSrvVT >= 0) allowedVTs[cd->reqSrvVT] = 0; + if (cd->serverVT >= 0) allowedVTs[cd->serverVT] = 0; + } else if (cd->zstatus == DS_REMOTE) { + /* dying, but will spawn new server for remote login */ + if (cd->serverVT >= 0) allowedVTs[cd->serverVT] = 0; + } else if (cd->zstatus != DS_REMOVE) { + /* dying, but will be restarted or reserved */ + if (cd->reqSrvVT >= 0) allowedVTs[cd->reqSrvVT] = 0; } - if (!volun || !((1 << tvt) & getBusyVTs())) { - d->serverVT = tvt; + } + } + + /* check for plymouth using newer methods */ + d->plymouth_vt = -1; + if (plymouth_is_running ()) { + if (plymouth_has_active_vt ()) { + int vt = get_active_vt (); + if (allowedVTs[vt]) { + logWarn ("plymouth is active on VT %d, reusing for %s\n", vt, d->name); + d->serverVT = vt; + d->plymouth_vt = vt; return; } - next: ; + } + /* fallback to old/deprecated method */ + } else if ( triggered_to_force_display_on_active_vt() >= 0 ) { + int vt = get_active_vt (); + if (allowedVTs[vt]) { + d->serverVT = vt; + return; + } + } + + for (tvt = 0; tvt < 16; tvt++) { + if ((allowedVTs[tvt] == 1) || + ((allowedVTs[tvt] == 2) && !((1 << tvt) & getBusyVTs()))) { + d->serverVT = tvt; + return; } } + + for (cd = displays; cd; cd = cd->next) { + if ((cd->status == zombie) && (cd->zstatus != DS_REMOTE) && + (cd->follower == 0) && (cd->reqSrvVT != cd->serverVT)) { + /* removed; or restarted/reserved on any VT */ + d->serverVT = -1; + cd->follower = d; + return; + } + } + } +} + +static void +replacePlymouth(void) +{ + struct display *cd; + + /* if one display reuses plymouth' VT, plymouth is stopped in the + * startServerSuccess/Failed callback (see server.c). In any other + * case plymouth is stopped now. + */ + for (cd = displays; cd; cd = cd->next) { + if ((cd->serverVT > 0) && (cd->serverVT == cd->plymouth_vt)) { + if (cd->status == notRunning) { + /* tell plymouth to quit when server has started */ + logWarn ("plymouth should quit after server startup\n"); + plymouth_prepare_for_transition (); + kickDisplay(cd); + return; + } else if (cd->status == running) { + /* replacing server is starting up, do nothing */ + return; + } + } + } + + if ( plymouth_is_running ()) { + plymouth_prepare_for_transition (); + plymouth_quit_without_transition (); } } #endif @@ -1407,6 +1560,7 @@ startDisplays(void) #ifdef HAVE_VTS activeVTs = -1; forEachDisplayRev(allocateVT); + replacePlymouth(); #endif forEachDisplay(kickDisplay); } diff --git a/kdm/backend/dm.h b/kdm/backend/dm.h index 64e106b..930af0e 100644 --- a/kdm/backend/dm.h +++ b/kdm/backend/dm.h @@ -304,6 +304,8 @@ struct display { int authNum; /* number of authorizations */ char *authFile; /* file to store authorization in */ char *greeterAuthFile; /* file to store authorization for greeter in */ + + int plymouth_vt; /* Plymouth's VT nr */ }; #define d_location 1 @@ -428,6 +430,9 @@ int anyDisplaysLeft(void); void forEachDisplay(void (*f)(struct display *)); #ifdef HAVE_VTS void forEachDisplayRev(void (*f)(struct display *)); +/* function for plymouth */ +int plymouth_quit_with_transition (void); +int plymouth_quit_without_transition (void); #endif void removeDisplay(struct display *old); struct display diff --git a/kdm/backend/server.c b/kdm/backend/server.c index d8dd6f3..8b4708e 100644 --- a/kdm/backend/server.c +++ b/kdm/backend/server.c @@ -80,6 +80,7 @@ startServerOnce(void) char **argv; debug("startServerOnce for %s, try %d\n", d->name, ++d->startTries); + d->serverStatus = starting; switch (Fork(&d->serverPid)) { case 0: @@ -137,6 +138,12 @@ startServerSuccess() struct display *d = startingServer; d->serverStatus = ignore; serverTimeout = TO_INF; + if ((d->serverVT > 0) && (d->serverVT == d->plymouth_vt)) { + int plymouth_running; + logWarn ("Quitting Plymouth with transition\n" ); + plymouth_running = !plymouth_quit_with_transition (); + logWarn ("Is Plymouth still running? %s\n", plymouth_running ? "yes" : "no"); + } debug("X server ready, starting session\n"); startDisplayP2(d); } @@ -154,6 +161,10 @@ startServerFailed() startingServer = 0; logError("X server for display %s cannot be started," " session disabled\n", d->name); + if ((d->serverVT > 0) && (d->serverVT == d->plymouth_vt)) { + logWarn ("Quitting Plymouth without transition\n" ); + plymouth_quit_without_transition (); + } stopDisplay(d); } }