©2004 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

c4/ptutil.c

Go to the documentation of this file.
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 /*[]*/

Generated on Fri Apr 23 10:56:55 2004 for AUP2 Example Source by doxygen 1.3.1