const char *lxc_global_config_value(const char *option_name) { static const char * const options[][2] = { { "lxc.bdev.lvm.vg", DEFAULT_VG }, { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL }, { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT }, { "lxc.lxcpath", NULL }, { "lxc.default_config", NULL }, { "lxc.cgroup.pattern", DEFAULT_CGROUP_PATTERN }, { "lxc.cgroup.use", NULL }, { NULL, NULL }, }; /* placed in the thread local storage pool for non-bionic targets */ #ifdef HAVE_TLS static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; #else static const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; #endif char *user_config_path = NULL; char *user_default_config_path = NULL; char *user_lxc_path = NULL; if (geteuid() > 0) { const char *user_home = getenv("HOME"); if (!user_home) user_home = "/"; user_config_path = malloc(sizeof(char) * (22 + strlen(user_home))); user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home))); user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home))); sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home); sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home); sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home); } else { user_config_path = strdup(LXC_GLOBAL_CONF); user_default_config_path = strdup(LXC_DEFAULT_CONFIG); user_lxc_path = strdup(LXCPATH); } const char * const (*ptr)[2]; size_t i; char buf[1024], *p, *p2; FILE *fin = NULL; for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) { if (!strcmp(option_name, (*ptr)[0])) break; } if (!(*ptr)[0]) { free(user_config_path); free(user_default_config_path); free(user_lxc_path); errno = EINVAL; return NULL; } if (values[i]) { free(user_config_path); free(user_default_config_path); free(user_lxc_path); return values[i]; } fin = fopen_cloexec(user_config_path, "r"); free(user_config_path); if (fin) { while (fgets(buf, 1024, fin)) { if (buf[0] == '#') continue; p = strstr(buf, option_name); if (!p) continue; /* see if there was just white space in front * of the option name */ for (p2 = buf; p2 < p; p2++) { if (*p2 != ' ' && *p2 != '\t') break; } if (p2 < p) continue; p = strchr(p, '='); if (!p) continue; /* see if there was just white space after * the option name */ for (p2 += strlen(option_name); p2 < p; p2++) { if (*p2 != ' ' && *p2 != '\t') break; } if (p2 < p) continue; p++; while (*p && (*p == ' ' || *p == '\t')) p++; if (!*p) continue; free(user_default_config_path); if (strcmp(option_name, "lxc.lxcpath") == 0) { free(user_lxc_path); user_lxc_path = copy_global_config_value(p); remove_trailing_slashes(user_lxc_path); values[i] = user_lxc_path; goto out; } values[i] = copy_global_config_value(p); free(user_lxc_path); goto out; } } /* could not find value, use default */ if (strcmp(option_name, "lxc.lxcpath") == 0) { remove_trailing_slashes(user_lxc_path); values[i] = user_lxc_path; free(user_default_config_path); } else if (strcmp(option_name, "lxc.default_config") == 0) { values[i] = user_default_config_path; free(user_lxc_path); } else { free(user_default_config_path); free(user_lxc_path); values[i] = (*ptr)[1]; } /* special case: if default value is NULL, * and there is no config, don't view that * as an error... */ if (!values[i]) errno = 0; out: if (fin) fclose(fin); return values[i]; }
const char *lxc_global_config_value(const char *option_name) { static const char *options[][2] = { { "lvm_vg", DEFAULT_VG }, { "lvm_thin_pool", DEFAULT_THIN_POOL }, { "zfsroot", DEFAULT_ZFSROOT }, { "lxcpath", LXCPATH }, { "cgroup.pattern", DEFAULT_CGROUP_PATTERN }, { "cgroup.use", NULL }, { NULL, NULL }, }; /* Protected by a mutex to eliminate conflicting load and store operations */ static const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; const char *(*ptr)[2]; const char *value; size_t i; char buf[1024], *p, *p2; FILE *fin = NULL; for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) { if (!strcmp(option_name, (*ptr)[0])) break; } if (!(*ptr)[0]) { errno = EINVAL; return NULL; } static_lock(); if (values[i]) { value = values[i]; static_unlock(); return value; } static_unlock(); process_lock(); fin = fopen_cloexec(LXC_GLOBAL_CONF, "r"); process_unlock(); if (fin) { while (fgets(buf, 1024, fin)) { if (buf[0] == '#') continue; p = strstr(buf, option_name); if (!p) continue; /* see if there was just white space in front * of the option name */ for (p2 = buf; p2 < p; p2++) { if (*p2 != ' ' && *p2 != '\t') break; } if (p2 < p) continue; p = strchr(p, '='); if (!p) continue; /* see if there was just white space after * the option name */ for (p2 += strlen(option_name); p2 < p; p2++) { if (*p2 != ' ' && *p2 != '\t') break; } if (p2 < p) continue; p++; while (*p && (*p == ' ' || *p == '\t')) p++; if (!*p) continue; static_lock(); values[i] = copy_global_config_value(p); static_unlock(); goto out; } } /* could not find value, use default */ static_lock(); values[i] = (*ptr)[1]; /* special case: if default value is NULL, * and there is no config, don't view that * as an error... */ if (!values[i]) errno = 0; static_unlock(); out: process_lock(); if (fin) fclose(fin); process_unlock(); static_lock(); value = values[i]; static_unlock(); return value; }