Rename public functions with grp in their name
[pacman-ng.git] / src / pacman / conf.c
blob50b4988f561f3c2868cf9c8733d8e75050f0a6cf
1 /*
2 * conf.c
4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include <errno.h>
24 #include <glob.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h> /* strdup */
29 #include <sys/stat.h>
30 #include <sys/utsname.h> /* uname */
31 #include <unistd.h>
33 /* pacman */
34 #include "conf.h"
35 #include "util.h"
36 #include "pacman.h"
37 #include "callback.h"
39 /* global config variable */
40 config_t *config = NULL;
42 config_t *config_new(void)
44 config_t *newconfig = calloc(1, sizeof(config_t));
45 if(!newconfig) {
46 pm_fprintf(stderr, PM_LOG_ERROR,
47 _("malloc failure: could not allocate %zd bytes\n"),
48 sizeof(config_t));
49 return NULL;
51 /* defaults which may get overridden later */
52 newconfig->op = PM_OP_MAIN;
53 newconfig->logmask = PM_LOG_ERROR | PM_LOG_WARNING;
54 newconfig->configfile = strdup(CONFFILE);
55 newconfig->sigverify = PM_PGP_VERIFY_UNKNOWN;
57 return newconfig;
60 int config_free(config_t *oldconfig)
62 if(oldconfig == NULL) {
63 return -1;
66 FREELIST(oldconfig->holdpkg);
67 FREELIST(oldconfig->syncfirst);
68 FREELIST(oldconfig->ignorepkg);
69 FREELIST(oldconfig->ignoregrp);
70 FREELIST(oldconfig->noupgrade);
71 FREELIST(oldconfig->noextract);
72 free(oldconfig->configfile);
73 free(oldconfig->rootdir);
74 free(oldconfig->dbpath);
75 free(oldconfig->logfile);
76 free(oldconfig->gpgdir);
77 FREELIST(oldconfig->cachedirs);
78 free(oldconfig->xfercommand);
79 free(oldconfig->print_format);
80 free(oldconfig->arch);
81 free(oldconfig);
82 oldconfig = NULL;
84 return 0;
87 /** Helper function for download_with_xfercommand() */
88 static char *get_filename(const char *url) {
89 char *filename = strrchr(url, '/');
90 if(filename != NULL) {
91 filename++;
93 return filename;
96 /** Helper function for download_with_xfercommand() */
97 static char *get_destfile(const char *path, const char *filename) {
98 char *destfile;
99 /* len = localpath len + filename len + null */
100 size_t len = strlen(path) + strlen(filename) + 1;
101 destfile = calloc(len, sizeof(char));
102 snprintf(destfile, len, "%s%s", path, filename);
104 return destfile;
107 /** Helper function for download_with_xfercommand() */
108 static char *get_tempfile(const char *path, const char *filename) {
109 char *tempfile;
110 /* len = localpath len + filename len + '.part' len + null */
111 size_t len = strlen(path) + strlen(filename) + 6;
112 tempfile = calloc(len, sizeof(char));
113 snprintf(tempfile, len, "%s%s.part", path, filename);
115 return tempfile;
118 /** External fetch callback */
119 static int download_with_xfercommand(const char *url, const char *localpath,
120 int force) {
121 int ret = 0;
122 int retval;
123 int usepart = 0;
124 struct stat st;
125 char *parsedcmd,*tempcmd;
126 char cwd[PATH_MAX];
127 int restore_cwd = 0;
128 char *destfile, *tempfile, *filename;
130 if(!config->xfercommand) {
131 return -1;
134 filename = get_filename(url);
135 if(!filename) {
136 return -1;
138 destfile = get_destfile(localpath, filename);
139 tempfile = get_tempfile(localpath, filename);
141 if(force && stat(tempfile, &st) == 0) {
142 unlink(tempfile);
144 if(force && stat(destfile, &st) == 0) {
145 unlink(destfile);
148 tempcmd = strdup(config->xfercommand);
149 /* replace all occurrences of %o with fn.part */
150 if(strstr(tempcmd, "%o")) {
151 usepart = 1;
152 parsedcmd = strreplace(tempcmd, "%o", tempfile);
153 free(tempcmd);
154 tempcmd = parsedcmd;
156 /* replace all occurrences of %u with the download URL */
157 parsedcmd = strreplace(tempcmd, "%u", url);
158 free(tempcmd);
160 /* save the cwd so we can restore it later */
161 if(getcwd(cwd, PATH_MAX) == NULL) {
162 pm_printf(PM_LOG_ERROR, _("could not get current working directory\n"));
163 } else {
164 restore_cwd = 1;
167 /* cwd to the download directory */
168 if(chdir(localpath)) {
169 pm_printf(PM_LOG_WARNING, _("could not chdir to download directory %s\n"), localpath);
170 ret = -1;
171 goto cleanup;
173 /* execute the parsed command via /bin/sh -c */
174 pm_printf(PM_LOG_DEBUG, "running command: %s\n", parsedcmd);
175 retval = system(parsedcmd);
177 if(retval == -1) {
178 pm_printf(PM_LOG_WARNING, _("running XferCommand: fork failed!\n"));
179 ret = -1;
180 } else if(retval != 0) {
181 /* download failed */
182 pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
183 "code (%d)\n", retval);
184 ret = -1;
185 } else {
186 /* download was successful */
187 if(usepart) {
188 rename(tempfile, destfile);
190 ret = 0;
193 cleanup:
194 /* restore the old cwd if we have it */
195 if(restore_cwd && chdir(cwd) != 0) {
196 pm_printf(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
197 cwd, strerror(errno));
200 if(ret == -1) {
201 /* hack to let an user the time to cancel a download */
202 sleep(2);
204 free(destfile);
205 free(tempfile);
206 free(parsedcmd);
208 return ret;
212 int config_set_arch(const char *arch)
214 if(strcmp(arch, "auto") == 0) {
215 struct utsname un;
216 uname(&un);
217 config->arch = strdup(un.machine);
218 } else {
219 config->arch = strdup(arch);
221 pm_printf(PM_LOG_DEBUG, "config: arch: %s\n", config->arch);
222 return 0;
225 static pgp_verify_t option_verifysig(const char *value)
227 pgp_verify_t level;
228 if(strcmp(value, "Always") == 0) {
229 level = PM_PGP_VERIFY_ALWAYS;
230 } else if(strcmp(value, "Optional") == 0) {
231 level = PM_PGP_VERIFY_OPTIONAL;
232 } else if(strcmp(value, "Never") == 0) {
233 level = PM_PGP_VERIFY_NEVER;
234 } else {
235 level = PM_PGP_VERIFY_UNKNOWN;
237 pm_printf(PM_LOG_DEBUG, "config: VerifySig = %s (%d)\n", value, level);
238 return level;
241 static int process_cleanmethods(alpm_list_t *values) {
242 alpm_list_t *i;
243 for(i = values; i; i = alpm_list_next(i)) {
244 const char *value = i->data;
245 if(strcmp(value, "KeepInstalled") == 0) {
246 config->cleanmethod |= PM_CLEAN_KEEPINST;
247 } else if(strcmp(value, "KeepCurrent") == 0) {
248 config->cleanmethod |= PM_CLEAN_KEEPCUR;
249 } else {
250 pm_printf(PM_LOG_ERROR, _("invalid value for 'CleanMethod' : '%s'\n"),
251 value);
252 return 1;
255 return 0;
258 /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
259 * settings. Refactored out of the parseconfig code since all of them did
260 * the exact same thing and duplicated code.
261 * @param ptr a pointer to the start of the multiple options
262 * @param option the string (friendly) name of the option, used for messages
263 * @param list the list to add the option to
265 static void setrepeatingoption(char *ptr, const char *option,
266 alpm_list_t **list)
268 char *q;
270 while((q = strchr(ptr, ' '))) {
271 *q = '\0';
272 *list = alpm_list_add(*list, strdup(ptr));
273 pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, ptr);
274 ptr = q;
275 ptr++;
277 *list = alpm_list_add(*list, strdup(ptr));
278 pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, ptr);
281 static int _parse_options(const char *key, char *value,
282 const char *file, int linenum)
284 if(value == NULL) {
285 /* options without settings */
286 if(strcmp(key, "UseSyslog") == 0) {
287 config->usesyslog = 1;
288 pm_printf(PM_LOG_DEBUG, "config: usesyslog\n");
289 } else if(strcmp(key, "ILoveCandy") == 0) {
290 config->chomp = 1;
291 pm_printf(PM_LOG_DEBUG, "config: chomp\n");
292 } else if(strcmp(key, "VerbosePkgLists") == 0) {
293 config->verbosepkglists = 1;
294 pm_printf(PM_LOG_DEBUG, "config: verbosepkglists\n");
295 } else if(strcmp(key, "UseDelta") == 0) {
296 config->usedelta = 1;
297 pm_printf(PM_LOG_DEBUG, "config: usedelta\n");
298 } else if(strcmp(key, "TotalDownload") == 0) {
299 config->totaldownload = 1;
300 pm_printf(PM_LOG_DEBUG, "config: totaldownload\n");
301 } else if(strcmp(key, "CheckSpace") == 0) {
302 config->checkspace = 1;
303 } else {
304 pm_printf(PM_LOG_WARNING,
305 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
306 file, linenum, key, "options");
308 } else {
309 /* options with settings */
310 if(strcmp(key, "NoUpgrade") == 0) {
311 setrepeatingoption(value, "NoUpgrade", &(config->noupgrade));
312 } else if(strcmp(key, "NoExtract") == 0) {
313 setrepeatingoption(value, "NoExtract", &(config->noextract));
314 } else if(strcmp(key, "IgnorePkg") == 0) {
315 setrepeatingoption(value, "IgnorePkg", &(config->ignorepkg));
316 } else if(strcmp(key, "IgnoreGroup") == 0) {
317 setrepeatingoption(value, "IgnoreGroup", &(config->ignoregrp));
318 } else if(strcmp(key, "HoldPkg") == 0) {
319 setrepeatingoption(value, "HoldPkg", &(config->holdpkg));
320 } else if(strcmp(key, "SyncFirst") == 0) {
321 setrepeatingoption(value, "SyncFirst", &(config->syncfirst));
322 } else if(strcmp(key, "CacheDir") == 0) {
323 setrepeatingoption(value, "CacheDir", &(config->cachedirs));
324 } else if(strcmp(key, "Architecture") == 0) {
325 if(!config->arch) {
326 config_set_arch(value);
328 } else if(strcmp(key, "DBPath") == 0) {
329 /* don't overwrite a path specified on the command line */
330 if(!config->dbpath) {
331 config->dbpath = strdup(value);
332 pm_printf(PM_LOG_DEBUG, "config: dbpath: %s\n", value);
334 } else if(strcmp(key, "RootDir") == 0) {
335 /* don't overwrite a path specified on the command line */
336 if(!config->rootdir) {
337 config->rootdir = strdup(value);
338 pm_printf(PM_LOG_DEBUG, "config: rootdir: %s\n", value);
340 } else if(strcmp(key, "GPGDir") == 0) {
341 if(!config->gpgdir) {
342 config->gpgdir = strdup(value);
343 pm_printf(PM_LOG_DEBUG, "config: gpgdir: %s\n", value);
345 } else if(strcmp(key, "LogFile") == 0) {
346 if(!config->logfile) {
347 config->logfile = strdup(value);
348 pm_printf(PM_LOG_DEBUG, "config: logfile: %s\n", value);
350 } else if(strcmp(key, "XferCommand") == 0) {
351 config->xfercommand = strdup(value);
352 pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", value);
353 } else if(strcmp(key, "CleanMethod") == 0) {
354 alpm_list_t *methods = NULL;
355 setrepeatingoption(value, "CleanMethod", &methods);
356 if(process_cleanmethods(methods)) {
357 FREELIST(methods);
358 return 1;
360 FREELIST(methods);
361 } else if(strcmp(key, "VerifySig") == 0) {
362 pgp_verify_t level = option_verifysig(value);
363 if(level != PM_PGP_VERIFY_UNKNOWN) {
364 config->sigverify = level;
365 } else {
366 pm_printf(PM_LOG_ERROR,
367 _("config file %s, line %d: directive '%s' has invalid value '%s'\n"),
368 file, linenum, key, value);
369 return 1;
371 } else {
372 pm_printf(PM_LOG_WARNING,
373 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
374 file, linenum, key, "options");
378 return 0;
381 static int _add_mirror(alpm_db_t *db, char *value)
383 const char *dbname = alpm_db_get_name(db);
384 /* let's attempt a replacement for the current repo */
385 char *temp = strreplace(value, "$repo", dbname);
386 /* let's attempt a replacement for the arch */
387 const char *arch = config->arch;
388 char *server;
389 if(arch) {
390 server = strreplace(temp, "$arch", arch);
391 free(temp);
392 } else {
393 if(strstr(temp, "$arch")) {
394 free(temp);
395 pm_printf(PM_LOG_ERROR, _("The mirror '%s' contains the $arch"
396 " variable, but no Architecture is defined.\n"), value);
397 return 1;
399 server = temp;
402 if(alpm_db_add_server(db, server) != 0) {
403 /* pm_errno is set by alpm_db_setserver */
404 pm_printf(PM_LOG_ERROR, _("could not add server URL to database '%s': %s (%s)\n"),
405 dbname, server, alpm_strerror(alpm_errno(config->handle)));
406 free(server);
407 return 1;
410 free(server);
411 return 0;
414 /** Sets up libalpm global stuff in one go. Called after the command line
415 * and inital config file parsing. Once this is complete, we can see if any
416 * paths were defined. If a rootdir was defined and nothing else, we want all
417 * of our paths to live under the rootdir that was specified. Safe to call
418 * multiple times (will only do anything the first time).
420 static int setup_libalpm(void)
422 int ret = 0;
423 enum _alpm_errno_t err;
424 alpm_handle_t *handle;
426 pm_printf(PM_LOG_DEBUG, "setup_libalpm called\n");
428 /* Configure root path first. If it is set and dbpath/logfile were not
429 * set, then set those as well to reside under the root. */
430 if(config->rootdir) {
431 char path[PATH_MAX];
432 if(!config->dbpath) {
433 snprintf(path, PATH_MAX, "%s/%s", config->rootdir, DBPATH + 1);
434 config->dbpath = strdup(path);
436 if(!config->logfile) {
437 snprintf(path, PATH_MAX, "%s/%s", config->rootdir, LOGFILE + 1);
438 config->logfile = strdup(path);
440 } else {
441 config->rootdir = strdup(ROOTDIR);
442 if(!config->dbpath) {
443 config->dbpath = strdup(DBPATH);
447 /* initialize library */
448 handle = alpm_initialize(config->rootdir, config->dbpath, &err);
449 if(!handle) {
450 pm_printf(PM_LOG_ERROR, _("failed to initialize alpm library (%s)\n"),
451 alpm_strerror(err));
452 if(err == PM_ERR_DB_VERSION) {
453 pm_printf(PM_LOG_ERROR, _(" try running pacman-db-upgrade\n"));
455 return -1;
457 config->handle = handle;
459 alpm_option_set_logcb(handle, cb_log);
460 alpm_option_set_dlcb(handle, cb_dl_progress);
462 config->logfile = config->logfile ? config->logfile : strdup(LOGFILE);
463 ret = alpm_option_set_logfile(handle, config->logfile);
464 if(ret != 0) {
465 pm_printf(PM_LOG_ERROR, _("problem setting logfile '%s' (%s)\n"),
466 config->logfile, alpm_strerror(alpm_errno(handle)));
467 return ret;
470 /* Set GnuPG's home directory. This is not relative to rootdir, even if
471 * rootdir is defined. Reasoning: gpgdir contains configuration data. */
472 config->gpgdir = config->gpgdir ? config->gpgdir : strdup(GPGDIR);
473 ret = alpm_option_set_gpgdir(handle, config->gpgdir);
474 if(ret != 0) {
475 pm_printf(PM_LOG_ERROR, _("problem setting gpgdir '%s' (%s)\n"),
476 config->gpgdir, alpm_strerror(alpm_errno(handle)));
477 return ret;
480 /* add a default cachedir if one wasn't specified */
481 if(config->cachedirs == NULL) {
482 alpm_option_add_cachedir(handle, CACHEDIR);
483 } else {
484 alpm_option_set_cachedirs(handle, config->cachedirs);
487 if(config->sigverify != PM_PGP_VERIFY_UNKNOWN) {
488 alpm_option_set_default_sigverify(handle, config->sigverify);
491 if(config->xfercommand) {
492 alpm_option_set_fetchcb(handle, download_with_xfercommand);
495 if(config->totaldownload) {
496 alpm_option_set_totaldlcb(handle, cb_dl_total);
499 alpm_option_set_arch(handle, config->arch);
500 alpm_option_set_checkspace(handle, config->checkspace);
501 alpm_option_set_usesyslog(handle, config->usesyslog);
502 alpm_option_set_usedelta(handle, config->usedelta);
504 alpm_option_set_ignorepkgs(handle, config->ignorepkg);
505 alpm_option_set_ignoregroups(handle, config->ignoregrp);
506 alpm_option_set_noupgrades(handle, config->noupgrade);
507 alpm_option_set_noextracts(handle, config->noextract);
509 return 0;
513 * Allows parsing in advance of an entire config section before we start
514 * calling library methods.
516 struct section_t {
517 /* useful for all sections */
518 char *name;
519 int is_options;
520 /* db section option gathering */
521 pgp_verify_t sigverify;
522 alpm_list_t *servers;
526 * Wrap up a section once we have reached the end of it. This should be called
527 * when a subsequent section is encountered, or when we have reached the end of
528 * the root config file. Once called, all existing saved config pieces on the
529 * section struct are freed.
530 * @param section the current parsed and saved section data
531 * @param parse_options whether we are parsing options or repo data
532 * @return 0 on success, 1 on failure
534 static int finish_section(struct section_t *section, int parse_options)
536 int ret = 0;
537 alpm_list_t *i;
538 alpm_db_t *db;
540 pm_printf(PM_LOG_DEBUG, "config: finish section '%s'\n", section->name);
542 /* parsing options (or nothing)- nothing to do except free the pieces */
543 if(!section->name || parse_options || section->is_options) {
544 goto cleanup;
547 /* if we are not looking at options sections only, register a db */
548 db = alpm_db_register_sync(config->handle, section->name, section->sigverify);
549 if(db == NULL) {
550 pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"),
551 section->name, alpm_strerror(alpm_errno(config->handle)));
552 ret = 1;
553 goto cleanup;
556 for(i = section->servers; i; i = alpm_list_next(i)) {
557 char *value = alpm_list_getdata(i);
558 if(_add_mirror(db, value) != 0) {
559 pm_printf(PM_LOG_ERROR,
560 _("could not add mirror '%s' to database '%s' (%s)\n"),
561 value, section->name, alpm_strerror(alpm_errno(config->handle)));
562 ret = 1;
563 goto cleanup;
565 free(value);
568 cleanup:
569 alpm_list_free(section->servers);
570 section->servers = NULL;
571 section->sigverify = 0;
572 free(section->name);
573 section->name = NULL;
574 return ret;
577 /** The "real" parseconfig. Each "Include" directive will recall this method so
578 * recursion and stack depth are limited to 10 levels. The publicly visible
579 * parseconfig calls this with a NULL section argument so we can recall from
580 * within ourself on an include.
581 * @param file path to the config file
582 * @param section the current active section
583 * @param parse_options whether to parse and call methods for the options
584 * section; if 0, parse and call methods for the repos sections
585 * @param depth the current recursion depth
586 * @return 0 on success, 1 on failure
588 static int _parseconfig(const char *file, struct section_t *section,
589 int parse_options, int depth)
591 FILE *fp = NULL;
592 char line[PATH_MAX];
593 int linenum = 0;
594 int ret = 0;
595 const int max_depth = 10;
597 if(depth >= max_depth) {
598 pm_printf(PM_LOG_ERROR,
599 _("config parsing exceeded max recursion depth of %d.\n"), max_depth);
600 ret = 1;
601 goto cleanup;
604 pm_printf(PM_LOG_DEBUG, "config: attempting to read file %s\n", file);
605 fp = fopen(file, "r");
606 if(fp == NULL) {
607 pm_printf(PM_LOG_ERROR, _("config file %s could not be read.\n"), file);
608 ret = 1;
609 goto cleanup;
612 while(fgets(line, PATH_MAX, fp)) {
613 char *key, *value, *ptr;
614 size_t line_len;
616 linenum++;
617 strtrim(line);
618 line_len = strlen(line);
620 /* ignore whole line and end of line comments */
621 if(line_len == 0 || line[0] == '#') {
622 continue;
624 if((ptr = strchr(line, '#'))) {
625 *ptr = '\0';
628 if(line[0] == '[' && line[line_len - 1] == ']') {
629 char *name;
630 /* only possibility here is a line == '[]' */
631 if(line_len <= 2) {
632 pm_printf(PM_LOG_ERROR, _("config file %s, line %d: bad section name.\n"),
633 file, linenum);
634 ret = 1;
635 goto cleanup;
637 /* new config section, skip the '[' */
638 name = strdup(line + 1);
639 name[line_len - 2] = '\0';
640 /* we're at a new section; perform any post-actions for the prior */
641 if(finish_section(section, parse_options)) {
642 ret = 1;
643 goto cleanup;
645 pm_printf(PM_LOG_DEBUG, "config: new section '%s'\n", name);
646 section->name = name;
647 section->is_options = (strcmp(name, "options") == 0);
648 continue;
651 /* directive */
652 /* strsep modifies the 'line' string: 'key \0 value' */
653 key = line;
654 value = line;
655 strsep(&value, "=");
656 strtrim(key);
657 strtrim(value);
659 if(key == NULL) {
660 pm_printf(PM_LOG_ERROR, _("config file %s, line %d: syntax error in config file- missing key.\n"),
661 file, linenum);
662 ret = 1;
663 goto cleanup;
665 /* For each directive, compare to the camelcase string. */
666 if(section->name == NULL) {
667 pm_printf(PM_LOG_ERROR, _("config file %s, line %d: All directives must belong to a section.\n"),
668 file, linenum);
669 ret = 1;
670 goto cleanup;
672 /* Include is allowed in both options and repo sections */
673 if(strcmp(key, "Include") == 0) {
674 glob_t globbuf;
675 int globret;
676 size_t gindex;
678 if(value == NULL) {
679 pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"),
680 file, linenum, key);
681 ret = 1;
682 goto cleanup;
684 /* Ignore include failures... assume non-critical */
685 globret = glob(value, GLOB_NOCHECK, NULL, &globbuf);
686 switch(globret) {
687 case GLOB_NOSPACE:
688 pm_printf(PM_LOG_DEBUG,
689 "config file %s, line %d: include globbing out of space\n",
690 file, linenum);
691 break;
692 case GLOB_ABORTED:
693 pm_printf(PM_LOG_DEBUG,
694 "config file %s, line %d: include globbing read error for %s\n",
695 file, linenum, value);
696 break;
697 case GLOB_NOMATCH:
698 pm_printf(PM_LOG_DEBUG,
699 "config file %s, line %d: no include found for %s\n",
700 file, linenum, value);
701 break;
702 default:
703 for(gindex = 0; gindex < globbuf.gl_pathc; gindex++) {
704 pm_printf(PM_LOG_DEBUG, "config file %s, line %d: including %s\n",
705 file, linenum, globbuf.gl_pathv[gindex]);
706 _parseconfig(globbuf.gl_pathv[gindex], section, parse_options, depth + 1);
708 break;
710 globfree(&globbuf);
711 continue;
713 if(parse_options && section->is_options) {
714 /* we are either in options ... */
715 if((ret = _parse_options(key, value, file, linenum)) != 0) {
716 goto cleanup;
718 } else if (!parse_options && !section->is_options) {
719 /* ... or in a repo section */
720 if(strcmp(key, "Server") == 0) {
721 if(value == NULL) {
722 pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"),
723 file, linenum, key);
724 ret = 1;
725 goto cleanup;
727 section->servers = alpm_list_add(section->servers, strdup(value));
728 } else if(strcmp(key, "VerifySig") == 0) {
729 pgp_verify_t level = option_verifysig(value);
730 if(level != PM_PGP_VERIFY_UNKNOWN) {
731 section->sigverify = level;
732 } else {
733 pm_printf(PM_LOG_ERROR,
734 _("config file %s, line %d: directive '%s' has invalid value '%s'\n"),
735 file, linenum, key, value);
736 ret = 1;
737 goto cleanup;
739 } else {
740 pm_printf(PM_LOG_WARNING,
741 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
742 file, linenum, key, section->name);
747 if(depth == 0) {
748 ret = finish_section(section, parse_options);
751 cleanup:
752 fclose(fp);
753 pm_printf(PM_LOG_DEBUG, "config: finished parsing %s\n", file);
754 return ret;
757 /** Parse a configuration file.
758 * @param file path to the config file
759 * @return 0 on success, non-zero on error
761 int parseconfig(const char *file)
763 int ret;
764 struct section_t section;
765 memset(&section, 0, sizeof(struct section_t));
766 /* the config parse is a two-pass affair. We first parse the entire thing for
767 * the [options] section so we can get all default and path options set.
768 * Next, we go back and parse everything but [options]. */
770 /* call the real parseconfig function with a null section & db argument */
771 pm_printf(PM_LOG_DEBUG, "parseconfig: options pass\n");
772 if((ret = _parseconfig(file, &section, 1, 0))) {
773 return ret;
775 if((ret = setup_libalpm())) {
776 return ret;
778 /* second pass, repo section parsing */
779 pm_printf(PM_LOG_DEBUG, "parseconfig: repo pass\n");
780 return _parseconfig(file, &section, 0, 0);
783 /* vim: set ts=2 sw=2 noet: */