GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
kpty.cpp
Go to the documentation of this file.
1/*
2
3 This file is part of the KDE libraries
4 Copyright (C) 2002, 2013 Waldo Bastian <bastian@kde.org>
5 Copyright (C) 2002-2003,2007 Oswald Buddenhagen <ossi@kde.org>
6
7 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8
9 This library is free software: you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with this library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23*/
24
25#ifdef HAVE_CONFIG_H
26# include "config.h"
27#endif
28
29#include "unix/kpty_p.h"
30
31#ifdef __sgi
32#define __svr4__
33#endif
34
35#ifdef __osf__
36#define _OSF_SOURCE
37#include <float.h>
38#endif
39
40#ifdef _AIX
41#define _ALL_SOURCE
42#endif
43
44// __USE_XOPEN isn't defined by default in ICC
45// (needed for ptsname(), grantpt() and unlockpt())
46#ifdef __INTEL_COMPILER
47# ifndef __USE_XOPEN
48# define __USE_XOPEN
49# endif
50#endif
51
52#include <sys/types.h>
53#include <sys/ioctl.h>
54#include <sys/time.h>
55#include <sys/resource.h>
56#include <sys/stat.h>
57#include <sys/param.h>
58
59#include <errno.h>
60#include <fcntl.h>
61#include <time.h>
62#include <stdlib.h>
63#include <stdio.h>
64#include <string.h>
65#include <unistd.h>
66#include <grp.h>
67
68#ifdef Q_OS_MAC
69# include <util.h>
70#else
71# if defined(HAVE_PTY_H)
72# include <pty.h>
73# endif
74# ifdef HAVE_LIBUTIL_H
75# include <libutil.h>
76# elif defined(HAVE_UTIL_H)
77# include <util.h>
78# endif
79#endif
80
81/*
82#ifdef HAVE_UTEMPTER
83extern "C" {
84# include <utempter.h>
85}
86#else
87# include <utmp.h>
88# ifdef HAVE_UTMPX
89# include <utmpx.h>
90# endif
91# if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
92# define _PATH_UTMPX _UTMPX_FILE
93# endif
94# if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
95# define _PATH_WTMPX _WTMPX_FILE
96# endif
97#endif
98*/
99
100/* for HP-UX (some versions) the extern C is needed, and for other
101 platforms it doesn't hurt */
102extern "C" {
103#include <termios.h>
104#if defined(HAVE_TERMIO_H)
105# include <termio.h> // struct winsize on some systems
106#endif
107}
108
109#if defined (_HPUX_SOURCE)
110# define _TERMIOS_INCLUDED
111# include <bsdtty.h>
112#endif
113
114#if defined (HAVE_STROPTS_H)
115# include <stropts.h> // Defines I_PUSH
116# define _NEW_TTY_CTRL
117#elif defined (HAVE_SYS_STROPTS_H)
118# include <sys/stropts.h> // Defines I_PUSH
119# define _NEW_TTY_CTRL
120#endif
121
122#if defined(HAVE_TCGETATTR)
123# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
124#elif defined(TIOCGETA)
125# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
126#elif defined(TCGETS)
127# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
128#else
129# error No method available to get terminal attributes
130#endif
131
132#if defined(HAVE_TCSETATTR) && defined(TCSANOW)
133# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
134#elif defined(TIOCSETA)
135# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
136#elif defined(TCSETS)
137# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
138#else
139# error No method available to set terminal attributes
140#endif
141
142#include <QtCore>
143
144// not defined on HP-UX for example
145#ifndef CTRL
146# define CTRL(x) ((x) & 037)
147#endif
148
149#define TTY_GROUP "tty"
150
151#ifndef PATH_MAX
152# ifdef MAXPATHLEN
153# define PATH_MAX MAXPATHLEN
154# else
155# define PATH_MAX 1024
156# endif
157#endif
158
159///////////////////////
160// private functions //
161///////////////////////
162
163//////////////////
164// private data //
165//////////////////
166
168 masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent)
169{
170}
171
172KPtyPrivate::KPtyPrivate(KPty *parent, int _masterFd, int _slaveFd):
173 masterFd(_masterFd), slaveFd(_slaveFd), ownMaster(true), q_ptr(parent)
174{
175}
176
177
179{
180}
181
183{
184// return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
185// QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
186 return true;
187}
188
189/////////////////////////////
190// public member functions //
191/////////////////////////////
192
194 d_ptr(new KPtyPrivate(this))
195{
196}
197
198KPty::KPty(int masterFd, int slaveFd) :
199 d_ptr(new KPtyPrivate(this, masterFd, slaveFd))
200{
201}
202
204 d_ptr(d)
205{
206 d_ptr->q_ptr = this;
207}
208
210{
211 close();
212 delete d_ptr;
213}
214
216{
217 Q_D(KPty);
218
219 if (d->masterFd >= 0) {
220 return true;
221 }
222
223 d->ownMaster = true;
224
225 QByteArray ptyName;
226
227 // Find a master pty that we can open ////////////////////////////////
228
229 // Because not all the pty animals are created equal, they want to
230 // be opened by several different methods.
231
232 // We try, as we know them, one by one.
233
234#ifdef HAVE_OPENPTY
235
236 char ptsn[PATH_MAX];
237 if (::openpty( &d->masterFd, &d->slaveFd, ptsn, nullptr, nullptr))
238 {
239 d->masterFd = -1;
240 d->slaveFd = -1;
241 qWarning() << "Can't open a pseudo teletype";
242 return false;
243 }
244 d->ttyName = ptsn;
245
246#else
247
248#ifdef HAVE__GETPTY // irix
249
250 char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
251 if (ptsn) {
252 d->ttyName = ptsn;
253 goto grantedpt;
254 }
255
256#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
257
258#ifdef HAVE_POSIX_OPENPT
259 d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
260#elif defined(HAVE_GETPT)
261 d->masterFd = ::getpt();
262#elif defined(PTM_DEVICE)
263 d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
264#else
265# error No method to open a PTY master detected.
266#endif
267 if (d->masterFd >= 0)
268 {
269#ifdef HAVE_PTSNAME
270 char *ptsn = ptsname(d->masterFd);
271 if (ptsn) {
272 d->ttyName = ptsn;
273#else
274 int ptyno;
275 if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
276 char buf[32];
277 sprintf(buf, "/dev/pts/%d", ptyno);
278 d->ttyName = buf;
279#endif
280#ifdef HAVE_GRANTPT
281 if (!grantpt(d->masterFd))
282 goto grantedpt;
283#else
284 goto gotpty;
285#endif
286 }
287 ::close(d->masterFd);
288 d->masterFd = -1;
289 }
290#endif // HAVE_PTSNAME || TIOCGPTN
291
292 // Linux device names, FIXME: Trouble on other systems?
293 for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
294 {
295 for (const char* s4 = "0123456789abcdef"; *s4; s4++)
296 {
297 ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
298 d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
299
300 d->masterFd = ::open(ptyName.data(), O_RDWR);
301 if (d->masterFd >= 0)
302 {
303#ifdef Q_OS_SOLARIS
304 /* Need to check the process group of the pty.
305 * If it exists, then the slave pty is in use,
306 * and we need to get another one.
307 */
308 int pgrp_rtn;
309 if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
310 ::close(d->masterFd);
311 d->masterFd = -1;
312 continue;
313 }
314#endif /* Q_OS_SOLARIS */
315 if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
316 {
317 if (!geteuid())
318 {
319 struct group* p = getgrnam(TTY_GROUP);
320 if (!p)
321 p = getgrnam("wheel");
322 gid_t gid = p ? p->gr_gid : getgid ();
323
324 if (!chown(d->ttyName.data(), getuid(), gid)) {
325 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
326 }
327 }
328 goto gotpty;
329 }
330 ::close(d->masterFd);
331 d->masterFd = -1;
332 }
333 }
334 }
335
336 qWarning() << "Can't open a pseudo teletype";
337 return false;
338
339 gotpty:
340 struct stat st;
341 if (stat(d->ttyName.data(), &st))
342 return false; // this just cannot happen ... *cough* Yeah right, I just
343 // had it happen when pty #349 was allocated. I guess
344 // there was some sort of leak? I only had a few open.
345 if (((st.st_uid != getuid()) ||
346 (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
347 !d->chownpty(true))
348 {
349 qWarning()
350 << "chownpty failed for device " << ptyName << "::" << d->ttyName
351 << "\nThis means the communication can be eavesdropped." << endl;
352 }
353
354#if defined(HAVE_GRANTPT) || defined(HAVE__GETPTY)
355 grantedpt:
356#endif
357
358#ifdef HAVE_REVOKE
359 revoke(d->ttyName.data());
360#endif
361
362#ifdef HAVE_UNLOCKPT
363 unlockpt(d->masterFd);
364#elif defined(TIOCSPTLCK)
365 int flag = 0;
366 ioctl(d->masterFd, TIOCSPTLCK, &flag);
367#endif
368
369 d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
370 if (d->slaveFd < 0)
371 {
372 qWarning() << "Can't open slave pseudo teletype";
373 ::close(d->masterFd);
374 d->masterFd = -1;
375 return false;
376 }
377
378#if (defined(__svr4__) || defined(__sgi__))
379 // Solaris
380 ioctl(d->slaveFd, I_PUSH, "ptem");
381 ioctl(d->slaveFd, I_PUSH, "ldterm");
382#endif
383
384#endif /* HAVE_OPENPTY */
385 fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
386 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
387
388 struct ::termios t;
389 tcGetAttr(&t);
390 t.c_iflag &= ~IXON;
391 t.c_lflag &= ~ECHOCTL;
392 tcSetAttr(&t);
393 return true;
394}
395
397{
398 Q_D(KPty);
399
400 if (d->slaveFd < 0)
401 return;
402 ::close(d->slaveFd);
403 d->slaveFd = -1;
404}
405
407{
408 Q_D(KPty);
409
410 if (d->masterFd < 0)
411 return;
412 closeSlave();
413 if (d->ownMaster) {
414#ifndef HAVE_OPENPTY
415 // don't bother resetting unix98 pty, it will go away after closing master anyway.
416 if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
417 if (!geteuid()) {
418 struct stat st;
419 if (!stat(d->ttyName.data(), &st)) {
420 if (!chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1)) {
421 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
422 }
423 }
424 } else {
425 fcntl(d->masterFd, F_SETFD, 0);
426 d->chownpty(false);
427 }
428 }
429 #endif
430 }
431 ::close(d->masterFd);
432 d->masterFd = -1;
433}
434
435// XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
436// Please verify.
437
438bool KPty::tcGetAttr(struct ::termios *ttmode) const
439{
440 Q_D(const KPty);
441
442 return _tcgetattr(d->masterFd, ttmode) == 0;
443}
444
445bool KPty::tcSetAttr(struct ::termios *ttmode)
446{
447 Q_D(KPty);
448
449 return _tcsetattr(d->masterFd, ttmode) == 0;
450}
451
452bool KPty::setWinSize(int lines, int columns)
453{
454 Q_D(KPty);
455
456 struct winsize winSize;
457 memset(&winSize, 0, sizeof(winSize));
458 winSize.ws_row = (unsigned short)lines;
459 winSize.ws_col = (unsigned short)columns;
460 return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
461}
462
463bool KPty::setEcho(bool echo)
464{
465 struct ::termios ttmode;
466 if (!tcGetAttr(&ttmode))
467 return false;
468 if (!echo)
469 ttmode.c_lflag &= ~ECHO;
470 else
471 ttmode.c_lflag |= ECHO;
472 return tcSetAttr(&ttmode);
473}
474
475const char *KPty::ttyName() const
476{
477 Q_D(const KPty);
478
479 return d->ttyName.data();
480}
481
482int KPty::masterFd() const
483{
484 Q_D(const KPty);
485
486 return d->masterFd;
487}
488
489int KPty::slaveFd() const
490{
491 Q_D(const KPty);
492
493 return d->slaveFd;
494}
Provides primitives for opening & closing a pseudo TTY pair, assigning the controlling TTY,...
Definition: kpty.h:35
~KPty()
Destructor:
Definition: kpty.cpp:209
int masterFd() const
Definition: kpty.cpp:482
KPtyPrivate *const d_ptr
Definition: kpty.h:162
bool setEcho(bool echo)
Set whether the pty should echo input.
Definition: kpty.cpp:463
bool open()
Create a pty master/slave pair.
Definition: kpty.cpp:215
bool tcGetAttr(struct ::termios *ttmode) const
Wrapper around tcgetattr(3).
Definition: kpty.cpp:438
void closeSlave()
Close the pty slave descriptor.
Definition: kpty.cpp:396
const char * ttyName() const
Definition: kpty.cpp:475
bool tcSetAttr(struct ::termios *ttmode)
Wrapper around tcsetattr(3) with mode TCSANOW.
Definition: kpty.cpp:445
bool setWinSize(int lines, int columns)
Change the logical (screen) size of the pty.
Definition: kpty.cpp:452
KPty()
Constructor.
Definition: kpty.cpp:193
int slaveFd() const
Definition: kpty.cpp:489
void close()
Close the pty master/slave pair.
Definition: kpty.cpp:406
#define PATH_MAX
Definition: kpty.cpp:155
#define TTY_GROUP
Definition: kpty.cpp:149
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
gid_t getgid(void)
uid_t getuid(void)
int fcntl(int fd, int cmd, long arg)
uid_t geteuid(void)
#define ECHO
KPtyPrivate(KPty *parent)
Definition: kpty.cpp:167
virtual ~KPtyPrivate()
Definition: kpty.cpp:178
KPty * q_ptr
Definition: kpty_p.h:46
bool chownpty(bool grant)
Definition: kpty.cpp:182
subroutine stat(x, n, av, var, xmin, xmax)
Definition: tstgmn.for:112