Annotation of libaitio/src/pty.c, revision 1.1.2.10
1.1.2.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.1.2.9 misho 6: * $Id: pty.c,v 1.1.2.8 2011/09/22 22:29:01 misho Exp $
1.1.2.1 misho 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
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: /*
1.1.2.3 misho 50: * ioAllocPTY() Allocate new PTY and TTY
1.1.2.1 misho 51: * @ptyfd = master fd, pty
52: * @ttyfd = slave fd, tty
53: * @name = tty device name if not null
54: * @namesiz = name length, must be above 63 bytes.
55: * @term = termios for terminal
56: * @winz = winsize for terminal
57: * return: -1 error or 0 ok
58: */
59: inline int
60: ioAllocPTY(int *ptyfd, int *ttyfd, char * __restrict name, int namesiz,
61: struct termios * __restrict term, struct winsize * __restrict winz)
62: {
63: assert(ptyfd && ttyfd);
64: if (!ptyfd || !ttyfd || (name && namesiz < 64)) {
65: io_SetErr(EINVAL, "Error:: invalid arguments ...");
66: return -1;
67: }
68:
69: memset(name, 0, namesiz);
70: if (openpty(ptyfd, ttyfd, name, term, winz) == -1) {
71: LOGERR;
72: return -1;
73: }
74:
75: return 0;
76: }
77:
78: /*
1.1.2.8 misho 79: * ioFreePTY() Release PTY and TTY device
80: * @ptyfd = master fd, pty (==-1 skip closing pty)
1.1.2.1 misho 81: * @ttyname = tty filename
82: * return: none
83: */
84: inline void
1.1.2.8 misho 85: ioFreePTY(int ptyfd, const char *ttyname)
1.1.2.1 misho 86: {
87: assert(ttyname);
88: if (!ttyname)
89: return;
90:
1.1.2.8 misho 91: if (ptyfd != -1)
92: close(ptyfd);
1.1.2.1 misho 93: chown(ttyname, (uid_t) 0, (gid_t) 0);
94: chmod(ttyname, (mode_t) 0666);
95: }
1.1.2.2 misho 96:
97: /*
98: * ioChgWinPTY() Change window size of PTY
99: * @ptyfd = master fd, pty
100: * @row = row
101: * @col = col
102: * @xpxl = x pixels
103: * @ypxl = y pixels
104: * return: -1 error or 0 ok
105: */
106: inline int
107: ioChgWinPTY(int ptyfd, u_short row, u_short col, u_short xpxl, u_short ypxl)
108: {
109: struct winsize w;
110:
111: w.ws_row = row;
112: w.ws_col = col;
113: w.ws_xpixel = xpxl;
114: w.ws_ypixel = ypxl;
115:
116: if (ioctl(ptyfd, TIOCSWINSZ, &w) == -1) {
117: LOGERR;
118: return -1;
119: }
120:
121: return 0;
122: }
123:
124: /*
1.1.2.3 misho 125: * ioSetOwnerTTY() Set owner to TTY
1.1.2.2 misho 126: * @ttyname = tty filename
127: * @UID = uid
128: * @GID = gid
129: * return: -1 error or 0 ok
130: */
131: int
1.1.2.3 misho 132: ioSetOwnerTTY(const char *ttyname, uid_t UID, gid_t GID)
1.1.2.2 misho 133: {
134: struct group *grp;
135: gid_t gid;
136: mode_t mode;
137: struct stat st;
138:
139: assert(ttyname);
140: if (!ttyname) {
141: io_SetErr(EINVAL, "Error:: invalid arguments ...");
142: return -1;
143: }
144:
145: grp = getgrnam("tty");
146: if (!grp) {
147: gid = GID;
148: mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
149: } else {
150: gid = grp->gr_gid;
151: mode = S_IRUSR | S_IWUSR | S_IWGRP;
152: }
153:
154: if (stat(ttyname, &st) == -1) {
155: LOGERR;
156: return -1;
157: }
158:
159: if (st.st_uid != UID || st.st_gid != gid)
160: if (chown(ttyname, UID, gid) == -1) {
161: LOGERR;
162: return -1;
163: }
164: if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode)
165: if (chmod(ttyname, mode) == -1) {
166: LOGERR;
167: return -1;
168: }
169:
170: return 0;
171: }
1.1.2.3 misho 172:
173: /*
174: * ioSetSidTTY() Makes the process's controlling TTY and sets it to sane modes.
175: * @ttyfd = slave fd, tty
176: * @ttyname = tty filename
177: * return: -1 error or 0 ok
178: */
179: int
180: ioSetSidTTY(int *ttyfd, const char *ttyname)
181: {
182: int fd;
183:
184: /* First disconnect from the old controlling tty. */
185: #ifdef TIOCNOTTY
186: fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
187: if (fd >= 0) {
188: ioctl(fd, TIOCNOTTY, NULL);
189: close(fd);
190: }
191: #endif
192: setsid();
193:
194: /* Verify that we are successfully disconnected from the controlling tty. */
195: fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
196: if (fd >= 0) {
197: io_SetErr(ENXIO, "Error:: Failed to disconnect from controlling tty.");
198: close(fd);
199: return -1;
200: }
201: /* Make it our controlling tty. */
202: #ifdef TIOCSCTTY
203: if (ioctl(*ttyfd, TIOCSCTTY, NULL) == -1) {
204: LOGERR;
205: return -1;
206: }
207: #endif
208: fd = open(ttyname, O_RDWR);
209: if (fd == -1) {
210: LOGERR;
211: return -1;
212: } else
213: close(fd);
214:
215: /* Verify that we now have a controlling tty. */
216: fd = open(_PATH_TTY, O_WRONLY);
217: if (fd == -1) {
218: LOGERR;
219: return -1;
220: } else
221: close(fd);
222:
1.1.2.5 misho 223: /* redirect standart handles to tty */
224: dup2(*ttyfd, STDIN_FILENO);
225: dup2(*ttyfd, STDOUT_FILENO);
226: dup2(*ttyfd, STDERR_FILENO);
227: if (*ttyfd > 2)
228: close(*ttyfd);
229:
230: /* NOW TTY IS READY! */
1.1.2.3 misho 231: return 0;
232: }
1.1.2.4 misho 233:
234: /*
235: * ioSetRAWMode() Enter into RAW mode
236: * @fd = tty fd
237: * @otio = saved old termios for later restore if !=NULL
238: * return: -1 error or 0 ok
239: */
240: inline int
241: ioSetRAWMode(int fd, struct termios *otio)
242: {
243: struct termios tio;
244:
245: if (tcgetattr(fd, &tio) == -1) {
246: LOGERR;
247: return -1;
248: }
249: if (otio)
250: *otio = tio;
251:
252: tio.c_iflag |= IGNPAR;
253: tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
254: #ifdef IUCLC
255: tio.c_iflag &= ~IUCLC;
256: #endif
257: tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
258: #ifdef IEXTEN
259: tio.c_lflag &= ~IEXTEN;
260: #endif
261: tio.c_oflag &= ~OPOST;
262: tio.c_cc[VMIN] = 1;
263: tio.c_cc[VTIME] = 0;
264:
265: if (tcsetattr(fd, TCSADRAIN, &tio) == -1) {
266: LOGERR;
267: return -1;
268: }
269:
270: return 0;
271: }
272:
273: /*
274: * ioRestoreMode() Restore termios to tty fd
275: * @fd = tty fd
276: * @tio = termios structure for restore
277: * return: -1 error or 0 ok
278: */
279: inline int
280: ioRestoreMode(int fd, struct termios tio)
281: {
282: if (tcsetattr(fd, TCSADRAIN, &tio) == -1) {
283: LOGERR;
284: return -1;
285: }
286:
287: return 0;
288: }
1.1.2.6 misho 289:
290: /*
291: * ioForkPTY() Fork new process with session leader and new TTY
292: * @ptyfd = master fd, pty
293: * @name = tty device name if not null
294: * @namesiz = name length, must be above 63 bytes.
295: * @term = termios for terminal
296: * @winz = winsize for terminal
297: * @otio = old termios structure for restore
298: * return: -1 error, 0 child process or >0 parent: pid of child
299: */
300: pid_t
301: ioForkPTY(int *ptyfd, char * __restrict name, int namesiz, struct termios * __restrict term,
302: struct winsize * __restrict winz, struct termios * __restrict otio)
303: {
304: int ttyfd;
305: pid_t pid;
306:
307: if (ioAllocPTY(ptyfd, &ttyfd, name, namesiz, term, winz))
308: return -1;
309:
310: switch ((pid = fork())) {
311: case -1:
312: LOGERR;
313: return -1;
314: case 0:
315: if (ioSetOwnerTTY(name, getuid(), getgid()) == -1) {
1.1.2.8 misho 316: ioFreePTY(*ptyfd, name);
1.1.2.6 misho 317: return -1;
318: }
319: if (ioSetSidTTY(&ttyfd, name) == -1) {
1.1.2.8 misho 320: ioFreePTY(*ptyfd, name);
1.1.2.6 misho 321: return -1;
322: }
1.1.2.7 misho 323: close(*ptyfd);
1.1.2.6 misho 324:
325: /* CHILD */
326: break;
327: default:
328: close(ttyfd);
329:
1.1.2.10! misho 330: ioSetRAWMode(*ptyfd, otio);
! 331:
1.1.2.6 misho 332: /* PARENT */
333: break;
334: }
335:
336: return pid;
337: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>