1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_arch_file_io.h" 18#include "apr_strings.h" 19#include "apr_portable.h" 20 21#include "apr_arch_inherit.h" 22 23/* Figure out how to get pipe block/nonblock on BeOS... 24 * Basically, BONE7 changed things again so that ioctl didn't work, 25 * but now fcntl does, hence we need to do this extra checking. 26 * The joys of beta programs. :-) 27 */ 28#if BEOS 29#if !BONE7 30# define BEOS_BLOCKING 1 31#else 32# define BEOS_BLOCKING 0 33#endif 34#endif 35 36static apr_status_t pipeblock(apr_file_t *thepipe) 37{ 38#if !BEOS_BLOCKING 39 int fd_flags; 40 41 fd_flags = fcntl(thepipe->filedes, F_GETFL, 0); 42# if defined(O_NONBLOCK) 43 fd_flags &= ~O_NONBLOCK; 44# elif defined(O_NDELAY) 45 fd_flags &= ~O_NDELAY; 46# elif defined(O_FNDELAY) 47 fd_flags &= ~O_FNDELAY; 48# else 49 /* XXXX: this breaks things, but an alternative isn't obvious...*/ 50 return APR_ENOTIMPL; 51# endif 52 if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) { 53 return errno; 54 } 55#else /* BEOS_BLOCKING */ 56 57# if BEOS_BONE /* This only works on BONE 0-6 */ 58 int on = 0; 59 if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) { 60 return errno; 61 } 62# else /* "classic" BeOS doesn't support this at all */ 63 return APR_ENOTIMPL; 64# endif 65 66#endif /* !BEOS_BLOCKING */ 67 68 thepipe->blocking = BLK_ON; 69 return APR_SUCCESS; 70} 71 72static apr_status_t pipenonblock(apr_file_t *thepipe) 73{ 74#if !BEOS_BLOCKING 75 int fd_flags = fcntl(thepipe->filedes, F_GETFL, 0); 76 77# if defined(O_NONBLOCK) 78 fd_flags |= O_NONBLOCK; 79# elif defined(O_NDELAY) 80 fd_flags |= O_NDELAY; 81# elif defined(O_FNDELAY) 82 fd_flags |= O_FNDELAY; 83# else 84 /* XXXX: this breaks things, but an alternative isn't obvious...*/ 85 return APR_ENOTIMPL; 86# endif 87 if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) { 88 return errno; 89 } 90 91#else /* BEOS_BLOCKING */ 92 93# if BEOS_BONE /* This only works on BONE 0-6 */ 94 int on = 1; 95 if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) { 96 return errno; 97 } 98# else /* "classic" BeOS doesn't support this at all */ 99 return APR_ENOTIMPL; 100# endif 101 102#endif /* !BEOS_BLOCKING */ 103 104 thepipe->blocking = BLK_OFF; 105 return APR_SUCCESS; 106} 107 108APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout) 109{ 110 if (thepipe->is_pipe == 1) { 111 thepipe->timeout = timeout; 112 if (timeout >= 0) { 113 if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */ 114 return pipenonblock(thepipe); 115 } 116 } 117 else { 118 if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */ 119 return pipeblock(thepipe); 120 } 121 } 122 return APR_SUCCESS; 123 } 124 return APR_EINVAL; 125} 126 127APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout) 128{ 129 if (thepipe->is_pipe == 1) { 130 *timeout = thepipe->timeout; 131 return APR_SUCCESS; 132 } 133 return APR_EINVAL; 134} 135 136APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, 137 apr_os_file_t *thefile, 138 int register_cleanup, 139 apr_pool_t *pool) 140{ 141 int *dafile = thefile; 142 143 (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); 144 (*file)->pool = pool; 145 (*file)->eof_hit = 0; 146 (*file)->is_pipe = 1; 147 (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */ 148 (*file)->timeout = -1; 149 (*file)->ungetchar = -1; /* no char avail */ 150 (*file)->filedes = *dafile; 151 if (!register_cleanup) { 152 (*file)->flags = APR_FOPEN_NOCLEANUP; 153 } 154 (*file)->buffered = 0; 155#if APR_HAS_THREADS 156 (*file)->thlock = NULL; 157#endif 158 if (register_cleanup) { 159 apr_pool_cleanup_register((*file)->pool, (void *)(*file), 160 apr_unix_file_cleanup, 161 apr_pool_cleanup_null); 162 } 163#ifndef WAITIO_USES_POLL 164 /* Start out with no pollset. apr_wait_for_io_or_timeout() will 165 * initialize the pollset if needed. 166 */ 167 (*file)->pollset = NULL; 168#endif 169 return APR_SUCCESS; 170} 171 172APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, 173 apr_os_file_t *thefile, 174 apr_pool_t *pool) 175{ 176 return apr_os_pipe_put_ex(file, thefile, 0, pool); 177} 178 179APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, apr_file_t **out, apr_pool_t *pool) 180{ 181 int filedes[2]; 182 183 if (pipe(filedes) == -1) { 184 return errno; 185 } 186 187 (*in) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); 188 (*in)->pool = pool; 189 (*in)->filedes = filedes[0]; 190 (*in)->is_pipe = 1; 191 (*in)->fname = NULL; 192 (*in)->buffered = 0; 193 (*in)->blocking = BLK_ON; 194 (*in)->timeout = -1; 195 (*in)->ungetchar = -1; 196 (*in)->flags = APR_INHERIT; 197#if APR_HAS_THREADS 198 (*in)->thlock = NULL; 199#endif 200#ifndef WAITIO_USES_POLL 201 (*in)->pollset = NULL; 202#endif 203 (*out) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); 204 (*out)->pool = pool; 205 (*out)->filedes = filedes[1]; 206 (*out)->is_pipe = 1; 207 (*out)->fname = NULL; 208 (*out)->buffered = 0; 209 (*out)->blocking = BLK_ON; 210 (*out)->flags = APR_INHERIT; 211 (*out)->timeout = -1; 212#if APR_HAS_THREADS 213 (*out)->thlock = NULL; 214#endif 215#ifndef WAITIO_USES_POLL 216 (*out)->pollset = NULL; 217#endif 218 apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup, 219 apr_pool_cleanup_null); 220 apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup, 221 apr_pool_cleanup_null); 222 return APR_SUCCESS; 223} 224 225APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, 226 apr_file_t **out, 227 apr_int32_t blocking, 228 apr_pool_t *pool) 229{ 230 apr_status_t status; 231 232 if ((status = apr_file_pipe_create(in, out, pool)) != APR_SUCCESS) 233 return status; 234 235 switch (blocking) { 236 case APR_FULL_BLOCK: 237 break; 238 case APR_READ_BLOCK: 239 apr_file_pipe_timeout_set(*out, 0); 240 break; 241 case APR_WRITE_BLOCK: 242 apr_file_pipe_timeout_set(*in, 0); 243 break; 244 default: 245 apr_file_pipe_timeout_set(*out, 0); 246 apr_file_pipe_timeout_set(*in, 0); 247 } 248 249 return APR_SUCCESS; 250} 251 252APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, 253 apr_fileperms_t perm, apr_pool_t *pool) 254{ 255 mode_t mode = apr_unix_perms2mode(perm); 256 257 if (mkfifo(filename, mode) == -1) { 258 return errno; 259 } 260 return APR_SUCCESS; 261} 262 263 264 265