/** * Copyright 2006 Paul Querna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "httpd.h" #include "http_core.h" #include "http_config.h" #include "http_protocol.h" #include "http_log.h" #include "ap_regex.h" #include "mod_dav_svn.h" #include "apr_strings.h" #include "svn_path.h" /* for setpriority/getpriority */ #include #include #include module AP_MODULE_DECLARE_DATA renice_module; typedef struct { const char *base_path; /* TODO/XXXX: Make this an array of matches/nice levels.*/ int renice; ap_regex_t regex; } renice_config_rec; typedef struct { int oldprio; } renice_baton; static void *create_config(apr_pool_t *p, char *d) { renice_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); conf->base_path = d; conf->renice = 0; return conf; } static const char *renice_set_config(cmd_parms *parms, void *vconf, const char *nice, const char *match) { renice_config_rec *conf = (renice_config_rec *) vconf; int inice = atoi(nice); if (inice > 20 || inice < -20) { return " must be between -20 and 20"; } if (ap_regcomp(&conf->regex, match, 0) != 0) { return "Unable to compile regex."; } conf->renice = inice; return NULL; } static apr_status_t reset_prio(void* vbaton) { renice_baton* baton = (renice_baton*) vbaton; setpriority(PRIO_PROCESS, getpid(), baton->oldprio); return APR_SUCCESS; } static int renice_it(request_rec *r) { int trailing_slash; const char *cleaned_uri; const char *repos_name; const char *relative_path; const char *repos_path; dav_error *dav_err; renice_baton *baton; renice_config_rec *conf = ap_get_module_config(r->per_dir_config, &renice_module); dav_err = dav_svn_split_uri(r, r->uri, conf->base_path, &cleaned_uri, &trailing_slash, &repos_name, &relative_path, &repos_path); if (dav_err) { /* give up, we don't care. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "renice: dav_err: %s [%d, #%d]", dav_err->desc, dav_err->status, dav_err->error_id); return OK; } if (repos_path == NULL) { repos_path = "/"; } if (ap_regexec(&conf->regex, svn_path_join("/", repos_path, r->pool), 0, NULL, 0) != 0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "renice: no match: %s", repos_path); } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "renice: matched."); baton = apr_palloc(r->pool, sizeof(renice_baton)); baton->oldprio = getpriority(getpid(), conf->renice); apr_pool_cleanup_register(r->pool, baton, reset_prio, apr_pool_cleanup_null); setpriority(PRIO_PROCESS, getpid(), conf->renice); } return OK; } static int renice_fixup(request_rec *r) { switch (r->method_number) { case M_REPORT: return renice_it(r); break; default: /* meh, only report hurts. */ break; } return OK; } static void register_hooks(apr_pool_t * p) { ap_hook_fixups(renice_fixup, NULL, NULL, APR_HOOK_FIRST); } static const command_rec renice_cmds[] = { AP_INIT_TAKE2("ReniceMatch", renice_set_config, NULL, OR_INDEXES, " "), {NULL} }; module AP_MODULE_DECLARE_DATA renice_module = { STANDARD20_MODULE_STUFF, create_config, NULL, NULL, NULL, renice_cmds, register_hooks, };