static int _read_array(struct pfilter *pf, struct config_tree *cft, const char *path, void *data) { const struct config_node *cn; struct config_value *cv; if (!(cn = find_config_node(cft->root, path))) { log_very_verbose("Couldn't find %s array in '%s'", path, pf->file); return 0; } /* * iterate through the array, adding * devices as we go. */ for (cv = cn->v; cv; cv = cv->next) { if (cv->type != CFG_STRING) { log_verbose("Devices array contains a value " "which is not a string ... ignoring"); continue; } if (!dm_hash_insert(pf->devices, cv->v.str, data)) log_verbose("Couldn't add '%s' to filter ... ignoring", cv->v.str); /* Populate dev_cache ourselves */ dev_cache_get(cv->v.str, NULL); } return 1; }
static void _add_lvs_to_lvname_hash(struct dm_list *lvs) { struct lvm_lv_list *lvl; dm_list_iterate_items(lvl, lvs) { /* Concatenate VG name with LV name */ dm_hash_insert(_lvname_hash, lvm_lv_get_name(lvl->lv), lvl->lv); }
/* Real locking */ static int _lock_resource(const char *resource, int mode, int flags, int *lockid) { struct lock *lck; DEBUGLOG("Locking resource %s, flags=%d, mode=%d\n", resource, flags, mode); mode &= LCK_TYPE_MASK; pthread_mutex_lock(&_lock_mutex); retry: if (!(lck = dm_hash_lookup(_locks, resource))) { /* Add new locked resource */ if (!(lck = dm_zalloc(sizeof(struct lock))) || !dm_hash_insert(_locks, resource, lck)) goto bad; lck->lockid = ++_lockid; goto out; } /* Update/convert lock */ if (flags == LCKF_CONVERT) { if (lck->excl) mode = LCK_EXCL; } else if ((lck->mode == LCK_WRITE) || (lck->mode == LCK_EXCL)) { DEBUGLOG("Resource %s already %s locked (%d)...\n", resource, (lck->mode == LCK_WRITE) ? "write" : "exclusively", lck->lockid); goto maybe_retry; } else if (lck->mode > mode) { DEBUGLOG("Resource %s already locked and %s lock requested...\n", resource, (mode == LCK_READ) ? "READ" : (mode == LCK_WRITE) ? "WRITE" : "EXCLUSIVE"); goto maybe_retry; } out: *lockid = lck->lockid; lck->mode = mode; lck->excl |= (mode == LCK_EXCL); DEBUGLOG("Locked resource %s, lockid=%d, mode=%d\n", resource, lck->lockid, mode); pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */ pthread_mutex_unlock(&_lock_mutex); return 0; maybe_retry: if (!(flags & LCK_NONBLOCK)) { pthread_cond_wait(&_lock_cond, &_lock_mutex); DEBUGLOG("Resource %s RETRYING lock...\n", resource); goto retry; } bad: DEBUGLOG("Failed to lock resource %s\n", resource); pthread_mutex_unlock(&_lock_mutex); return 1; /* fail */ }
static int insert_info(const char *resource, struct lv_info *lvi) { int ret; pthread_mutex_lock(&lv_hash_lock); ret = dm_hash_insert(lv_hash, resource, lvi); pthread_mutex_unlock(&lv_hash_lock); return ret; }
static int _lookup_p(struct dev_filter *f, struct device *dev) { struct pfilter *pf = (struct pfilter *) f->private; void *l = dm_hash_lookup(pf->devices, dev_name(dev)); struct str_list *sl; if (!l) { l = pf->real->passes_filter(pf->real, dev) ? PF_GOOD_DEVICE : PF_BAD_DEVICE; list_iterate_items(sl, struct str_list, &dev->aliases) dm_hash_insert(pf->devices, sl->str, l); } else if (l == PF_BAD_DEVICE)
static void insert_info(const char *resource, struct lv_info *lvi) { pthread_mutex_lock(&lv_hash_lock); dm_hash_insert(lv_hash, resource, lvi); pthread_mutex_unlock(&lv_hash_lock); }
void print_log(int level, const char *file, int line, int dm_errno_or_class, const char *format, ...) { va_list ap; char buf[1024], message[4096]; int bufused, n; const char *trformat; /* Translated format string */ char *newbuf; int use_stderr = level & _LOG_STDERR; int log_once = level & _LOG_ONCE; int fatal_internal_error = 0; size_t msglen; const char *indent_spaces = ""; FILE *stream; static int _abort_on_internal_errors_env_present = -1; static int _abort_on_internal_errors_env = 0; char *env_str; level &= ~(_LOG_STDERR|_LOG_ONCE); if (_abort_on_internal_errors_env_present < 0) { if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) { _abort_on_internal_errors_env_present = 1; /* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */ _abort_on_internal_errors_env = strcmp(env_str, "0"); } else _abort_on_internal_errors_env_present = 0; } /* Use value from environment if present, otherwise use value from config. */ if (((_abort_on_internal_errors_env_present && _abort_on_internal_errors_env) || (!_abort_on_internal_errors_env_present && _abort_on_internal_errors_config)) && !strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1)) { fatal_internal_error = 1; /* Internal errors triggering abort cannot be suppressed. */ _log_suppress = 0; level = _LOG_FATAL; } if (level <= _LOG_ERR) init_error_message_produced(1); trformat = _(format); if (level < _LOG_DEBUG && dm_errno_or_class && !_lvm_errno) _lvm_errno = dm_errno_or_class; if (_lvm2_log_fn || (_store_errmsg && (level <= _LOG_ERR)) || log_once) { va_start(ap, format); n = vsnprintf(message, sizeof(message), trformat, ap); va_end(ap); /* When newer glibc returns >= sizeof(locn), we will just log what * has fit into buffer, it's '\0' terminated string */ if (n < 0) { fprintf(stderr, _("vsnprintf failed: skipping external " "logging function")); goto log_it; } } /* FIXME Avoid pointless use of message buffer when it'll never be read! */ if (_store_errmsg && (level <= _LOG_ERR) && _lvm_errmsg_len < MAX_ERRMSG_LEN) { msglen = strlen(message); if ((_lvm_errmsg_len + msglen + 1) >= _lvm_errmsg_size) { _lvm_errmsg_size = 2 * (_lvm_errmsg_len + msglen + 1); if ((newbuf = dm_realloc(_lvm_errmsg, _lvm_errmsg_size))) _lvm_errmsg = newbuf; else _lvm_errmsg_size = _lvm_errmsg_len; } if (_lvm_errmsg && (_lvm_errmsg_len + msglen + 2) < _lvm_errmsg_size) { /* prepend '\n' and copy with '\0' but do not count in */ if (_lvm_errmsg_len) _lvm_errmsg[_lvm_errmsg_len++] = '\n'; memcpy(_lvm_errmsg + _lvm_errmsg_len, message, msglen + 1); _lvm_errmsg_len += msglen; } } if (log_once) { if (!_duplicated) _duplicated = dm_hash_create(128); if (_duplicated) { if (dm_hash_lookup(_duplicated, message)) level = _LOG_NOTICE; else (void) dm_hash_insert(_duplicated, message, (void*)1); } } if (_lvm2_log_fn) { _lvm2_log_fn(level, file, line, 0, message); if (fatal_internal_error) abort(); return; } log_it: if ((verbose_level() >= level) && !_log_suppress) { if (verbose_level() > _LOG_DEBUG) { (void) dm_snprintf(buf, sizeof(buf), "#%s:%d ", file, line); } else buf[0] = '\0'; if (_indent) switch (level) { case _LOG_NOTICE: indent_spaces = " "; break; case _LOG_INFO: indent_spaces = " "; break; case _LOG_DEBUG: indent_spaces = " "; break; default: /* nothing to do */; } va_start(ap, format); switch (level) { case _LOG_DEBUG: if (verbose_level() < _LOG_DEBUG) break; if (!debug_class_is_logged(dm_errno_or_class)) break; if ((verbose_level() == level) && (strcmp("<backtrace>", format) == 0)) break; /* fall through */ default: /* Typically only log_warn goes to stdout */ stream = (use_stderr || (level != _LOG_WARN)) ? stderr : stdout; if (stream == stderr) fflush(stdout); fprintf(stream, "%s%s%s%s", buf, log_command_name(), _msg_prefix, indent_spaces); vfprintf(stream, trformat, ap); fputc('\n', stream); } va_end(ap); } if ((level > debug_level()) || (level >= _LOG_DEBUG && !debug_class_is_logged(dm_errno_or_class))) { if (fatal_internal_error) abort(); return; } if (_log_to_file && (_log_while_suspended || !critical_section())) { fprintf(_log_file, "%s:%d %s%s", file, line, log_command_name(), _msg_prefix); va_start(ap, format); vfprintf(_log_file, trformat, ap); va_end(ap); fputc('\n', _log_file); fflush(_log_file); } if (_syslog && (_log_while_suspended || !critical_section())) { va_start(ap, format); vsyslog(level, trformat, ap); va_end(ap); } if (fatal_internal_error) abort(); /* FIXME This code is unfinished - pre-extend & condense. */ if (!_already_logging && _log_direct && critical_section()) { _already_logging = 1; memset(&buf, ' ', sizeof(buf)); bufused = 0; if ((n = dm_snprintf(buf, sizeof(buf), "%s:%d %s%s", file, line, log_command_name(), _msg_prefix)) == -1) goto done; bufused += n; /* n does not include '\0' */ va_start(ap, format); n = vsnprintf(buf + bufused, sizeof(buf) - bufused, trformat, ap); va_end(ap); if (n < 0) goto done; bufused += n; if (n >= sizeof(buf)) bufused = sizeof(buf) - 1; done: buf[bufused] = '\n'; buf[sizeof(buf) - 1] = '\n'; /* FIXME real size bufused */ dev_append(&_log_dev, sizeof(buf), buf); _already_logging = 0; } }
void print_log(int level, const char *file, int line, int dm_errno, const char *format, ...) { va_list ap; char buf[1024], locn[4096]; int bufused, n; const char *message; const char *trformat; /* Translated format string */ char *newbuf; int use_stderr = level & _LOG_STDERR; int log_once = level & _LOG_ONCE; int fatal_internal_error = 0; size_t msglen; level &= ~(_LOG_STDERR|_LOG_ONCE); if (_abort_on_internal_errors && !strncmp(format, INTERNAL_ERROR, strlen(INTERNAL_ERROR))) { fatal_internal_error = 1; /* Internal errors triggering abort cannot be suppressed. */ _log_suppress = 0; level = _LOG_FATAL; } if (_log_suppress == 2) return; if (level <= _LOG_ERR) init_error_message_produced(1); trformat = _(format); if (dm_errno && !_lvm_errno) _lvm_errno = dm_errno; if (_lvm2_log_fn || (_store_errmsg && (level <= _LOG_ERR)) || log_once) { va_start(ap, format); n = vsnprintf(locn, sizeof(locn) - 1, trformat, ap); va_end(ap); if (n < 0) { fprintf(stderr, _("vsnprintf failed: skipping external " "logging function")); goto log_it; } locn[sizeof(locn) - 1] = '\0'; message = locn; } /* FIXME Avoid pointless use of message buffer when it'll never be read! */ if (_store_errmsg && (level <= _LOG_ERR) && _lvm_errmsg_len < MAX_ERRMSG_LEN) { msglen = strlen(message); if ((_lvm_errmsg_len + msglen + 1) >= _lvm_errmsg_size) { _lvm_errmsg_size = 2 * (_lvm_errmsg_len + msglen + 1); if ((newbuf = dm_realloc(_lvm_errmsg, _lvm_errmsg_size))) _lvm_errmsg = newbuf; else _lvm_errmsg_size = _lvm_errmsg_len; } if (_lvm_errmsg && (_lvm_errmsg_len + msglen + 2) < _lvm_errmsg_size) { /* prepend '\n' and copy with '\0' but do not count in */ if (_lvm_errmsg_len) _lvm_errmsg[_lvm_errmsg_len++] = '\n'; memcpy(_lvm_errmsg + _lvm_errmsg_len, message, msglen + 1); _lvm_errmsg_len += msglen; } } if (log_once) { if (!_duplicated) _duplicated = dm_hash_create(128); if (_duplicated) { if (dm_hash_lookup(_duplicated, message)) level = _LOG_NOTICE; (void) dm_hash_insert(_duplicated, message, (void*)1); } } if (_lvm2_log_fn) { _lvm2_log_fn(level, file, line, 0, message); if (fatal_internal_error) abort(); return; } log_it: if (!_log_suppress) { if (verbose_level() > _LOG_DEBUG) (void) dm_snprintf(locn, sizeof(locn), "#%s:%d ", file, line); else locn[0] = '\0'; va_start(ap, format); switch (level) { case _LOG_DEBUG: if (!strcmp("<backtrace>", format) && verbose_level() <= _LOG_DEBUG) break; if (verbose_level() >= _LOG_DEBUG) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); if (_indent) fprintf(stderr, " "); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_INFO: if (verbose_level() >= _LOG_INFO) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); if (_indent) fprintf(stderr, " "); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_NOTICE: if (verbose_level() >= _LOG_NOTICE) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); if (_indent) fprintf(stderr, " "); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_WARN: if (verbose_level() >= _LOG_WARN) { fprintf(use_stderr ? stderr : stdout, "%s%s", log_command_name(), _msg_prefix); vfprintf(use_stderr ? stderr : stdout, trformat, ap); fputc('\n', use_stderr ? stderr : stdout); } break; case _LOG_ERR: if (verbose_level() >= _LOG_ERR) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; case _LOG_FATAL: default: if (verbose_level() >= _LOG_FATAL) { fprintf(stderr, "%s%s%s", locn, log_command_name(), _msg_prefix); vfprintf(stderr, trformat, ap); fputc('\n', stderr); } break; } va_end(ap); } if (level > debug_level()) return; if (_log_to_file && (_log_while_suspended || !critical_section())) { fprintf(_log_file, "%s:%d %s%s", file, line, log_command_name(), _msg_prefix); va_start(ap, format); vfprintf(_log_file, trformat, ap); va_end(ap); fprintf(_log_file, "\n"); fflush(_log_file); } if (_syslog && (_log_while_suspended || !critical_section())) { va_start(ap, format); vsyslog(level, trformat, ap); va_end(ap); } if (fatal_internal_error) abort(); /* FIXME This code is unfinished - pre-extend & condense. */ if (!_already_logging && _log_direct && critical_section()) { _already_logging = 1; memset(&buf, ' ', sizeof(buf)); bufused = 0; if ((n = dm_snprintf(buf, sizeof(buf) - 1, "%s:%d %s%s", file, line, log_command_name(), _msg_prefix)) == -1) goto done; bufused += n; va_start(ap, format); n = vsnprintf(buf + bufused - 1, sizeof(buf) - bufused - 1, trformat, ap); va_end(ap); bufused += n; buf[bufused - 1] = '\n'; done: buf[bufused] = '\n'; buf[sizeof(buf) - 1] = '\n'; /* FIXME real size bufused */ dev_append(&_log_dev, sizeof(buf), buf); _already_logging = 0; } }
/* Real locking */ static int _lock_resource(const char *resource, int mode, int flags, int *lockid) { /* DLM table of allowed transition states */ static const int _dlm_table[6][6] = { /* Mode NL CR CW PR PW EX */ /* NL */ { 1, 1, 1, 1, 1, 1}, /* CR */ { 1, 1, 1, 1, 1, 0}, /* CW */ { 1, 1, 1, 0, 0, 0}, /* PR */ { 1, 1, 0, 1, 0, 0}, /* PW */ { 1, 1, 0, 0, 0, 0}, /* EX */ { 1, 0, 0, 0, 0, 0} }; struct lock *lck = NULL, *lckt; struct dm_list *head; DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n", resource, flags, (flags & LCKF_NOQUEUE) ? "NOQUEUE" : "", ((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) == (LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "", (flags & LCKF_CONVERT) ? "CONVERT" : "", _get_mode(mode), mode); mode &= LCK_TYPE_MASK; pthread_mutex_lock(&_lock_mutex); retry: pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */ if (!(head = dm_hash_lookup(_locks, resource))) { if (flags & LCKF_CONVERT) { /* In real DLM, lock is identified only by lockid, resource is not used */ DEBUGLOG("Unlocked resource %s cannot be converted\n", resource); goto_bad; } /* Add new locked resource */ if (!(head = dm_malloc(sizeof(struct dm_list))) || !dm_hash_insert(_locks, resource, head)) { dm_free(head); goto_bad; } dm_list_init(head); } else /* Update/convert locked resource */ dm_list_iterate_items(lck, head) { /* Check is all locks are compatible with requested lock */ if (flags & LCKF_CONVERT) { if (lck->lockid != *lockid) continue; DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n", resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode)); dm_list_iterate_items(lckt, head) { if ((lckt->lockid != *lockid) && !_dlm_table[mode][lckt->mode]) { if (!(flags & LCKF_NOQUEUE) && /* TODO: Real dlm uses here conversion queues */ !pthread_cond_wait(&_lock_cond, &_lock_mutex) && _locks) /* End of the game? */ goto retry; goto bad; } } lck->mode = mode; /* Lock is now converted */ goto out; } else if (!_dlm_table[mode][lck->mode]) { DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n", resource, lck->lockid, _get_mode(lck->mode)); if (!(flags & LCKF_NOQUEUE) && !pthread_cond_wait(&_lock_cond, &_lock_mutex) && _locks) { /* End of the game? */ DEBUGLOG("Resource %s retrying lock in mode:%s...\n", resource, _get_mode(mode)); goto retry; } goto bad; } }
int config_def_check(struct cmd_context *cmd, struct cft_check_handle *handle) { cfg_def_item_t *def; struct dm_config_node *cn; char *vp = _cfg_path, rp[CFG_PATH_MAX_LEN]; size_t rplen; int id, r = 1; /* * vp = virtual path, it might contain substitutes for variable parts * of the path, used while working with the hash * rp = real path, the real path of the config element as found in the * configuration, used for message output */ /* * If the check has already been done and 'skip_if_checked' is set, * skip the actual check and use last result if available. * If not available, we must do the check. The global status * is stored in root node. */ if (handle->skip_if_checked && (handle->status[root_CFG_SECTION] & CFG_USED)) return handle->status[root_CFG_SECTION] & CFG_VALID; /* Nothing to do if checks are disabled and also not forced. */ if (!handle->force_check && !find_config_tree_bool(cmd, config_checks_CFG, NULL)) return 1; /* Clear 'used' and 'valid' status flags. */ for (id = 0; id < CFG_COUNT; id++) handle->status[id] &= ~(CFG_USED | CFG_VALID); /* * Create a hash of all possible configuration * sections and settings with full path as a key. * If section name is variable, use '#' as a substitute. */ if (!cmd->cft_def_hash) { if (!(cmd->cft_def_hash = dm_hash_create(64))) { log_error("Failed to create configuration definition hash."); r = 0; goto out; } for (id = 1; id < CFG_COUNT; id++) { def = cfg_def_get_item_p(id); if (!cfg_def_get_path(def)) { dm_hash_destroy(cmd->cft_def_hash); cmd->cft_def_hash = NULL; r = 0; goto out; } if (!dm_hash_insert(cmd->cft_def_hash, vp, def)) { log_error("Failed to insert configuration to hash."); r = 0; goto out; } } } /* * Mark this handle as used so next time we know that the check * has already been done and so we can just reuse the previous * status instead of running this whole check again. */ handle->status[root_CFG_SECTION] |= CFG_USED; /* * Allow only sections as top-level elements. * Iterate top-level sections and dive deeper. * If any of subsequent checks fails, the whole check fails. */ for (cn = handle->cft->root; cn; cn = cn->sib) { if (!cn->v) { /* top level node: vp=vp, rp=rp */ if (!_config_def_check_node(handle, vp, vp, rp, rp, CFG_PATH_MAX_LEN, cn, cmd->cft_def_hash)) { r = 0; continue; } rplen = strlen(rp); if (!_config_def_check_tree(handle, vp, vp + strlen(vp), rp, rp + rplen, CFG_PATH_MAX_LEN - rplen, cn, cmd->cft_def_hash)) r = 0; } else { log_error_suppress(handle->suppress_messages, "Configuration setting \"%s\" invalid. " "It's not part of any section.", cn->key); r = 0; } } out: if (r) handle->status[root_CFG_SECTION] |= CFG_VALID; else handle->status[root_CFG_SECTION] &= ~CFG_VALID; return r; }