pty.c revision 175350
161033Sdfr/*-
261033Sdfr * Copyright (c) 1990, 1993, 1994
361033Sdfr *	The Regents of the University of California.  All rights reserved.
461033Sdfr *
561033Sdfr * Redistribution and use in source and binary forms, with or without
661033Sdfr * modification, are permitted provided that the following conditions
761033Sdfr * are met:
861033Sdfr * 1. Redistributions of source code must retain the above copyright
961033Sdfr *    notice, this list of conditions and the following disclaimer.
1061033Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1161033Sdfr *    notice, this list of conditions and the following disclaimer in the
1261033Sdfr *    documentation and/or other materials provided with the distribution.
1361033Sdfr * 4. Neither the name of the University nor the names of its contributors
1461033Sdfr *    may be used to endorse or promote products derived from this software
1561033Sdfr *    without specific prior written permission.
1661033Sdfr *
1761033Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1861033Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1961033Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2061033Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2161033Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2261033Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2361033Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2461033Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2561033Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2661033Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27116182Sobrien * SUCH DAMAGE.
28116182Sobrien */
29116182Sobrien
3061033Sdfr#include <sys/cdefs.h>
3185521Sjhb__FBSDID("$FreeBSD: head/lib/libutil/pty.c 175350 2008-01-15 13:59:13Z cperciva $");
3265822Sjhb
3385560Sjhb#if defined(LIBC_SCCS) && !defined(lint)
3461033Sdfr#if 0
35123614Sjhbstatic char sccsid[] = "@(#)pty.c	8.3 (Berkeley) 5/16/94";
36225570Sadrian#endif
3785521Sjhb#endif /* LIBC_SCCS and not lint */
3861033Sdfr
3985521Sjhb#include <sys/types.h>
40145729Ssam#include <sys/ioctl.h>
41154333Sscottl#include <sys/stat.h>
4285521Sjhb
43119708Sken#include <errno.h>
44154333Sscottl#include <fcntl.h>
4561033Sdfr#include <grp.h>
4669774Sphk#include <libutil.h>
47123614Sjhb#include <stdlib.h>
48123614Sjhb#include <string.h>
4967551Sjhb#include <termios.h>
50213813Smdf#include <unistd.h>
51213813Smdf
52213813Smdfint __use_pts(void);
53213813Smdf
54213813Smdfstatic int
5561033Sdfrnew_openpty(int *amaster, int *aslave, char *name, struct termios *termp,
5661033Sdfr    struct winsize *winp)
5761033Sdfr{
5861033Sdfr	const char *slavename;
59213813Smdf	int master, slave;
6085521Sjhb
61178015Ssam	master = posix_openpt(O_RDWR);
62178015Ssam	if (master == -1)
63180588Skmacy		return (-1);
64154333Sscottl
65221059Skib	if (grantpt(master) == -1) {
6661033Sdfr		close(master);
6761033Sdfr		return (-1);
68154333Sscottl	}
69177621Sscottl
70177621Sscottl	slavename = ptsname(master);
71154333Sscottl	if (slavename == NULL) {
72221059Skib		close(master);
73221059Skib		return (-1);
74215021Sjmallett	}
75215021Sjmallett
76215021Sjmallett	if (revoke(slavename) == -1) {
77215021Sjmallett		close(master);
78215021Sjmallett		return (-1);
79215021Sjmallett	}
80215021Sjmallett
81154167Sscottl	slave = open(slavename, O_RDWR);
82215021Sjmallett	if (slave == -1) {
83215021Sjmallett		close(master);
84215021Sjmallett		return (-1);
85215021Sjmallett	}
86215021Sjmallett
87215021Sjmallett	if (unlockpt(master) == -1) {
88215021Sjmallett		close(master);
89154167Sscottl		close(slave);
90221059Skib		return (-1);
91221059Skib	}
92221059Skib
93221059Skib	*amaster = master;
94221059Skib	*aslave = slave;
95221059Skib
96221059Skib	if (name)
97221059Skib		strcpy(name, ptsname(master));
98221059Skib	if (termp)
99221059Skib		tcsetattr(slave, TCSAFLUSH, termp);
100221059Skib	if (winp)
101154167Sscottl		ioctl(slave, TIOCSWINSZ, (char *)winp);
102154167Sscottl
103154167Sscottl	return (0);
104154167Sscottl}
105180588Skmacy
106154167Sscottlint
107154167Sscottlopenpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp)
108154167Sscottl{
109154167Sscottl	char line[] = "/dev/ptyXX";
110154167Sscottl	const char *cp1, *cp2;
111215750Savg	int master, slave, ttygid;
112145729Ssam	struct group *gr;
113154167Sscottl
11461033Sdfr	if (__use_pts())
11561033Sdfr		return (new_openpty(amaster, aslave, name, termp, winp));
116180588Skmacy
11785521Sjhb	if ((gr = getgrnam("tty")) != NULL)
11861033Sdfr		ttygid = gr->gr_gid;
119188058Simp	else
120180588Skmacy		ttygid = -1;
12161033Sdfr
122213813Smdf	for (cp1 = "pqrsPQRSlmnoLMNO"; *cp1; cp1++) {
12361033Sdfr		line[8] = *cp1;
12461033Sdfr		for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
125180588Skmacy			line[5] = 'p';
126180588Skmacy			line[9] = *cp2;
127154167Sscottl			if ((master = open(line, O_RDWR, 0)) == -1) {
12861033Sdfr				if (errno == ENOENT)
12961033Sdfr					break; /* try the next pty group */
13061033Sdfr			} else {
13161033Sdfr				line[5] = 't';
132154167Sscottl				(void) chown(line, getuid(), ttygid);
133154167Sscottl				(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
134154333Sscottl				(void) revoke(line);
135154167Sscottl				if ((slave = open(line, O_RDWR, 0)) != -1) {
136154333Sscottl					*amaster = master;
137154167Sscottl					*aslave = slave;
138154167Sscottl					if (name)
139154167Sscottl						strcpy(name, line);
140145729Ssam					if (termp)
141145729Ssam						(void) tcsetattr(slave,
142145729Ssam							TCSAFLUSH, termp);
143145729Ssam					if (winp)
144178015Ssam						(void) ioctl(slave, TIOCSWINSZ,
145145729Ssam							(char *)winp);
146145729Ssam					return (0);
147221059Skib				}
148154333Sscottl				(void) close(master);
149154333Sscottl			}
150145729Ssam		}
151145729Ssam	}
152145729Ssam	errno = ENOENT;	/* out of ptys */
15361033Sdfr	return (-1);
15461033Sdfr}
15561033Sdfr
15685521Sjhbint
157154167Sscottlforkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
158154333Sscottl{
159178015Ssam	int master, slave, pid;
160213813Smdf
161221059Skib	if (openpty(&master, &slave, name, termp, winp) == -1)
16285521Sjhb		return (-1);
163178015Ssam	switch (pid = fork()) {
16461033Sdfr	case -1:
16561033Sdfr		return (-1);
16661033Sdfr	case 0:
167221059Skib		/*
168221059Skib		 * child
16961033Sdfr		 */
17061033Sdfr		(void) close(master);
17161033Sdfr		login_tty(slave);
17261033Sdfr		return (0);
17361033Sdfr	}
17461033Sdfr	/*
17561033Sdfr	 * parent
176180588Skmacy	 */
177225570Sadrian	*amaster = master;
178225570Sadrian	(void) close(slave);
179221059Skib	return (pid);
18061033Sdfr}
18161033Sdfr