Apache HTTPD
util_mutex.c
Go to the documentation of this file.
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/*
18 * util_mutex.c: Useful functions for determining allowable
19 * mutexes and mutex settings
20 */
21
22
23#include "apr.h"
24#include "apr_hash.h"
25#include "apr_strings.h"
26#include "apr_lib.h"
27
28#define APR_WANT_STRFUNC
29#include "apr_want.h"
30
31#include "ap_config.h"
32#include "httpd.h"
33#include "http_main.h"
34#include "http_config.h"
35#include "http_core.h"
36#include "http_log.h"
37#include "util_mutex.h"
38#if AP_NEED_SET_MUTEX_PERMS
39#include "unixd.h"
40#endif
41#ifdef HAVE_UNISTD_H
42#include <unistd.h> /* getpid() */
43#endif
44
45/* we know core's module_index is 0 */
46#undef APLOG_MODULE_INDEX
47#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
48
51 const char **mutexfile)
52{
53 /* Split arg into meth and file */
54 char *meth = apr_pstrdup(pool, arg);
55 char *file = strchr(meth, ':');
56 if (file) {
57 *(file++) = '\0';
58 if (!*file) {
59 file = NULL;
60 }
61 }
62
63 /* APR determines temporary filename unless overridden below,
64 * we presume file indicates an mutexfile is a file path
65 * unless the method sets mutexfile=file and NULLs file
66 */
67 *mutexfile = NULL;
68
69 if (!strcasecmp(meth, "none") || !strcasecmp(meth, "no")) {
70 return APR_ENOLOCK;
71 }
72
73 /* NOTE: previously, 'yes' implied 'sem' */
74 if (!strcasecmp(meth, "default") || !strcasecmp(meth, "yes")) {
76 }
77#if APR_HAS_FCNTL_SERIALIZE
78 else if (!strcasecmp(meth, "fcntl") || !strcasecmp(meth, "file")) {
80 }
81#endif
82#if APR_HAS_FLOCK_SERIALIZE
83 else if (!strcasecmp(meth, "flock") || !strcasecmp(meth, "file")) {
85 }
86#endif
87#if APR_HAS_POSIXSEM_SERIALIZE
88 else if (!strcasecmp(meth, "posixsem") || !strcasecmp(meth, "sem")) {
90 /* Posix/SysV semaphores aren't file based, use the literal name
91 * if provided and fall back on APR's default if not. Today, APR
92 * will ignore it, but once supported it has an absurdly short limit.
93 */
94 if (file) {
96
97 file = NULL;
98 }
99 }
100#endif
101#if APR_HAS_SYSVSEM_SERIALIZE
102 else if (!strcasecmp(meth, "sysvsem") || !strcasecmp(meth, "sem")) {
104 }
105#endif
106#if APR_HAS_PROC_PTHREAD_SERIALIZE
107 else if (!strcasecmp(meth, "pthread")) {
109 }
110#endif
111 else {
112 return APR_ENOTIMPL;
113 }
114
115 /* Unless the method above assumed responsibility for setting up
116 * mutexfile and NULLing out file, presume it is a file we
117 * are looking to use
118 */
119 if (file) {
121 if (!*mutexfile) {
122 return APR_BADARG;
123 }
124 }
125
126 return APR_SUCCESS;
127}
128
129typedef struct {
131 int set;
132 int none;
135 const char *dir;
137
138/* hash is created the first time a module calls ap_mutex_register(),
139 * rather than attempting to be the REALLY_REALLY_FIRST pre-config
140 * hook; it is cleaned up when the associated pool goes away; assume
141 * pconf is the pool passed to ap_mutex_register()
142 */
144
146{
147 mutex_cfg_t *def;
148
149 if (mxcfg_by_type) {
150 return;
151 }
152
156
157 /* initialize default mutex configuration */
158 def = apr_pcalloc(p, sizeof *def);
159 def->mech = APR_LOCK_DEFAULT;
160 def->dir = ap_runtime_dir_relative(p, "");
162}
163
165 const char *arg)
166{
167 apr_pool_t *p = cmd->pool;
168 apr_pool_t *ptemp = cmd->temp_pool;
169 const char **elt;
170 const char *mechdir;
171 int no_mutex = 0, omit_pid = 0;
174 apr_status_t rv;
175 const char *mutexdir;
177 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
178
179 if (err != NULL) {
180 return err;
181 }
182
183 mechdir = ap_getword_conf(cmd->pool, &arg);
184 if (*mechdir == '\0') {
185 return "Mutex requires at least a mechanism argument ("
187 }
188
190 if (rv == APR_ENOTIMPL) {
191 return apr_pstrcat(p, "Invalid Mutex argument ", mechdir,
193 }
194 else if (rv == APR_BADARG
195 || (mutexdir && !ap_is_directory(ptemp, mutexdir))) {
196 return apr_pstrcat(p, "Invalid Mutex directory in argument ",
197 mechdir, NULL);
198 }
199 else if (rv == APR_ENOLOCK) { /* "none" */
200 no_mutex = 1;
201 }
202
203 /* "OmitPID" can appear at the end of the list, so build a list of
204 * mutex type names while looking for "OmitPID" (anywhere) or the end
205 */
206 type_list = apr_array_make(cmd->pool, 4, sizeof(const char *));
207 while (*arg) {
208 const char *s = ap_getword_conf(cmd->pool, &arg);
209
210 if (!strcasecmp(s, "omitpid")) {
211 omit_pid = 1;
212 }
213 else {
214 const char **new_type = (const char **)apr_array_push(type_list);
215 *new_type = s;
216 }
217 }
218
219 if (apr_is_empty_array(type_list)) { /* no mutex type? assume "default" */
220 const char **new_type = (const char **)apr_array_push(type_list);
221 *new_type = "default";
222 }
223
224 while ((elt = (const char **)apr_array_pop(type_list)) != NULL) {
225 const char *type = *elt;
227 if (!mxcfg) {
228 return apr_psprintf(p, "Mutex type %s is not valid", type);
229 }
230
231 mxcfg->none = 0; /* in case that was the default */
232 mxcfg->omit_pid = omit_pid;
233
234 mxcfg->set = 1;
235 if (no_mutex) {
236 if (!(mxcfg->options & AP_MUTEX_ALLOW_NONE)) {
237 return apr_psprintf(p,
238 "None is not allowed for mutex type %s",
239 type);
240 }
241 mxcfg->none = 1;
242 }
243 else {
244 mxcfg->mech = mech;
245 if (mutexdir) { /* retain mutex default if not configured */
246 mxcfg->dir = mutexdir;
247 }
248 }
249 }
250
251 return NULL;
252}
253
255 const char *type,
256 const char *default_dir,
258 apr_int32_t options)
259{
261
262 if ((options & ~(AP_MUTEX_ALLOW_NONE | AP_MUTEX_DEFAULT_NONE))) {
263 return APR_EINVAL;
264 }
265
266 ap_mutex_init(pconf); /* in case this mod's pre-config ran before core's */
267
268 mxcfg->options = options;
269 if (options & AP_MUTEX_DEFAULT_NONE) {
270 mxcfg->none = 1;
271 }
272 mxcfg->dir = default_dir; /* usually NULL */
273 mxcfg->mech = default_mech; /* usually APR_LOCK_DEFAULT */
275
276 return APR_SUCCESS;
277}
278
280{
281 if (mech != APR_LOCK_FLOCK
282 && mech != APR_LOCK_FCNTL
285#endif
286 ) {
287 return 0;
288 }
289 return 1;
290}
291
293 const char *type,
294 const char *instance_id)
295{
296 const char *pid_suffix = "";
297
298 if (!mutex_needs_file(mxcfg->mech)) {
299 return NULL;
300 }
301
302#if HAVE_UNISTD_H
303 if (!mxcfg->omit_pid) {
305 }
306#endif
307
310 mxcfg->dir,
311 "/",
312 type,
313 instance_id ? "-" : "",
316 NULL));
317}
318
320{
322
324
325 /* MUST exist in table, or wasn't registered */
327 if (!mxcfg) {
328 return NULL;
329 }
330
331 /* order of precedence:
332 * 1. Mutex directive for this mutex
333 * 2. Mutex directive for "default"
334 * 3. Defaults for this mutex from ap_mutex_register()
335 * 4. Global defaults
336 */
337
338 if (mxcfg->set) {
339 newcfg = mxcfg;
340 }
341 else if (defcfg->set) {
342 newcfg = defcfg;
343 }
344 else if (mxcfg->none || mxcfg->mech != APR_LOCK_DEFAULT) {
345 newcfg = mxcfg;
346 }
347 else {
348 newcfg = defcfg;
349 }
350
351 if (!newcfg->none && mutex_needs_file(newcfg->mech) && !newcfg->dir) {
352 /* a file-based mutex mechanism was configured, but
353 * without a mutex file directory; go back through
354 * the chain to find the directory, store in new
355 * mutex cfg structure
356 */
357 newcfg = apr_pmemdup(p, newcfg, sizeof *newcfg);
358
359 /* !true if dir not already set: mxcfg->set && defcfg->dir */
360 if (defcfg->set && defcfg->dir) {
361 newcfg->dir = defcfg->dir;
362 }
363 else if (mxcfg->dir) {
364 newcfg->dir = mxcfg->dir;
365 }
366 else {
367 newcfg->dir = defcfg->dir;
368 }
369 }
370
371 return newcfg;
372}
373
374static void log_bad_create_options(server_rec *s, const char *type)
375{
377 "Invalid options were specified when creating the %s mutex",
378 type);
379}
380
381static void log_unknown_type(server_rec *s, const char *type)
382{
384 "Can't create mutex of unknown type %s", type);
385}
386
387static void log_create_failure(apr_status_t rv, server_rec *s, const char *type,
388 const char *fname)
389{
391 "Couldn't create the %s mutex %s%s%s", type,
392 fname ? "(file " : "",
393 fname ? fname : "",
394 fname ? ")" : "");
395}
396
397#ifdef AP_NEED_SET_MUTEX_PERMS
398static void log_perms_failure(apr_status_t rv, server_rec *s, const char *type)
399{
401 "Couldn't set permissions on the %s mutex; "
402 "check User and Group directives",
403 type);
404}
405#endif
406
408 const char **name,
409 const char *type,
410 const char *instance_id,
412 apr_int32_t options)
413{
414 apr_status_t rv;
415 const char *fname;
417
418 if (options) {
420 return APR_EINVAL;
421 }
422
423 if (!mxcfg) {
425 return APR_EINVAL;
426 }
427
428 if (mxcfg->none) {
429 *mutex = NULL;
430 return APR_SUCCESS;
431 }
432
434
435 rv = apr_global_mutex_create(mutex, fname, mxcfg->mech, p);
436 if (rv != APR_SUCCESS) {
438 return rv;
439 }
440
441 if (name)
442 *name = fname;
443
444#ifdef AP_NEED_SET_MUTEX_PERMS
446 if (rv != APR_SUCCESS) {
448 }
449#endif
450
451 return rv;
452}
453
455 const char **name,
456 const char *type,
457 const char *instance_id,
459 apr_int32_t options)
460{
461 apr_status_t rv;
462 const char *fname;
464
465 if (options) {
467 return APR_EINVAL;
468 }
469
470 if (!mxcfg) {
472 return APR_EINVAL;
473 }
474
475 if (mxcfg->none) {
476 *mutex = NULL;
477 return APR_SUCCESS;
478 }
479
481
482 rv = apr_proc_mutex_create(mutex, fname, mxcfg->mech, p);
483 if (rv != APR_SUCCESS) {
485 return rv;
486 }
487
488 if (name)
489 *name = fname;
490
491#ifdef AP_NEED_SET_MUTEX_PERMS
493 if (rv != APR_SUCCESS) {
495 }
496#endif
497
498 return rv;
499}
500
502{
506 {
508 const char *name, *mech = "<unknown>";
509 const void *name_;
510 const char *dir = "";
512 name = name_;
514 if (mxcfg == defcfg && strcmp(name, "default") != 0) {
515 apr_file_printf(out, "Mutex %s: using_defaults\n", name);
516 continue;
517 }
518 if (mxcfg->none) {
519 apr_file_printf(out, "Mutex %s: none\n", name);
520 continue;
521 }
522 switch (mxcfg->mech) {
523 case APR_LOCK_DEFAULT:
524 mech = "default";
525 break;
526#if APR_HAS_FCNTL_SERIALIZE
527 case APR_LOCK_FCNTL:
528 mech = "fcntl";
529 break;
530#endif
531#if APR_HAS_FLOCK_SERIALIZE
532 case APR_LOCK_FLOCK:
533 mech = "flock";
534 break;
535#endif
536#if APR_HAS_POSIXSEM_SERIALIZE
538 mech = "posixsem";
539 break;
540#endif
541#if APR_HAS_SYSVSEM_SERIALIZE
542 case APR_LOCK_SYSVSEM:
543 mech = "sysvsem";
544 break;
545#endif
546#if APR_HAS_PROC_PTHREAD_SERIALIZE
548 mech = "pthread";
549 break;
550#endif
551 default:
552 ap_assert(0);
553 }
554
555 if (mxcfg->dir)
557
558 apr_file_printf(out, "Mutex %s: dir=\"%s\" mechanism=%s %s\n", name, dir, mech,
559 mxcfg->omit_pid ? "[OmitPid]" : "");
560 }
561}
Symbol export macros and hook functions.
#define AP_DECLARE_NONSTD(type)
Definition ap_config.h:77
#define AP_DECLARE(type)
Definition ap_config.h:67
APR Hash Tables.
APR general purpose library routines.
APR Strings library.
APR Standard Headers Support.
static apr_pool_t * pconf
Definition event.c:441
char * ap_runtime_dir_relative(apr_pool_t *p, const char *fname)
Definition config.c:1610
apr_status_t ap_pool_cleanup_set_null(void *data)
Definition util.c:2710
char * ap_server_root_relative(apr_pool_t *p, const char *fname)
Definition config.c:1594
#define AP_CORE_DECLARE
Definition httpd.h:381
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_EMERG
Definition http_log.h:64
apr_status_t ap_global_mutex_create(apr_global_mutex_t **mutex, const char **name, const char *type, const char *instance_id, server_rec *s, apr_pool_t *p, apr_int32_t options)
Definition util_mutex.c:407
#define AP_MUTEX_DEFAULT_NONE
Definition util_mutex.h:114
apr_status_t ap_proc_mutex_create(apr_proc_mutex_t **mutex, const char **name, const char *type, const char *instance_id, server_rec *s, apr_pool_t *p, apr_int32_t options)
Definition util_mutex.c:454
apr_status_t ap_parse_mutex(const char *arg, apr_pool_t *pool, apr_lockmech_e *mutexmech, const char **mutexfile)
Definition util_mutex.c:49
#define AP_MUTEX_ALLOW_NONE
Definition util_mutex.h:113
#define AP_ALL_AVAILABLE_MUTEXES_STRING
Definition util_mutex.h:69
const char * ap_set_mutex(cmd_parms *cmd, void *dummy, const char *arg)
Definition util_mutex.c:164
void ap_mutex_init(apr_pool_t *p)
Definition util_mutex.c:145
apr_status_t ap_mutex_register(apr_pool_t *pconf, const char *type, const char *default_dir, apr_lockmech_e default_mech, apr_int32_t options)
Definition util_mutex.c:254
void ap_dump_mutexes(apr_pool_t *p, server_rec *s, apr_file_t *out)
Definition util_mutex.c:501
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define APR_BADARG
Definition apr_errno.h:459
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENOLOCK
Definition apr_errno.h:303
#define APR_EINVAL
Definition apr_errno.h:711
const char apr_lockmech_e mech
int ap_is_directory(apr_pool_t *p, const char *name)
Definition util.c:2326
#define ap_assert(exp)
Definition httpd.h:2271
char * ap_getword_conf(apr_pool_t *p, const char **line)
Definition util.c:833
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char apr_file_t * file
int type
const char * fname
int strcasecmp(const char *a, const char *b)
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_dir_t * dir
apr_lockmech_e
@ APR_LOCK_FLOCK
@ APR_LOCK_SYSVSEM
@ APR_LOCK_POSIXSEM
@ APR_LOCK_PROC_PTHREAD
@ APR_LOCK_FCNTL
@ APR_LOCK_DEFAULT
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
Command line options.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static apr_file_t * out
Definition mod_info.c:85
return NULL
Definition mod_so.c:359
char * name
const char * dir
Definition util_mutex.c:135
apr_lockmech_e mech
Definition util_mutex.c:134
apr_int32_t options
Definition util_mutex.c:130
A structure to store information for each virtual server.
Definition httpd.h:1322
static const char * get_mutex_filename(apr_pool_t *p, mutex_cfg_t *mxcfg, const char *type, const char *instance_id)
Definition util_mutex.c:292
static void log_bad_create_options(server_rec *s, const char *type)
Definition util_mutex.c:374
static void log_create_failure(apr_status_t rv, server_rec *s, const char *type, const char *fname)
Definition util_mutex.c:387
static void log_unknown_type(server_rec *s, const char *type)
Definition util_mutex.c:381
static mutex_cfg_t * mxcfg_lookup(apr_pool_t *p, const char *type)
Definition util_mutex.c:319
static apr_hash_t * mxcfg_by_type
Definition util_mutex.c:143
static int mutex_needs_file(apr_lockmech_e mech)
Definition util_mutex.c:279
Apache Mutex support library.