static const lwan_module_t *lwan_module_find(lwan_t *l, const char *name) { lwan_module_t *module = hash_find(l->module_registry, name); if (!module) { lwan_module_t *(*module_fn)(void); char module_symbol[128]; int r; for (const char *p = name; *p; p++) { if (isalnum(*p) || *p == '_') continue; lwan_status_error("Module name (%s) contains invalid character: %c", name, *p); return NULL; } r = snprintf(module_symbol, sizeof(module_symbol), "lwan_module_%s", name); if (r < 0 || r >= (int)sizeof(module_symbol)) { lwan_status_error("Module name too long: %s", name); return NULL; } module_fn = find_handler_symbol(module_symbol); if (!module_fn) { lwan_status_error("Module \"%s\" does not exist", name); return NULL; } module = module_fn(); if (!module) { lwan_status_error("Function \"%s()\" didn't return a module", module_symbol); return NULL; } lwan_status_debug("Module \"%s\" registered", name); hash_add(l->module_registry, module->name, module); } return module; }
static bool get_user_uid_gid(const char *user, uid_t *uid, gid_t *gid) { struct passwd pwd = { }; struct passwd *result; char *buf; long pw_size_max = sysconf(_SC_GETPW_R_SIZE_MAX); int r; if (!user || !*user) { lwan_status_error("Username should be provided"); return false; } if (pw_size_max < 0) pw_size_max = 16384; buf = malloc((size_t)pw_size_max); if (!buf) { lwan_status_error("Could not allocate buffer for passwd struct"); return false; } r = getpwnam_r(user, &pwd, buf, (size_t)pw_size_max, &result); *uid = pwd.pw_uid; *gid = pwd.pw_gid; free(buf); if (result) return true; if (!r) { lwan_status_error("Username not found: %s", user); } else { errno = r; lwan_status_perror("Could not obtain uid/gid for user %s", user); } return false; }
void lwan_thread_shutdown(lwan_t *l) { lwan_status_debug("Shutting down threads"); for (int i = l->thread.count - 1; i >= 0; i--) { lwan_thread_t *t = &l->thread.threads[i]; char less_than_int = 0; ssize_t r; lwan_status_debug("Closing epoll for thread %d (fd=%d)", i, t->epoll_fd); /* Close the epoll_fd and write less than an int to signal the * thread to gracefully finish. */ close(t->epoll_fd); while (true) { r = write(t->pipe_fd[1], &less_than_int, sizeof(less_than_int)); if (r >= 0) break; if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; lwan_status_error("Could not write to I/O thread (%d) pipe to shutdown", i); break; } } for (int i = l->thread.count - 1; i >= 0; i--) { lwan_thread_t *t = &l->thread.threads[i]; lwan_status_debug("Waiting for thread %d to finish", i); pthread_join(l->thread.threads[i].self, NULL); lwan_status_debug("Closing pipe (%d, %d)", t->pipe_fd[0], t->pipe_fd[1]); close(t->pipe_fd[0]); close(t->pipe_fd[1]); } free(l->thread.threads); }
static void *parse_config(struct parser *parser) { struct lexeme *lexeme; while (lex_next(&parser->lexer, &lexeme)) { switch (lexeme->type) { case LEXEME_EQUAL: return parse_key_value; case LEXEME_OPEN_BRACKET: return parse_section; case LEXEME_LINEFEED: if (parser->buffer.population) return parse_section_shorthand; return parse_config; case LEXEME_STRING: lexeme_buffer_emit(&parser->buffer, lexeme); break; case LEXEME_CLOSE_BRACKET: { struct config_line line = { .type = CONFIG_LINE_TYPE_SECTION_END }; config_buffer_emit(&parser->items, &line); return parse_config; } case LEXEME_EOF: return NULL; default: lwan_status_error("Unexpected lexeme type: %s", lexeme_type_str[lexeme->type]); return NULL; } } return NULL; }
static void *parse_key_value(struct parser *parser) { struct config_line line = { .type = CONFIG_LINE_TYPE_LINE }; struct lexeme *lexeme; size_t key_size; while (lexeme_buffer_consume(&parser->buffer, &lexeme)) { strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len); if (parser->buffer.population >= 1) strbuf_append_char(&parser->strbuf, '_'); } key_size = strbuf_get_length(&parser->strbuf); strbuf_append_char(&parser->strbuf, '\0'); while (lex_next(&parser->lexer, &lexeme)) { switch (lexeme->type) { case LEXEME_VARIABLE: { const char *value; value = secure_getenv_len(lexeme->value.value, lexeme->value.len); if (!value) { lwan_status_error("Variable '$%.*s' not defined in environment", (int)lexeme->value.len, lexeme->value.value); return NULL; } strbuf_append_str(&parser->strbuf, value, 0); break; } case LEXEME_EQUAL: strbuf_append_char(&parser->strbuf, '='); break; case LEXEME_STRING: strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len); break; case LEXEME_CLOSE_BRACKET: backup(&parser->lexer); /* fallthrough */ case LEXEME_LINEFEED: line.key = strbuf_get_buffer(&parser->strbuf); line.value = line.key + key_size + 1; if (!config_buffer_emit(&parser->items, &line)) return NULL; return parse_config; default: lwan_status_error("Unexpected token while parsing key-value: %s", lexeme_type_str[lexeme->type]); return NULL; } } lwan_status_error("EOF while parsing key-value"); return NULL; }