GNU Octave  8.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
83 extern "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 */
102 extern "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 
172 KPtyPrivate::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 
198 KPty::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).toLatin1();
298  d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toLatin1();
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 
438 bool KPty::tcGetAttr(struct ::termios *ttmode) const
439 {
440  Q_D(const KPty);
441 
442  return _tcgetattr(d->masterFd, ttmode) == 0;
443 }
444 
445 bool KPty::tcSetAttr(struct ::termios *ttmode)
446 {
447  Q_D(KPty);
448 
449  return _tcsetattr(d->masterFd, ttmode) == 0;
450 }
451 
452 bool 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 
463 bool 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 
475 const char *KPty::ttyName() const
476 {
477  Q_D(const KPty);
478 
479  return d->ttyName.data();
480 }
481 
482 int KPty::masterFd() const
483 {
484  Q_D(const KPty);
485 
486  return d->masterFd;
487 }
488 
489 int 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
static group getgrnam(const std::string &nm)
Definition: oct-group.cc:131
gid_t gid(void) const
Definition: oct-group.cc:73
#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
uid_t getuid(void)
gid_t getgid(void)
uid_t geteuid(void)
int fcntl(int fd, int cmd, long arg)
#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