Code:
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ioctl.h>
#ifndef TIOCNOTTY
#include <termios.h>
#endif
static char pty_name[12];
int pty_master();
int pty_slave();
int reaper;
void handler(i)
int i;
{
if (i==
#ifdef SIGCHLD
SIGCHLD
#else
SIGCLD
#endif
)
{
/* reaper++;*/
}
}
int main(argc,argv)
int argc;
char **argv;
{
int master=-1;
int fd=-1;
int pid=-1;
int pipes[2];
pipe(pipes);
master=pty_master();
if (master < 0) return 1;
/* disconnect */
/* if (setpgrp(getpid(),getpid()) < 0)
{
perror("setpgrp");
return 1;
}
*/
/* if (setsid()==-1)
{
perror("setsid");
return 1;
}
*/
/* end disconnect */
/* if (ioctl(master,TIOCSCTTY,NULL))
{
perror("TIOCSCTTY master initial");
}
*/
pid=fork();
if (pid)
{
int status=0;
char buf[1];
/* master */
buf[0]=0;
close(pipes[1]);
read(pipes[0],buf,sizeof(buf));
close(pipes[0]);
if (buf[0]==0)
{
printf("child reported error\n");
return 1;
}
#ifdef SIGCHLD
signal(SIGCHLD,handler);
#else
signal(SIGCLD,handler);
#endif
while (!reaper)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(master,&fds);
FD_SET(0,&fds);
if (select(master+1,&fds,NULL,NULL,NULL) > 0)
{
if (FD_ISSET(master,&fds))
{
char buf[256];
int i=read(master,buf,sizeof(buf));
if (i > 0)
{
write(1,buf,i);
}
else
{
i=errno;
break;
}
}
if (FD_ISSET(0,&fds))
{
char buf[256];
int i=read(0,buf,sizeof(buf));
if (i > 0)
{
write(master,buf,i);
}
else
{
kill(pid,SIGHUP);
break;
}
}
}
}
printf("out of loop, reaper=%d\n",reaper);
kill(pid,SIGTERM);
}
else
{
/* child */
int slave;
/* signal(SIGHUP,handler);
signal(SIGTERM,handler);
signal(SIGINT,handler);
*/
fd=open("/dev/tty",O_RDWR);
if (fd >= 0)
{
if (ioctl(fd,TIOCNOTTY,(char *)0) < 0)
{
perror("TIOCNOTTY /dev/tty");
}
close(fd);
}
else
{
perror("/dev/tty");
}
if (setsid() < 0)
{
perror("setsid");
}
slave=pty_slave(master);
if (slave < 0)
{
perror("pty_slave");
return 1;
}
/* if (setsid()==-1)
{
perror("setsid(2)");
}
*/
if (ioctl(slave,TIOCSCTTY,NULL))
{
perror("slave TIOCSCTTY");
if (ioctl(master,TIOCSCTTY,NULL))
{
perror("master TIOCSCTTY");
}
}
{
pid_t grp=getpgrp();
if (ioctl(master,TIOCSPGRP,&grp))
{
perror("TIOCSPGRP master");
}
if (ioctl(slave,TIOCSPGRP,&grp))
{
perror("TIOCSPGRP slave");
}
}
if (dup2(slave,0)==-1) { perror("dup 0") ; return 1; }
if (dup2(slave,2)==-1) { perror("dup 2") ; return 1; }
if (dup2(slave,1)==-1) { perror("dup 1"); return 1; }
close(slave);
close(master);
printf("[%d] on %s\n",getpid(),ttyname(0));
fflush(stdout);
fd=open("/dev/tty",O_RDWR);
if (fd >= 0)
{
close(fd);
}
else
{
perror("open /dev/tty for TIOCSPGRP");
return 1;
}
write(pipes[1],"1",1);
close(pipes[0]);
close(pipes[1]);
if (argc==1)
{
char *argv2[2];
char *p=getenv("SHELL");
if (!p) p="/bin/sh";
argv2[0]=p;
argv2[1]=NULL;
execvp(p,argv2);
printf("exec(%s) failed\n",p);
return 1;
}
else
{
execvp(argv[1],argv+1);
printf("exec(%s) failed\n",argv[1]);
return 1;
}
}
return 0;
}
int pty_master()
{
int i,master_fd=-1;
char *ptr;
struct stat statbuff;
static char ptychar[]="pqrs";
static char hexdigit[]="0123456789abcdef";
for (ptr=ptychar; *ptr!=0; ptr++)
{
strcpy(pty_name,"/dev/ptyXY");
pty_name[8]=*ptr;
pty_name[9]='0';
if (stat(pty_name,&statbuff) < 0) break;
for (i=0;i<16;i++)
{
pty_name[9]=hexdigit[i];
if ((master_fd=open(pty_name,O_RDWR))>=0)
{
return master_fd;
}
}
}
return master_fd;
}
int pty_slave(master_fd)
int master_fd;
{
int slave_fd=-1;
pty_name[5]='t';
printf("pty_slave(%s)\n",pty_name);
if ((slave_fd=open(pty_name,O_RDWR))<0)
{
close(master_fd);
return -1;
}
return slave_fd;
}