Repository URL to install this package:
|
Version:
2.0.17 ▾
|
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
advanced (pluggable) hooks
they are executed before the other hooks, and can be extended by plugins
if a plugin tries to register an hook with a name already available in the list, its function
will be overridden
*/
struct uwsgi_hook *uwsgi_hook_by_name(char *name) {
struct uwsgi_hook *uh = uwsgi.hooks;
while(uh) {
if (!strcmp(uh->name, name)) {
return uh;
}
uh = uh->next;
}
return NULL;
}
void uwsgi_register_hook(char *name, int (*func)(char *)) {
struct uwsgi_hook *old_uh = NULL, *uh = uwsgi.hooks;
while(uh) {
if (!strcmp(uh->name, name)) {
uh->func = func;
return;
}
old_uh = uh;
uh = uh->next;
}
uh = uwsgi_calloc(sizeof(struct uwsgi_hook));
uh->name = name;
uh->func = func;
if (old_uh) {
old_uh->next = uh;
}
else {
uwsgi.hooks = uh;
}
}
static int uwsgi_hook_alarm(char *arg) {
char *space = strchr(arg,' ');
if (!space) {
uwsgi_log("invalid alarm hook syntax, must be: <alarm> <msg>\n");
return -1;
}
*space = 0;
uwsgi_alarm_trigger(arg, space+1, strlen(space+1));
*space = ' ';
return 0;
}
static int uwsgi_hook_chdir(char *arg) {
int ret = chdir(arg);
if (ret) {
uwsgi_error("uwsgi_hook_chdir()");
}
return ret;
}
static int uwsgi_hook_mkdir(char *arg) {
int ret = mkdir(arg, 0777);
if (ret) {
uwsgi_error("uwsgi_hook_mkdir()");
}
return ret;
}
static int uwsgi_hook_putenv(char *arg) {
int ret = putenv(arg);
if (ret) {
uwsgi_error("uwsgi_hook_putenv()");
}
return ret;
}
static int uwsgi_hook_exec(char *arg) {
int ret = uwsgi_run_command_and_wait(NULL, arg);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret);
}
return ret;
}
static int uwsgi_hook_safeexec(char *arg) {
int ret = uwsgi_run_command_and_wait(NULL, arg);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret);
}
return 0;
}
static int uwsgi_hook_exit(char *arg) {
int exit_code = 0;
if (strlen(arg) > 1) {
exit_code = atoi(arg);
}
exit(exit_code);
}
static int uwsgi_hook_print(char *arg) {
char *line = uwsgi_concat2(arg, "\n");
uwsgi_log(line);
free(line);
return 0;
}
static int uwsgi_hook_unlink(char *arg) {
int ret = unlink(arg);
if (ret) {
uwsgi_error("uwsgi_hook_unlink()/unlink()");
}
return ret;
}
static int uwsgi_hook_writefifo(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook writefifo syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY|O_NONBLOCK);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
if (errno == ENODEV) return 0;
#ifdef ENXIO
if (errno == ENXIO) return 0;
#endif
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
if (write(fd, space+1, l) != (ssize_t) l) {
uwsgi_error("uwsgi_hook_writefifo()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int uwsgi_hook_write(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook write syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
if (write(fd, space+1, l) != (ssize_t) l) {
uwsgi_error("uwsgi_hook_write()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int uwsgi_hook_creat(char *arg) {
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
return -1;
}
close(fd);
return 0;
}
static int uwsgi_hook_append(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook append syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
if (write(fd, space+1, l) != (ssize_t) l) {
uwsgi_error("uwsgi_hook_append()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int uwsgi_hook_writen(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook writen syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
char *buf = uwsgi_malloc(l + 1);
memcpy(buf, space+1, l);
buf[l] = '\n';
if (write(fd, buf, l+1) != (ssize_t) (l+1)) {
uwsgi_error("uwsgi_hook_writen()/write()");
free(buf);
close(fd);
return -1;
}
free(buf);
close(fd);
return 0;
}
static int uwsgi_hook_appendn(char *arg) {
char *space = strchr(arg, ' ');
if (space)
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
if (space)
*space = ' ';
return -1;
}
if (!space) {
// simple newline
if (write(fd, "\n", 1) != 1) {
uwsgi_error("uwsgi_hook_appendn()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
*space = ' ';
size_t l = strlen(space+1);
char *buf = uwsgi_malloc(l + 1);
memcpy(buf, space+1, l);
buf[l] = '\n';
if (write(fd, buf, l+1) != (ssize_t) (l+1)) {
uwsgi_error("uwsgi_hook_appendn()/write()");
free(buf);
close(fd);
return -1;
}
free(buf);
close(fd);
return 0;
}
static int uwsgi_hook_chmod(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook chmod syntax, must be: <file> <mode>\n");
return -1;
}
*space = 0;
int error = 0;
mode_t mask = uwsgi_mode_t(space+1, &error);
if (error) {
uwsgi_log("invalid hook chmod mask: %s\n", space+1);
*space = ' ';
return -1;
}
int ret = chmod(arg, mask);
*space = ' ';
if (ret) {
uwsgi_error("uwsgi_hook_chmod()/chmod()");
}
return ret;
}
static int uwsgi_hook_sticky(char *arg) {
struct stat st;
if (stat(arg, &st)) {
uwsgi_error("uwsgi_hook_sticky()/stat()");
return -1;
}
if (chmod(arg, st.st_mode | S_ISVTX)) {
uwsgi_error("uwsgi_hook_sticky()/chmod()");
return -1;
}
return 0;
}
static int uwsgi_hook_chown(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook chown syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space = 0;
char *space2 = strchr(space+1, ' ');
if (!space2) {
*space = ' ';
uwsgi_log("invalid hook chown syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space2 = 0;
struct passwd *pw = getpwnam(space+1);
if (!pw) {
uwsgi_log("unable to find uid %s\n", space+1);
*space = ' ';
*space2 = ' ';
return -1;
}
struct group *gr = getgrnam(space2+1);
if (!gr) {
uwsgi_log("unable to find gid %s\n", space2+1);
*space = ' ';
*space2 = ' ';
return -1;
}
int ret = chown(arg, pw->pw_uid, gr->gr_gid);
*space = ' ';
*space2 = ' ';
if (ret) {
uwsgi_error("uwsgi_hook_chown()/chown)");
}
return ret;
}
static int uwsgi_hook_chown2(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook chown2 syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space = 0;
char *space2 = strchr(space+1, ' ');
if (!space2) {
*space = ' ';
uwsgi_log("invalid hook chown2 syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space2 = 0;
if (!is_a_number(space+1)) {
uwsgi_log("invalid hook chown2 syntax, uid must be a number\n");
*space = ' ';
*space2 = ' ';
return -1;
}
if (!is_a_number(space2+1)) {
uwsgi_log("invalid hook chown2 syntax, gid must be a number\n");
*space = ' ';
*space2 = ' ';
return -1;
}
int ret = chown(arg, atoi(space+1), atoi(space2+1));
*space = ' ';
*space2 = ' ';
if (ret) {
uwsgi_error("uwsgi_hook_chown2()/chown)");
}
return ret;
}
#ifdef __sun__
extern int sethostname(char *, int);
#endif
static int uwsgi_hook_hostname(char *arg) {
#ifdef __CYGWIN__
return -1;
#else
return sethostname(arg, strlen(arg));
#endif
}
static int uwsgi_hook_unix_signal(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid unix_signal syntax, must be <signum> <func>\n");
return -1;
}
*space = 0;
int signum = atoi(arg);
*space = ' ';
void (*func)(int) = dlsym(RTLD_DEFAULT, space+1);
if (!func) {
uwsgi_log("unable to find function \"%s\"\n", space+1);
return -1;
}
uwsgi_unix_signal(signum, func);
return 0;
}
static int uwsgi_hook_callint(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
int num = atoi(space+1);
void (*func)(int) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num);
*space = ' ';
return -1;
}
*space = ' ';
func(num);
}
else {
void (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
func();
}
return 0;
}
static int uwsgi_hook_call(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
void (*func)(char *) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1);
*space = ' ';
return -1;
}
*space = ' ';
func(space + 1);
}
else {
void (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
func();
}
return 0;
}
static int uwsgi_hook_callintret(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
int num = atoi(space+1);
int (*func)(int) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num);
*space = ' ';
return -1;
}
*space = ' ';
return func(num);
}
int (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
return func();
}
static int uwsgi_hook_callret(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
int (*func)(char *) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1);
*space = ' ';
return -1;
}
*space = ' ';
return func(space + 1);
}
int (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
return func();
}
static int uwsgi_hook_rpc(char *arg) {
int ret = -1;
size_t i, argc = 0;
char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
if (!argc) goto end;
if (argc > 256) goto destroy;
char *argv[256];
uint16_t argvs[256];
char *node = NULL;
char *func = rargv[0];
char *at = strchr(func, '@');
if (at) {
*at = 0;
node = at + 1;
}
for(i=0;i<(argc-1);i++) {
size_t a_len = strlen(rargv[i+1]);
if (a_len > 0xffff) goto destroy;
argv[i] = rargv[i+1] ;
argvs[i] = a_len;
}
uint64_t size = 0;
// response must be always freed
char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size);
if (response) {
if (at) *at = '@';
uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response);
free(response);
ret = 0;
}
destroy:
for(i=0;i<argc;i++) {
free(rargv[i]);
}
end:
free(rargv);
return ret;
}
static int uwsgi_hook_retryrpc(char *arg) {
for(;;) {
int ret = uwsgi_hook_rpc(arg);
if (!ret) break;
sleep(2);
}
return 0;
}
static int uwsgi_hook_wait_for_fs(char *arg) {
return uwsgi_wait_for_fs(arg, 0);
}
static int uwsgi_hook_wait_for_file(char *arg) {
return uwsgi_wait_for_fs(arg, 1);
}
static int uwsgi_hook_wait_for_dir(char *arg) {
return uwsgi_wait_for_fs(arg, 2);
}
static int uwsgi_hook_wait_for_socket(char *arg) {
return uwsgi_wait_for_socket(arg);
}
static int spinningfifo_hook(char *arg) {
int fd;
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook spinningfifo syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
retry:
uwsgi_log("waiting for %s ...\n", arg);
fd = open(arg, O_WRONLY|O_NONBLOCK);
if (fd < 0) {
if (errno == ENODEV || errno == ENOENT) {
sleep(1);
goto retry;
}
#ifdef ENXIO
if (errno == ENXIO) {
sleep(1);
goto retry;
}
#endif
uwsgi_error_open(arg);
*space = ' ';
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
if (write(fd, space+1, l) != (ssize_t) l) {
uwsgi_error("spinningfifo_hook()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
uwsgi_register_hook("chdir", uwsgi_hook_chdir);
uwsgi_register_hook("mkdir", uwsgi_hook_mkdir);
uwsgi_register_hook("putenv", uwsgi_hook_putenv);
uwsgi_register_hook("chmod", uwsgi_hook_chmod);
uwsgi_register_hook("chown", uwsgi_hook_chown);
uwsgi_register_hook("chown2", uwsgi_hook_chown2);
uwsgi_register_hook("sticky", uwsgi_hook_sticky);
uwsgi_register_hook("exec", uwsgi_hook_exec);
uwsgi_register_hook("safeexec", uwsgi_hook_safeexec);
uwsgi_register_hook("create", uwsgi_hook_creat);
uwsgi_register_hook("creat", uwsgi_hook_creat);
uwsgi_register_hook("write", uwsgi_hook_write);
uwsgi_register_hook("writen", uwsgi_hook_writen);
uwsgi_register_hook("append", uwsgi_hook_append);
uwsgi_register_hook("appendn", uwsgi_hook_appendn);
uwsgi_register_hook("writefifo", uwsgi_hook_writefifo);
uwsgi_register_hook("unlink", uwsgi_hook_unlink);
uwsgi_register_hook("mount", uwsgi_mount_hook);
uwsgi_register_hook("umount", uwsgi_umount_hook);
uwsgi_register_hook("call", uwsgi_hook_call);
uwsgi_register_hook("callret", uwsgi_hook_callret);
uwsgi_register_hook("callint", uwsgi_hook_callint);
uwsgi_register_hook("callintret", uwsgi_hook_callintret);
uwsgi_register_hook("hostname", uwsgi_hook_hostname);
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
uwsgi_register_hook("wait_for_fs", uwsgi_hook_wait_for_fs);
uwsgi_register_hook("wait_for_file", uwsgi_hook_wait_for_file);
uwsgi_register_hook("wait_for_dir", uwsgi_hook_wait_for_dir);
uwsgi_register_hook("wait_for_socket", uwsgi_hook_wait_for_socket);
uwsgi_register_hook("unix_signal", uwsgi_hook_unix_signal);
uwsgi_register_hook("spinningfifo", spinningfifo_hook);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
uwsgi_register_hook("log", uwsgi_hook_print);
}
void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, l) {
char *colon = strchr(usl->value, ':');
if (!colon) {
uwsgi_log("invalid hook syntax, must be hook:args\n");
exit(1);
}
*colon = 0;
int private = 0;
char *action = usl->value;
// private hook ?
if (action[0] == '!') {
action++;
private = 1;
}
struct uwsgi_hook *uh = uwsgi_hook_by_name(action);
if (!uh) {
uwsgi_log("hook action not found: %s\n", action);
exit(1);
}
*colon = ':';
if (private) {
uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase);
}
else {
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
}
int ret = uh->func(colon+1);
if (fatal && ret != 0) {
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
if (uwsgi.master_process) {
if (uwsgi.workers) {
if (uwsgi.workers[0].pid == getpid()) {
kill_them_all(0);
return;
}
else {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("uwsgi_hooks_run()/kill()");
exit(1);
}
return;
}
}
}
exit(1);
}
}
}