int login_tty(int fd) { pid_t s; s = setsid(); if (s == -1) s = getsid(0); if (tcsetsid(fd, s) == -1) return (-1); (void) dup2(fd, 0); (void) dup2(fd, 1); (void) dup2(fd, 2); if (fd > 2) (void) close(fd); return (0); }
int ioctl(int fd, int cmd, ...) { va_list vl; void *data; struct termios ltermios; #ifdef NOT_USED struct termios *ptermios; struct termio ltermio; #endif struct termio *ptermio; int match, tempint; //Pull out the command and the data va_start(vl, cmd); data = va_arg(vl, void *); va_end(vl); /* These calls have significantly different inputs or outputs that we have to manipulate (or re-direct entirely) */ switch ((unsigned)cmd) { /**** These calls map to fcntl's ****/ //Set/Clear FD_CLOEXEC state case FIOCLEX: return(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)); case FIONCLEX: return(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC)); //These are undoced uses for fcntl case SIOCGPGRP: case FIOGETOWN: if ( (tempint = fcntl (fd, F_GETOWN)) != -1) *(int *)data = tempint; return(tempint); case SIOCSPGRP: case FIOSETOWN: return(fcntl(fd, F_SETOWN, *(int *)data)); //Set the non-blocking state for reads on and off case FIONBIO: if (*(int *)data) return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)); else return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK)); //Set the async state on and off case FIOASYNC: if (*(int *)data) return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC)); else return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC)); //Set/Clear exclusive mode case TIOCEXCL: { struct flock lflock; memset(&lflock, 0, sizeof(lflock)); lflock.l_type = F_WRLCK; //Fails if file opened read only? lflock.l_whence = SEEK_SET; lflock.l_start = 0; lflock.l_len = 0; lflock.l_pid = getpid(); return(__fcntl2ioctl(fcntl(fd, F_SETLK, &lflock))); } case TIOCNXCL: { struct flock lflock; memset(&lflock, 0, sizeof(lflock)); lflock.l_type = F_UNLCK; lflock.l_whence = SEEK_SET; lflock.l_start = 0; lflock.l_len = 0; lflock.l_pid = getpid(); (void)fcntl(fd, F_GETLK, &lflock); return(__fcntl2ioctl(fcntl(fd, F_SETLK, &lflock))); } //Make the terminal the controlling terminal for the process case TIOCSCTTY: return(tcsetsid(fd, getpid())); //Dis-associate this terminal as the controlling terminal case TIOCNOTTY: return(tcsetsid(-1, getpid())); /**** These calls translate from one type to another using tc[s|g]etattr ****/ //Terminal properties w/ termio case TCGETA: { ptermio = (struct termio *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termios2termio(<ermios, ptermio); return(EOK); } case TCSETA: { ptermio = (struct termio *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termio2termios(ptermio, <ermios); return(tcsetattr(fd, TCSANOW, <ermios)); } case TCSETAW: { ptermio = (struct termio *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termio2termios(ptermio, <ermios); return(tcsetattr(fd, TCSADRAIN, <ermios)); } case TCSETAF: { ptermio = (struct termio *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termio2termios(ptermio, <ermios); return(tcsetattr(fd, TCSAFLUSH, <ermios)); } //Set terminal state in an sgttyb structure (incomplete) case TIOCGETP: { struct sgttyb *psgttyb = (struct sgttyb *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termios2sgttyb(<ermios, psgttyb); return(EOK); } case TIOCSETP: { struct sgttyb *psgttyb = (struct sgttyb *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); sgttyb2termios(psgttyb, <ermios); return(tcsetattr(fd, TCSAFLUSH, <ermios)); } case TIOCSETN: { struct sgttyb *psgttyb = (struct sgttyb *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); sgttyb2termios(psgttyb, <ermios); return(tcsetattr(fd, TCSANOW, <ermios)); } //Terminal state in tchars structure case TIOCGETC: { struct tchars *ptchars = (struct tchars *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termios2tchars(<ermios, ptchars); return(EOK); } case TIOCSETC: { struct tchars *ptchars = (struct tchars *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); tchars2termios(ptchars, <ermios); return(tcsetattr(fd, TCSANOW, <ermios)); } //Terminal state in an ltchars structure case TIOCGLTC: { struct ltchars *pltchars = (struct ltchars *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); termios2ltchars(<ermios, pltchars); return(EOK); } case TIOCSLTC: { struct ltchars *pltchars = (struct ltchars *)data; if (tcgetattr(fd, <ermios) == -1) return(-1); ltchars2termios(pltchars, <ermios); return(tcsetattr(fd, TCSANOW, <ermios)); } //Set/Get the local flags structure case TIOCLGET: { if (tcgetattr(fd, <ermios) == -1) return(-1); *((int *)data) = (int)ltermios.c_lflag; return(EOK); } case TIOCLSET: { if (tcgetattr(fd, <ermios) == -1) return(-1); ltermios.c_lflag &= ~0xffff; ltermios.c_lflag |= *((int*)data); return(tcsetattr(fd, TCSANOW, <ermios)); } //Clear the break flag (implement TIOCSBRK?) case TIOCCBRK: { if (tcgetattr(fd, <ermios) == -1) return(-1); ltermios.c_iflag &= ~(BRKINT); ltermios.c_iflag |= IGNBRK; return(tcsetattr(fd, TCSANOW, <ermios)); } //Set the HUPCL flag case TIOCHPCL: { if (tcgetattr(fd, <ermios) != -1) { ltermios.c_cflag |= HUPCL; return(tcsetattr(fd, TCSANOW, <ermios)); } } /**** These calls map to devctl's, but need serious data munging ****/ //Inject a character into the stream case TIOCSTI: { return(tcinject(fd, (char*)data, sizeof(char))); } //Send a break for a period of time case TCSBRK: { int *duration = (int *) data; //Duration is measured in ms return(tcsendbreak(fd, *duration)); //tempint = (((*duration) ? *duration : 300) << 16) | _SERCTL_BRK_CHG | _SERCTL_BRK; //return(devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), &ret)); } /**** Modem control operations (via devctl) ****/ //Clear the state of the modem by ~AND'ing in the int argument case TIOCMBIC: { int tmpmodem; if (_devctl(fd, DCMD_CHR_LINESTATUS, &tmpmodem, sizeof(tmpmodem), _DEVCTL_FLAG_NOTTY) == -1) return(-1); tmpmodem &= ~(*((int*)data)); tempint = 0; modem2serctl(&tmpmodem, &tempint); return(_devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), _DEVCTL_FLAG_NOTTY)); } //Set the state of the modem by OR'ing in the int argument case TIOCMBIS: { int tmpmodem; if (_devctl(fd, DCMD_CHR_LINESTATUS, &tmpmodem, sizeof(tmpmodem), _DEVCTL_FLAG_NOTTY) == -1) return(-1); tmpmodem |= *((int*)data); tempint = 0; modem2serctl(&tmpmodem, &tempint); return(_devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), _DEVCTL_FLAG_NOTTY)); } //Set the state of the modem lines case TIOCMSET: { tempint = 0; modem2serctl((int*)data, &tempint); return(_devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), _DEVCTL_FLAG_NOTTY)); } //Set/Clear DTR lines case TIOCCDTR: { int status; if (_devctl(fd, DCMD_CHR_LINESTATUS, &status, sizeof(status), _DEVCTL_FLAG_NOTTY) == -1) return(-1); if (status & _LINESTATUS_SER_DTR) { status = _SERCTL_DTR_CHG; return(_devctl(fd, DCMD_CHR_SERCTL, &status, sizeof(status), _DEVCTL_FLAG_NOTTY)); } return(EOK); } case TIOCSDTR: { int status; if (_devctl(fd, DCMD_CHR_LINESTATUS, &status, sizeof(status), _DEVCTL_FLAG_NOTTY) == -1) return(-1); if (!(status & _LINESTATUS_SER_DTR)) { status = _SERCTL_DTR | _SERCTL_DTR_CHG; return(_devctl(fd, DCMD_CHR_SERCTL, &status, sizeof(status), _DEVCTL_FLAG_NOTTY)); } return(EOK); } default: break; } /* * The following block can go away when 6.4 is released * and <sys/sockio.h> from the networking project is * generally available. */ #ifndef NOSIOCGIFCONF /* Define these as in the latest <sys/sockio.h> */ #define NOSIOCGIFCONF _IOWR('i', 36, struct ifconf) #undef SIOCGIFCONF #define SIOCGIFCONF _IOWR('i', 38, struct ifconf) #endif /* Generic handling for all but SIOCGIFCONF networking IOCTL's */ if ((unsigned)cmd == SIOCGIFCONF || (unsigned)cmd == NOSIOCGIFCONF) { io_devctl_t msg; iov_t wiov[2], riov[3]; struct ifconf *ifconfp = (struct ifconf *)data; msg.i.type = _IO_DEVCTL; msg.i.combine_len = sizeof(msg.i); msg.i.dcmd = cmd; msg.i.zero = 0; msg.i.nbytes = ifconfp->ifc_len; SETIOV (wiov + 0, &msg, sizeof (msg.i)); SETIOV (wiov + 1, data, IOCPARM_LEN((unsigned)cmd)); SETIOV (riov + 0, &msg, sizeof (msg.o)); SETIOV (riov + 1, ifconfp, sizeof (ifconfp->ifc_len)); SETIOV (riov + 2, ifconfp->ifc_buf, ifconfp->ifc_len); return MsgSendv(fd, wiov, 2, riov, 3); } /* These calls require their command types to be translated */ switch ((unsigned)cmd) { case TCGETS: //Not on NetBSD SETNEWNUM(cmd, TIOCGETA); match = 1; break; case TCSETS: //Not on NetBSD SETNEWNUM(cmd, TIOCSETA); match = 1; break; case TCSETSW: //Not on NetBSD SETNEWNUM(cmd, TIOCSETAW); match = 1; break; case TCSETSF: //Not on NetBSD SETNEWNUM(cmd, TIOCSETAF); match = 1; break; case TIOCSETPGRP: //Not on Sun SETNEWNUM(cmd, TIOCSPGRP); match = 1; break; case TIOCGETPGRP: //Not on Sun SETNEWNUM(cmd, TIOCGPGRP); match = 1; break; case TIOCSTOP: case TIOCSTART: //These functions pass in void but we need to pass an int so ... data = &tempint; tempint = (cmd == TIOCSTOP) ? TCOOFF : TIOCSTART; cmd = _IOW(_DCMD_CHR,TCXONC,int); //Create new command case TCXONC: //Not on NetBSD //Assume incoming data already looks like: //data = 0= suspend output = TCOOFF, 1= restart output = TCOON // 2= suspend input = TCIOFF, 3= restart input = TCION SETNEWNUM(cmd, TCXONC); match = 1; break; case TIOCFLUSH: //Need to re-map 0 -> 2, FREAD -> 0, FWRITE -> 1 switch (*((int*)data)) { case 0: *((int*)data) = TCIOFLUSH; break; case FREAD: *((int*)data) = TCIFLUSH; break; case FWRITE: *((int*)data) = TCOFLUSH; break; default: break; } /* Fall Through */ case TCFLSH: //Not on NetBSD //Assume input data looks like: //data = 0 = flush in, 1 = flush output, 2 = flush both SETNEWNUM(cmd, TIOCFLUSH); match = 1; break; default: break; } //If you got this far then out you go as a generic devctl return(_devctl(fd, cmd, data, IOCPARM_LEN((unsigned)cmd), _DEVCTL_FLAG_NOTTY)); /* Returns different things for different commands: - GETPRGRP returns pid_t - FIOREAD returns number of chars in input queue - TIOCOUTQ returns number of chars in output queue - 0 for all other cases */ }