示例#1
0
文件: logger.c 项目: gencer/memcached
/* Public function for logging an entry.
 * Tries to encapsulate as much of the formatting as possible to simplify the
 * caller's code.
 */
enum logger_ret_type logger_log(logger *l, const enum log_entry_type event, const void *entry, ...) {
    bipbuf_t *buf = l->buf;
    bool nospace = false;
    va_list ap;
    int total = 0;
    logentry *e;

    const entry_details *d = &l->entry_map[event];
    int reqlen = d->reqlen;

    pthread_mutex_lock(&l->mutex);
    /* Request a maximum length of data to write to */
    e = (logentry *) bipbuf_request(buf, (sizeof(logentry) + reqlen));
    if (e == NULL) {
        pthread_mutex_unlock(&l->mutex);
        l->dropped++;
        return LOGGER_RET_NOSPACE;
    }
    e->gid = logger_get_gid();
    e->event = d->subtype;
    /* TODO: Could pass this down as an argument now that we're using
     * LOGGER_LOG() macro.
     */
    e->eflags = d->eflags;
    /* Noting time isn't optional. A feature may be added to avoid rendering
     * time and/or gid to a logger.
     */
    gettimeofday(&e->tv, NULL);

    switch (d->subtype) {
        case LOGGER_TEXT_ENTRY:
            va_start(ap, entry);
            total = vsnprintf((char *) e->data, reqlen, d->format, ap);
            va_end(ap);
            if (total >= reqlen || total <= 0) {
                fprintf(stderr, "LOGGER: Failed to vsnprintf a text entry: (total) %d\n", total);
                break;
            }
            e->size = total + 1; /* null byte */

            break;
        case LOGGER_EVICTION_ENTRY:
            _logger_log_evictions(e, (item *)entry);
            break;
#ifdef EXTSTORE
        case LOGGER_EXT_WRITE_ENTRY:
            va_start(ap, entry);
            int ew_bucket = va_arg(ap, int);
            va_end(ap);
            _logger_log_ext_write(e, (item *)entry, ew_bucket);
            break;
#endif
        case LOGGER_ITEM_GET_ENTRY:
            va_start(ap, entry);
            int was_found = va_arg(ap, int);
            char *key = va_arg(ap, char *);
            size_t nkey = va_arg(ap, size_t);
            uint8_t gclsid = va_arg(ap, int);
            _logger_log_item_get(e, was_found, key, nkey, gclsid);
            va_end(ap);
            break;
        case LOGGER_ITEM_STORE_ENTRY:
            va_start(ap, entry);
            enum store_item_type status = va_arg(ap, enum store_item_type);
            int comm = va_arg(ap, int);
            char *skey = va_arg(ap, char *);
            size_t snkey = va_arg(ap, size_t);
            rel_time_t sttl = va_arg(ap, rel_time_t);
            uint8_t sclsid = va_arg(ap, int);
            _logger_log_item_store(e, status, comm, skey, snkey, sttl, sclsid);
            break;
    }

    /* Push pointer forward by the actual amount required */
    if (bipbuf_push(buf, (sizeof(logentry) + e->size)) == 0) {
        fprintf(stderr, "LOGGER: Failed to bipbuf push a text entry\n");
        pthread_mutex_unlock(&l->mutex);
        return LOGGER_RET_ERR;
    }
    l->written++;
    L_DEBUG("LOGGER: Requested %d bytes, wrote %lu bytes\n", reqlen,
            (sizeof(logentry) + e->size));

    pthread_mutex_unlock(&l->mutex);

    if (nospace) {
        return LOGGER_RET_NOSPACE;
    } else {
        return LOGGER_RET_OK;
    }
}
示例#2
0
static ya_result
config_main_section_postprocess(struct config_section_descriptor_s *csd)
{
    u32 port = 0;
    u32 cpu_per_core = (sys_has_hyperthreading())?2:1;
    int ret;
    char tmp[PATH_MAX];



    if(FAIL(parse_u32_check_range(g_config->server_port, &port, 1, MAX_U16, 10)))
    {
        port = DNS_DEFAULT_PORT;
        ttylog_err("config: main: wrong dns port set in main '%s', defaulted to %d", g_config->server_port, port);
    }
    
    if(g_config->hostname_chaos == NULL)
    {
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200112L 
        if(gethostname(tmp, sizeof(tmp)) == 0)
        {
            g_config->hostname_chaos = strdup(tmp);
        }
        else
        {
            osformatln(termerr,"config: main: unable to get hostname: %r", ERRNO_ERROR);
            g_config->hostname_chaos = strdup("not disclosed");
        }
#else
        g_config->hostname_chaos = strdup("not disclosed");
#endif
    }
       
    if(g_config->thread_affinity_multiplier == 0)
    {
        g_config->thread_affinity_multiplier = cpu_per_core;
    }
    
    class_ch_set_hostname(g_config->hostname_chaos);    
    class_ch_set_id_server(g_config->serverid_chaos);
    class_ch_set_version(g_config->version_chaos);
    
    host_set_default_port_value(g_config->listen, ntohs(port));

    if(g_config->server_flags & SERVER_FL_CHROOT)
    {
        uid_t euid = geteuid();
        
        if(euid != 0)
        {
            ttylog_err("config: main: chroot has been enabled but euid is not root (%i != 0)", (int)euid);
            return INVALID_STATE_ERROR;
        }
    }
    else // disables the base-path/chroot-path feature
    {
        if(strcmp(g_config->chroot_path, "/") != 0)
        {
            free(g_config->chroot_path);
            g_config->chroot_path = strdup("/");
            chroot_set_path(g_config->chroot_path);
        }
    }
    
    message_edns0_setmaxsize(g_config->edns0_max_size);    
    
    g_config->total_interfaces = host_address_count(g_config->listen);
    
    if(g_config->total_interfaces > MAX_INTERFACES)
    {
        ttylog_err("error: more than %d listening addresses defined.", MAX_INTERFACES);
        return CONFIG_TOO_MANY_HOSTS;
    }

#ifndef SO_REUSEPORT
    if(g_config->network_model == 1)
    {
        ttylog_err("error: network-model 1 requires features not available on this system (SO_REUSEPORT)");
        return FEATURE_NOT_SUPPORTED;
    }
#endif
    
    g_config->axfr_retry_jitter = BOUND(AXFR_RETRY_JITTER_MIN, g_config->axfr_retry_jitter, g_config->axfr_retry_delay);
    
    g_config->dnssec_thread_count = BOUND(1, g_config->dnssec_thread_count, sys_get_cpu_count());
    
    if(g_config->cpu_count_override > 0)
    {
        sys_set_cpu_count(g_config->cpu_count_override);
    }

    if(g_config->thread_count_by_address == 0)
    {
        ttylog_err("config: single thread engine has been removed, thread-count-by-address set to 1");
        g_config->thread_count_by_address = 1;
    }
    
    if(g_config->thread_count_by_address < 0)
    {
        g_config->thread_count_by_address = MAX(sys_get_cpu_count() / cpu_per_core, 1);
    }
    else if((g_config->thread_count_by_address > sys_get_cpu_count()))
    {
        g_config->thread_count_by_address = MAX(sys_get_cpu_count() / cpu_per_core, 1);
        ttylog_err("config: bounding down thread-count-by-address to the number of physical CPUs (%d)", g_config->thread_count_by_address);
    }
    
    g_config->tcp_query_min_rate_us = g_config->tcp_query_min_rate * 0.000001;
    
#if HAS_DNSSEC_SUPPORT
    g_config->dnssec_thread_count = BOUND(1, g_config->dnssec_thread_count, sys_get_cpu_count());

    if(!IS_TYPE_PRIVATE(g_config->sig_signing_type))
    {
        ttylog_err("error: signing type is not in the accepted range: %hx", g_config->sig_signing_type);
        return CONFIG_WRONG_SIG_TYPE;
    }
    
    if(g_config->sig_validity_interval > SIGNATURE_VALIDITY_INTERVAL_MAX)
    {
        ttylog_err("error: signature validity interval too high");
        return CONFIG_WRONG_SIG_VALIDITY;
    }

    if(g_config->sig_validity_regeneration * SIGNATURE_VALIDITY_REGENERATION_S * 2 > g_config->sig_validity_interval * SIGNATURE_VALIDITY_INTERVAL_S)
    {
        ttylog_err("error: default signature regeneration is more than half the interval (%ds * 2 > %ds)",
                g_config->sig_validity_regeneration * SIGNATURE_VALIDITY_REGENERATION_S,
                g_config->sig_validity_interval * SIGNATURE_VALIDITY_INTERVAL_S);
        return CONFIG_WRONG_SIG_REGEN;
    }
#endif


    
    /// @note config_main_verify_and_update_directory updates the folder with the base_path
    
    /**
     * 
     * @note All base paths are updated with the chroot variable so it does not
     *       need to be added all the time.
     * 
     */
    
    const char *base_path = g_config->chroot_path;

    if(FAIL(ret = config_main_verify_and_update_directory(base_path, &g_config->data_path)))
    {
        return ret;
    }
    
    if(FAIL(ret = config_main_verify_and_update_directory(base_path, &g_config->keys_path)))
    {
        return ret;
    }
    
    if(FAIL(ret = config_main_verify_and_update_directory(base_path, &g_config->log_path)))
    {
        return ret;
    }
#if 0 /* fix */
#else
    if(FAIL(ret = config_main_verify_and_update_file(base_path, &g_config->pid_file)))
    {
        return ret;
    }
#endif
    
    g_config->reloadable = TRUE;
    
    if((g_config->server_flags & SERVER_FL_CHROOT) != 0)
    {
        if(FAIL(chroot_manage_path(&g_config->config_file, g_config->config_file, FALSE)))
        {
            log_warn("config file '%s' will not be accessible within the chroot jail '%s' : config reload will not work", g_config->config_file, base_path);
            g_config->reloadable = FALSE;
        }
    }
    
    if(FAIL(ret = config_main_verify_and_update_directory(base_path, &g_config->xfr_path)))
    {
        return ret;
    }
    
#if ZDB_HAS_DNSSEC_SUPPORT
    dnssec_keystore_setpath(g_config->keys_path);
    dnssec_set_xfr_path(g_config->xfr_path);
    journal_set_xfr_path(g_config->xfr_path);
#endif
    
    if((logger_get_uid() != g_config->uid) || (logger_get_gid() != g_config->gid))
    {
        logger_set_uid(g_config->uid);
        logger_set_gid(g_config->gid);
        
        logger_reopen();
    }
    
    return SUCCESS;
}
示例#3
0
static ya_result
config_section_handles_set_wild(struct config_section_descriptor_s *csd, const char *key, const char *value)
{
    if(logger_channel_get_usage_count(key) >= 0)
    {
        return CONFIG_LOGGER_HANDLE_ALREADY_DEFINED; // already defined
    }
    
    char value_target[PATH_MAX];
    parse_copy_word(value_target, sizeof(value_target), value);
    
    if(strcasecmp("stdout", value_target) == 0)
    {
        output_stream stdout_os;
        fd_output_stream_attach(&stdout_os, dup_ex(1));
        logger_channel *stdout_channel = logger_channel_alloc();
        logger_channel_stream_open(&stdout_os, FALSE, stdout_channel);
        logger_channel_register(key, stdout_channel);
    }
    else if(strcasecmp("stderr", value_target) == 0)
    {
        output_stream stderr_os;
        fd_output_stream_attach(&stderr_os, dup_ex(2));
        logger_channel *stderr_channel = logger_channel_alloc();
        logger_channel_stream_open(&stderr_os, FALSE, stderr_channel);
        logger_channel_register(key, stderr_channel);
    }
    else if(strcasecmp("syslog", value_target) == 0)
    {
        char* token;

        /*
         * Tokenize
         */

        u32 options = 0;
        u32 facility = 0;

        /* WARNING: NEVER EVER USE A CONST STRING AS ARGUMENT OR strtok WILL SIGSEGV */

        char *tmp_value = strdup(value); // value, not value_target
        
        for(token =  strtok(tmp_value, SYSLOG_CHANNEL_TOKEN_DELIMITER);
            token != NULL;
            token =  strtok(NULL, SYSLOG_CHANNEL_TOKEN_DELIMITER))
        {
            u32 token_value;
            
            if(ISOK(get_value_from_casename(syslog_channel_arguments_options, token, &token_value)))
            {
                options |= token_value;
            }
            else if(ISOK(get_value_from_casename(syslog_channel_arguments_facility, token, &token_value)))
            {
                facility = token_value; // Facility is NOT a bit mask
            }
            else
            {
                /* Note: empty statement is taken care of here */
                osformatln(termerr, "wrong syslog argument '%s' : ", csd->vtbl->name);
                
                free(tmp_value);
                return PARSE_INVALID_ARGUMENT;
            }
        }
        
        free(tmp_value);
        
        logger_channel *syslog_channel = logger_channel_alloc();
        logger_channel_syslog_open(key, options, facility, syslog_channel);
        logger_channel_register(key, syslog_channel);
    }
    else
    {
        const char *chroot_base = chroot_get_path();
        
        uid_t uid = logger_get_uid();
        gid_t gid = logger_get_gid();
        
        ya_result return_code;
        unsigned int access_rights;
        char fullpath[PATH_MAX];
        
        // find the end of the word
        // cut it
        
        const char *path_limit = parse_next_blank(value);
        size_t path_len = path_limit - value;
        size_t pathbase_len;
        
        if(value[0] != '/')
        {
            pathbase_len = snformat(fullpath, sizeof(fullpath), "%s%s", chroot_base, log_path);
        }
        else
        {
            pathbase_len = snformat(fullpath, sizeof(fullpath), "%s", chroot_base);
        }
        
        if(pathbase_len + path_len + 1 >= sizeof(fullpath))
        {
            return CONFIG_FILE_PATH_TOO_BIG;
        }
        
        memcpy(&fullpath[pathbase_len], value, path_len);
        path_len += pathbase_len;
        fullpath[path_len] = '\0';
        
        
        // parse the next word, it is supposed to be an octal number
        
        if(sscanf(path_limit, "%o", &access_rights) != 1)
        {
            access_rights = FILE_CHANNEL_DEFAULT_ACCESS_RIGHTS;
        }
        
        // if the path starts with a slash, it's absolute, else it's relative
        // to the log directory

        logger_channel* file_channel = logger_channel_alloc();
        if(FAIL(return_code = logger_channel_file_open(fullpath, uid, gid, access_rights, FALSE, file_channel)))
        {
            osformatln(termerr, "config: unable to open file channel '%s' (%d:%d %o) : %r", fullpath, uid, gid, access_rights, return_code);
            flusherr();
            
            return return_code;
        }
        
        logger_channel_register(key, file_channel);
    }
    
    return SUCCESS;
}