kdesu_pty.cpp
00001 /* vi: ts=8 sts=4 sw=4 00002 * 00003 * $Id$ 00004 * 00005 * This file is part of the KDE project, module kdesu. 00006 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org> 00007 * 00008 * This file contains code from TEShell.C of the KDE konsole. 00009 * Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> 00010 * 00011 * This is free software; you can use this library under the GNU Library 00012 * General Public License, version 2. See the file "COPYING.LIB" for the 00013 * exact licensing terms. 00014 * 00015 * pty.cpp: Access to PTY's on different systems a la UNIX98. 00016 */ 00017 00018 00019 #ifndef _GNU_SOURCE 00020 #define _GNU_SOURCE /* Needed for getpt, ptsname in glibc 2.1.x systems */ 00021 #endif 00022 00023 #include <config.h> 00024 00025 #include <stdio.h> 00026 #include <fcntl.h> 00027 #include <unistd.h> 00028 #include <string.h> 00029 #include <stdlib.h> 00030 #include <errno.h> 00031 00032 #include <sys/types.h> 00033 #include <sys/stat.h> 00034 #include <sys/wait.h> 00035 #include <sys/ioctl.h> 00036 #if defined(__osf__) || defined(__CYGWIN__) 00037 #include <pty.h> 00038 #endif 00039 00040 #include <tqglobal.h> 00041 #include <tqcstring.h> 00042 00043 #include <kdebug.h> 00044 #include <kstandarddirs.h> 00045 #include "kdesu_pty.h" 00046 00047 // stdlib.h is meant to declare the prototypes but doesn't :( 00048 #ifndef __THROW 00049 #define __THROW 00050 #endif 00051 00052 #ifdef HAVE_GRANTPT 00053 extern "C" int grantpt(int fd) __THROW; 00054 #endif 00055 00056 #ifdef HAVE_PTSNAME 00057 extern "C" char * ptsname(int fd) __THROW; 00058 #endif 00059 00060 #ifdef HAVE_UNLOCKPT 00061 extern "C" int unlockpt(int fd) __THROW; 00062 #endif 00063 00064 #ifdef HAVE__GETPTY 00065 extern "C" char *_getpty(int *, int, mode_t, int); 00066 #endif 00067 00068 #ifdef HAVE_PTY_H 00069 #include <pty.h> 00070 #endif 00071 00072 #include <termios.h> 00073 00074 #ifdef HAVE_LIBUTIL_H 00075 #include <libutil.h> 00076 #elif defined(HAVE_UTIL_H) 00077 #include <util.h> 00078 #endif 00079 00080 PTY::PTY() 00081 { 00082 ptyfd = -1; 00083 } 00084 00085 PTY::~PTY() 00086 { 00087 if (ptyfd >= 0) 00088 close(ptyfd); 00089 } 00090 00091 00092 // Opens a pty master and returns its filedescriptor. 00093 00094 int PTY::getpt() 00095 { 00096 00097 #if (defined(HAVE_GETPT) || defined(HAVE_POSIX_OPENPT)) && defined(HAVE_PTSNAME) 00098 00099 // 1: UNIX98: preferred way 00100 #ifdef HAVE_GETPT 00101 ptyfd = ::getpt(); 00102 #elif defined(HAVE_POSIX_OPENPT) 00103 ptyfd = ::posix_openpt(O_RDWR); 00104 #endif 00105 ttyname = ::ptsname(ptyfd); 00106 return ptyfd; 00107 00108 #elif defined(HAVE_OPENPTY) 00109 // 2: BSD interface 00110 // More preferred than the linux hacks 00111 char name[30]; 00112 int master_fd, slave_fd; 00113 if (openpty(&master_fd, &slave_fd, name, 0L, 0L) != -1) { 00114 ttyname = name; 00115 name[5]='p'; 00116 ptyname = name; 00117 close(slave_fd); // We don't need this yet // Yes, we do. 00118 ptyfd = master_fd; 00119 return ptyfd; 00120 } 00121 ptyfd = -1; 00122 kdDebug(900) << k_lineinfo << "Opening pty failed.\n"; 00123 return -1; 00124 00125 #elif defined(HAVE__GETPTY) 00126 // 3: Irix interface 00127 int master_fd; 00128 ttyname = _getpty(&master_fd,O_RDWR,0600,0); 00129 if (ttyname) 00130 ptyfd = master_fd; 00131 else{ 00132 ptyfd = -1; 00133 kdDebug(900) << k_lineinfo << "Opening pty failed.error" << errno << '\n'; 00134 } 00135 return ptyfd; 00136 00137 #else 00138 00139 // 4: Open terminal device directly 00140 // 4.1: Try /dev/ptmx first. (Linux w/ Unix98 PTYs, Solaris) 00141 00142 ptyfd = open("/dev/ptmx", O_RDWR); 00143 if (ptyfd >= 0) { 00144 ptyname = "/dev/ptmx"; 00145 #ifdef HAVE_PTSNAME 00146 ttyname = ::ptsname(ptyfd); 00147 return ptyfd; 00148 #elif defined (TIOCGPTN) 00149 int ptyno; 00150 if (ioctl(ptyfd, TIOCGPTN, &ptyno) == 0) { 00151 ttyname.sprintf("/dev/pts/%d", ptyno); 00152 return ptyfd; 00153 } 00154 #endif 00155 close(ptyfd); 00156 } 00157 00158 // 4.2: Try /dev/pty[p-e][0-f] (Linux w/o UNIX98 PTY's) 00159 00160 for (const char *c1 = "pqrstuvwxyzabcde"; *c1 != '\0'; c1++) 00161 { 00162 for (const char *c2 = "0123456789abcdef"; *c2 != '\0'; c2++) 00163 { 00164 ptyname.sprintf("/dev/pty%c%c", *c1, *c2); 00165 ttyname.sprintf("/dev/tty%c%c", *c1, *c2); 00166 if (access(ptyname, F_OK) < 0) 00167 goto linux_out; 00168 ptyfd = open(ptyname, O_RDWR); 00169 if (ptyfd >= 0) 00170 return ptyfd; 00171 } 00172 } 00173 linux_out: 00174 00175 // 4.3: Try /dev/pty%d (SCO, Unixware) 00176 00177 for (int i=0; i<256; i++) 00178 { 00179 ptyname.sprintf("/dev/ptyp%d", i); 00180 ttyname.sprintf("/dev/ttyp%d", i); 00181 if (access(ptyname, F_OK) < 0) 00182 break; 00183 ptyfd = open(ptyname, O_RDWR); 00184 if (ptyfd >= 0) 00185 return ptyfd; 00186 } 00187 00188 00189 // Other systems ?? 00190 ptyfd = -1; 00191 kdDebug(900) << k_lineinfo << "Unknown system or all methods failed.\n"; 00192 return -1; 00193 00194 #endif // HAVE_GETPT && HAVE_PTSNAME 00195 00196 } 00197 00198 00199 int PTY::grantpt() 00200 { 00201 if (ptyfd < 0) 00202 return -1; 00203 00204 #ifdef HAVE_GRANTPT 00205 00206 return ::grantpt(ptyfd); 00207 00208 #elif defined(HAVE_OPENPTY) 00209 00210 // the BSD openpty() interface chowns the devices properly for us, 00211 // no need to do this at all 00212 return 0; 00213 00214 #else 00215 00216 // konsole_grantpty only does /dev/pty?? 00217 if (ptyname.left(8) != "/dev/pty") 00218 return 0; 00219 00220 // Use konsole_grantpty: 00221 if (KStandardDirs::findExe("konsole_grantpty").isEmpty()) 00222 { 00223 kdError(900) << k_lineinfo << "konsole_grantpty not found.\n"; 00224 return -1; 00225 } 00226 00227 // As defined in konsole_grantpty.c 00228 const int pty_fileno = 3; 00229 00230 pid_t pid; 00231 if ((pid = fork()) == -1) 00232 { 00233 kdError(900) << k_lineinfo << "fork(): " << perror << "\n"; 00234 return -1; 00235 } 00236 00237 if (pid) 00238 { 00239 // Parent: wait for child 00240 int ret; 00241 waitpid(pid, &ret, 0); 00242 if (WIFEXITED(ret) && !WEXITSTATUS(ret)) 00243 return 0; 00244 kdError(900) << k_lineinfo << "konsole_grantpty returned with error: " 00245 << WEXITSTATUS(ret) << "\n"; 00246 return -1; 00247 } else 00248 { 00249 // Child: exec konsole_grantpty 00250 if (ptyfd != pty_fileno && dup2(ptyfd, pty_fileno) < 0) 00251 _exit(1); 00252 execlp("konsole_grantpty", "konsole_grantpty", "--grant", (void *)0); 00253 kdError(900) << k_lineinfo << "exec(): " << perror << "\n"; 00254 _exit(1); 00255 } 00256 00257 // shut up, gcc 00258 return 0; 00259 00260 #endif // HAVE_GRANTPT 00261 } 00262 00263 00268 int PTY::unlockpt() 00269 { 00270 if (ptyfd < 0) 00271 return -1; 00272 00273 #ifdef HAVE_UNLOCKPT 00274 00275 // (Linux w/ glibc 2.1, Solaris, ...) 00276 00277 return ::unlockpt(ptyfd); 00278 00279 #elif defined(TIOCSPTLCK) 00280 00281 // Unlock pty (Linux w/ UNIX98 PTY's & glibc 2.0) 00282 int flag = 0; 00283 return ioctl(ptyfd, TIOCSPTLCK, &flag); 00284 00285 #else 00286 00287 // Other systems (Linux w/o UNIX98 PTY's, ...) 00288 return 0; 00289 00290 #endif 00291 00292 } 00293 00294 00299 TQCString PTY::ptsname() 00300 { 00301 if (ptyfd < 0) 00302 return 0; 00303 00304 return ttyname; 00305 } 00306