static int _parse_repo(const char *key, char *value, const char *file, int line, struct section_t *section) { int ret = 0; config_repo_t *repo = section->repo; if(strcmp(key, "Server") == 0) { if(!value) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), file, line, key); ret = 1; } else { repo->servers = alpm_list_add(repo->servers, strdup(value)); } } else if(strcmp(key, "SigLevel") == 0) { if(!value) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), file, line, key); } else { alpm_list_t *values = NULL; setrepeatingoption(value, "SigLevel", &values); if(values) { ret = process_siglevel(values, &repo->siglevel, &repo->siglevel_mask, file, line); FREELIST(values); } } } else if(strcmp(key, "Usage") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "Usage", &values); if(values) { if(process_usage(values, &repo->usage, file, line)) { FREELIST(values); return 1; } FREELIST(values); } } else { pm_printf(ALPM_LOG_WARNING, _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), file, line, key, repo->name); } return ret; }
static int _parse_options(const char *key, char *value, const char *file, int linenum) { if(value == NULL) { /* options without settings */ if(strcmp(key, "UseSyslog") == 0) { config->usesyslog = 1; pm_printf(ALPM_LOG_DEBUG, "config: usesyslog\n"); } else if(strcmp(key, "ILoveCandy") == 0) { config->chomp = 1; pm_printf(ALPM_LOG_DEBUG, "config: chomp\n"); } else if(strcmp(key, "VerbosePkgLists") == 0) { config->verbosepkglists = 1; pm_printf(ALPM_LOG_DEBUG, "config: verbosepkglists\n"); } else if(strcmp(key, "UseDelta") == 0) { config->deltaratio = 0.7; pm_printf(ALPM_LOG_DEBUG, "config: usedelta (default 0.7)\n"); } else if(strcmp(key, "TotalDownload") == 0) { config->totaldownload = 1; pm_printf(ALPM_LOG_DEBUG, "config: totaldownload\n"); } else if(strcmp(key, "CheckSpace") == 0) { config->checkspace = 1; } else if(strcmp(key, "Color") == 0) { if(config->color == PM_COLOR_UNSET) { config->color = isatty(fileno(stdout)) ? PM_COLOR_ON : PM_COLOR_OFF; enable_colors(config->color); } } else { pm_printf(ALPM_LOG_WARNING, _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), file, linenum, key, "options"); } } else { /* options with settings */ if(strcmp(key, "NoUpgrade") == 0) { setrepeatingoption(value, "NoUpgrade", &(config->noupgrade)); } else if(strcmp(key, "NoExtract") == 0) { setrepeatingoption(value, "NoExtract", &(config->noextract)); } else if(strcmp(key, "IgnorePkg") == 0) { setrepeatingoption(value, "IgnorePkg", &(config->ignorepkg)); } else if(strcmp(key, "IgnoreGroup") == 0) { setrepeatingoption(value, "IgnoreGroup", &(config->ignoregrp)); } else if(strcmp(key, "HoldPkg") == 0) { setrepeatingoption(value, "HoldPkg", &(config->holdpkg)); } else if(strcmp(key, "CacheDir") == 0) { setrepeatingoption(value, "CacheDir", &(config->cachedirs)); } else if(strcmp(key, "Architecture") == 0) { if(!config->arch) { config_set_arch(value); } } else if(strcmp(key, "UseDelta") == 0) { double ratio; char *endptr; const char *oldlocale; /* set the locale to 'C' for consistent decimal parsing (0.7 and never * 0,7) from config files, then restore old setting when we are done */ oldlocale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); ratio = strtod(value, &endptr); setlocale(LC_NUMERIC, oldlocale); if(*endptr != '\0' || ratio < 0.0 || ratio > 2.0) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: invalid value for '%s' : '%s'\n"), file, linenum, "UseDelta", value); return 1; } config->deltaratio = ratio; pm_printf(ALPM_LOG_DEBUG, "config: usedelta = %f\n", ratio); } else if(strcmp(key, "DBPath") == 0) { /* don't overwrite a path specified on the command line */ if(!config->dbpath) { config->dbpath = strdup(value); pm_printf(ALPM_LOG_DEBUG, "config: dbpath: %s\n", value); } } else if(strcmp(key, "RootDir") == 0) { /* don't overwrite a path specified on the command line */ if(!config->rootdir) { config->rootdir = strdup(value); pm_printf(ALPM_LOG_DEBUG, "config: rootdir: %s\n", value); } } else if(strcmp(key, "GPGDir") == 0) { if(!config->gpgdir) { config->gpgdir = strdup(value); pm_printf(ALPM_LOG_DEBUG, "config: gpgdir: %s\n", value); } } else if(strcmp(key, "LogFile") == 0) { if(!config->logfile) { config->logfile = strdup(value); pm_printf(ALPM_LOG_DEBUG, "config: logfile: %s\n", value); } } else if(strcmp(key, "XferCommand") == 0) { config->xfercommand = strdup(value); pm_printf(ALPM_LOG_DEBUG, "config: xfercommand: %s\n", value); } else if(strcmp(key, "CleanMethod") == 0) { alpm_list_t *methods = NULL; setrepeatingoption(value, "CleanMethod", &methods); if(process_cleanmethods(methods, file, linenum)) { FREELIST(methods); return 1; } FREELIST(methods); } else if(strcmp(key, "SigLevel") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "SigLevel", &values); if(process_siglevel(values, &config->siglevel, &config->siglevel_mask, file, linenum)) { FREELIST(values); return 1; } FREELIST(values); } else if(strcmp(key, "LocalFileSigLevel") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "LocalFileSigLevel", &values); if(process_siglevel(values, &config->localfilesiglevel, &config->localfilesiglevel_mask, file, linenum)) { FREELIST(values); return 1; } FREELIST(values); } else if(strcmp(key, "RemoteFileSigLevel") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "RemoteFileSigLevel", &values); if(process_siglevel(values, &config->remotefilesiglevel, &config->remotefilesiglevel_mask, file, linenum)) { FREELIST(values); return 1; } FREELIST(values); } else { pm_printf(ALPM_LOG_WARNING, _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), file, linenum, key, "options"); } } return 0; }
/** The "real" parseconfig. Each "Include" directive will recall this method so * recursion and stack depth are limited to 10 levels. The publicly visible * parseconfig calls this with a NULL section argument so we can recall from * within ourself on an include. * @param file path to the config file * @param section the current active section * @param parse_options whether to parse and call methods for the options * section; if 0, parse and call methods for the repos sections * @param depth the current recursion depth * @return 0 on success, 1 on failure */ static int _parseconfig(const char *file, struct section_t *section, int parse_options, int depth) { FILE *fp = NULL; char line[PATH_MAX]; int linenum = 0; int ret = 0; const int max_depth = 10; if(depth >= max_depth) { pm_printf(ALPM_LOG_ERROR, _("config parsing exceeded max recursion depth of %d.\n"), max_depth); ret = 1; goto cleanup; } pm_printf(ALPM_LOG_DEBUG, "config: attempting to read file %s\n", file); fp = fopen(file, "r"); if(fp == NULL) { pm_printf(ALPM_LOG_ERROR, _("config file %s could not be read: %s\n"), file, strerror(errno)); ret = 1; goto cleanup; } while(fgets(line, PATH_MAX, fp)) { char *key, *value, *ptr; size_t line_len; linenum++; /* ignore whole line and end of line comments */ if((ptr = strchr(line, '#'))) { *ptr = '\0'; } line_len = strtrim(line); if(line_len == 0) { continue; } if(line[0] == '[' && line[line_len - 1] == ']') { char *name; /* only possibility here is a line == '[]' */ if(line_len <= 2) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: bad section name.\n"), file, linenum); ret = 1; goto cleanup; } /* new config section, skip the '[' */ name = strdup(line + 1); name[line_len - 2] = '\0'; /* we're at a new section; perform any post-actions for the prior */ if(finish_section(section, parse_options)) { ret = 1; goto cleanup; } pm_printf(ALPM_LOG_DEBUG, "config: new section '%s'\n", name); section->name = name; section->is_options = (strcmp(name, "options") == 0); continue; } /* directive */ /* strsep modifies the 'line' string: 'key \0 value' */ key = line; value = line; strsep(&value, "="); strtrim(key); strtrim(value); if(key == NULL) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: syntax error in config file- missing key.\n"), file, linenum); ret = 1; goto cleanup; } /* For each directive, compare to the camelcase string. */ if(section->name == NULL) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: All directives must belong to a section.\n"), file, linenum); ret = 1; goto cleanup; } /* Include is allowed in both options and repo sections */ if(strcmp(key, "Include") == 0) { glob_t globbuf; int globret; size_t gindex; if(value == NULL) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), file, linenum, key); ret = 1; goto cleanup; } /* Ignore include failures... assume non-critical */ globret = glob(value, GLOB_NOCHECK, NULL, &globbuf); switch(globret) { case GLOB_NOSPACE: pm_printf(ALPM_LOG_DEBUG, "config file %s, line %d: include globbing out of space\n", file, linenum); break; case GLOB_ABORTED: pm_printf(ALPM_LOG_DEBUG, "config file %s, line %d: include globbing read error for %s\n", file, linenum, value); break; case GLOB_NOMATCH: pm_printf(ALPM_LOG_DEBUG, "config file %s, line %d: no include found for %s\n", file, linenum, value); break; default: for(gindex = 0; gindex < globbuf.gl_pathc; gindex++) { pm_printf(ALPM_LOG_DEBUG, "config file %s, line %d: including %s\n", file, linenum, globbuf.gl_pathv[gindex]); _parseconfig(globbuf.gl_pathv[gindex], section, parse_options, depth + 1); } break; } globfree(&globbuf); continue; } if(parse_options && section->is_options) { /* we are either in options ... */ if((ret = _parse_options(key, value, file, linenum)) != 0) { goto cleanup; } } else if(!parse_options && !section->is_options) { /* ... or in a repo section */ if(strcmp(key, "Server") == 0) { if(value == NULL) { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), file, linenum, key); ret = 1; goto cleanup; } section->servers = alpm_list_add(section->servers, strdup(value)); } else if(strcmp(key, "SigLevel") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "SigLevel", &values); if(values) { if(section->siglevel == ALPM_SIG_USE_DEFAULT) { section->siglevel = config->siglevel; } if(process_siglevel(values, §ion->siglevel, file, linenum)) { FREELIST(values); ret = 1; goto cleanup; } FREELIST(values); } } else { pm_printf(ALPM_LOG_WARNING, _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), file, linenum, key, section->name); } } } if(depth == 0) { ret = finish_section(section, parse_options); } cleanup: if(fp) { fclose(fp); } pm_printf(ALPM_LOG_DEBUG, "config: finished parsing %s\n", file); return ret; }