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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 1993-2003 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 32 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5.3.3 */ 33 34 #include "mt.h" 35 #include <fcntl.h> 36 #include <rpc/trace.h> 37 #include <unistd.h> 38 #include <errno.h> 39 #include <stropts.h> 40 #define _SUN_TPI_VERSION 2 41 #include <sys/timod.h> 42 #include <xti.h> 43 #include <signal.h> 44 #include <syslog.h> 45 #include "tx.h" 46 47 /* 48 * If _tx_open is called for transport that doesn't understand T_CAPABILITY_REQ 49 * TPI message, call to _t_create may fail the first time it is called with 50 * given transport (in the rare case when transport shuts down the stream with 51 * M_ERROR in reply to unknown T_CAPABILITY_REQ). In this case we may reopen the 52 * stream again since timod will emulate T_CAPABILITY_REQ behaviour. 53 * 54 * _t_create sends T_CAPABILITY_REQ through TI_CAPABILITY ioctl. 55 */ 56 57 int 58 _tx_open(const char *path, int flags, struct t_info *info, int api_semantics) 59 { 60 int retval, fd, sv_errno; 61 int sv_terrno; 62 int sv_errno_global; 63 struct _ti_user *tiptr; 64 sigset_t mask; 65 int t_create_first_attempt = 1; 66 int ticap_ioctl_failed = 0; 67 68 trace2(TR_t_open, 0, flags); 69 if (!(flags & O_RDWR)) { 70 t_errno = TBADFLAG; 71 trace2(TR_t_open, 1, flags); 72 return (-1); 73 } 74 75 sv_errno_global = errno; 76 sv_terrno = t_errno; 77 78 retry: 79 if ((fd = open(path, flags)) < 0) { 80 sv_errno = errno; 81 82 trace2(TR_t_open, 1, flags); 83 errno = sv_errno; 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 trace2(TR_t_open, 1, flags); 103 errno = sv_errno; 104 return (-1); 105 } 106 107 if (retval == 0) { 108 /* 109 * "timod" not already on stream, then push it 110 */ 111 do { 112 /* 113 * Assumes (correctly) that I_PUSH is 114 * atomic w.r.t signals (EINTR error) 115 */ 116 retval = _ioctl(fd, I_PUSH, "timod"); 117 } while (retval < 0 && errno == EINTR); 118 119 if (retval < 0) { 120 int sv_errno = errno; 121 122 t_errno = TSYSERR; 123 (void) close(fd); 124 trace2(TR_t_open, 1, flags); 125 errno = sv_errno; 126 return (-1); 127 } 128 } 129 130 /* 131 * _t_create() requires that all signals be blocked. 132 * Note that sig_mutex_lock() only defers signals, it does not 133 * block them, so interruptible syscalls could still get EINTR. 134 */ 135 (void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask); 136 sig_mutex_lock(&_ti_userlock); 137 /* 138 * Call to _t_create may fail either because transport doesn't 139 * understand T_CAPABILITY_REQ or for some other reason. It is nearly 140 * impossible to distinguish between these cases so it is implicitly 141 * assumed that it is always save to close and reopen the same stream 142 * and that open/close doesn't have side effects. _t_create may fail 143 * only once if its' failure is caused by unimplemented 144 * T_CAPABILITY_REQ. 145 */ 146 tiptr = _t_create(fd, info, api_semantics, &ticap_ioctl_failed); 147 if (tiptr == NULL) { 148 /* 149 * If _t_create failed due to fail of ti_capability_req we may 150 * try to reopen the stream in the hope that timod will emulate 151 * TI_CAPABILITY and it will succeed when called again. 152 */ 153 if (t_create_first_attempt == 1 && ticap_ioctl_failed == 1) { 154 t_create_first_attempt = 0; 155 (void) close(fd); 156 errno = sv_errno_global; 157 t_errno = sv_terrno; 158 sig_mutex_unlock(&_ti_userlock); 159 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 160 goto retry; 161 } else { 162 int sv_errno = errno; 163 (void) close(fd); 164 sig_mutex_unlock(&_ti_userlock); 165 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 166 errno = sv_errno; 167 return (-1); 168 } 169 } 170 171 /* 172 * _t_create synchronizes state witk kernel timod and 173 * already sets it to T_UNBND - what it needs to be 174 * be on T_OPEN event. No _T_TX_NEXTSTATE needed here. 175 */ 176 sig_mutex_unlock(&_ti_userlock); 177 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 178 179 do { 180 retval = _ioctl(fd, I_FLUSH, FLUSHRW); 181 } while (retval < 0 && errno == EINTR); 182 183 /* 184 * We ignore other error cases (retval < 0) - assumption is 185 * that I_FLUSH failures is temporary (e.g. ENOSR) or 186 * otherwise benign failure on a this newly opened file 187 * descriptor and not a critical failure. 188 */ 189 190 trace2(TR_t_open, 1, flags); 191 return (fd); 192 } 193