1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 24 /* All Rights Reserved */ 25 26 /* 27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5.3.3 */ 32 33 #include "mt.h" 34 #include <stdlib.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <unistd.h> 38 #include <errno.h> 39 #include <stropts.h> 40 #include <sys/stream.h> 41 #define _SUN_TPI_VERSION 2 42 #include <sys/tihdr.h> 43 #include <sys/timod.h> 44 #include <sys/stat.h> 45 #include <xti.h> 46 #include <fcntl.h> 47 #include <signal.h> 48 #include <assert.h> 49 #include <syslog.h> 50 #include <limits.h> 51 #include "tx.h" 52 53 /* 54 * If _tx_open is called for transport that doesn't understand T_CAPABILITY_REQ 55 * TPI message, call to _t_create may fail the first time it is called with 56 * given transport (in the rare case when transport shuts down the stream with 57 * M_ERROR in reply to unknown T_CAPABILITY_REQ). In this case we may reopen the 58 * stream again since timod will emulate T_CAPABILITY_REQ behaviour. 59 * 60 * _t_create sends T_CAPABILITY_REQ through TI_CAPABILITY ioctl. 61 */ 62 63 int 64 _tx_open(const char *path, int flags, struct t_info *info, int api_semantics) 65 { 66 int retval, fd, sv_errno; 67 int sv_terrno; 68 int sv_errno_global; 69 struct _ti_user *tiptr; 70 sigset_t mask; 71 int t_create_first_attempt = 1; 72 int ticap_ioctl_failed = 0; 73 74 if (!(flags & O_RDWR)) { 75 t_errno = TBADFLAG; 76 return (-1); 77 } 78 79 sv_errno_global = errno; 80 sv_terrno = t_errno; 81 82 retry: 83 if ((fd = open(path, flags)) < 0) { 84 t_errno = TSYSERR; 85 if (_T_IS_XTI(api_semantics) && errno == ENOENT) 86 /* XTI only */ 87 t_errno = TBADNAME; 88 return (-1); 89 } 90 /* 91 * is module already pushed 92 */ 93 do { 94 retval = ioctl(fd, I_FIND, "timod"); 95 } while (retval < 0 && errno == EINTR); 96 97 if (retval < 0) { 98 sv_errno = errno; 99 100 t_errno = TSYSERR; 101 (void) close(fd); 102 errno = sv_errno; 103 return (-1); 104 } 105 106 if (retval == 0) { 107 /* 108 * "timod" not already on stream, then push it 109 */ 110 do { 111 /* 112 * Assumes (correctly) that I_PUSH is 113 * atomic w.r.t signals (EINTR error) 114 */ 115 retval = ioctl(fd, I_PUSH, "timod"); 116 } while (retval < 0 && errno == EINTR); 117 118 if (retval < 0) { 119 int sv_errno = errno; 120 121 t_errno = TSYSERR; 122 (void) close(fd); 123 errno = sv_errno; 124 return (-1); 125 } 126 } 127 128 /* 129 * _t_create() requires that all signals be blocked. 130 * Note that sig_mutex_lock() only defers signals, it does not 131 * block them, so interruptible syscalls could still get EINTR. 132 */ 133 (void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask); 134 sig_mutex_lock(&_ti_userlock); 135 /* 136 * Call to _t_create may fail either because transport doesn't 137 * understand T_CAPABILITY_REQ or for some other reason. It is nearly 138 * impossible to distinguish between these cases so it is implicitly 139 * assumed that it is always save to close and reopen the same stream 140 * and that open/close doesn't have side effects. _t_create may fail 141 * only once if its' failure is caused by unimplemented 142 * T_CAPABILITY_REQ. 143 */ 144 tiptr = _t_create(fd, info, api_semantics, &ticap_ioctl_failed); 145 if (tiptr == NULL) { 146 /* 147 * If _t_create failed due to fail of ti_capability_req we may 148 * try to reopen the stream in the hope that timod will emulate 149 * TI_CAPABILITY and it will succeed when called again. 150 */ 151 if (t_create_first_attempt == 1 && ticap_ioctl_failed == 1) { 152 t_create_first_attempt = 0; 153 (void) close(fd); 154 errno = sv_errno_global; 155 t_errno = sv_terrno; 156 sig_mutex_unlock(&_ti_userlock); 157 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 158 goto retry; 159 } else { 160 int sv_errno = errno; 161 (void) close(fd); 162 sig_mutex_unlock(&_ti_userlock); 163 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 164 errno = sv_errno; 165 return (-1); 166 } 167 } 168 169 /* 170 * _t_create synchronizes state witk kernel timod and 171 * already sets it to T_UNBND - what it needs to be 172 * be on T_OPEN event. No _T_TX_NEXTSTATE needed here. 173 */ 174 sig_mutex_unlock(&_ti_userlock); 175 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 176 177 do { 178 retval = ioctl(fd, I_FLUSH, FLUSHRW); 179 } while (retval < 0 && errno == EINTR); 180 181 /* 182 * We ignore other error cases (retval < 0) - assumption is 183 * that I_FLUSH failures is temporary (e.g. ENOSR) or 184 * otherwise benign failure on a this newly opened file 185 * descriptor and not a critical failure. 186 */ 187 188 return (fd); 189 } 190