diff options
author | millert <> | 2012-12-03 20:08:33 +0000 |
---|---|---|
committer | millert <> | 2012-12-03 20:08:33 +0000 |
commit | e10e53f72f10d68e0212baefb36069e88ef863a3 (patch) | |
tree | dcd259d2d99c6c999bb25321e53b0ea6d3fef8db /src/lib/libc/stdlib/posix_pty.c | |
parent | 2a264863e549e493a466a263d4d8a7d2d3523756 (diff) | |
download | openbsd-e10e53f72f10d68e0212baefb36069e88ef863a3.tar.gz openbsd-e10e53f72f10d68e0212baefb36069e88ef863a3.tar.bz2 openbsd-e10e53f72f10d68e0212baefb36069e88ef863a3.zip |
Simple emulation of POSIX pty APIs posix_openpt(), ptsname(),
grantpt() and unlockpt() using /dev/ptm. Man pages from FreeBSD.
OK kettenis@ deraadt@ beck@ ajacoutot@ naddy@
Diffstat (limited to 'src/lib/libc/stdlib/posix_pty.c')
-rw-r--r-- | src/lib/libc/stdlib/posix_pty.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/lib/libc/stdlib/posix_pty.c b/src/lib/libc/stdlib/posix_pty.c new file mode 100644 index 0000000000..a2025ddbb6 --- /dev/null +++ b/src/lib/libc/stdlib/posix_pty.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* $OpenBSD: posix_pty.c,v 1.1 2012/12/03 20:08:33 millert Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2012 Todd C. Miller <Todd.Miller@courtesan.com> | ||
5 | * | ||
6 | * Permission to use, copy, modify, and distribute this software for any | ||
7 | * purpose with or without fee is hereby granted, provided that the above | ||
8 | * copyright notice and this permission notice appear in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <sys/types.h> | ||
20 | #include <sys/ioctl.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <sys/tty.h> | ||
23 | #include <errno.h> | ||
24 | #include <fcntl.h> | ||
25 | #include <paths.h> | ||
26 | #include <stddef.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include <unistd.h> | ||
30 | |||
31 | int | ||
32 | posix_openpt(int oflag) | ||
33 | { | ||
34 | struct ptmget ptm; | ||
35 | int fd, mfd = -1; | ||
36 | |||
37 | /* User must specify O_RDWR in oflag. */ | ||
38 | if (!(oflag & O_RDWR)) { | ||
39 | errno = EINVAL; | ||
40 | return -1; | ||
41 | } | ||
42 | |||
43 | /* Get pty master and slave (this API only uses the master). */ | ||
44 | fd = open(PATH_PTMDEV, O_RDWR); | ||
45 | if (fd != -1) { | ||
46 | if (ioctl(fd, PTMGET, &ptm) != -1) { | ||
47 | close(ptm.sfd); | ||
48 | mfd = ptm.cfd; | ||
49 | } | ||
50 | close(fd); | ||
51 | } | ||
52 | |||
53 | return mfd; | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Look up the name of the specified pty master fd. | ||
58 | * Note that the name returned does *not* include the /dev/ prefix. | ||
59 | * Returns the name on success and NULL on error, setting errno. | ||
60 | */ | ||
61 | static const char * | ||
62 | ptmname(int mfd) | ||
63 | { | ||
64 | struct stat sb; | ||
65 | const char *name; | ||
66 | |||
67 | /* Make sure it is a pty master. */ | ||
68 | if (fstat(mfd, &sb) != 0) | ||
69 | return NULL; | ||
70 | if (!S_ISCHR(sb.st_mode)) { | ||
71 | errno = EINVAL; | ||
72 | return NULL; | ||
73 | } | ||
74 | name = devname(sb.st_rdev, S_IFCHR); | ||
75 | if (strncmp(name, "pty", 3) != 0) { | ||
76 | errno = EINVAL; | ||
77 | return NULL; | ||
78 | } | ||
79 | return name; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * The PTMGET ioctl handles the mode and owner for us. | ||
84 | */ | ||
85 | int | ||
86 | grantpt(int mfd) | ||
87 | { | ||
88 | return ptmname(mfd) ? 0 : -1; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * The PTMGET ioctl unlocks the pty master and slave for us. | ||
93 | */ | ||
94 | int | ||
95 | unlockpt(int mfd) | ||
96 | { | ||
97 | return ptmname(mfd) ? 0 : -1; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Look up the path of the slave pty that corresponds to the master fd. | ||
102 | * Returns the path if successful or NULL on error. | ||
103 | */ | ||
104 | char * | ||
105 | ptsname(int mfd) | ||
106 | { | ||
107 | const char *master; | ||
108 | static char slave[sizeof(((struct ptmget *)NULL)->sn)]; | ||
109 | |||
110 | if ((master = ptmname(mfd)) == NULL) | ||
111 | return NULL; | ||
112 | |||
113 | /* Add /dev/ prefix and convert "pty" to "tty". */ | ||
114 | strlcpy(slave, _PATH_DEV, sizeof(slave)); | ||
115 | strlcat(slave, master, sizeof(slave)); | ||
116 | slave[sizeof(_PATH_DEV) - 1] = 't'; | ||
117 | |||
118 | return slave; | ||
119 | } | ||