File:
[ELWIX - Embedded LightWeight unIX -] /
libaitio /
src /
pty.c
Revision
1.4:
download - view:
text,
annotated -
select for diffs -
revision graph
Mon May 14 12:49:21 2012 UTC (12 years, 3 months ago) by
misho
Branches:
MAIN
CVS tags:
io5_2,
io5_1,
io5_0,
io4_1,
io4_0,
io3_9,
io3_8,
io3_7,
io3_6,
io3_5,
io3_4,
io3_3,
io3_2,
io3_1,
io2_8,
io2_7,
IO5_1,
IO5_0,
IO4_1,
IO4_0,
IO3_9,
IO3_8,
IO3_7,
IO3_6,
IO3_5,
IO3_4,
IO3_3,
IO3_2,
IO3_1,
IO3_0,
IO2_7,
IO2_6,
HEAD
version 2.6
1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: pty.c,v 1.4 2012/05/14 12:49:21 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * ioAllocPTY() - Allocate new PTY and TTY
51: *
52: * @ptyfd = master fd, pty
53: * @ttyfd = slave fd, tty
54: * @name = tty device name if not null
55: * @namesiz = name length, must be above 63 bytes.
56: * @term = termios for terminal
57: * @winz = winsize for terminal
58: * return: -1 error or 0 ok
59: */
60: inline int
61: ioAllocPTY(int *ptyfd, int *ttyfd, char * __restrict name, int namesiz,
62: struct termios * __restrict term, struct winsize * __restrict winz)
63: {
64: assert(ptyfd && ttyfd);
65: if (!ptyfd || !ttyfd || (name && namesiz < 64)) {
66: io_SetErr(EINVAL, "Invalid arguments");
67: return -1;
68: }
69:
70: memset(name, 0, namesiz);
71: if (openpty(ptyfd, ttyfd, name, term, winz) == -1) {
72: LOGERR;
73: return -1;
74: }
75:
76: return 0;
77: }
78:
79: /*
80: * ioFreePTY() - Release PTY and TTY device
81: *
82: * @ptyfd = master fd, pty (==-1 skip closing pty)
83: * @ttyname = tty filename
84: * return: none
85: */
86: inline void
87: ioFreePTY(int ptyfd, const char *ttyname)
88: {
89: assert(ttyname);
90: if (!ttyname)
91: return;
92:
93: if (ptyfd != -1)
94: close(ptyfd);
95: if (ttyname) {
96: chown(ttyname, (uid_t) 0, (gid_t) 0);
97: chmod(ttyname, (mode_t) 0666);
98: }
99: }
100:
101: /*
102: * ioChgWinPTY() - Change window size of PTY
103: *
104: * @ptyfd = master fd, pty
105: * @row = row
106: * @col = col
107: * @xpxl = x pixels
108: * @ypxl = y pixels
109: * return: -1 error or 0 ok
110: */
111: inline int
112: ioChgWinPTY(int ptyfd, u_short row, u_short col, u_short xpxl, u_short ypxl)
113: {
114: struct winsize w;
115:
116: w.ws_row = row;
117: w.ws_col = col;
118: w.ws_xpixel = xpxl;
119: w.ws_ypixel = ypxl;
120:
121: if (ioctl(ptyfd, TIOCSWINSZ, &w) == -1) {
122: LOGERR;
123: return -1;
124: }
125:
126: return 0;
127: }
128:
129: /*
130: * ioSetOwnerTTY() - Set owner to TTY
131: *
132: * @ttyname = tty filename
133: * @UID = uid
134: * @GID = gid
135: * return: -1 error or 0 ok
136: */
137: int
138: ioSetOwnerTTY(const char *ttyname, uid_t UID, gid_t GID)
139: {
140: struct group *grp;
141: gid_t gid;
142: mode_t mode;
143: struct stat st;
144:
145: assert(ttyname);
146: if (!ttyname) {
147: io_SetErr(EINVAL, "Invalid arguments");
148: return -1;
149: }
150:
151: grp = getgrnam("tty");
152: if (!grp) {
153: gid = GID;
154: mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
155: } else {
156: gid = grp->gr_gid;
157: mode = S_IRUSR | S_IWUSR | S_IWGRP;
158: }
159:
160: if (stat(ttyname, &st) == -1) {
161: LOGERR;
162: return -1;
163: }
164:
165: if (st.st_uid != UID || st.st_gid != gid)
166: if (chown(ttyname, UID, gid) == -1) {
167: LOGERR;
168: return -1;
169: }
170: if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode)
171: if (chmod(ttyname, mode) == -1) {
172: LOGERR;
173: return -1;
174: }
175:
176: return 0;
177: }
178:
179: /*
180: * ioSetSidTTY() - Makes the process's controlling TTY and sets it to sane modes.
181: *
182: * @ttyfd = slave fd, tty
183: * @ttyname = tty filename
184: * return: -1 error or 0 ok
185: */
186: int
187: ioSetSidTTY(int *ttyfd, const char *ttyname)
188: {
189: int fd;
190:
191: /* First disconnect from the old controlling tty. */
192: #ifdef TIOCNOTTY
193: fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
194: if (fd >= 0) {
195: ioctl(fd, TIOCNOTTY, NULL);
196: close(fd);
197: }
198: #endif
199: setsid();
200:
201: /* Verify that we are successfully disconnected from the controlling tty. */
202: fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
203: if (fd >= 0) {
204: io_SetErr(ENXIO, "Failed to disconnect from controlling tty");
205: close(fd);
206: return -1;
207: }
208: /* Make it our controlling tty. */
209: #ifdef TIOCSCTTY
210: if (ioctl(*ttyfd, TIOCSCTTY, NULL) == -1) {
211: LOGERR;
212: return -1;
213: }
214: #endif
215: fd = open(ttyname, O_RDWR);
216: if (fd == -1) {
217: LOGERR;
218: return -1;
219: } else
220: close(fd);
221:
222: /* Verify that we now have a controlling tty. */
223: fd = open(_PATH_TTY, O_WRONLY);
224: if (fd == -1) {
225: LOGERR;
226: return -1;
227: } else
228: close(fd);
229:
230: /* redirect standart handles to tty */
231: dup2(*ttyfd, STDIN_FILENO);
232: dup2(*ttyfd, STDOUT_FILENO);
233: dup2(*ttyfd, STDERR_FILENO);
234: if (*ttyfd > 2)
235: close(*ttyfd);
236:
237: /* NOW TTY IS READY! */
238: return 0;
239: }
240:
241: /*
242: * ioSetRAWMode() - Enter into RAW mode
243: *
244: * @fd = tty fd
245: * @otio = saved old termios for later restore if !=NULL
246: * return: -1 error or 0 ok
247: */
248: inline int
249: ioSetRAWMode(int fd, struct termios *otio)
250: {
251: struct termios tio;
252:
253: if (tcgetattr(fd, &tio) == -1) {
254: LOGERR;
255: return -1;
256: }
257: if (otio)
258: *otio = tio;
259:
260: tio.c_iflag |= IGNPAR;
261: tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
262: #ifdef IUCLC
263: tio.c_iflag &= ~IUCLC;
264: #endif
265: tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
266: #ifdef IEXTEN
267: tio.c_lflag &= ~IEXTEN;
268: #endif
269: tio.c_oflag &= ~OPOST;
270: tio.c_cc[VMIN] = 1;
271: tio.c_cc[VTIME] = 0;
272:
273: if (tcsetattr(fd, TCSADRAIN, &tio) == -1) {
274: LOGERR;
275: return -1;
276: }
277:
278: return 0;
279: }
280:
281: /*
282: * ioRestoreMode() - Restore termios to tty fd
283: *
284: * @fd = tty fd
285: * @tio = termios structure for restore
286: * return: -1 error or 0 ok
287: */
288: inline int
289: ioRestoreMode(int fd, struct termios tio)
290: {
291: if (tcsetattr(fd, TCSADRAIN, &tio) == -1) {
292: LOGERR;
293: return -1;
294: }
295:
296: return 0;
297: }
298:
299: /*
300: * ioForkPTY() - Fork new process with session leader and new TTY
301: *
302: * @ptyfd = master fd, pty
303: * @name = tty device name if not null
304: * @namesiz = name length, must be above 63 bytes.
305: * @term = termios for terminal
306: * @winz = winsize for terminal
307: * @otio = old termios structure for restore
308: * return: -1 error, 0 child process or >0 parent: pid of child
309: */
310: pid_t
311: ioForkPTY(int *ptyfd, char * __restrict name, int namesiz, struct termios * __restrict term,
312: struct winsize * __restrict winz, struct termios * __restrict otio)
313: {
314: int ttyfd;
315: pid_t pid;
316:
317: if (ioAllocPTY(ptyfd, &ttyfd, name, namesiz, term, winz))
318: return -1;
319:
320: switch ((pid = fork())) {
321: case -1:
322: LOGERR;
323: return -1;
324: case 0:
325: if (ioSetOwnerTTY(name, getuid(), getgid()) == -1) {
326: ioFreePTY(*ptyfd, name);
327: return -1;
328: }
329: if (ioSetSidTTY(&ttyfd, name) == -1) {
330: ioFreePTY(*ptyfd, name);
331: return -1;
332: }
333: close(*ptyfd);
334:
335: /* CHILD */
336: break;
337: default:
338: close(ttyfd);
339:
340: /* PARENT */
341: break;
342: }
343:
344: return pid;
345: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>