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 defined(BEOS) 29#if !defined(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 !defined(BEOS) || !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 !defined(BEOS) || !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 179static apr_status_t file_pipe_create(apr_file_t **in, apr_file_t **out, 180 apr_pool_t *pool_in, apr_pool_t *pool_out) 181{ 182 int filedes[2]; 183 184 if (pipe(filedes) == -1) { 185 return errno; 186 } 187 188 (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t)); 189 (*in)->pool = pool_in; 190 (*in)->filedes = filedes[0]; 191 (*in)->is_pipe = 1; 192 (*in)->fname = NULL; 193 (*in)->buffered = 0; 194 (*in)->blocking = BLK_ON; 195 (*in)->timeout = -1; 196 (*in)->ungetchar = -1; 197 (*in)->flags = APR_INHERIT; 198#if APR_HAS_THREADS 199 (*in)->thlock = NULL; 200#endif 201#ifndef WAITIO_USES_POLL 202 (*in)->pollset = NULL; 203#endif 204 (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t)); 205 (*out)->pool = pool_out; 206 (*out)->filedes = filedes[1]; 207 (*out)->is_pipe = 1; 208 (*out)->fname = NULL; 209 (*out)->buffered = 0; 210 (*out)->blocking = BLK_ON; 211 (*out)->flags = APR_INHERIT; 212 (*out)->timeout = -1; 213#if APR_HAS_THREADS 214 (*out)->thlock = NULL; 215#endif 216#ifndef WAITIO_USES_POLL 217 (*out)->pollset = NULL; 218#endif 219 apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup, 220 apr_pool_cleanup_null); 221 apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup, 222 apr_pool_cleanup_null); 223 return APR_SUCCESS; 224} 225 226static void file_pipe_block(apr_file_t **in, apr_file_t **out, apr_int32_t blocking) 227{ 228 switch (blocking) { 229 case APR_FULL_BLOCK: 230 break; 231 case APR_READ_BLOCK: 232 apr_file_pipe_timeout_set(*out, 0); 233 break; 234 case APR_WRITE_BLOCK: 235 apr_file_pipe_timeout_set(*in, 0); 236 break; 237 default: 238 apr_file_pipe_timeout_set(*out, 0); 239 apr_file_pipe_timeout_set(*in, 0); 240 break; 241 } 242} 243 244APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, 245 apr_file_t **out, apr_pool_t *pool) 246{ 247 return file_pipe_create(in, out, pool, pool); 248} 249 250APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, 251 apr_file_t **out, 252 apr_int32_t blocking, 253 apr_pool_t *pool) 254{ 255 apr_status_t status; 256 257 if ((status = file_pipe_create(in, out, pool, pool)) != APR_SUCCESS) { 258 return status; 259 } 260 261 file_pipe_block(in, out, blocking); 262 263 return APR_SUCCESS; 264} 265 266APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, 267 apr_file_t **out, apr_int32_t blocking, apr_pool_t *pool_in, apr_pool_t *pool_out) 268{ 269 apr_status_t status; 270 271 if ((status = file_pipe_create(in, out, pool_in, pool_out)) != APR_SUCCESS) { 272 return status; 273 } 274 275 file_pipe_block(in, out, blocking); 276 277 return APR_SUCCESS; 278} 279 280APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, 281 apr_fileperms_t perm, apr_pool_t *pool) 282{ 283 mode_t mode = apr_unix_perms2mode(perm); 284 285 if (mkfifo(filename, mode) == -1) { 286 return errno; 287 } 288 return APR_SUCCESS; 289} 290 291 292 293