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