/* * str_replace_home -- (internal) replace $HOME string with user home directory * * If function does not find $HOME string it will return haystack untouched. * Otherwise it will allocate new string with $HOME replaced with provided * home_dir path. haystack will be released and newly created string returned. */ static char * str_replace_home(char *haystack, const char *home_dir) { const size_t placeholder_len = strlen(HOME_STR_PLACEHOLDER); const size_t home_len = strlen(home_dir); size_t haystack_len = strlen(haystack); char *pos = strstr(haystack, HOME_STR_PLACEHOLDER); if (!pos) return haystack; const char *after = pos + placeholder_len; if (isalnum(*after)) return haystack; haystack_len += home_len - placeholder_len + 1; char *buf = malloc(sizeof(char) * haystack_len); if (!buf) RPMEMD_FATAL("!snprintf"); *pos = '\0'; int r = snprintf(buf, haystack_len, "%s%s%s", haystack, home_dir, after); if (r < 0) RPMEMD_FATAL("!snprintf"); free(haystack); return buf; }
/* * config_set_default -- (internal) load default config */ static void config_set_default(struct rpmemd_config *config, const char *poolset_dir) { config->log_file = strdup(RPMEMD_DEFAULT_LOG_FILE); if (!config->log_file) RPMEMD_FATAL("!strdup"); config->poolset_dir = strdup(poolset_dir); if (!config->poolset_dir) RPMEMD_FATAL("!strdup"); config->persist_apm = false; config->persist_general = true; config->use_syslog = true; config->max_lanes = RPMEM_DEFAULT_MAX_LANES; config->log_level = RPD_LOG_ERR; }
/* * concat_dir_and_file_name -- (internal) concatenate directory and file name * into single string path */ static void concat_dir_and_file_name(char *path, size_t size, const char *dir, const char *file) { int r = snprintf(path, size, "%s/%s", dir, file); if (r < 0) RPMEMD_FATAL("!snprintf"); }
/* * get_home_dir -- (internal) return user home directory * * Function will lookup user home directory in order: * 1. HOME environment variable * 2. Password file entry using real user ID */ static void get_home_dir(char *str, size_t size) { char *home = getenv(HOME_ENV); if (home) { int r = snprintf(str, size, "%s", home); if (r < 0) RPMEMD_FATAL("!snprintf"); } else { uid_t uid = getuid(); struct passwd *pw = getpwuid(uid); if (pw == NULL) RPMEMD_FATAL("!getpwuid"); int r = snprintf(str, size, "%s", pw->pw_dir); if (r < 0) RPMEMD_FATAL("!snprintf"); } }
/* * parse_config_string -- (internal) parse string value */ static inline char * parse_config_string(const char *value) { if (strlen(value) == 0) { errno = EINVAL; return NULL; } char *output = strdup(value); if (output == NULL) RPMEMD_FATAL("!strdup"); return output; }
/* * get_config_line -- (internal) read single line from file */ static int get_config_line(FILE *file, char **line, uint64_t *line_max, uint8_t *line_max_increased, struct rpmemd_special_chars_pos *pos) { uint8_t line_complete = 0; uint64_t line_length = 0; char *line_part = *line; do { char *ret = fgets(line_part, (int)(*line_max - line_length), file); if (ret == NULL) return 0; for (uint64_t i = 0; i < *line_max; ++i) { if (line_part[i] == '\n') line_complete = 1; else if (line_part[i] == '\0') { line_length += i; if (line_length + 1 < *line_max) line_complete = 1; break; } else if (line_part[i] == '#' && pos->comment_char == UINT64_MAX) pos->comment_char = line_length + i; else if (line_part[i] == '=' && pos->equal_char == UINT64_MAX) pos->equal_char = line_length + i; } if (line_complete == 0) { *line = realloc(*line, sizeof(char) * (*line_max) * 2); if (*line == NULL) { RPMEMD_FATAL("!realloc"); } line_part = *line + *line_max - 1; line_length = *line_max - 1; *line_max *= 2; *line_max_increased = 1; } } while (line_complete != 1); pos->EOL_char = line_length; return 0; }
/* * rpmemd_apply_pm_policy -- choose the persistency method and the flush * function according to the pool type and the persistency method read from the * config */ int rpmemd_apply_pm_policy(enum rpmem_persist_method *persist_method, int (**persist)(const void *addr, size_t len), void *(**memcpy_persist)(void *pmemdest, const void *src, size_t len), const int is_pmem) { switch (*persist_method) { case RPMEM_PM_APM: if (is_pmem) { *persist_method = RPMEM_PM_APM; *persist = rpmemd_flush_fatal; } else { *persist_method = RPMEM_PM_GPSPM; *persist = pmem_msync; } break; case RPMEM_PM_GPSPM: *persist_method = RPMEM_PM_GPSPM; *persist = is_pmem ? rpmemd_pmem_persist : pmem_msync; break; default: RPMEMD_FATAL("invalid persist method: %d", *persist_method); return -1; } /* this is for RPMEM_PERSIST_INLINE */ if (is_pmem) *memcpy_persist = pmem_memcpy_persist; else *memcpy_persist = rpmem_memcpy_msync; RPMEMD_LOG(NOTICE, "persistency policy:"); rpmem_print_pm_policy(*persist_method, *persist); return 0; }
/* * rpmemd_log -- main logging function */ void rpmemd_log(enum rpmemd_log_level level, const char *fname, int lineno, const char *fmt, ...) { if (!rpmemd_use_syslog && level > rpmemd_log_level) return; char buff[RPMEMD_MAX_MSG]; size_t cnt = 0; int ret; if (fname) { ret = snprintf(&buff[cnt], RPMEMD_MAX_MSG - cnt, "[%s:%d] ", basename(fname), lineno); if (ret < 0) RPMEMD_FATAL("snprintf failed"); cnt += (size_t)ret; } if (rpmemd_prefix_buff[0]) { ret = snprintf(&buff[cnt], RPMEMD_MAX_MSG - cnt, "%s ", rpmemd_prefix_buff); if (ret < 0) RPMEMD_FATAL("snprintf failed"); cnt += (size_t)ret; } const char *errorstr = ""; const char *prefix = ""; const char *suffix = "\n"; if (fmt) { if (*fmt == '!') { fmt++; errorstr = strerror(errno); prefix = ": "; } } va_list ap; va_start(ap, fmt); ret = vsnprintf(&buff[cnt], RPMEMD_MAX_MSG - cnt, fmt, ap); va_end(ap); if (ret < 0) RPMEMD_FATAL("vsnprintf failed"); cnt += (size_t)ret; ret = snprintf(&buff[cnt], RPMEMD_MAX_MSG - cnt, "%s%s%s", prefix, errorstr, suffix); if (ret < 0) RPMEMD_FATAL("snprintf failed"); cnt += (size_t)ret; if (rpmemd_use_syslog) { int prio = rpmemd_level2prio[level]; syslog(prio, "%s", buff); } else { fprintf(rpmemd_log_file, "%s", buff); fflush(rpmemd_log_file); } }
int main(int argc, char *argv[]) { START(argc, argv, "rpmemd_log"); if (argc < 4) { USAGE(); return 1; } const char *log_op = argv[1]; const char *log_type = argv[2]; const char *file = argv[3]; int do_fatal = 0; int do_assert = 0; if (strcmp(log_op, "fatal") == 0) { do_fatal = 1; } else if (strcmp(log_op, "assert") == 0) { do_assert = 1; } else if (strcmp(log_op, "log") == 0) { } else { USAGE(); return 1; } enum test_log_type type; if (strcmp(log_type, "stdout") == 0) { type = TEST_STDOUT; } else if (strcmp(log_type, "file") == 0) { type = TEST_FILE; } else if (strcmp(log_type, "syslog") == 0) { type = TEST_SYSLOG; } else { USAGE(); return 1; } int fd_stdout = -1; FILE *stdout_fh = NULL; switch (type) { case TEST_STDOUT: /* * Duplicate stdout file descriptor in order to preserve * the file list after redirecting the stdout to a file. */ fd_stdout = dup(1); UT_ASSERTne(fd_stdout, -1); close(1); stdout_fh = fopen(file, "a"); UT_ASSERTne(stdout_fh, NULL); break; case TEST_SYSLOG: syslog_fh = fopen(file, "a"); UT_ASSERTne(syslog_fh, NULL); break; default: break; } /* * Check an invalid configuration */ int ret; ret = rpmemd_log_init("rpmemd_log", file, 1); UT_ASSERTne(ret, 0); switch (type) { case TEST_STDOUT: ret = rpmemd_log_init("rpmemd_log", NULL, 0); UT_ASSERTeq(ret, 0); break; case TEST_SYSLOG: ret = rpmemd_log_init("rpmemd_log", NULL, 1); UT_ASSERTeq(ret, 0); break; case TEST_FILE: ret = rpmemd_log_init("rpmemd_log", file, 0); UT_ASSERTeq(ret, 0); break; default: break; } if (do_fatal) { RPMEMD_FATAL("fatal"); } else if (do_assert) { RPMEMD_ASSERT(1); RPMEMD_ASSERT(0); } else { test_all_log_messages(); } rpmemd_log_close(); switch (type) { case TEST_STDOUT: /* restore the original stdout file descriptor */ fclose(stdout_fh); UT_ASSERTeq(dup2(fd_stdout, 1), 1); close(fd_stdout); break; case TEST_SYSLOG: fclose(syslog_fh); break; default: break; } DONE(NULL); }
/* * rpmemd_flush_fatal -- APM specific flush function which should never be * called because APM does not require flushes */ int rpmemd_flush_fatal(const void *addr, size_t len) { RPMEMD_FATAL("rpmemd_flush_fatal should never be called"); }