Coverage Report

Created: 2026-09-04 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httpd/srclib/apr/file_io/unix/pipe.c
Line
Count
Source
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
static apr_status_t pipeblock(apr_file_t *thepipe)
24
0
{
25
0
      int fd_flags;
26
27
0
      fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
28
0
#  if defined(O_NONBLOCK)
29
0
      fd_flags &= ~O_NONBLOCK;
30
#  elif defined(O_NDELAY)
31
      fd_flags &= ~O_NDELAY;
32
#  elif defined(O_FNDELAY)
33
      fd_flags &= ~O_FNDELAY;
34
#  else
35
      /* XXXX: this breaks things, but an alternative isn't obvious...*/
36
      return APR_ENOTIMPL;
37
#  endif
38
0
      if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
39
0
          return errno;
40
0
      }
41
42
0
    thepipe->blocking = BLK_ON;
43
0
    return APR_SUCCESS;
44
0
}
45
46
static apr_status_t pipenonblock(apr_file_t *thepipe)
47
0
{
48
0
      int fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
49
50
0
#  if defined(O_NONBLOCK)
51
0
      fd_flags |= O_NONBLOCK;
52
#  elif defined(O_NDELAY)
53
      fd_flags |= O_NDELAY;
54
#  elif defined(O_FNDELAY)
55
      fd_flags |= O_FNDELAY;
56
#  else
57
      /* XXXX: this breaks things, but an alternative isn't obvious...*/
58
      return APR_ENOTIMPL;
59
#  endif
60
0
      if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
61
0
          return errno;
62
0
      }
63
64
0
    thepipe->blocking = BLK_OFF;
65
0
    return APR_SUCCESS;
66
0
}
67
68
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout)
69
0
{
70
0
    if (thepipe->is_pipe == 1) {
71
0
        thepipe->timeout = timeout;
72
0
        if (timeout >= 0) {
73
0
            if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */
74
0
                return pipenonblock(thepipe);
75
0
            }
76
0
        }
77
0
        else {
78
0
            if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */
79
0
                return pipeblock(thepipe);
80
0
            }
81
0
        }
82
0
        return APR_SUCCESS;
83
0
    }
84
0
    return APR_EINVAL;
85
0
}
86
87
APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout)
88
0
{
89
0
    if (thepipe->is_pipe == 1) {
90
0
        *timeout = thepipe->timeout;
91
0
        return APR_SUCCESS;
92
0
    }
93
0
    return APR_EINVAL;
94
0
}
95
96
APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file,
97
                                             apr_os_file_t *thefile,
98
                                             int register_cleanup,
99
                                             apr_pool_t *pool)
100
0
{
101
0
    int *dafile = thefile;
102
103
0
    (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
104
0
    (*file)->pool = pool;
105
0
    (*file)->eof_hit = 0;
106
0
    (*file)->is_pipe = 1;
107
0
    (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */
108
0
    (*file)->timeout = -1;
109
0
    (*file)->ungetchar = -1; /* no char avail */
110
0
    (*file)->filedes = *dafile;
111
0
    if (!register_cleanup) {
112
0
        (*file)->flags = APR_FOPEN_NOCLEANUP;
113
0
    }
114
0
    (*file)->buffered = 0;
115
0
#if APR_HAS_THREADS
116
0
    (*file)->thlock = NULL;
117
0
#endif
118
0
    if (register_cleanup) {
119
0
        apr_pool_cleanup_register((*file)->pool, (void *)(*file),
120
0
                                  apr_unix_file_cleanup,
121
0
                                  apr_pool_cleanup_null);
122
0
    }
123
#ifndef WAITIO_USES_POLL
124
    /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
125
     * initialize the pollset if needed.
126
     */
127
    (*file)->pollset = NULL;
128
#endif
129
0
    return APR_SUCCESS;
130
0
}
131
132
APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file,
133
                                          apr_os_file_t *thefile,
134
                                          apr_pool_t *pool)
135
0
{
136
0
    return apr_os_pipe_put_ex(file, thefile, 0, pool);
137
0
}
138
139
static apr_status_t file_pipe_create(apr_file_t **in,
140
                                     apr_file_t **out,
141
                                     apr_int32_t blocking,
142
                                     apr_pool_t *pool_in,
143
                                     apr_pool_t *pool_out)
144
0
{
145
0
    int filedes[2], fd_blocking;
146
0
    apr_interval_time_t fd_timeout;
147
148
0
#ifdef HAVE_PIPE2
149
0
    if (blocking == APR_FULL_NONBLOCK) {
150
0
        if (pipe2(filedes, O_NONBLOCK) == -1) {
151
0
            return errno;
152
0
        }
153
0
        fd_blocking = BLK_OFF;
154
0
        fd_timeout = 0;
155
0
    }
156
0
    else
157
0
#endif
158
0
    {
159
0
        if (pipe(filedes) == -1) {
160
0
            return errno;
161
0
        }
162
0
        fd_blocking = BLK_ON;
163
0
        fd_timeout = -1;
164
0
    }
165
166
0
    (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t));
167
0
    (*in)->pool = pool_in;
168
0
    (*in)->filedes = filedes[0];
169
0
    (*in)->is_pipe = 1;
170
0
    (*in)->fname = NULL;
171
0
    (*in)->buffered = 0;
172
0
    (*in)->blocking = fd_blocking;
173
0
    (*in)->timeout = fd_timeout;
174
0
    (*in)->ungetchar = -1;
175
0
    (*in)->flags = APR_INHERIT;
176
0
#if APR_HAS_THREADS
177
0
    (*in)->thlock = NULL;
178
0
#endif
179
#ifndef WAITIO_USES_POLL
180
    (*in)->pollset = NULL;
181
#endif
182
0
    (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t));
183
0
    (*out)->pool = pool_out;
184
0
    (*out)->filedes = filedes[1];
185
0
    (*out)->is_pipe = 1;
186
0
    (*out)->fname = NULL;
187
0
    (*out)->buffered = 0;
188
0
    (*out)->blocking = fd_blocking;
189
0
    (*out)->flags = APR_INHERIT;
190
0
    (*out)->timeout = fd_timeout;
191
0
#if APR_HAS_THREADS
192
0
    (*out)->thlock = NULL;
193
0
#endif
194
#ifndef WAITIO_USES_POLL
195
    (*out)->pollset = NULL;
196
#endif
197
0
    apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup,
198
0
                         apr_pool_cleanup_null);
199
0
    apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup,
200
0
                         apr_pool_cleanup_null);
201
202
0
    switch (blocking) {
203
0
    case APR_FULL_BLOCK:
204
0
        break;
205
0
    case APR_READ_BLOCK:
206
0
        apr_file_pipe_timeout_set(*out, 0);
207
0
        break;
208
0
    case APR_WRITE_BLOCK:
209
0
        apr_file_pipe_timeout_set(*in, 0);
210
0
        break;
211
0
    default:
212
        /* These are noops for the pipe2() case */
213
0
        apr_file_pipe_timeout_set(*out, 0);
214
0
        apr_file_pipe_timeout_set(*in, 0);
215
0
        break;
216
0
    }
217
0
    return APR_SUCCESS;
218
0
}
219
220
APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in,
221
                                               apr_file_t **out,
222
                                               apr_pool_t *pool)
223
0
{
224
    /* Default is full blocking pipes. */
225
0
    return file_pipe_create(in, out, APR_FULL_BLOCK, pool, pool);
226
0
}
227
228
APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in,
229
                                                  apr_file_t **out,
230
                                                  apr_int32_t blocking,
231
                                                  apr_pool_t *pool)
232
0
{
233
0
    return file_pipe_create(in, out, blocking, pool, pool);
234
0
}
235
236
APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in,
237
                                                     apr_file_t **out,
238
                                                     apr_int32_t blocking,
239
                                                     apr_pool_t *pool_in,
240
                                                     apr_pool_t *pool_out)
241
0
{
242
0
    return file_pipe_create(in, out, blocking, pool_in, pool_out);
243
0
}
244
245
APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
246
                                                    apr_fileperms_t perm, apr_pool_t *pool)
247
0
{
248
0
    mode_t mode = apr_unix_perms2mode(perm);
249
250
0
    if (mkfifo(filename, mode) == -1) {
251
0
        return errno;
252
0
    }
253
0
    return APR_SUCCESS;
254
0
}
255
256
257