• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KPty

kpty.cpp

Go to the documentation of this file.
00001 /*
00002 
00003    This file is part of the KDE libraries
00004    Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
00005    Copyright (C) 2002-2003,2007-2008 Oswald Buddenhagen <ossi@kde.org>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "kpty_p.h"
00024 
00025 #include <config.h>
00026 
00027 #ifdef __sgi
00028 #define __svr4__
00029 #endif
00030 
00031 #ifdef __osf__
00032 #define _OSF_SOURCE
00033 #include <float.h>
00034 #endif
00035 
00036 #ifdef _AIX
00037 #define _ALL_SOURCE
00038 #endif
00039 
00040 // __USE_XOPEN isn't defined by default in ICC
00041 // (needed for ptsname(), grantpt() and unlockpt())
00042 #ifdef __INTEL_COMPILER
00043 #  ifndef __USE_XOPEN
00044 #    define __USE_XOPEN
00045 #  endif
00046 #endif
00047 
00048 #include <sys/types.h>
00049 #include <sys/ioctl.h>
00050 #include <sys/time.h>
00051 #include <sys/resource.h>
00052 #include <sys/stat.h>
00053 #include <sys/param.h>
00054 
00055 #include <errno.h>
00056 #include <fcntl.h>
00057 #include <time.h>
00058 #include <stdlib.h>
00059 #include <stdio.h>
00060 #include <string.h>
00061 #include <unistd.h>
00062 #include <grp.h>
00063 
00064 #if defined(HAVE_PTY_H)
00065 # include <pty.h>
00066 #endif
00067 
00068 #ifdef HAVE_LIBUTIL_H
00069 # include <libutil.h>
00070 #elif defined(HAVE_UTIL_H)
00071 # include <util.h>
00072 #endif
00073 
00074 #ifdef HAVE_UTEMPTER
00075 extern "C" {
00076 # include <utempter.h>
00077 }
00078 #else
00079 # include <utmp.h>
00080 # ifdef HAVE_UTMPX
00081 #  include <utmpx.h>
00082 # endif
00083 # if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
00084 #  define _PATH_UTMPX _UTMPX_FILE
00085 # endif
00086 # if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
00087 #  define _PATH_WTMPX _WTMPX_FILE
00088 # endif
00089 #endif
00090 
00091 /* for HP-UX (some versions) the extern C is needed, and for other
00092    platforms it doesn't hurt */
00093 extern "C" {
00094 #include <termios.h>
00095 #if defined(HAVE_TERMIO_H)
00096 # include <termio.h> // struct winsize on some systems
00097 #endif
00098 }
00099 
00100 #if defined (_HPUX_SOURCE)
00101 # define _TERMIOS_INCLUDED
00102 # include <bsdtty.h>
00103 #endif
00104 
00105 #ifdef HAVE_SYS_STROPTS_H
00106 # include <sys/stropts.h>   // Defines I_PUSH
00107 # define _NEW_TTY_CTRL
00108 #endif
00109 
00110 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
00111 # define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
00112 #else
00113 # if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
00114 #  define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
00115 # else
00116 #  define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
00117 # endif
00118 #endif
00119 
00120 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
00121 # define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
00122 #else
00123 # if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
00124 #  define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
00125 # else
00126 #  define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
00127 # endif
00128 #endif
00129 
00130 #include <kdebug.h>
00131 #include <kstandarddirs.h>  // findExe
00132 #include <kde_file.h>
00133 
00134 #include <QtCore/Q_PID>
00135 
00136 #define TTY_GROUP "tty"
00137 
00139 // private functions //
00141 
00143 // private data //
00145 
00146 KPtyPrivate::KPtyPrivate(KPty* parent) :
00147     masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent)
00148 {
00149 }
00150 
00151 KPtyPrivate::~KPtyPrivate()
00152 {
00153 }
00154 
00155 #ifndef HAVE_OPENPTY
00156 bool KPtyPrivate::chownpty(bool grant)
00157 {
00158     return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
00159         QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
00160 }
00161 #endif
00162 
00164 // public member functions //
00166 
00167 KPty::KPty() :
00168     d_ptr(new KPtyPrivate(this))
00169 {
00170 }
00171 
00172 KPty::KPty(KPtyPrivate *d) :
00173     d_ptr(d)
00174 {
00175     d_ptr->q_ptr = this;
00176 }
00177 
00178 KPty::~KPty()
00179 {
00180     close();
00181     delete d_ptr;
00182 }
00183 
00184 bool KPty::open()
00185 {
00186   Q_D(KPty);
00187 
00188   if (d->masterFd >= 0)
00189     return true;
00190 
00191   d->ownMaster = true;
00192 
00193   QByteArray ptyName;
00194 
00195   // Find a master pty that we can open ////////////////////////////////
00196 
00197   // Because not all the pty animals are created equal, they want to
00198   // be opened by several different methods.
00199 
00200   // We try, as we know them, one by one.
00201 
00202 #ifdef HAVE_OPENPTY
00203 
00204   char ptsn[PATH_MAX];
00205   if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0))
00206   {
00207     d->masterFd = -1;
00208     d->slaveFd = -1;
00209     kWarning(175) << "Can't open a pseudo teletype";
00210     return false;
00211   }
00212   d->ttyName = ptsn;
00213 
00214 #else
00215 
00216 #ifdef HAVE__GETPTY // irix
00217 
00218   char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
00219   if (ptsn) {
00220     d->ttyName = ptsn;
00221     goto grantedpt;
00222   }
00223 
00224 #elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
00225 
00226 #ifdef HAVE_POSIX_OPENPT
00227   d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
00228 #elif defined(HAVE_GETPT)
00229   d->masterFd = ::getpt();
00230 #elif defined(PTM_DEVICE)
00231   d->masterFd = KDE_open(PTM_DEVICE, O_RDWR|O_NOCTTY);
00232 #else
00233 # error No method to open a PTY master detected.
00234 #endif
00235   if (d->masterFd >= 0)
00236   {
00237 #ifdef HAVE_PTSNAME
00238     char *ptsn = ptsname(d->masterFd);
00239     if (ptsn) {
00240         d->ttyName = ptsn;
00241 #else
00242     int ptyno;
00243     if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
00244         char buf[32];
00245         sprintf(buf, "/dev/pts/%d", ptyno);
00246         d->ttyName = buf;
00247 #endif
00248 #ifdef HAVE_GRANTPT
00249         if (!grantpt(d->masterFd))
00250            goto grantedpt;
00251 #else
00252         goto gotpty;
00253 #endif
00254     }
00255     ::close(d->masterFd);
00256     d->masterFd = -1;
00257   }
00258 #endif // HAVE_PTSNAME || TIOCGPTN
00259 
00260   // Linux device names, FIXME: Trouble on other systems?
00261   for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
00262   {
00263     for (const char* s4 = "0123456789abcdef"; *s4; s4++)
00264     {
00265       ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
00266       d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
00267 
00268       d->masterFd = KDE_open(ptyName.data(), O_RDWR);
00269       if (d->masterFd >= 0)
00270       {
00271 #ifdef Q_OS_SOLARIS
00272         /* Need to check the process group of the pty.
00273          * If it exists, then the slave pty is in use,
00274          * and we need to get another one.
00275          */
00276         int pgrp_rtn;
00277         if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
00278           ::close(d->masterFd);
00279           d->masterFd = -1;
00280           continue;
00281         }
00282 #endif /* Q_OS_SOLARIS */
00283         if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
00284         {
00285           if (!geteuid())
00286           {
00287             struct group* p = getgrnam(TTY_GROUP);
00288             if (!p)
00289               p = getgrnam("wheel");
00290             gid_t gid = p ? p->gr_gid : getgid ();
00291 
00292             chown(d->ttyName.data(), getuid(), gid);
00293             chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
00294           }
00295           goto gotpty;
00296         }
00297         ::close(d->masterFd);
00298         d->masterFd = -1;
00299       }
00300     }
00301   }
00302 
00303   kWarning(175) << "Can't open a pseudo teletype";
00304   return false;
00305 
00306  gotpty:
00307   KDE_struct_stat st;
00308   if (KDE_stat(d->ttyName.data(), &st))
00309     return false; // this just cannot happen ... *cough*  Yeah right, I just
00310                   // had it happen when pty #349 was allocated.  I guess
00311                   // there was some sort of leak?  I only had a few open.
00312   if (((st.st_uid != getuid()) ||
00313        (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
00314       !d->chownpty(true))
00315   {
00316     kWarning(175)
00317       << "chownpty failed for device " << ptyName << "::" << d->ttyName
00318       << "\nThis means the communication can be eavesdropped." << endl;
00319   }
00320 
00321  grantedpt:
00322 
00323 #ifdef HAVE_REVOKE
00324   revoke(d->ttyName.data());
00325 #endif
00326 
00327 #ifdef HAVE_UNLOCKPT
00328   unlockpt(d->masterFd);
00329 #elif defined(TIOCSPTLCK)
00330   int flag = 0;
00331   ioctl(d->masterFd, TIOCSPTLCK, &flag);
00332 #endif
00333 
00334   d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY);
00335   if (d->slaveFd < 0)
00336   {
00337     kWarning(175) << "Can't open slave pseudo teletype";
00338     ::close(d->masterFd);
00339     d->masterFd = -1;
00340     return false;
00341   }
00342 
00343 #if (defined(__svr4__) || defined(__sgi__))
00344   // Solaris
00345   ioctl(d->slaveFd, I_PUSH, "ptem");
00346   ioctl(d->slaveFd, I_PUSH, "ldterm");
00347 #endif
00348 
00349 #endif /* HAVE_OPENPTY */
00350 
00351   fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
00352   fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
00353 
00354   return true;
00355 }
00356 
00357 bool KPty::open(int fd)
00358 {
00359 #if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN)
00360     kWarning(175) << "Unsupported attempt to open pty with fd" << fd;
00361     return false;
00362 #else
00363     Q_D(KPty);
00364 
00365     if (d->masterFd >= 0) {
00366         kWarning(175) << "Attempting to open an already open pty";
00367         return false;
00368     }
00369 
00370     d->ownMaster = false;
00371 
00372 # ifdef HAVE_PTSNAME
00373     char *ptsn = ptsname(fd);
00374     if (ptsn) {
00375         d->ttyName = ptsn;
00376 # else
00377     int ptyno;
00378     if (!ioctl(fd, TIOCGPTN, &ptyno)) {
00379         char buf[32];
00380         sprintf(buf, "/dev/pts/%d", ptyno);
00381         d->ttyName = buf;
00382 # endif
00383     } else {
00384         kWarning(175) << "Failed to determine pty slave device for fd" << fd;
00385         return false;
00386     }
00387 
00388     d->masterFd = fd;
00389     if (!openSlave()) {
00390         d->masterFd = -1;
00391         return false;
00392     }
00393 
00394     return true;
00395 #endif
00396 }
00397 
00398 void KPty::closeSlave()
00399 {
00400     Q_D(KPty);
00401 
00402     if (d->slaveFd < 0)
00403         return;
00404     ::close(d->slaveFd);
00405     d->slaveFd = -1;
00406 }
00407 
00408 bool KPty::openSlave()
00409 {
00410     Q_D(KPty);
00411 
00412     if (d->slaveFd >= 0)
00413         return true;
00414     if (d->masterFd < 0) {
00415         kWarning(175) << "Attempting to open pty slave while master is closed";
00416         return false;
00417     }
00418     d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY);
00419     if (d->slaveFd < 0) {
00420         kWarning(175) << "Can't open slave pseudo teletype";
00421         return false;
00422     }
00423     fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
00424     return true;
00425 }
00426 
00427 void KPty::close()
00428 {
00429     Q_D(KPty);
00430 
00431     if (d->masterFd < 0)
00432         return;
00433     closeSlave();
00434     if (d->ownMaster) {
00435 #ifndef HAVE_OPENPTY
00436         // don't bother resetting unix98 pty, it will go away after closing master anyway.
00437         if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
00438             if (!geteuid()) {
00439                 struct stat st;
00440                 if (!stat(d->ttyName.data(), &st)) {
00441                     chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
00442                     chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00443                 }
00444             } else {
00445                 fcntl(d->masterFd, F_SETFD, 0);
00446                 d->chownpty(false);
00447             }
00448         }
00449 #endif
00450         ::close(d->masterFd);
00451     }
00452     d->masterFd = -1;
00453 }
00454 
00455 void KPty::setCTty()
00456 {
00457     Q_D(KPty);
00458 
00459     // Setup job control //////////////////////////////////
00460 
00461     // Become session leader, process group leader,
00462     // and get rid of the old controlling terminal.
00463     setsid();
00464 
00465     // make our slave pty the new controlling terminal.
00466 #ifdef TIOCSCTTY
00467     ioctl(d->slaveFd, TIOCSCTTY, 0);
00468 #else
00469     // __svr4__ hack: the first tty opened after setsid() becomes controlling tty
00470     ::close(KDE_open(d->ttyName, O_WRONLY, 0));
00471 #endif
00472 
00473     // make our new process group the foreground group on the pty
00474     int pgrp = getpid();
00475 #if defined(_POSIX_VERSION) || defined(__svr4__)
00476     tcsetpgrp(d->slaveFd, pgrp);
00477 #elif defined(TIOCSPGRP)
00478     ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
00479 #endif
00480 }
00481 
00482 void KPty::login(const char *user, const char *remotehost)
00483 {
00484 #ifdef HAVE_UTEMPTER
00485     Q_D(KPty);
00486 
00487     addToUtmp(d->ttyName, remotehost, d->masterFd);
00488     Q_UNUSED(user);
00489 #else
00490 # ifdef HAVE_UTMPX
00491     struct utmpx l_struct;
00492 # else
00493     struct utmp l_struct;
00494 # endif
00495     memset(&l_struct, 0, sizeof(l_struct));
00496     // note: strncpy without terminators _is_ correct here. man 4 utmp
00497 
00498     if (user)
00499       strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
00500 
00501     if (remotehost) {
00502       strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
00503 # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
00504       l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
00505 # endif
00506     }
00507 
00508 # ifndef __GLIBC__
00509     Q_D(KPty);
00510     const char *str_ptr = d->ttyName.data();
00511     if (!memcmp(str_ptr, "/dev/", 5))
00512         str_ptr += 5;
00513     strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
00514 #  ifdef HAVE_STRUCT_UTMP_UT_ID
00515     strncpy(l_struct.ut_id,
00516             str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
00517             sizeof(l_struct.ut_id));
00518 #  endif
00519 # endif
00520 
00521 # ifdef HAVE_UTMPX
00522     gettimeofday(&l_struct.ut_tv, 0);
00523 # else
00524     l_struct.ut_time = time(0);
00525 # endif
00526 
00527 # ifdef HAVE_LOGIN
00528 #  ifdef HAVE_LOGINX
00529     ::loginx(&l_struct);
00530 #  else
00531     ::login(&l_struct);
00532 #  endif
00533 # else
00534 #  ifdef HAVE_STRUCT_UTMP_UT_TYPE
00535     l_struct.ut_type = USER_PROCESS;
00536 #  endif
00537 #  ifdef HAVE_STRUCT_UTMP_UT_PID
00538     l_struct.ut_pid = getpid();
00539 #   ifdef HAVE_STRUCT_UTMP_UT_SESSION
00540     l_struct.ut_session = getsid(0);
00541 #   endif
00542 #  endif
00543 #  ifdef HAVE_UTMPX
00544     utmpxname(_PATH_UTMPX);
00545     setutxent();
00546     pututxline(&l_struct);
00547     endutxent();
00548     updwtmpx(_PATH_WTMPX, &l_struct);
00549 #  else
00550     utmpname(_PATH_UTMP);
00551     setutent();
00552     pututline(&l_struct);
00553     endutent();
00554     updwtmp(_PATH_WTMP, &l_struct);
00555 #  endif
00556 # endif
00557 #endif
00558 }
00559 
00560 void KPty::logout()
00561 {
00562 #ifdef HAVE_UTEMPTER
00563     Q_D(KPty);
00564 
00565     removeLineFromUtmp(d->ttyName, d->masterFd);
00566 #else
00567     Q_D(KPty);
00568 
00569     const char *str_ptr = d->ttyName.data();
00570     if (!memcmp(str_ptr, "/dev/", 5))
00571         str_ptr += 5;
00572 # ifdef __GLIBC__
00573     else {
00574         const char *sl_ptr = strrchr(str_ptr, '/');
00575         if (sl_ptr)
00576             str_ptr = sl_ptr + 1;
00577     }
00578 # endif
00579 # ifdef HAVE_LOGIN
00580 #  ifdef HAVE_LOGINX
00581     ::logoutx(str_ptr, 0, DEAD_PROCESS);
00582 #  else
00583     ::logout(str_ptr);
00584 #  endif
00585 # else
00586 #  ifdef HAVE_UTMPX
00587     struct utmpx l_struct, *ut;
00588 #  else
00589     struct utmp l_struct, *ut;
00590 #  endif
00591     memset(&l_struct, 0, sizeof(l_struct));
00592 
00593     strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
00594 
00595 #  ifdef HAVE_UTMPX
00596     utmpxname(_PATH_UTMPX);
00597     setutxent();
00598     if ((ut = getutxline(&l_struct))) {
00599 #  else
00600     utmpname(_PATH_UTMP);
00601     setutent();
00602     if ((ut = getutline(&l_struct))) {
00603 #  endif
00604         memset(ut->ut_name, 0, sizeof(*ut->ut_name));
00605         memset(ut->ut_host, 0, sizeof(*ut->ut_host));
00606 #  ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
00607         ut->ut_syslen = 0;
00608 #  endif
00609 #  ifdef HAVE_STRUCT_UTMP_UT_TYPE
00610         ut->ut_type = DEAD_PROCESS;
00611 #  endif
00612 #  ifdef HAVE_UTMPX
00613         gettimeofday(&(ut->ut_tv), 0);
00614         pututxline(ut);
00615     }
00616     endutxent();
00617 #  else
00618         ut->ut_time = time(0);
00619         pututline(ut);
00620     }
00621     endutent();
00622 #  endif
00623 # endif
00624 #endif
00625 }
00626 
00627 // XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
00628 // Please verify.
00629 
00630 bool KPty::tcGetAttr(struct ::termios *ttmode) const
00631 {
00632     Q_D(const KPty);
00633 
00634     return _tcgetattr(d->masterFd, ttmode) == 0;
00635 }
00636 
00637 bool KPty::tcSetAttr(struct ::termios *ttmode)
00638 {
00639     Q_D(KPty);
00640 
00641     return _tcsetattr(d->masterFd, ttmode) == 0;
00642 }
00643 
00644 bool KPty::setWinSize(int lines, int columns)
00645 {
00646     Q_D(KPty);
00647 
00648     struct winsize winSize;
00649     memset(&winSize, 0, sizeof(winSize));
00650     winSize.ws_row = (unsigned short)lines;
00651     winSize.ws_col = (unsigned short)columns;
00652     return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
00653 }
00654 
00655 bool KPty::setEcho(bool echo)
00656 {
00657     struct ::termios ttmode;
00658     if (!tcGetAttr(&ttmode))
00659         return false;
00660     if (!echo)
00661         ttmode.c_lflag &= ~ECHO;
00662     else
00663         ttmode.c_lflag |= ECHO;
00664     return tcSetAttr(&ttmode);
00665 }
00666 
00667 const char *KPty::ttyName() const
00668 {
00669     Q_D(const KPty);
00670 
00671     return d->ttyName.data();
00672 }
00673 
00674 int KPty::masterFd() const
00675 {
00676     Q_D(const KPty);
00677 
00678     return d->masterFd;
00679 }
00680 
00681 int KPty::slaveFd() const
00682 {
00683     Q_D(const KPty);
00684 
00685     return d->slaveFd;
00686 }

KPty

Skip menu "KPty"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal