/* This is mostly mingetty without printf */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "fmt.h" static struct utsname uts; static char hn[MAXHOSTNAMELEN + 6]="HOST="; static int hn_len=5; static time_t cur_time; static char *tty; static int noclear=0; void whine(const char* message) { write(2,message,strlen(message)); } void error(char *message,int exitcode) { whine(message); exit(exitcode); } static void echo_off() { struct termios foo; if (!tcgetattr(0,&foo)) { foo.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); tcsetattr(0, TCSANOW, &foo); } } int doutmp() { off_t curpos; struct utmp ut; pid_t mypid=getpid(); int fd=open(_PATH_UTMP,O_RDWR); if (fd) { for (;;) { int len; curpos=lseek(fd,0,SEEK_CUR); len=read(fd,&ut,sizeof(ut)); if (len!=sizeof(ut)) break; if (ut.ut_pid==mypid || !strcmp(ut.ut_line,tty+5)) { /* write(1,"found my utmp record\n",21); */ break; } } if (ut.ut_pid!=mypid) { memset(&ut,0,sizeof(ut)); ut.ut_pid=mypid; memcpy(ut.ut_id,tty+3,sizeof(ut.ut_id)); } memcpy(ut.ut_user,"LOGIN",6); memcpy(ut.ut_line,tty+5,sizeof(ut.ut_line)); ut.ut_tv.tv_sec=cur_time; ut.ut_type=LOGIN_PROCESS; lseek(fd,curpos,SEEK_SET); write(fd,&ut,sizeof(ut)); close(fd); } if ((fd=open(_PATH_WTMP,O_APPEND|O_WRONLY))>=0) { write(fd,&ut,sizeof(ut)); close(fd); } } void sigquit_handler(int signum) { error("SIGQUIT received\n",23); } void open_tty() { struct sigaction sa; int fd; if (chown(tty,0,0) || chmod(tty,0600)) 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); setsid(); if ((fd=open(tty, O_RDWR, 0))<0) error("fgetty: could not open tty device\n",3); if (!isatty(fd)) 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("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) write(0,"\033c",2); /* linux specific */ sa.sa_handler=SIG_DFL; sa.sa_flags=0; sigemptyset(&sa.sa_mask); sigaction(SIGHUP,&sa,NULL); } void output_special_char(char c) { switch (c) { case 's': write(1,uts.sysname,strlen(uts.sysname)); break; case 'n': write(1,uts.nodename,strlen(uts.nodename)); break; case 'r': write(1,uts.release,strlen(uts.release)); break; case 'v': write(1,uts.version,strlen(uts.version)); break; case 'm': write(1,uts.machine,strlen(uts.machine)); break; case 'o': write(1,uts.domainname,strlen(uts.domainname)); break; case 't': case 'd': { time_t now; struct tm *tm; char buf[30]; char *tmp; time (&now); tm = localtime (&now); if (c == 'd') { tmp=buf+fmt_ulong(buf,tm->tm_year+1900); *tmp++='-'; tm->tm_mon++; *tmp++=tm->tm_mon/10+'0'; *tmp++=tm->tm_mon%10+'0'; *tmp++='-'; *tmp++=tm->tm_mday/10+'0'; *tmp++=tm->tm_mday%10+'0'; *tmp++=0; write(1,buf,strlen(buf)); #if 0 /* ISO 8601 */ printf ("%d-%02d-%02d", tm->tm_year, tm->tm_mon+1, tm->tm_mday); #endif } else { buf[0]=tm->tm_hour/10+'0'; buf[1]=tm->tm_hour%10+'0'; buf[2]=':'; buf[3]=tm->tm_min/10+'0'; buf[4]=tm->tm_min%10+'0'; buf[5]=':'; buf[6]=tm->tm_sec/10+'0'; buf[7]=tm->tm_sec%10+'0'; write(1,buf,8); } #if 0 tmp=buf; printf ("%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); #endif break; } case 'l': write(1,tty+5,strlen(tty)-5); break; case 'u': case 'U': { int users=0; struct utmp ut; int fd=open(_PATH_UTMP,O_RDWR); char buf[20]; if (fd) { for (;;) { int len; len=read(fd,&ut,sizeof(ut)); if (len!=sizeof(ut)) break; if (ut.ut_type == USER_PROCESS) users++; } close(fd); } write(1,buf,fmt_ulong(buf,users)); if (c=='U') { if (users==1) write(1," user",5); else write(1," users",6); } } break; default: write(1,&c,1); } } void do_prompt() { int fd=open("/etc/issue",O_RDONLY); char *buf; off_t length; write(1,"\n",1); if (fd) { char *c,*last; length=lseek(fd,0,SEEK_END); lseek(fd,0,SEEK_SET); buf=alloca(length+1); read(fd,buf,length); close(fd); last=buf+length; for (c=buf; c='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || (c=='_' || c=='.' || c==',' || c=='-')); } char *get_logname() { static char logname[40]; char *c; ioctl(0, TCFLSH, 0); /* flush pending input */ for (*logname=0; *logname==0; ) { do_prompt(); for (c=logname;;) { if (read(0,c,1)<1) { if (errno==EINTR || errno==EIO || errno==ENOENT) exit(0); error("received strange error\n",9); } if (*c == '\n' || *c == '\r') { *c=0; break; } 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); else c++; } } #if 0 write(1,"\n\ngot name ",11); write(1,logname,strlen(logname)); write(1,"\n\n",2); #endif return logname; } extern char ** environ; char ttybuf[20]="/dev/"; char ttybuf2[25]="TTY="; int main(int argc,char *argv[]) { char *loginargv[]={"/bin/login", "--", 0, 0}; char *logname; 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 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); uname(&uts); if (gethostname(hn+5, MAXHOSTNAMELEN)!=0) hn[5]=0; hn[5+MAXHOSTNAMELEN]=0; putenv("TERM=linux"); putenv(ttybuf2); putenv(hn); time(&cur_time); for (i=2; i