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);
}
}