00001 /* 00002 Pseudo-Terminal Library 00003 AUP2, Sec. 4.10.1 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 #include "defs.h" 00022 #include "ptutil.h" 00023 /*[NONPORTABILITY_SYMBOLS]*/ 00024 #if defined(SOLARIS) /* add to this as necessary */ 00025 #define NEED_STREAM_SETUP 00026 #endif 00027 00028 #if defined(FREEBSD) /* add to this as necessary */ 00029 #define NEED_TIOCSCTTY 00030 #endif 00031 00032 #ifndef _XOPEN_UNIX 00033 #define MASTER_NAME_SEARCH 00034 #endif 00035 /*[incl]*/ 00036 #ifdef _XOPEN_UNIX 00037 #include <stropts.h> /* for STREAMS */ 00038 #endif 00039 #ifdef NEED_TIOCSCTTY 00040 #include <sys/ttycom.h> /* for TIOCSCTTY */ 00041 #endif 00042 /*[]*/ 00043 /* 00044 Masters are of the form /dev/ptyXY. According to the FreeBSD 00045 documentation, X is in the range [p-sP-S] and Y is in the 00046 range [0-9a-v]. But, this is unlikely to be true of every 00047 FREEBSD-type system, so we will search X in the range [0-9A-Za-z] 00048 and Y in the same range. However, our algorithm assumes that for 00049 any X, the first valid Y is 0. That is, there is no need to waste 00050 time checking values of Y if there is no master with a Y of 0. 00051 */ 00052 /*[find_and_open_master]*/ 00053 #if defined(MASTER_NAME_SEARCH) 00054 #define PTY_RANGE \ 00055 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 00056 #define PTY_PROTO "/dev/ptyXY" 00057 #define PTY_X 8 00058 #define PTY_Y 9 00059 #define PTY_MS 5 /* replace with 't' to get slave name */ 00060 #endif /* MASTER_NAME_SEARCH */ 00061 00062 static bool find_and_open_master(PTINFO *p) 00063 { 00064 #if defined(_XOPEN_UNIX) 00065 #if _XOPEN_VERSION >= 600 00066 p->pt_name_m[0] = '\0'; /* don't know or need name */ 00067 ec_neg1( p->pt_fd_m = posix_openpt(O_RDWR | O_NOCTTY) ) 00068 #else 00069 strcpy(p->pt_name_m, "/dev/ptmx"); /* clone device */ 00070 ec_neg1( p->pt_fd_m = open(p->pt_name_m, O_RDWR) ) 00071 #endif 00072 #elif defined(MASTER_NAME_SEARCH) 00073 int i, j; 00074 char proto[] = PTY_PROTO; 00075 00076 if (p->pt_fd_m != -1) { 00077 (void)close(p->pt_fd_m); 00078 p->pt_fd_m = -1; 00079 } 00080 for (i = 0; i < sizeof(PTY_RANGE) - 1; i++) { 00081 proto[PTY_X] = PTY_RANGE[i]; 00082 proto[PTY_Y] = PTY_RANGE[0]; 00083 if (access(proto, F_OK) == -1) { 00084 if (errno == ENOENT) 00085 continue; 00086 EC_FAIL 00087 } 00088 for (j = 0; j < sizeof(PTY_RANGE) - 1; j++) { 00089 proto[PTY_Y] = PTY_RANGE[j]; 00090 if ((p->pt_fd_m = open(proto, O_RDWR)) == -1) { 00091 if (errno == ENOENT) 00092 break; 00093 } 00094 else { 00095 strcpy(p->pt_name_m, proto); 00096 break; 00097 } 00098 } 00099 if (p->pt_fd_m != -1) 00100 break; 00101 } 00102 if (p->pt_fd_m == -1) { 00103 errno = EAGAIN; 00104 EC_FAIL 00105 } 00106 #else 00107 errno = ENOSYS; 00108 EC_FAIL 00109 #endif 00110 return true; 00111 00112 EC_CLEANUP_BGN 00113 return false; 00114 EC_CLEANUP_END 00115 } 00116 /*[pt_open_master]*/ 00117 PTINFO *pt_open_master(void) 00118 { 00119 PTINFO *p = NULL; 00120 #ifdef _XOPEN_UNIX 00121 char *s; 00122 #endif 00123 00124 ec_null( p = calloc(1, sizeof(PTINFO)) ) 00125 p->pt_fd_m = -1; 00126 p->pt_fd_s = -1; 00127 ec_false( find_and_open_master(p) ) 00128 #ifdef _XOPEN_UNIX 00129 ec_neg1( grantpt(p->pt_fd_m) ) 00130 ec_neg1( unlockpt(p->pt_fd_m) ) 00131 ec_null( s = ptsname(p->pt_fd_m) ) 00132 if (strlen(s) >= PT_MAX_NAME) { 00133 errno = ENAMETOOLONG; 00134 EC_FAIL 00135 } 00136 strcpy(p->pt_name_s, s); 00137 #elif defined(MASTER_NAME_SEARCH) 00138 strcpy(p->pt_name_s, p->pt_name_m); 00139 p->pt_name_s[PTY_MS] = 't'; 00140 #else 00141 errno = ENOSYS; 00142 EC_FAIL 00143 #endif 00144 return p; 00145 00146 EC_CLEANUP_BGN 00147 if (p != NULL) { 00148 (void)close(p->pt_fd_m); 00149 (void)close(p->pt_fd_s); 00150 free(p); 00151 } 00152 return NULL; 00153 EC_CLEANUP_END 00154 } 00155 /*[]*/ 00156 /* 00157 Following function must be opened in child process, 00158 as it will set the controlling terminal. 00159 */ 00160 /*[pt_open_slave]*/ 00161 bool pt_open_slave(PTINFO *p) 00162 { 00163 ec_neg1( setsid() ) 00164 if (p->pt_fd_s != -1) 00165 ec_neg1( close(p->pt_fd_s) ) 00166 ec_neg1( p->pt_fd_s = open(p->pt_name_s, O_RDWR) ) 00167 #if defined(NEED_TIOCSCTTY) 00168 ec_neg1( ioctl(p->pt_fd_s, TIOCSCTTY, 0) ) 00169 #endif 00170 #if defined(NEED_STREAM_SETUP) 00171 ec_neg1( ioctl(p->pt_fd_s, I_PUSH, "ptem") ) 00172 ec_neg1( ioctl(p->pt_fd_s, I_PUSH, "ldterm") ) 00173 #endif 00174 /* 00175 Changing mode not that important, so don't fail if it doesn't 00176 work only because we're not superuser. 00177 */ 00178 if (fchmod(p->pt_fd_s, PERM_FILE) == -1 && errno != EPERM) 00179 EC_FAIL 00180 return true; 00181 00182 EC_CLEANUP_BGN 00183 return false; 00184 EC_CLEANUP_END 00185 } 00186 /*[pt_wait_master]*/ 00187 bool pt_wait_master(PTINFO *p) 00188 { 00189 fd_set fd_set_write; 00190 00191 FD_ZERO(&fd_set_write); 00192 FD_SET(PT_GET_MASTER_FD(p), &fd_set_write); 00193 ec_neg1( select(PT_GET_MASTER_FD(p) + 1, NULL, &fd_set_write, NULL, 00194 NULL) ) 00195 return true; 00196 00197 EC_CLEANUP_BGN 00198 return false; 00199 EC_CLEANUP_END 00200 } 00201 /*[pt_close_master]*/ 00202 bool pt_close_master(PTINFO *p) 00203 { 00204 ec_neg1( close(p->pt_fd_m) ) 00205 free(p); 00206 return true; 00207 00208 EC_CLEANUP_BGN 00209 return false; 00210 EC_CLEANUP_END 00211 } 00212 /*[pt_close_slave]*/ 00213 bool pt_close_slave(PTINFO *p) 00214 { 00215 (void)close(p->pt_fd_s); /* probably already closed */ 00216 free(p); 00217 return true; 00218 } 00219 /*[]*/