kpty.cpp

The source code correct for FreeBSD (I hope) - slash -, 2009-10-21 10:30 AM

Download (17.7 KB)

 
1
/*
2

3
   This file is part of the KDE libraries
4
   Copyright (C) 2002 Waldo Bastian <[email protected]>
5
   Copyright (C) 2002-2003,2007 Oswald Buddenhagen <[email protected]>
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
#include "kpty_p.h"
26

    
27
#ifdef __sgi
28
#define __svr4__
29
#endif
30

    
31
#ifdef __osf__
32
#define _OSF_SOURCE
33
#include <float.h>
34
#endif
35

    
36
#ifdef _AIX
37
#define _ALL_SOURCE
38
#endif
39

    
40
// __USE_XOPEN isn't defined by default in ICC
41
// (needed for ptsname(), grantpt() and unlockpt())
42
#ifdef __INTEL_COMPILER
43
#  ifndef __USE_XOPEN
44
#    define __USE_XOPEN
45
#  endif
46
#endif
47

    
48
#include <sys/types.h>
49
#include <sys/ioctl.h>
50
#include <sys/time.h>
51
#include <sys/resource.h>
52
#include <sys/stat.h>
53
#include <sys/param.h>
54

    
55
#include <errno.h>
56
#include <fcntl.h>
57
#include <time.h>
58
#include <stdlib.h>
59
#include <stdio.h>
60
#include <string.h>
61
#include <unistd.h>
62
#include <grp.h>
63
#include "utmp.h"
64
#if defined(HAVE_PTY_H)
65
# include <pty.h>
66
#endif
67

    
68
#ifdef HAVE_LIBUTIL_H
69
# include <libutil.h>
70
#elif defined(HAVE_UTIL_H)
71
# include <util.h>
72
#endif
73

    
74
#ifdef HAVE_UTEMPTER
75
extern "C" {
76
# include <utempter.h>
77
}
78
#else
79
# include <utmp.h>
80
# ifdef HAVE_UTMPX
81
#  include <utmpx.h>
82
# endif
83
# if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
84
#  define _PATH_UTMPX _UTMPX_FILE
85
# endif
86
# if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
87
#  define _PATH_WTMPX _WTMPX_FILE
88
# endif
89
#endif
90

    
91
/* for HP-UX (some versions) the extern C is needed, and for other
92
   platforms it doesn't hurt */
93
extern "C" {
94
#include <termios.h>
95
#if defined(HAVE_TERMIO_H)
96
# include <termio.h> // struct winsize on some systems
97
#endif
98
}
99

    
100
#if defined (_HPUX_SOURCE)
101
# define _TERMIOS_INCLUDED
102
# include <bsdtty.h>
103
#endif
104

    
105
#ifdef HAVE_SYS_STROPTS_H
106
# include <sys/stropts.h>        // Defines I_PUSH
107
# define _NEW_TTY_CTRL
108
#endif
109

    
110
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
111
# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
112

    
113
// http://markmail.org/download.xqy?id=atu7scqmvlsku4n5&number=2
114
typedef enum { F=0, T=1 } boolean;
115

    
116
static int utmpfd = -1;
117
static char utmpath[PATH_MAX+1] = _PATH_UTMP;
118
static boolean readonly = F;
119
static struct utmp utmp;
120

    
121

    
122
struct utmp *getutent();
123
struct utmp *getutid( struct utmp * );
124
struct utmp *getutline( struct utmp * );
125
void pututline( struct utmp * );
126
void setutent();
127
void endutent();
128
void utmpname( char * );
129

    
130

    
131
 static
132
 struct utmp *
133
_getutent( struct utmp *utmp )
134
{
135
  if ( utmpfd == -1 )
136
    {
137
      if ( (utmpfd = open(utmpath,O_RDWR)) == -1 )
138
        {
139
          if ( (utmpfd = open(utmpath,O_RDONLY)) == -1 )
140
            return NULL;
141
          else
142
            readonly = T;
143
        }
144
      else
145
        readonly = F;
146
    }
147

    
148
  if ( read(utmpfd,utmp,sizeof(struct utmp)) == sizeof(struct utmp) )
149
    return utmp;
150

    
151
  return NULL;
152
}
153

    
154

    
155
 struct utmp *
156
getutent()
157
{
158
  return _getutent( &utmp );
159
}
160

    
161

    
162
 struct utmp *
163
getutid( struct utmp *id )
164
{
165
  struct utmp *up;
166

    
167
  if ( strncmp(id->ut_name,utmp.ut_name,UT_NAMESIZE) == 0 )
168
    return &utmp;
169

    
170
  while( (up = getutent()) != NULL )
171
    {
172
      if ( strncmp(id->ut_name,up->ut_name,UT_NAMESIZE) == 0 )
173
        return up;
174
    }
175

    
176
  return NULL;
177
}
178

    
179

    
180
 struct utmp *
181
getutline( struct utmp *line )
182
{
183
  struct utmp *up;
184

    
185
  if ( strncmp(line->ut_line,utmp.ut_line,UT_LINESIZE) == 0 )
186
    return &utmp;
187

    
188
  while( (up = getutent()) != NULL )
189
    {
190
      if ( strncmp(line->ut_line,up->ut_line,UT_LINESIZE) == 0 )
191
        return up;
192
    }
193

    
194
  return NULL;
195
}
196

    
197

    
198
 void
199
pututline( struct utmp *up )
200
{
201
  struct utmp temp;
202
  struct stat buf;
203

    
204
  /* Note that UP might be equal to &UTMP */
205

    
206
  if ( strncmp(up->ut_name,utmp.ut_name,UT_NAMESIZE) == 0 )
207
    /* File already at correct position */
208
    {
209
      if ( ! readonly )
210
        {
211
          lseek( utmpfd, -(off_t)sizeof(struct utmp), SEEK_CUR );
212
          write( utmpfd, up, sizeof(struct utmp) );
213
        }
214

    
215
      utmp = *up;
216
    }
217
  else
218
    /* File is not at the correct postion; read forward, but do not destroy 
219
UTMP */
220
    {
221
      while( _getutent(&temp) != NULL )
222
        {
223
          if ( strncmp(up->ut_name,temp.ut_name,UT_NAMESIZE) == 0 )
224
            /* File is now at the correct position */
225
            {
226
              if ( ! readonly )
227
                {
228
                  lseek( utmpfd, -(off_t)sizeof(struct utmp), SEEK_CUR );
229
                  write( utmpfd, up, sizeof(struct utmp) );
230
                }
231

    
232
              utmp = *up;
233
              return;
234
            }
235
        }
236

    
237
      /* File is now at EOF */
238
      if ( ! readonly )
239
        {
240
          if ( fstat(utmpfd,&buf) == 0 && lseek(utmpfd,0,SEEK_END) != -1 )
241
            {
242
              if ( write(utmpfd,up,sizeof(struct utmp)) != sizeof(struct utmp) 
243
)
244
                ftruncate( utmpfd, buf.st_size );
245
            }
246
        }
247

    
248
      utmp = *up;
249
    }
250
}
251

    
252

    
253
 void
254
setutent()
255
{
256
  if ( utmpfd != -1 )
257
    lseek( utmpfd, 0, SEEK_SET );
258
}
259

    
260

    
261
 void
262
endutent()
263
{
264
  if ( utmpfd != -1 )
265
    {
266
      close( utmpfd );
267
      utmpfd = -1;
268

    
269
      memset( &utmp, 0, sizeof(struct utmp) );
270
    }
271
}
272

    
273

    
274
 void
275
utmpname( char *file )
276
{
277
  endutent();
278

    
279
  strncpy( utmpath, file, PATH_MAX );
280
}
281
// https://dev.mobileread.com/svn/iliados/upstream/tinylogin-1.4/libbb/libc5.c
282
void updwtmp(const char *wtmp_file, const struct utmp *lutmp)
283
{
284
        int fd;
285

    
286
        fd = open(wtmp_file, O_APPEND | O_WRONLY, 0);
287
        if (fd >= 0) {
288
                if (lockf(fd, F_LOCK, 0)==0) {
289
                        write(fd, (const char *) lutmp, sizeof(struct utmp));
290
                        lockf(fd, F_ULOCK, 0);
291
                        close(fd);
292
                }
293
        }
294
}
295

    
296
#else
297
# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
298
#  define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
299
# else
300
#  define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
301
# endif
302
#endif
303

    
304
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
305
# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
306
#else
307
# if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
308
#  define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
309
# else
310
#  define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
311
# endif
312
#endif
313

    
314
//#include <kdebug.h>
315
//#include <kstandarddirs.h>        // findExe
316

    
317
#include <QtCore>
318

    
319
// not defined on HP-UX for example
320
#ifndef CTRL
321
# define CTRL(x) ((x) & 037)
322
#endif
323

    
324
#define TTY_GROUP "tty"
325

    
326
///////////////////////
327
// private functions //
328
///////////////////////
329

    
330
//////////////////
331
// private data //
332
//////////////////
333

    
334
KPtyPrivate::KPtyPrivate() :
335
    masterFd(-1), slaveFd(-1)
336
{
337
}
338

    
339
bool KPtyPrivate::chownpty(bool)
340
{
341
//    return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
342
//        QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
343
    return true;
344
}
345

    
346
/////////////////////////////
347
// public member functions //
348
/////////////////////////////
349

    
350
KPty::KPty() :
351
    d_ptr(new KPtyPrivate)
352
{
353
    d_ptr->q_ptr = this;
354
}
355

    
356
KPty::KPty(KPtyPrivate *d) :
357
    d_ptr(d)
358
{
359
    d_ptr->q_ptr = this;
360
}
361

    
362
KPty::~KPty()
363
{
364
    close();
365
    delete d_ptr;
366
}
367

    
368
bool KPty::open()
369
{
370
  Q_D(KPty);
371

    
372
  if (d->masterFd >= 0)
373
    return true;
374

    
375
  QByteArray ptyName;
376

    
377
  // Find a master pty that we can open ////////////////////////////////
378

    
379
  // Because not all the pty animals are created equal, they want to
380
  // be opened by several different methods.
381

    
382
  // We try, as we know them, one by one.
383
/*
384
#ifdef HAVE_OPENPTY
385

386
  char ptsn[PATH_MAX];
387
  if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0))
388
  {
389
    d->masterFd = -1;
390
    d->slaveFd = -1;
391
    qWarning(175) << "Can't open a pseudo teletype";
392
    return false;
393
  }
394
  d->ttyName = ptsn;
395

396
#else
397
*/
398
#ifdef HAVE__GETPTY // irix
399

    
400
  char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
401
  if (ptsn) {
402
    d->ttyName = ptsn;
403
    goto grantedpt;
404
  }
405

    
406
#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
407

    
408
#ifdef HAVE_POSIX_OPENPT
409
  d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
410
#elif defined(HAVE_GETPT)
411
  d->masterFd = ::getpt();
412
#elif defined(PTM_DEVICE)
413
  d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
414
#else
415
# error No method to open a PTY master detected.
416
#endif
417

    
418
  if (d->masterFd >= 0)
419
  {
420
 
421
#ifdef HAVE_PTSNAME
422
    char *ptsn = ptsname(d->masterFd);
423
    if (ptsn) {
424
        d->ttyName = ptsn;
425
#else
426
    int ptyno;
427
    if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
428
        d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno);
429
#endif
430
#ifdef HAVE_GRANTPT
431
        if (!grantpt(d->masterFd))
432
           goto grantedpt;
433
#else
434

    
435
        goto gotpty;
436
#endif
437
    }
438
    ::close(d->masterFd);
439
    d->masterFd = -1;
440
  }
441
#endif // HAVE_PTSNAME || TIOCGPTN
442

    
443
  // Linux device names, FIXME: Trouble on other systems?
444
  for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
445
  {
446
    for (const char* s4 = "0123456789abcdef"; *s4; s4++)
447
    {
448
      ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
449
      d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
450

    
451
      d->masterFd = ::open(ptyName.data(), O_RDWR);
452
      if (d->masterFd >= 0)
453
      {
454
#ifdef Q_OS_SOLARIS
455
        /* Need to check the process group of the pty.
456
         * If it exists, then the slave pty is in use,
457
         * and we need to get another one.
458
         */
459
        int pgrp_rtn;
460
        if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
461
          ::close(d->masterFd);
462
          d->masterFd = -1;
463
          continue;
464
        }
465
#endif /* Q_OS_SOLARIS */
466
        if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
467
        {
468
          if (!geteuid())
469
          {
470
            struct group* p = getgrnam(TTY_GROUP);
471
            if (!p)
472
              p = getgrnam("wheel");
473
            gid_t gid = p ? p->gr_gid : getgid ();
474

    
475
            chown(d->ttyName.data(), getuid(), gid);
476
            chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
477
          }
478
          goto gotpty;
479
        }
480
        ::close(d->masterFd);
481
        d->masterFd = -1;
482
      }
483
    }
484
  }
485

    
486
  qWarning() << "Can't open a pseudo teletype";
487
  return false;
488

    
489
 gotpty:
490
  struct stat st;
491
  if (stat(d->ttyName.data(), &st)) {
492
    return false; // this just cannot happen ... *cough*  Yeah right, I just
493
                  // had it happen when pty #349 was allocated.  I guess
494
                  // there was some sort of leak?  I only had a few open.
495
    }
496
  if (((st.st_uid != getuid()) ||
497
       (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
498
      !d->chownpty(true))
499
  {
500
    qWarning()
501
      << "chownpty failed for device " << ptyName << "::" << d->ttyName
502
      << "\nThis means the communication can be eavesdropped." << endl;
503
  }
504

    
505
#if defined (HAVE__GETPTY) || defined (HAVE_GRANTPT)
506
 grantedpt:
507
#endif 
508

    
509
#ifdef HAVE_REVOKE
510
  revoke(d->ttyName.data());
511
#endif
512

    
513
#ifdef HAVE_UNLOCKPT
514
  unlockpt(d->masterFd);
515
#elif defined(TIOCSPTLCK)
516
  int flag = 0;
517
  ioctl(d->masterFd, TIOCSPTLCK, &flag);
518
#endif
519

    
520
  d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
521
  if (d->slaveFd < 0)
522
  {
523
    qWarning() << "Can't open slave pseudo teletype";
524
    ::close(d->masterFd);
525
    d->masterFd = -1;
526
    return false;
527
  }
528

    
529
#if (defined(__svr4__) || defined(__sgi__))
530
  // Solaris
531
  ioctl(d->slaveFd, I_PUSH, "ptem");
532
  ioctl(d->slaveFd, I_PUSH, "ldterm");
533
#endif
534

    
535
//#endif /* HAVE_OPENPTY */
536

    
537
  fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
538
  fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
539

    
540
  return true;
541
}
542

    
543
void KPty::closeSlave()
544
{
545
    Q_D(KPty);
546

    
547
    if (d->slaveFd < 0)
548
        return;
549
    ::close(d->slaveFd);
550
    d->slaveFd = -1;
551
}
552

    
553
void KPty::close()
554
{
555
   Q_D(KPty);
556

    
557
   if (d->masterFd < 0)
558
      return;
559
   closeSlave();
560
   // don't bother resetting unix98 pty, it will go away after closing master anyway.
561
   if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
562
      if (!geteuid()) {
563
         struct stat st;
564
         if (!stat(d->ttyName.data(), &st)) {
565
            chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
566
            chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
567
         }
568
      } else {
569
         fcntl(d->masterFd, F_SETFD, 0);
570
         d->chownpty(false);
571
      }
572
   }
573
   ::close(d->masterFd);
574
   d->masterFd = -1;
575
}
576

    
577
void KPty::setCTty()
578
{
579
    Q_D(KPty);
580

    
581
    // Setup job control //////////////////////////////////
582

    
583
    // Become session leader, process group leader,
584
    // and get rid of the old controlling terminal.
585
    setsid();
586

    
587
    // make our slave pty the new controlling terminal.
588
#ifdef TIOCSCTTY
589
    ioctl(d->slaveFd, TIOCSCTTY, 0);
590
#else
591
    // __svr4__ hack: the first tty opened after setsid() becomes controlling tty
592
    ::close(::open(d->ttyName, O_WRONLY, 0));
593
#endif
594

    
595
    // make our new process group the foreground group on the pty
596
    int pgrp = getpid();
597
#if defined(_POSIX_VERSION) || defined(__svr4__)
598
    tcsetpgrp(d->slaveFd, pgrp);
599
#elif defined(TIOCSPGRP)
600
    ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
601
#endif
602
}
603

    
604
#ifndef Q_OS_MAC
605
void KPty::login(const char *user, const char *remotehost)
606
{
607
#ifdef HAVE_UTEMPTER
608
    Q_D(KPty);
609

    
610
    addToUtmp(d->ttyName, remotehost, d->masterFd);
611
    Q_UNUSED(user);
612
#else
613
# ifdef HAVE_UTMPX
614
    struct utmpx l_struct;
615
# else
616
    struct utmp l_struct;
617
# endif
618
    memset(&l_struct, 0, sizeof(l_struct));
619
    // note: strncpy without terminators _is_ correct here. man 4 utmp
620

    
621
    if (user)
622
      strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
623

    
624
    if (remotehost) {
625
      strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
626
# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
627
      l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
628
# endif
629
    }
630

    
631
# ifndef __GLIBC__
632
    Q_D(KPty);
633
    const char *str_ptr = d->ttyName.data();
634
    if (!memcmp(str_ptr, "/dev/", 5))
635
        str_ptr += 5;
636
    strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
637
#  ifdef HAVE_STRUCT_UTMP_UT_ID
638
    strncpy(l_struct.ut_id,
639
            str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
640
            sizeof(l_struct.ut_id));
641
#  endif
642
# endif
643

    
644
# ifdef HAVE_UTMPX
645
    gettimeofday(&l_struct.ut_tv, 0);
646
# else
647
    l_struct.ut_time = time(0);
648
# endif
649

    
650
# ifdef HAVE_LOGIN
651
#  ifdef HAVE_LOGINX
652
    ::loginx(&l_struct);
653
#  else
654
    ::login(&l_struct);
655
#  endif
656
# else
657
#  ifdef HAVE_STRUCT_UTMP_UT_TYPE
658
    l_struct.ut_type = USER_PROCESS;
659
#  endif
660
#  ifdef HAVE_STRUCT_UTMP_UT_PID
661
    l_struct.ut_pid = getpid();
662
#   ifdef HAVE_STRUCT_UTMP_UT_SESSION
663
    l_struct.ut_session = getsid(0);
664
#   endif
665
#  endif
666
#  ifdef HAVE_UTMPX
667
    utmpxname(_PATH_UTMPX);
668
    setutxent();
669
    pututxline(&l_struct);
670
    endutxent();
671
    updwtmpx(_PATH_WTMPX, &l_struct);
672
#  else
673
    utmpname(_PATH_UTMP);
674
    setutent();
675
    pututline(&l_struct);
676
    endutent();
677
    updwtmp(_PATH_WTMP, &l_struct);
678
#  endif
679
# endif
680
#endif
681
}
682

    
683
void KPty::logout()
684
{
685
#ifdef HAVE_UTEMPTER
686
    Q_D(KPty);
687

    
688
    removeLineFromUtmp(d->ttyName, d->masterFd);
689
#else
690
    Q_D(KPty);
691

    
692
    const char *str_ptr = d->ttyName.data();
693
    if (!memcmp(str_ptr, "/dev/", 5))
694
        str_ptr += 5;
695
# ifdef __GLIBC__
696
    else {
697
        const char *sl_ptr = strrchr(str_ptr, '/');
698
        if (sl_ptr)
699
            str_ptr = sl_ptr + 1;
700
    }
701
# endif
702
# ifdef HAVE_LOGIN
703
#  ifdef HAVE_LOGINX
704
    ::logoutx(str_ptr, 0, DEAD_PROCESS);
705
#  else
706
    ::logout(str_ptr);
707
#  endif
708
# else
709
#  ifdef HAVE_UTMPX
710
    struct utmpx l_struct, *ut;
711
#  else
712
    struct utmp l_struct, *ut;
713
#  endif
714
    memset(&l_struct, 0, sizeof(l_struct));
715

    
716
    strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
717

    
718
#  ifdef HAVE_UTMPX
719
    utmpxname(_PATH_UTMPX);
720
    setutxent();
721
    if ((ut = getutxline(&l_struct))) {
722
#  else
723
    utmpname(_PATH_UTMP);
724
    setutent();
725
    if ((ut = getutline(&l_struct))) {
726
#  endif
727
        memset(ut->ut_name, 0, sizeof(*ut->ut_name));
728
        memset(ut->ut_host, 0, sizeof(*ut->ut_host));
729
#  ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
730
        ut->ut_syslen = 0;
731
#  endif
732
#  ifdef HAVE_STRUCT_UTMP_UT_TYPE
733
        ut->ut_type = DEAD_PROCESS;
734
#  endif
735
#  ifdef HAVE_UTMPX
736
        gettimeofday(ut->ut_tv, 0);
737
        pututxline(ut);
738
    }
739
    endutxent();
740
#  else
741
        ut->ut_time = time(0);
742
        pututline(ut);
743
    }
744
    endutent();
745
#  endif
746
# endif
747
#endif
748
}
749
#endif
750

    
751
// XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
752
// Please verify.
753

    
754
bool KPty::tcGetAttr(struct ::termios *ttmode) const
755
{
756
    Q_D(const KPty);
757

    
758
    return _tcgetattr(d->masterFd, ttmode) == 0;
759
}
760

    
761
bool KPty::tcSetAttr(struct ::termios *ttmode)
762
{
763
    Q_D(KPty);
764

    
765
    return _tcsetattr(d->masterFd, ttmode) == 0;
766
}
767

    
768
bool KPty::setWinSize(int lines, int columns)
769
{
770
    Q_D(KPty);
771

    
772
    struct winsize winSize;
773
    memset(&winSize, 0, sizeof(winSize));
774
    winSize.ws_row = (unsigned short)lines;
775
    winSize.ws_col = (unsigned short)columns;
776
    return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
777
}
778

    
779
bool KPty::setEcho(bool echo)
780
{
781
    struct ::termios ttmode;
782
    if (!tcGetAttr(&ttmode))
783
        return false;
784
    if (!echo)
785
        ttmode.c_lflag &= ~ECHO;
786
    else
787
        ttmode.c_lflag |= ECHO;
788
    return tcSetAttr(&ttmode);
789
}
790

    
791
const char *KPty::ttyName() const
792
{
793
    Q_D(const KPty);
794

    
795
    return d->ttyName.data();
796
}
797

    
798
int KPty::masterFd() const
799
{
800
    Q_D(const KPty);
801

    
802
    return d->masterFd;
803
}
804

    
805
int KPty::slaveFd() const
806
{
807
    Q_D(const KPty);
808

    
809
    return d->slaveFd;
810
}