From: Modestas Vainius <modax@debian.org>
Subject: implement VT switching and status detection support in KDM on kFreeBSD
Forwarded: no
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=586540
Last-Update: 2010-10-24

This patch implements proper VT switching for KDM on kFreeBSD. It also includes
detection of the next available VT which should prevent KDM from taking over
vt2 on bootup and locking up keyboard/mouse input.

This revision of the patch is pretty hackish. What is more, it does not cover
FreeBSD (only kFreeBSD) while it could perfectly do so.
--- a/kdm/backend/dm.c
+++ b/kdm/backend/dm.c
@@ -48,7 +48,13 @@ from the copyright holder.
 
 #ifdef HAVE_VTS
 # include <sys/ioctl.h>
+#if defined(__linux__)
 # include <sys/vt.h>
+#elif defined(__FreeBSD_kernel__)
+# include <sys/consio.h>
+# include <sys/tty.h>
+# include <sys/sysctl.h>
+#endif
 #endif
 
 static void sigHandler( int n );
@@ -329,7 +335,12 @@ main( int argc, char **argv )
 int
 TTYtoVT( const char *tty )
 {
-	return memcmp( tty, "tty", 3 ) ? 0 : atoi( tty + 3 );
+	if (!memcmp( tty, "ttyv", 4 )) /* FreeBSD, tty no is in hex */
+		return (int) strtoul( tty+4, NULL, 16 );
+	else if (!memcmp( tty, "tty", 3 )) /* Linux */
+		return atoi( tty + 3 );
+	else
+		return 0;
 }
 
 int
@@ -1036,9 +1047,15 @@ reapChildren( void )
 					} else {
 						int con = open( "/dev/console", O_RDONLY );
 						if (con >= 0) {
+							int activevt;
+#if defined(__linux__)
 							struct vt_stat vtstat;
 							ioctl( con, VT_GETSTATE, &vtstat );
-							if (vtstat.v_active == d->serverVT) {
+							activevt = vtstat.v_active;
+#elif defined(__FreeBSD_kernel__)
+							ioctl( con, VT_GETACTIVE, &activevt);
+#endif
+							if (activevt == d->serverVT) {
 								int vt = 1;
 								struct display *di;
 								for (di = displays; di; di = di->next)
@@ -1051,7 +1068,9 @@ reapChildren( void )
 										vt = di->serverVT;
 								ioctl( con, VT_ACTIVATE, vt );
 							}
+#ifdef __linux__
 							ioctl( con, VT_DISALLOCATE, d->serverVT );
+#endif
 							close( con );
 						}
 					}
@@ -1327,16 +1346,41 @@ static int activeVTs;
 static int
 getBusyVTs( void )
 {
-	struct vt_stat vtstat;
-	int con;
-
 	if (activeVTs == -1) {
+#if defined(__linux__)
+		struct vt_stat vtstat;
+		int con;
+
 		vtstat.v_state = 0;
 		if ((con = open( "/dev/console", O_RDONLY )) >= 0) {
 			ioctl( con, VT_GETSTATE, &vtstat );
 			close( con );
 		}
 		activeVTs = vtstat.v_state;
+#elif defined(__FreeBSD_kernel__)
+		struct xtty *ttys;
+		size_t s, i, firstvt;
+		struct stat st;
+
+		activeVTs = 0;
+		firstvt = ~0;
+		/* We need rdev of the first tty */
+		if (stat("/dev/ttyv0", &st))
+			firstvt = 0; /* If stat fails, 0 should be safe default */
+
+		if (!sysctlbyname("kern.ttys", NULL, &s, NULL, 0)) {
+			ttys = (struct xtty *) malloc(s);
+			sysctlbyname("kern.ttys", ttys, &s, NULL, 0);
+			for (i = 0; (i < s / sizeof(struct xtty)) &&
+				    (i < sizeof(activeVTs) * 8); i++)
+			{
+				if (firstvt == ~0 && st.st_rdev == ttys[i].xt_dev)
+					firstvt = i;
+				if (i >= firstvt)
+					activeVTs |= !!(ttys[i].xt_flags & TF_OPENED) << (i - firstvt);
+			}
+		}
+#endif
 	}
 	return activeVTs;
 }
--- a/kdm/backend/greet.h
+++ b/kdm/backend/greet.h
@@ -53,7 +53,7 @@ from the copyright holder.
 # define USE_SYSLOG
 #endif
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD_kernel__)
 /* This needs to be run-time configurable, additionally. */
 # define HAVE_VTS
 #endif
--- a/kdm/backend/client.c
+++ b/kdm/backend/client.c
@@ -1301,7 +1301,11 @@ startClient( volatile int *pid )
 	
 # ifdef HAVE_VTS
 	if (td->serverVT > 0)
+# if defined(__linux__)
 		sprintf( ckDeviceBuf, "/dev/tty%d", td->serverVT );
+# elif defined(__FreeBSD_kernel__)
+		sprintf( ckDeviceBuf, "/dev/ttyv%x", td->serverVT );
+# endif
 # endif
 	isLocal = ((td->displayType & d_location) == dLocal);
 # ifdef XDMCP
--- a/kdm/kfrontend/genkdmconf.c
+++ b/kdm/kfrontend/genkdmconf.c
@@ -1483,7 +1483,8 @@ static void
 upd_servervts( Entry *ce, Section *cs ATTR_UNUSED )
 {
 	if (!ce->active) { /* there is only the Global one */
-#ifdef __linux__ /* XXX actually, sysvinit */
+/* XXX actually, sysvinit */
+#if defined(__linux__) || defined(__FreeBSD_kernel__)
 		getInitTab();
 		ASPrintf( (char **)&ce->value, "-%d", maxTTY + 1 );
 		ce->active = ce->written = True;
@@ -1495,14 +1496,19 @@ static void
 upd_consolettys( Entry *ce, Section *cs ATTR_UNUSED )
 {
 	if (!ce->active) { /* there is only the Global one */
-#ifdef __linux__ /* XXX actually, sysvinit */
+/* XXX actually, sysvinit */
+#if defined(__linux__) || defined(__FreeBSD_kernel__)
 		char *buf;
 		int i;
 
 		getInitTab();
 		for (i = 0, buf = 0; i < 16; i++)
 			if (TTYmask & (1 << i))
+#if defined(__linux__)
 				strCat( &buf, ",tty%d", i + 1 );
+#elif defined(__FreeBSD_kernel__)
+				strCat( &buf, ",ttyv%x", i );
+#endif
 		if (buf) {
 			ce->value = buf + 1;
 			ce->active = ce->written = True;
@@ -3072,7 +3078,7 @@ int main( int argc, char **argv )
 			}
 		}
 	}
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD_kernel__)
 	if (!stat( "/etc/debian_version", &st )) { /* debian */
 		defminuid = "1000";
 		defmaxuid = "29999";
--- a/kdm/config.def
+++ b/kdm/config.def
@@ -870,7 +870,7 @@ Description:
  This option is for operating systems (<acronym>OS</acronym>s) with support
  for virtual terminals (<acronym>VT</acronym>s), by both &kdm; and the
  <acronym>OS</acronym>s itself.
- Currently this applies only to Linux.
+ Currently this applies only to Linux and kFreeBSD.
  </para><para>
  When &kdm; switches to console mode, it starts monitoring all
  <acronym>TTY</acronym> lines listed here (without the leading
--- a/kdm/backend/util.c
+++ b/kdm/backend/util.c
@@ -53,6 +53,15 @@ from the copyright holder.
 # include <sys/utsname.h>
 #endif
 
+#ifdef HAVE_VTS
+#  include <sys/ioctl.h>
+#  if defined(__linux__)
+#    include <linux/vt.h>
+#  elif defined(__FreeBSD_kernel__)
+#    include <sys/consio.h>
+#  endif
+#endif
+
 void *
 Calloc( size_t nmemb, size_t size )
 {
@@ -621,6 +630,29 @@ hexToBinary( char *out, const char *in )
 
 #undef atox
 
+#ifdef HAVE_VTS
+/* Get next free VT. Works only on virtual terminal devices */
+static int
+getNextFreeVT( const char *tty )
+{
+	int fd, vt;
+	char *dev;
+
+	vt = -1;
+	dev = (char*) Malloc( strlen(tty) + 6 );
+	sprintf( dev, "/dev/%s", tty );
+
+	fd = open( dev, O_RDONLY );
+        if (fd >= 0) {
+                if (ioctl( fd, VT_OPENQRY, &vt ))
+			vt = -1;
+		close( fd );
+        }
+	free( dev );
+	return vt;
+}
+#endif
+
 /* X -from ip6-addr does not work here, so i don't know whether this is needed.
 #define IP6_MAGIC
 */
@@ -640,6 +672,10 @@ listSessions( int flags, struct display
 #else
 	STRUCTUTMP *ut;
 #endif
+#ifdef HAVE_VTS
+	int con_fvt;
+	con_fvt = -2;
+#endif
 
 	for (di = displays; di; di = di->next)
 		if (((flags & lstRemote) || (di->displayType & d_location) == dLocal) &&
@@ -671,12 +707,20 @@ listSessions( int flags, struct display
 				if (!(flags & lstRemote))
 					continue;
 			} else {
+				if (!*ut->ut_line)
+					continue;
 				/* hack around broken konsole which does not set ut_host. */
+#ifdef HAVE_VTS
+				if (con_fvt == -2)
+					con_fvt = getNextFreeVT("console");
+				if (con_fvt >= 0 && con_fvt != getNextFreeVT( ut->ut_line ))
+					continue;
+#else
 				/* this check is probably linux-specific. */
-				/* alternatively we could open the device and try VT_OPENQRY. */
 				if (memcmp( ut->ut_line, "tty", 3 ) ||
 				    !isdigit( ut->ut_line[3] ))
 					continue;
+#endif
 			}
 			if (strNChrCnt( ut->ut_line, sizeof(ut->ut_line), ':' ))
 				continue; /* x login */
