diff -urNxCVS -xdebian ../../fgetty/CHANGES ./CHANGES
--- ../../fgetty/CHANGES	2004-02-16 10:07:34.000000000 +0000
+++ ./CHANGES	2004-11-17 13:33:22.000000000 +0000
@@ -1,8 +1,22 @@
+0.7:
+  You can now run fgetty as "fgetty 1" and it will try "/dev/vc/1" and
+    "/dev/tty1" before giving up.  That means, the same fgetty line can
+    be run with and without devfs.  Your boot sequence may fail but at
+    least you get a getty!
+  call setsid in case your init does not do it. Minit and sysvinit do.
+    Now you can run fgetty under runit, and maybe even directly from
+    the console.  Patch by John Palkovic.
+  checkpassword now gives an error message if stdout is a TTY.
+  fgetty now works (a little) if it can't set the controlling TTY.
+  checkpassword now also accepts an empty password if the password
+    field in /etc/passwd or /etc/shadow is empty.
+  fix bug if someone left descriptors open in login.c (Florian Westphal)
+
 0.6:
   the utmp code was broken.  It only looked for the PID, not for the
     "line" (device).  So utmp grew needlessly.
   fixed make install
-  add man page from Tino Reichard
+  add man page from Tino Reichardt
   Enrico Scholz sent a patch that adds --long-hostname and adds error
     checking for gethostname when it is not \0-terminated.
 
diff -urNxCVS -xdebian ../../fgetty/Makefile ./Makefile
--- ../../fgetty/Makefile	2004-10-06 11:50:44.000000000 +0000
+++ ./Makefile	2003-12-05 16:47:51.000000000 +0000
@@ -13,22 +13,24 @@
 #	gcc -march=i386 -mcpu=i386 -pipe -Os -fomit-frame-pointer -I../dietlibc/include -c $^ -DTEST
 	$(DIET) $(CROSS)gcc -pipe -Os -fomit-frame-pointer -I../dietlibc/include -c $^ -DTEST
 #	gcc -march=i386 -mcpu=i386 -pipe -g -I../dietlibc/include -DTEST -c $^
-	strip -x -R .comment -R .note $@
+	$(CROSS)strip -x -R .comment -R .note $@
 
 %: %.o
-	$(DIET) $(CROSS)gcc -nostdlib -o $@ $^ $(LDFLAGS)
+	$(DIET) $(CROSS)gcc -o $@ $^ $(LDFLAGS)
 
 fgetty: fgetty.o fmt_ulong.o
 
 login: login.o
 login2: login2.o
 checkpassword: checkpassword.o
+checkpassword-pam: checkpassword-pam.o checkpassword-pam2.o
+	$(CROSS)gcc -o $@ $^ -lmisc $(LDFLAGS)
 
 debug: fgetty.c fmt_ulong.o
 	gcc -g -o debug fgetty.c fmt_ulong.o -DDEBUG
 
 install:
-	install -d $(DESTDIR)/bin $(DESTDIR)/sbin
+	install -d $(DESTDIR)/bin $(DESTDIR)/sbin $(DESTDIR)/usr/man/man8
 	install login $(DESTDIR)/bin/login1
 	install login2 $(DESTDIR)/bin
 	install fgetty $(DESTDIR)/sbin
@@ -46,7 +48,7 @@
 %.sig: %
 	gpg --detach-sign $<
 
-VERSION=fgetty-$(shell head -1 CHANGES|sed 's/://')
+VERSION=fgetty-$(shell head -n 1 CHANGES|sed 's/://')
 CURNAME=$(notdir $(shell pwd))
 
 tar: clean rename
diff -urNxCVS -xdebian ../../fgetty/README.PAM ./README.PAM
--- ../../fgetty/README.PAM	1970-01-01 00:00:00.000000000 +0000
+++ ./README.PAM	2006-11-13 14:31:37.000000000 +0000
@@ -0,0 +1,28 @@
+I received an email and a patch on Sep 15 2002.  I incorporated the
+patch, here is the email.
+
+  From: <kromJx@crosswinds.net>
+  To: <web@fefe.de>
+  Subject: fgetty-0.6: a checkpassword with PAM support
+
+  Hi Felix,
+
+  I put together a checkpassword-pam program. I understand that
+  you don't like PAM, but nevertheless it could be useful to
+  someone else besides me. It is based on your checkpassword program
+  and the routines found in support-pam.c of the checkpassword-pam-0.95
+  program.
+
+  Feel free to edit/distribute/(or even ignore it)   :-)
+
+  Thanks for writing/sharing such great non-bloated tools.
+
+  - J
+
+To build it, say
+
+  $ make checkpassword-pam
+
+Please note that you can't link checkpassword-pam with the diet libc,
+and I could not test the patch because I don't have PAM installed on any
+box.
diff -urNxCVS -xdebian ../../fgetty/checkpassword-pam.c ./checkpassword-pam.c
--- ../../fgetty/checkpassword-pam.c	1970-01-01 00:00:00.000000000 +0000
+++ ./checkpassword-pam.c	2006-11-13 14:31:37.000000000 +0000
@@ -0,0 +1,74 @@
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+extern char** environ;
+
+unsigned int fmt_ulong(char *dest,unsigned long i) {
+  register unsigned long len,tmp,len2;
+  /* first count the number of bytes needed */
+  for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
+  if (dest)
+    for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
+      *--dest = (tmp%10)+'0';
+  return len;
+}
+
+int main(int argc,char* argv[]) {
+  char buf[513];
+  char* last;
+  int len;
+  char *login,*ptr;
+  struct passwd *pw;
+
+  if (!argv[1]) return 2;
+  for (len=0; len<512; ) {
+    int tmp;
+    tmp=read(3,buf+len,512-len);
+    if (tmp==-1) return 111;
+    if (tmp==0) break;
+    len+=tmp;
+  }
+  close(3);
+  buf[len]=0; last=buf+len;
+  login=buf;
+  if ((pw=getpwnam(login))) {
+    ptr=login+strlen(login)+1;
+    if (!authenticate_using_pam("login", login, ptr)) {
+      char **env,**ep, *eptty;
+      char buf[100];
+      for (len=0; environ[len]; ++len) ;
+      env=alloca((len+4)*sizeof(char*));
+      ep=env;
+      for (len=0; environ[len]; ++len) {
+	if (!strncmp(environ[len],"USER=",5)) continue;
+	if (!strncmp(environ[len],"HOME=",5)) continue;
+	if (!strncmp(environ[len],"SHELL=",6)) continue;
+	if (!strncmp(environ[len],"UID=",4)) continue;
+	*ep=environ[len]; ++ep;
+      }
+      *ep=alloca(strlen(pw->pw_shell)+7); strcat(strcpy(*ep,"SHELL="),pw->pw_shell); ++ep;
+      *ep=alloca(strlen(login)+6); strcat(strcpy(*ep,"USER="),login); ++ep;
+      *ep=alloca(strlen(pw->pw_dir)+7); strcat(strcpy(*ep,"HOME="),pw->pw_dir); ++ep;
+      strcpy(buf,"UID=");
+      buf[4+fmt_ulong(buf+4,pw->pw_uid)]=0;
+      *ep=buf; ++ep;
+      *ep=0;
+
+      ptr+=strlen(ptr)+1;	/* skip password */
+
+      if (initgroups(pw->pw_name,pw->pw_gid)==-1) return 1;
+/*      if (setgroups(1,&pw->pw_gid)==-1) return 1; */
+      if (setgid(pw->pw_gid)==-1) return 1;
+      if (ptr) {
+	ptr+=strlen(ptr)+1;		/* skip timestamp */
+	if (ptr>=last) ptr=0;
+      }
+      if (!ptr || strcmp(ptr,"nosetuid")) if (setuid(pw->pw_uid)==-1) return -1;
+      if (chdir(pw->pw_dir)==-1) return 111;
+      execve(argv[1],argv+1,env);
+      return 111;
+    }
+  }
+  return 1;
+}
diff -urNxCVS -xdebian ../../fgetty/checkpassword-pam2.c ./checkpassword-pam2.c
--- ../../fgetty/checkpassword-pam2.c	1970-01-01 00:00:00.000000000 +0000
+++ ./checkpassword-pam2.c	2006-11-13 14:31:37.000000000 +0000
@@ -0,0 +1,131 @@
+/*
+   PAM support for a fgetty-style checkpasswd
+
+   This file is a (slightly modified) concatenation of the files
+   pam-support.[ch] that come with Alexey Mahotkin's fine
+   "checkpassword-pam".  Only the essential stuff has been kept, ie. 
+   only what is needed to build a "checkpassword" compatible with the
+   one that is distributed with "fgetty".
+
+   Thanks, Alexey!
+*/
+/* 
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Copyright (c) Alexey Mahotkin <alexm@hsys.msk.ru> 2002
+
+   PAM support for checkpassword-pam
+
+*/
+#include <string.h>
+#include <security/pam_appl.h>
+
+static const char* global_password;
+
+static int
+conversation (int num_msg, const struct pam_message **msgs,
+	      struct pam_response **resp, void *appdata_ptr)
+{
+    int i;
+    struct pam_response* responses;
+    (void) appdata_ptr;
+
+    /* safety check */
+    if (num_msg <= 0) {
+	return PAM_CONV_ERR;
+    }
+
+    /* allocate array of responses */
+    responses =  calloc(num_msg, sizeof(struct pam_response));
+    if (!responses) {
+	return PAM_CONV_ERR;
+    }
+
+    for (i = 0; i < num_msg; i++) {
+	const struct pam_message *msg = msgs[i];
+	struct pam_response* response = &(responses[i]);
+	char* style = NULL;
+	switch (msg->msg_style) {
+	case PAM_PROMPT_ECHO_OFF: style = "PAM_PROMPT_ECHO_OFF"; break;
+	case PAM_PROMPT_ECHO_ON: style = "PAM_PROMPT_ECHO_ON"; break;
+	case PAM_ERROR_MSG: style = "PAM_ERROR_MSG"; break;
+	case PAM_TEXT_INFO: style = "PAM_TEXT_INFO"; break;
+	}
+
+	switch (msg->msg_style) {
+	case PAM_PROMPT_ECHO_OFF:
+	    /* reply with password */
+	    response->resp = strdup(global_password);
+	    if (!response->resp)
+		return PAM_CONV_ERR;
+	    break;
+
+	default:
+	    return PAM_CONV_ERR;
+	}
+	response->resp_retcode = 0;
+    }
+
+    *resp = responses;
+
+    return PAM_SUCCESS;
+}
+
+
+   
+int
+authenticate_using_pam (const char* service_name,
+			const char* username,
+			const char* password)
+{
+    struct pam_conv pam_conversation = { conversation, NULL };
+    pam_handle_t* pamh;
+    int retval;
+
+    /* to be used later from conversation() */
+    global_password = password;
+
+    /* initialize the PAM library */
+    retval = pam_start(service_name, username, &pam_conversation, &pamh);
+    if (retval != PAM_SUCCESS) {
+	return 111;
+    }
+
+    /* PAM_TTY is needed by the securetty module */
+    retval = pam_set_item(pamh, PAM_TTY, (void *)getenv("TTY"));
+    if (retval != PAM_SUCCESS) {
+	return 1;
+    }
+
+    /* Authenticate the user */
+    retval = pam_authenticate(pamh, 0);
+    if (retval != PAM_SUCCESS) {
+	return 1;
+    }
+
+    retval = pam_acct_mgmt(pamh, 0);
+    if (retval != PAM_SUCCESS) {
+	return 1;
+    }
+
+    retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+    if (retval != PAM_SUCCESS) {
+	return 1;
+    }
+    
+    /* terminate the PAM library */
+    retval = pam_end(pamh, retval);
+    if (retval != PAM_SUCCESS) {
+	return 1;
+    }
+
+    return 0;
+}
diff -urNxCVS -xdebian ../../fgetty/checkpassword.c ./checkpassword.c
--- ../../fgetty/checkpassword.c	2004-10-06 11:50:44.000000000 +0000
+++ ./checkpassword.c	2004-03-26 13:40:49.000000000 +0000
@@ -2,6 +2,14 @@
 #include <unistd.h>
 #include <pwd.h>
 #include <shadow.h>
+#include <stdio.h>
+#ifdef __dietlibc__
+#include <write12.h>
+#else
+inline void __write2(const char* message) {
+  write(2,message,strlen(message));
+}
+#endif
 
 extern char** environ;
 
@@ -38,7 +46,8 @@
     passwd=pw->pw_passwd;
     if ((spw=getspnam(login)))
       passwd=spw->sp_pwdp;
-    if (*passwd && !strcmp(crypt(ptr=login+strlen(login)+1,passwd),passwd)) {
+    ptr=login+strlen(login)+1;
+    if (!*passwd || !strcmp(crypt(ptr,passwd),passwd)) {
       char **env,**ep;
       char buf[100];
       for (len=0; environ[len]; ++len) ;
@@ -74,5 +83,9 @@
       return 111;
     }
   }
+  if (isatty(0) && isatty(1)) {
+    __write2("checkpassword: wrong password.\n");
+    sleep(5);
+  }
   return 1;
 }
diff -urNxCVS -xdebian ../../fgetty/fgetty.c ./fgetty.c
--- ../../fgetty/fgetty.c	2006-11-13 14:31:07.000000000 +0000
+++ ./fgetty.c	2005-10-04 11:45:26.000000000 +0000
@@ -10,6 +10,7 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 #include <termios.h>
+#include <stdlib.h>
 
 #include "fmt.h"
 
@@ -21,8 +22,12 @@
 
 static int noclear=0;
 
-void error(char *message,int exitcode) {
+void whine(const char* message) {
   write(2,message,strlen(message));
+}
+
+void error(char *message,int exitcode) {
+  whine(message);
   exit(exitcode);
 }
 
@@ -77,22 +82,26 @@
   struct sigaction sa;
   int fd;
   if (chown(tty,0,0) || chmod(tty,0600))
-    error("could not chown/chmod tty device\n",1);
+    error("fgetty: could not chown/chmod tty device\n",1);
   sa.sa_handler=SIG_IGN;
   sa.sa_flags=0;
   sigemptyset(&sa.sa_mask);
   sigaction(SIGHUP,&sa,NULL);
   sa.sa_handler=sigquit_handler;
   sigaction(SIGQUIT,&sa,NULL);
-  if ((fd=open(tty, O_RDWR, 0))<0 || ioctl (fd, TIOCSCTTY, (void *)1)==-1)
-    error("could not open tty device\n",3);
+  setsid();
+  if ((fd=open(tty, O_RDWR, 0))<0)
+    error("fgetty: could not open tty device\n",3);
   if (!isatty(fd))
-    error("\"not a typewriter\" ;-)\n",4);
-  if (vhangup())	/* linux specific */
-    error("vhangup failed\n",5);
+    error("fgetty: \"not a typewriter\" ;-)\n",4);
+  if (ioctl (fd, TIOCSCTTY, (void *)1)==0) {
+    if (vhangup())	/* linux specific */
+      error("fgetty: vhangup failed\n",5);
+  } else
+    whine("fgetty: warning: could not set controlling tty!\n");
   close(2); close(1); close(0); close(fd);
   if (open(tty,O_RDWR,0) != 0)
-    error("could not open tty\n",6);
+    error("fgetty: could not open tty\n",6);
   if (dup(0) != 1 || dup(0) != 2)
     error("could not dup stdout and stderr\n",7);
   if (!noclear)
@@ -211,7 +220,7 @@
   write(1," login: ",8);
 }
 
-static inline int isprint(char c) {
+static inline int _isprint(char c) {
   return ((c>='A' && c<='Z') ||
           (c>='a' && c<='z') ||
           (c>='0' && c<='9') ||
@@ -233,7 +242,7 @@
       if (*c == '\n' || *c == '\r') {
 	*c=0;
 	break;
-      } else if (!isprint(*c))
+      } else if (!_isprint(*c))
 	error("unprintable character in login name\n",10);
       else if (c-logname >= sizeof(logname)-1)
 	error("login name too long\n",11);
@@ -260,9 +269,20 @@
   int  i;
   char hostname_end='.';
   tty=argv[1];
+  if (!tty)
+    error("usage: fgetty 1\n"
+	  "       fgetty vc/1\n"
+	  "       fgetty /dev/tty1\n",111);
   if (tty[0]=='/')
     strncpy(ttybuf,tty,15);
-  else
+  else if (isdigit(tty[0])) {
+    struct stat ss;
+    /* try prepending /dev/vc/1 and /dev/tty1 */
+    strcpy(ttybuf,"/dev/vc/"); strncpy(ttybuf+8,tty,3);
+    if (stat(ttybuf,&ss) && errno==ENOENT) {
+      ttybuf[5]=ttybuf[6]='t'; ttybuf[7]='y';
+    }
+  } else
     strncpy(ttybuf+5,tty,10);
   tty=ttybuf;
   strcpy(ttybuf2+4,ttybuf);
diff -urNxCVS -xdebian ../../fgetty/login.c ./login.c
--- ../../fgetty/login.c	2004-09-09 10:09:41.000000000 +0000
+++ ./login.c	2004-11-17 13:33:23.000000000 +0000
@@ -35,10 +35,10 @@
 #include <utmp.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <write12.h>
 
 void die(const char *message) {
-  write(2,message,strlen(message));
-  write(2,"\n",1);
+  __write2(message); __write2("\n");
   exit(1);
 }
 
@@ -82,7 +82,7 @@
       write(0,host,len+1);
       host[len]=0;
     }
-    write(0,"login: ",7);
+    __write1("login: ");
     pwlen=read(0,__username,9);
     if (pwlen<0) die("read failed");
     __username[pwlen-1]=0; /* skip newline */
@@ -92,14 +92,14 @@
     buf=alloca(strlen(username)+20);
     strcpy(buf,username);
     strcat(buf,"'s password: ");
-    write(1,buf,strlen(buf));
+    __write1(buf);
   }
   echo_off();
   pwlen=read(0,password,99);
   if (pwlen<0) die("read failed");
   password[pwlen-1]=0;
   echo_on();
-  write(1,"\n",1);
+  __write1("\n");
 
   if (pipe(filedes))
     die("pipe failed");
@@ -132,10 +132,14 @@
   default:
     close(4);
     utmpfd=open(_PATH_UTMP,O_RDWR);
+    if (utmpfd==-1)  utmpfd=open("/dev/null",O_RDWR);
+    if (utmpfd>0 && utmpfd!=4) { dup2(utmpfd,4); close(utmpfd); utmpfd=4; };
     wtmpfd=open(_PATH_WTMP,O_APPEND|O_WRONLY);
+    if (wtmpfd==-1)  wtmpfd=open("/dev/null",O_WRONLY);
+    if (wtmpfd>0 && wtmpfd!=5) { dup2(wtmpfd,5); close(wtmpfd); wtmpfd=5; };
     if (utmpfd!=4 || wtmpfd!=5) {
       close(utmpfd); close(wtmpfd);
-      write(2,"utmpfd!=4 || wtmpfd!=5\n",24);
+      __write2("utmpfd!=4 || wtmpfd!=5\n");
     }
     execve(CHECKPASSWORD,Argv,environ);
     if (errno==ENOENT)
diff -urNxCVS -xdebian ../../fgetty/login2.c ./login2.c
--- ../../fgetty/login2.c	2004-02-16 10:07:34.000000000 +0000
+++ ./login2.c	2002-06-20 21:34:59.000000000 +0000
@@ -15,12 +15,12 @@
 #include <fcntl.h>
 #include <utmp.h>
 #include <grp.h>
+#include <write12.h>
 
 #include <sys/stat.h>
 
 void die(const char *message) {
-  write(2,message,strlen(message));
-  write(2,"\n",1);
+  __write2(message); __write2("\n");
   exit(1);
 }
 
@@ -74,7 +74,7 @@
         /* if it fails, too bad.  checkpassword should already have made
 	 * sure no additional groups are there */
       setuid(u);
-      if (u && getuid()!=u) return 2;
+      if (u && getuid()!=u) { die("getuid() != u!\n"); return 2; }
     } else return 2;
   }
   close(11);
