📄 tty.c
字号:
/* tty.c -- Magic C++ tty property setup (Mostly) portable public-domain implementation -- Copyright(C) 2003 Magicunix Infomation Technology Limited This file is part of magicd. magicd 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 of the License, or (at your option) any later version. For details, see the Magic C++ World-Wide-Web page, `http://www.magicunix.com', or send a mail to the Magic C++ developers <support@magicunix.com>. */#include <stdio.h>#include <stdlib.h>#include <string.h> #include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <signal.h>#include "tools.h"extern void d_zero(), d_copy();#ifdef HAVE_TERMIO_H#include <termio.h>#else#include <sys/ioctl.h>#endif /* HAVE_TERMIO_H */#ifdef HAVE_BSDTTY_H#include <sys/bsdtty.h>#ifndef TIOCNOTTY#define TIOCNOTTY _IO('t', 113) /* HP-UX void tty definition */#endif#endif /* HAVE_BSDTTY_H */#ifdef HAVE_SYS_IOCTL_COMPAT_H#include <sys/ioctl_compat.h>#endif /* NEED_COMPAT_H *//* * Pseudo-terminal routines for Unix System V Release 3.2 and BSD4.2-3 * I actually have three sets of routines, for three different methods * of obtaining a pseudo-tty. The first is for IRIX System V UNIX, * which uses _getpty() to obtain a pty. The second is for Solaris * 2.x which uses a clone open with some funky streams stuff to get * a pseudo-tty. The last is the brute-force method that works on * every thing else I have come across, including Sun/OS 4.x, AIX, * HP-UX, BSD 4.2-3, ULTRIX, and AT&T System V.3 */extern int errno; /*from magicd.c*/extern int debug; /*from magicd.c*/int master_fd;char tty_name[18];char pty_name[12];#ifdef IRIX /* IRIX System V for SGI machines */extern char *_getpty();int get_pty_master(){ char *ttyptr; if ( (ttyptr=_getpty(&master_fd, O_RDWR, 0600, 0)) == 0 ) return(-1); else strcpy(tty_name, ttyptr); return(master_fd);}/* * Open the slave half of a pseudo-terminal. */int get_pty_slave(){ int slave_fd; char *slavename; slavename=tty_name; if (slavename == NULL) { close(master_fd); return(-1); } if ( (slave_fd=open(slavename, O_RDWR, 0666)) < 0 ) /* open the slave */ { close(master_fd); return(-1); } return(slave_fd);}#else /* not IRIX */#ifdef SOLARIS /* Solaris 2.1 (UNIX System V r4) */#include <stropts.h>#define DEV_CLONE "/dev/ptmx"extern char *ptsname();int get_pty_master(){ char *ttyptr; if(debug) util_log("open master!\n"); if ( (master_fd=open(DEV_CLONE, O_RDWR, 0666)) < 0 ) { util_err_log("get_pty_master() failed on open!\n",__FILE__,__LINE__,errno ); return(-1); } if ( grantpt(master_fd) < 0 ) /* grant access to slave */ { util_err_log("get_pty_master() failed on grantpt!\n",__FILE__,__LINE__,errno ); close(master_fd); return(-1); } if ( unlockpt(master_fd) < 0 ) /* clear slave's lock flag */ { util_err_log("get_pty_master() failed on unlockpt!\n",__FILE__,__LINE__,errno ); close(master_fd); return(-1); } if ( (ttyptr=ptsname(master_fd)) == NULL ) { util_err_log("get_pty_master() failed on ptsname!\n",__FILE__,__LINE__,errno ); close(master_fd); return(-1); } else strcpy(tty_name, ttyptr); return(master_fd);}/* * Open the slave half of a pseudo-terminal. */int get_pty_slave(){ int slave_fd; char *slavename; slavename=tty_name; if ( (slave_fd=open(slavename, O_RDWR, 0666)) < 0 ) /* open the slave */ { close(master_fd); return(-1); } if ( ioctl(slave_fd, I_PUSH, "ptem") < 0 ) { close(master_fd); close(slave_fd); return(-1); } if ( ioctl(slave_fd, I_PUSH, "ldterm") < 0 ) { close(master_fd); close(slave_fd); return(-1); } if ( ioctl(slave_fd, I_PUSH, "ttcompat") < 0 ) { close(master_fd); close(slave_fd); return(-1); } return(slave_fd);}#else /* BSD, Sun/OS, AIX, ULTRIX, HP-UX, AT&T SYSV */#include <setjmp.h>#ifndef X_OK#define R_OK 4 /* Test for Read permission */#define W_OK 2 /* Test for Write permission */#define X_OK 1 /* Test for eXecute permission */#endif#define PTY_OWNER 0 /* the uid of the owner of pty's. usually bin or root */#define BIN_UID 2 /* Secondary pty owner */jmp_buf next;void trynext(){ longjmp(next, 2);}int get_pty_master(){ int i, master_fd; char *ptr; struct stat statbuff; static char ptychar[]="pqrst"; /* X */ static char hexdigit[]="0123456789abcdef"; /* Y */ for (ptr=ptychar; *ptr != 0; ptr++) { strcpy(pty_name, "/dev/ptyXY"); pty_name[8]=(*ptr); /* X */ pty_name[9]='0'; /* Y */ if ( stat(pty_name, &statbuff) < 0 ) break;#ifdef OLDDEBUG fprintf(stderr, "statted.\n");#endif i=(-1); /* Initialize i */ /*timeout checking*/ /* Set a time limit for the open */ /*if it's timeout ,back here*/ if ( setjmp(next) == -1 ) return(-1); signal(SIGALRM, trynext); for ( ++i; hexdigit[i]; ++i) { pty_name[5]='p'; pty_name[9]=hexdigit[i]; /*set timeout*/ alarm(2); /* Set an open timeout */ if ( (master_fd=open(pty_name, O_RDWR, 0666)) >= 0 ) { alarm(0); /* Reset the alarm */ pty_name[5]='t'; sprintf(tty_name, "%s", pty_name); if ( access(tty_name, R_OK|W_OK) == 0 ) { signal(SIGALRM, SIG_DFL); return (master_fd); } else { pty_name[5]='p'; (void) close(master_fd); } } /* reset the alarm */ alarm(0); } } util_err_log("Get master pty failed!\n",__FILE__,__LINE__,errno); return(-1);}/* Open the slave half of a pseudo-terminal. */int get_pty_slave(){ int slave_fd; if ( (slave_fd=open(tty_name, O_RDWR, 0666)) < 0 ) { util_err_log("Get slave pty failed!\n",__FILE__,__LINE__,errno); close(master_fd); return(-1); } return(slave_fd);}#endif /* is SOLARIS? */#endif /* is IRIX? */ /* The end of the Pseudo-tty routines *//* These are the terminal manipulation routines. :) Fun! */#ifdef SIGWINCH /* Starting window structure *//* I am using struct winsize here, but redefining it, because Each system seems to define it in a different place, or not at all. The actual structure never seems to change though. :) */struct winstats { unsigned short ws_row; /* rows, in characters */ unsigned short ws_col; /* columns, in characters */ unsigned short ws_xpixel; /* horizontal size, pixels - not used */ unsigned short ws_ypixel; /* vertical size, pixels - not used */ } tty_win;#ifdef NEED_UPDATEWIN /* Not used *//* The window size has changed, let the pty know. Used as a signal handler */void updatewin(){#ifdef TIOCGWINSZ (void) ioctl(ttyfd, TIOCGWINSZ, &tty_win); (void) ioctl(masterfd, TIOCSWINSZ, &tty_win);#endif /* TIOCGWINSZ */ /* An interesting note... I had code here to send a SIGWINCH to the pty process, but it turns out the kernel does when the pty recieves the TIOCSWINSZ ioctl. */}#endif /* NEED_UPDATEWIN */#endif /* SIGWINCH */ /* Code to disassociate from my tty. Yay! :) */void dropctty(){ int fd; #ifdef _POSIX_SOURCE setsid(); /* The POSIX solution is simple. :) */#else#ifdef TIOCNOTTY /* We want to get HP-UX, BSD, and Sun/OS here */ /*setpgrp(0, 0);*/ /*there are no args in sun and linux*/#ifdef FREEBSD setpgrp(0,0);#else setpgrp();#endif#if !defined( CIBAUD) && !defined(FREEBSD)/* Sun/OS doesn't need to do TIOCNOTTY. */ if ( (fd=open("/dev/tty", O_RDWR)) > (-1) ) { if (ioctl(fd, TIOCNOTTY, 0) < 0) { util_log("ioctl TIOCNOTTY error\n"); fprintf(stderr, "\r"); } close(fd); }#endif /* CIBAUD */#else /* SYSV */ setpgrp();#endif /* TIOCNOTTY */#endif /* _POSIX_SOURCE */}/* Just fork, and exit, leaving the child running as a daemon */void daemonize(){ switch (fork()) { case -1: perror("fork() failed"); exit(3); break; case 0: dropctty(); return; default: exit(0); }}#ifdef HAVE_TERMIO_H/* Get the modes of the contorlling tty and save them. Saves ttymodes in tty_mode and returns -1 if ioctl fails. */struct termio tty_mode; /* Save tty mode here */int tty_init=0;int tty_getmode(fd)int fd;{ /* If not a tty, don't set tty_init, but return ok */ if ( !isatty(fd) ) return(0); d_zero((char *)&tty_mode, sizeof(struct termio)); if (ioctl(fd, TCGETA, (char *) &tty_mode) < 0) return(-1); tty_init=1; /* Flag: we have initialized the tty_mode struct */#if defined(SIGWINCH) && defined(TIOCGWINSZ) d_zero((char *)&tty_win, sizeof(struct winstats)); (void) ioctl(fd, TIOCGWINSZ, &tty_win);#endif /* SIGWINCH */ return(0);}/* Restore terminal's mode to whatever it was on the most recent call to the tty_getmode() function. */int tty_reset(fd)int fd;{ if ( ! tty_init ) return(-1); if ( ! isatty(fd) ) return(0); if (ioctl(fd, TCSETA, (char *) &tty_mode) < 0) return(-1);#if defined(SIGWINCH) && defined(TIOCSWINSZ) (void) ioctl(fd, TIOCSWINSZ, &tty_win);#endif /* SIGWINCH */ return(0);}/* Set a tty to a sane mode */int tty_sane(fd)int fd;{#ifdef TIOCGWINSZ struct winstats temp_win;#endif struct termio temp_mode; if ( ! isatty(fd) ) return(0); if( debug ) fprintf(stderr, "tty_init: %d\r\n", tty_init); temp_mode.c_lflag=(ISIG|ICANON|ECHO|ECHOE); temp_mode.c_iflag=(BRKINT|IGNPAR|ISTRIP|ICRNL|IXON); temp_mode.c_oflag=(OPOST|ONLCR); temp_mode.c_cflag=(CS8|PARENB|CREAD); temp_mode.c_cc[VERASE]=('H'^64); temp_mode.c_cc[VKILL]=('U'^64); temp_mode.c_cc[VQUIT]=('\\'^64); temp_mode.c_cc[VINTR]=('C'^64); temp_mode.c_cc[VEOF]=('D'^64); temp_mode.c_cc[VMIN]=1; temp_mode.c_cc[VTIME]=0; if (ioctl(fd, TCSETA, (char *) &temp_mode) < 0) return(-1);#if defined(SIGWINCH) && defined(TIOCSWINSZ) d_zero((char *)&temp_win, sizeof(struct winstats)); temp_win.ws_row=24; temp_win.ws_col=80; (void) ioctl(fd, TIOCSWINSZ, &temp_win);#endif return(0);}/* Set a terminal in raw mode */int tty_raw(fd)int fd; /* file descriptor of tty device */{ struct termio temp_mode; if ( ! isatty(fd) ) return(0); if ( ioctl(fd, TCGETA, (char *)&temp_mode) < 0 ) return(-1); temp_mode.c_iflag=(IGNBRK | ISTRIP); /* turn off all input control */ temp_mode.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONLRET); /* disable output post-processing */ temp_mode.c_lflag = 0; temp_mode.c_cc[VMIN]=1; /* 1 or more chars satisfy read */ temp_mode.c_cc[VTIME]=0; /* 10'ths of seconds between chars */ if (ioctl(fd, TCSETA, (char *) &temp_mode) < 0) return(-1); return(0);}/* Function to set a tty echo or no echo */int tty_echo(fd, echo)int fd;int echo;{ struct termio temp_mode; if ( ! isatty(fd) ) return(0); if ( ioctl(fd, TCGETA, &temp_mode) < 0 ) return(-1); if ( echo ) temp_mode.c_lflag|=ECHO; else temp_mode.c_lflag&=(~ECHO); util_log("set echo!\n"); if ( ioctl(fd, TCSETA, &temp_mode) < 0 ) return(-1); return(0);}#else /* no /usr/include/termio.h *//* Get the modes of the controlling tty and save them. Saves ttymodes in tty_mode and returns 1 if ioctl fails. */static struct sgttyb tty_mode; /* save tty mode here */int tty_init=0;int tty_getmode(fd)int fd;{ if ( ! isatty(fd) ) return(0); tty_init=1; /* Flag: we have initialized the tty_mode struct */ if (ioctl(fd, TIOCGETP, (char *) &tty_mode) < 0) return(-1);#ifdef SIGWINCH if ( ioctl(fd, TIOCGWINSZ, &tty_win) < 0 ) perror("ioctl TIOCGWINSZ error");#endif /* SIGWINCH */ return(0);}/* * Restore a terminal's mode to whatever it was on the most * recent call to the tty_getmode() function above. */int tty_reset(fd)int fd; /* of terminal device */{ if ( ! tty_init ) /* Have we been initialized? */ return(-1); if ( ! isatty(fd) ) return(0); if (ioctl(fd, TIOCSETP, (char *) &tty_mode) < 0) return(-1);#ifdef SIGWINCH (void) ioctl(fd, TIOCSWINSZ, &tty_win);#endif /* SIGWINCH */ return(0);}/* Set a tty to a sane mode */int tty_sane(fd)int fd;{ struct sgttyb temp_mode; if ( ! isatty(fd) ) return(0); if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0) return(-1); temp_mode.sg_flags &= ~RAW; /* turn RAW mode off */ temp_mode.sg_flags |= ECHO; /* turn ECHO on */ if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0) return(-1); return(0);}/* * Put a terminal device into RAW mode with ECHO off. */int tty_raw(fd)int fd; /* of terminal device */{ struct sgttyb temp_mode; if ( ! isatty(fd) ) return(0); if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0) return(-1); temp_mode.sg_flags |= RAW; /* turn RAW mode on */ temp_mode.sg_flags &= ~ECHO; /* turn ECHO off */ if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0) return(-1); return(0);}/* Set a terminal echo or no echo, as requested. */int tty_echo(fd, echo)int fd;int echo;{ struct sgttyb temp_mode; if ( ! isatty(fd) ) return(0); if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0) return(-1); if ( echo ) temp_mode.sg_flags |= ECHO; /* turn ECHO on */ else temp_mode.sg_flags &= ~ECHO; /* turn ECHO off */ if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0) return(-1); return(0);}#endif /* HAVE_TERMIO_H *//* * Write "n" bytes to a descriptor. * Use in place of write() when fd is a stream socket. */int writen(fd, ptr, nbytes)register int fd;register char *ptr;register int nbytes;{ int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = write(fd, ptr, nleft); if (nwritten <= 0) return(nwritten); /* error */ nleft -= nwritten; ptr += nwritten; } return(nbytes - nleft);} /* Replacement for bzero(), which isn't always available. */void d_zero(data, size)char *data;int size;{ int i; for ( i=0; (i < size); ++i, ++data ) *data='\0';}/* Replacement for bcopy(), which isn't always available. */void d_copy(frombuf, tobuf, size)char *frombuf;char *tobuf;int size;{ int i; for ( i=0; (i < size); ++i, ++frombuf, ++tobuf ) *tobuf=(*frombuf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -