1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_file_io.h"
18251875Speter#include "apr_strings.h"
19251875Speter#include "apr_portable.h"
20251875Speter
21251875Speter#include "apr_arch_inherit.h"
22251875Speter
23251875Speter/* Figure out how to get pipe block/nonblock on BeOS...
24251875Speter * Basically, BONE7 changed things again so that ioctl didn't work,
25251875Speter * but now fcntl does, hence we need to do this extra checking.
26251875Speter * The joys of beta programs. :-)
27251875Speter */
28266735Speter#if defined(BEOS)
29266735Speter#if !defined(BONE7)
30251875Speter# define BEOS_BLOCKING 1
31251875Speter#else
32251875Speter# define BEOS_BLOCKING 0
33251875Speter#endif
34251875Speter#endif
35251875Speter
36251875Speterstatic apr_status_t pipeblock(apr_file_t *thepipe)
37251875Speter{
38266735Speter#if !defined(BEOS) || !BEOS_BLOCKING
39251875Speter      int fd_flags;
40251875Speter
41251875Speter      fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
42251875Speter#  if defined(O_NONBLOCK)
43251875Speter      fd_flags &= ~O_NONBLOCK;
44251875Speter#  elif defined(O_NDELAY)
45251875Speter      fd_flags &= ~O_NDELAY;
46251875Speter#  elif defined(O_FNDELAY)
47251875Speter      fd_flags &= ~O_FNDELAY;
48251875Speter#  else
49251875Speter      /* XXXX: this breaks things, but an alternative isn't obvious...*/
50251875Speter      return APR_ENOTIMPL;
51251875Speter#  endif
52251875Speter      if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
53251875Speter          return errno;
54251875Speter      }
55251875Speter#else /* BEOS_BLOCKING */
56251875Speter
57251875Speter#  if BEOS_BONE /* This only works on BONE 0-6 */
58251875Speter      int on = 0;
59251875Speter      if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) {
60251875Speter          return errno;
61251875Speter      }
62251875Speter#  else /* "classic" BeOS doesn't support this at all */
63251875Speter      return APR_ENOTIMPL;
64251875Speter#  endif
65251875Speter
66251875Speter#endif /* !BEOS_BLOCKING */
67251875Speter
68251875Speter    thepipe->blocking = BLK_ON;
69251875Speter    return APR_SUCCESS;
70251875Speter}
71251875Speter
72251875Speterstatic apr_status_t pipenonblock(apr_file_t *thepipe)
73251875Speter{
74266735Speter#if !defined(BEOS) || !BEOS_BLOCKING
75251875Speter      int fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
76251875Speter
77251875Speter#  if defined(O_NONBLOCK)
78251875Speter      fd_flags |= O_NONBLOCK;
79251875Speter#  elif defined(O_NDELAY)
80251875Speter      fd_flags |= O_NDELAY;
81251875Speter#  elif defined(O_FNDELAY)
82251875Speter      fd_flags |= O_FNDELAY;
83251875Speter#  else
84251875Speter      /* XXXX: this breaks things, but an alternative isn't obvious...*/
85251875Speter      return APR_ENOTIMPL;
86251875Speter#  endif
87251875Speter      if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
88251875Speter          return errno;
89251875Speter      }
90251875Speter
91251875Speter#else /* BEOS_BLOCKING */
92251875Speter
93251875Speter#  if BEOS_BONE /* This only works on BONE 0-6 */
94251875Speter      int on = 1;
95251875Speter      if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) {
96251875Speter          return errno;
97251875Speter      }
98251875Speter#  else /* "classic" BeOS doesn't support this at all */
99251875Speter      return APR_ENOTIMPL;
100251875Speter#  endif
101251875Speter
102251875Speter#endif /* !BEOS_BLOCKING */
103251875Speter
104251875Speter    thepipe->blocking = BLK_OFF;
105251875Speter    return APR_SUCCESS;
106251875Speter}
107251875Speter
108251875SpeterAPR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout)
109251875Speter{
110251875Speter    if (thepipe->is_pipe == 1) {
111251875Speter        thepipe->timeout = timeout;
112251875Speter        if (timeout >= 0) {
113251875Speter            if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */
114251875Speter                return pipenonblock(thepipe);
115251875Speter            }
116251875Speter        }
117251875Speter        else {
118251875Speter            if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */
119251875Speter                return pipeblock(thepipe);
120251875Speter            }
121251875Speter        }
122251875Speter        return APR_SUCCESS;
123251875Speter    }
124251875Speter    return APR_EINVAL;
125251875Speter}
126251875Speter
127251875SpeterAPR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout)
128251875Speter{
129251875Speter    if (thepipe->is_pipe == 1) {
130251875Speter        *timeout = thepipe->timeout;
131251875Speter        return APR_SUCCESS;
132251875Speter    }
133251875Speter    return APR_EINVAL;
134251875Speter}
135251875Speter
136251875SpeterAPR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file,
137251875Speter                                             apr_os_file_t *thefile,
138251875Speter                                             int register_cleanup,
139251875Speter                                             apr_pool_t *pool)
140251875Speter{
141251875Speter    int *dafile = thefile;
142251875Speter
143251875Speter    (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
144251875Speter    (*file)->pool = pool;
145251875Speter    (*file)->eof_hit = 0;
146251875Speter    (*file)->is_pipe = 1;
147251875Speter    (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */
148251875Speter    (*file)->timeout = -1;
149251875Speter    (*file)->ungetchar = -1; /* no char avail */
150251875Speter    (*file)->filedes = *dafile;
151251875Speter    if (!register_cleanup) {
152251875Speter        (*file)->flags = APR_FOPEN_NOCLEANUP;
153251875Speter    }
154251875Speter    (*file)->buffered = 0;
155251875Speter#if APR_HAS_THREADS
156251875Speter    (*file)->thlock = NULL;
157251875Speter#endif
158251875Speter    if (register_cleanup) {
159251875Speter        apr_pool_cleanup_register((*file)->pool, (void *)(*file),
160251875Speter                                  apr_unix_file_cleanup,
161251875Speter                                  apr_pool_cleanup_null);
162251875Speter    }
163251875Speter#ifndef WAITIO_USES_POLL
164251875Speter    /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
165251875Speter     * initialize the pollset if needed.
166251875Speter     */
167251875Speter    (*file)->pollset = NULL;
168251875Speter#endif
169251875Speter    return APR_SUCCESS;
170251875Speter}
171251875Speter
172251875SpeterAPR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file,
173251875Speter                                          apr_os_file_t *thefile,
174251875Speter                                          apr_pool_t *pool)
175251875Speter{
176251875Speter    return apr_os_pipe_put_ex(file, thefile, 0, pool);
177251875Speter}
178251875Speter
179362181Sdimstatic apr_status_t file_pipe_create(apr_file_t **in, apr_file_t **out,
180362181Sdim        apr_pool_t *pool_in, apr_pool_t *pool_out)
181251875Speter{
182251875Speter    int filedes[2];
183251875Speter
184251875Speter    if (pipe(filedes) == -1) {
185251875Speter        return errno;
186251875Speter    }
187251875Speter
188362181Sdim    (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t));
189362181Sdim    (*in)->pool = pool_in;
190251875Speter    (*in)->filedes = filedes[0];
191251875Speter    (*in)->is_pipe = 1;
192251875Speter    (*in)->fname = NULL;
193251875Speter    (*in)->buffered = 0;
194251875Speter    (*in)->blocking = BLK_ON;
195251875Speter    (*in)->timeout = -1;
196251875Speter    (*in)->ungetchar = -1;
197251875Speter    (*in)->flags = APR_INHERIT;
198251875Speter#if APR_HAS_THREADS
199251875Speter    (*in)->thlock = NULL;
200251875Speter#endif
201251875Speter#ifndef WAITIO_USES_POLL
202251875Speter    (*in)->pollset = NULL;
203251875Speter#endif
204362181Sdim    (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t));
205362181Sdim    (*out)->pool = pool_out;
206251875Speter    (*out)->filedes = filedes[1];
207251875Speter    (*out)->is_pipe = 1;
208251875Speter    (*out)->fname = NULL;
209251875Speter    (*out)->buffered = 0;
210251875Speter    (*out)->blocking = BLK_ON;
211251875Speter    (*out)->flags = APR_INHERIT;
212251875Speter    (*out)->timeout = -1;
213251875Speter#if APR_HAS_THREADS
214251875Speter    (*out)->thlock = NULL;
215251875Speter#endif
216251875Speter#ifndef WAITIO_USES_POLL
217251875Speter    (*out)->pollset = NULL;
218251875Speter#endif
219251875Speter    apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup,
220251875Speter                         apr_pool_cleanup_null);
221251875Speter    apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup,
222251875Speter                         apr_pool_cleanup_null);
223251875Speter    return APR_SUCCESS;
224251875Speter}
225251875Speter
226362181Sdimstatic void file_pipe_block(apr_file_t **in, apr_file_t **out, apr_int32_t blocking)
227362181Sdim{
228362181Sdim    switch (blocking) {
229362181Sdim    case APR_FULL_BLOCK:
230362181Sdim        break;
231362181Sdim    case APR_READ_BLOCK:
232362181Sdim        apr_file_pipe_timeout_set(*out, 0);
233362181Sdim        break;
234362181Sdim    case APR_WRITE_BLOCK:
235362181Sdim        apr_file_pipe_timeout_set(*in, 0);
236362181Sdim        break;
237362181Sdim    default:
238362181Sdim        apr_file_pipe_timeout_set(*out, 0);
239362181Sdim        apr_file_pipe_timeout_set(*in, 0);
240362181Sdim        break;
241362181Sdim    }
242362181Sdim}
243362181Sdim
244362181SdimAPR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in,
245362181Sdim        apr_file_t **out, apr_pool_t *pool)
246362181Sdim{
247362181Sdim    return file_pipe_create(in, out, pool, pool);
248362181Sdim}
249362181Sdim
250251875SpeterAPR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in,
251251875Speter                                                  apr_file_t **out,
252251875Speter                                                  apr_int32_t blocking,
253251875Speter                                                  apr_pool_t *pool)
254251875Speter{
255251875Speter    apr_status_t status;
256251875Speter
257362181Sdim    if ((status = file_pipe_create(in, out, pool, pool)) != APR_SUCCESS) {
258251875Speter        return status;
259362181Sdim    }
260251875Speter
261362181Sdim    file_pipe_block(in, out, blocking);
262362181Sdim
263362181Sdim    return APR_SUCCESS;
264362181Sdim}
265362181Sdim
266362181SdimAPR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in,
267362181Sdim        apr_file_t **out, apr_int32_t blocking, apr_pool_t *pool_in, apr_pool_t *pool_out)
268362181Sdim{
269362181Sdim    apr_status_t status;
270362181Sdim
271362181Sdim    if ((status = file_pipe_create(in, out, pool_in, pool_out)) != APR_SUCCESS) {
272362181Sdim        return status;
273251875Speter    }
274251875Speter
275362181Sdim    file_pipe_block(in, out, blocking);
276362181Sdim
277251875Speter    return APR_SUCCESS;
278251875Speter}
279251875Speter
280251875SpeterAPR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
281251875Speter                                                    apr_fileperms_t perm, apr_pool_t *pool)
282251875Speter{
283251875Speter    mode_t mode = apr_unix_perms2mode(perm);
284251875Speter
285251875Speter    if (mkfifo(filename, mode) == -1) {
286251875Speter        return errno;
287251875Speter    }
288251875Speter    return APR_SUCCESS;
289251875Speter}
290251875Speter
291251875Speter
292251875Speter
293