4 * Copyright (c) 2006-2012 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/>.
24 #include <fcntl.h> /* open */
27 #include <string.h> /* strdup */
29 #include <sys/types.h>
30 #include <sys/utsname.h> /* uname */
39 /* global config variable */
40 config_t
*config
= NULL
;
42 config_t
*config_new(void)
44 config_t
*newconfig
= calloc(1, sizeof(config_t
));
46 pm_printf(ALPM_LOG_ERROR
,
47 _("malloc failure: could not allocate %zd bytes\n"),
51 /* defaults which may get overridden later */
52 newconfig
->op
= PM_OP_MAIN
;
53 newconfig
->logmask
= ALPM_LOG_ERROR
| ALPM_LOG_WARNING
;
54 newconfig
->configfile
= strdup(CONFFILE
);
55 newconfig
->deltaratio
= 0.0;
56 if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES
) {
57 newconfig
->siglevel
= ALPM_SIG_PACKAGE
| ALPM_SIG_PACKAGE_OPTIONAL
|
58 ALPM_SIG_DATABASE
| ALPM_SIG_DATABASE_OPTIONAL
;
64 int config_free(config_t
*oldconfig
)
66 if(oldconfig
== NULL
) {
70 alpm_list_free(oldconfig
->explicit_adds
);
71 alpm_list_free(oldconfig
->explicit_removes
);
73 FREELIST(oldconfig
->holdpkg
);
74 FREELIST(oldconfig
->syncfirst
);
75 FREELIST(oldconfig
->ignorepkg
);
76 FREELIST(oldconfig
->ignoregrp
);
77 FREELIST(oldconfig
->noupgrade
);
78 FREELIST(oldconfig
->noextract
);
79 free(oldconfig
->configfile
);
80 free(oldconfig
->rootdir
);
81 free(oldconfig
->dbpath
);
82 free(oldconfig
->logfile
);
83 free(oldconfig
->gpgdir
);
84 FREELIST(oldconfig
->cachedirs
);
85 free(oldconfig
->xfercommand
);
86 free(oldconfig
->print_format
);
87 free(oldconfig
->arch
);
93 /** Helper function for download_with_xfercommand() */
94 static char *get_filename(const char *url
) {
95 char *filename
= strrchr(url
, '/');
96 if(filename
!= NULL
) {
102 /** Helper function for download_with_xfercommand() */
103 static char *get_destfile(const char *path
, const char *filename
) {
105 /* len = localpath len + filename len + null */
106 size_t len
= strlen(path
) + strlen(filename
) + 1;
107 destfile
= calloc(len
, sizeof(char));
108 snprintf(destfile
, len
, "%s%s", path
, filename
);
113 /** Helper function for download_with_xfercommand() */
114 static char *get_tempfile(const char *path
, const char *filename
) {
116 /* len = localpath len + filename len + '.part' len + null */
117 size_t len
= strlen(path
) + strlen(filename
) + 6;
118 tempfile
= calloc(len
, sizeof(char));
119 snprintf(tempfile
, len
, "%s%s.part", path
, filename
);
124 /** External fetch callback */
125 static int download_with_xfercommand(const char *url
, const char *localpath
,
131 char *parsedcmd
,*tempcmd
;
132 char *destfile
, *tempfile
, *filename
;
134 if(!config
->xfercommand
) {
138 filename
= get_filename(url
);
142 destfile
= get_destfile(localpath
, filename
);
143 tempfile
= get_tempfile(localpath
, filename
);
145 if(force
&& stat(tempfile
, &st
) == 0) {
148 if(force
&& stat(destfile
, &st
) == 0) {
152 tempcmd
= strdup(config
->xfercommand
);
153 /* replace all occurrences of %o with fn.part */
154 if(strstr(tempcmd
, "%o")) {
156 parsedcmd
= strreplace(tempcmd
, "%o", tempfile
);
160 /* replace all occurrences of %u with the download URL */
161 parsedcmd
= strreplace(tempcmd
, "%u", url
);
164 /* save the cwd so we can restore it later */
166 cwdfd
= open(".", O_RDONLY
);
167 } while(cwdfd
== -1 && errno
== EINTR
);
169 pm_printf(ALPM_LOG_ERROR
, _("could not get current working directory\n"));
172 /* cwd to the download directory */
173 if(chdir(localpath
)) {
174 pm_printf(ALPM_LOG_WARNING
, _("could not chdir to download directory %s\n"), localpath
);
178 /* execute the parsed command via /bin/sh -c */
179 pm_printf(ALPM_LOG_DEBUG
, "running command: %s\n", parsedcmd
);
180 retval
= system(parsedcmd
);
183 pm_printf(ALPM_LOG_WARNING
, _("running XferCommand: fork failed!\n"));
185 } else if(retval
!= 0) {
186 /* download failed */
187 pm_printf(ALPM_LOG_DEBUG
, "XferCommand command returned non-zero status "
188 "code (%d)\n", retval
);
191 /* download was successful */
194 if(rename(tempfile
, destfile
)) {
195 pm_printf(ALPM_LOG_ERROR
, _("could not rename %s to %s (%s)\n"),
196 tempfile
, destfile
, strerror(errno
));
203 /* restore the old cwd if we have it */
206 if(fchdir(cwdfd
) != 0) {
207 pm_printf(ALPM_LOG_ERROR
, _("could not restore working directory (%s)\n"),
211 close_ret
= close(cwdfd
);
212 } while(close_ret
== -1 && errno
== EINTR
);
216 /* hack to let an user the time to cancel a download */
227 int config_set_arch(const char *arch
)
229 if(strcmp(arch
, "auto") == 0) {
232 config
->arch
= strdup(un
.machine
);
234 config
->arch
= strdup(arch
);
236 pm_printf(ALPM_LOG_DEBUG
, "config: arch: %s\n", config
->arch
);
241 * Parse a signature verification level line.
242 * @param values the list of parsed option values
243 * @param storage location to store the derived signature level; any existing
244 * value here is used as a starting point
245 * @param file path to the config file
246 * @param linenum current line number in file
247 * @return 0 on success, 1 on any parsing error
249 static int process_siglevel(alpm_list_t
*values
, alpm_siglevel_t
*storage
,
250 const char *file
, int linenum
)
252 alpm_siglevel_t level
= *storage
;
256 /* Collapse the option names into a single bitmasked value */
257 for(i
= values
; i
; i
= alpm_list_next(i
)) {
258 const char *original
= i
->data
, *value
;
259 int package
= 0, database
= 0;
261 if(strncmp(original
, "Package", strlen("Package")) == 0) {
262 /* only packages are affected, don't flip flags for databases */
263 value
= original
+ strlen("Package");
265 } else if(strncmp(original
, "Database", strlen("Database")) == 0) {
266 /* only databases are affected, don't flip flags for packages */
267 value
= original
+ strlen("Database");
270 /* no prefix, so anything found will affect both packages and dbs */
272 package
= database
= 1;
275 /* now parse out and store actual flag if it is valid */
276 if(strcmp(value
, "Never") == 0) {
278 level
&= ~ALPM_SIG_PACKAGE
;
281 level
&= ~ALPM_SIG_DATABASE
;
283 } else if(strcmp(value
, "Optional") == 0) {
285 level
|= ALPM_SIG_PACKAGE
;
286 level
|= ALPM_SIG_PACKAGE_OPTIONAL
;
289 level
|= ALPM_SIG_DATABASE
;
290 level
|= ALPM_SIG_DATABASE_OPTIONAL
;
292 } else if(strcmp(value
, "Required") == 0) {
294 level
|= ALPM_SIG_PACKAGE
;
295 level
&= ~ALPM_SIG_PACKAGE_OPTIONAL
;
298 level
|= ALPM_SIG_DATABASE
;
299 level
&= ~ALPM_SIG_DATABASE_OPTIONAL
;
301 } else if(strcmp(value
, "TrustedOnly") == 0) {
303 level
&= ~ALPM_SIG_PACKAGE_MARGINAL_OK
;
304 level
&= ~ALPM_SIG_PACKAGE_UNKNOWN_OK
;
307 level
&= ~ALPM_SIG_DATABASE_MARGINAL_OK
;
308 level
&= ~ALPM_SIG_DATABASE_UNKNOWN_OK
;
310 } else if(strcmp(value
, "TrustAll") == 0) {
312 level
|= ALPM_SIG_PACKAGE_MARGINAL_OK
;
313 level
|= ALPM_SIG_PACKAGE_UNKNOWN_OK
;
316 level
|= ALPM_SIG_DATABASE_MARGINAL_OK
;
317 level
|= ALPM_SIG_DATABASE_UNKNOWN_OK
;
320 pm_printf(ALPM_LOG_ERROR
,
321 _("config file %s, line %d: invalid value for '%s' : '%s'\n"),
322 file
, linenum
, "SigLevel", original
);
325 level
&= ~ALPM_SIG_USE_DEFAULT
;
328 /* ensure we have sig checking ability and are actually turning it on */
329 if(!(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES
) &&
330 level
& (ALPM_SIG_PACKAGE
| ALPM_SIG_DATABASE
)) {
331 pm_printf(ALPM_LOG_ERROR
,
332 _("config file %s, line %d: '%s' option invalid, no signature support\n"),
333 file
, linenum
, "SigLevel");
343 static int process_cleanmethods(alpm_list_t
*values
,
344 const char *file
, int linenum
)
347 for(i
= values
; i
; i
= alpm_list_next(i
)) {
348 const char *value
= i
->data
;
349 if(strcmp(value
, "KeepInstalled") == 0) {
350 config
->cleanmethod
|= PM_CLEAN_KEEPINST
;
351 } else if(strcmp(value
, "KeepCurrent") == 0) {
352 config
->cleanmethod
|= PM_CLEAN_KEEPCUR
;
354 pm_printf(ALPM_LOG_ERROR
,
355 _("config file %s, line %d: invalid value for '%s' : '%s'\n"),
356 file
, linenum
, "CleanMethod", value
);
363 /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
364 * settings. Refactored out of the parseconfig code since all of them did
365 * the exact same thing and duplicated code.
366 * @param ptr a pointer to the start of the multiple options
367 * @param option the string (friendly) name of the option, used for messages
368 * @param list the list to add the option to
370 static void setrepeatingoption(char *ptr
, const char *option
,
375 while((q
= strchr(ptr
, ' '))) {
377 *list
= alpm_list_add(*list
, strdup(ptr
));
378 pm_printf(ALPM_LOG_DEBUG
, "config: %s: %s\n", option
, ptr
);
382 *list
= alpm_list_add(*list
, strdup(ptr
));
383 pm_printf(ALPM_LOG_DEBUG
, "config: %s: %s\n", option
, ptr
);
386 static int _parse_options(const char *key
, char *value
,
387 const char *file
, int linenum
)
390 /* options without settings */
391 if(strcmp(key
, "UseSyslog") == 0) {
392 config
->usesyslog
= 1;
393 pm_printf(ALPM_LOG_DEBUG
, "config: usesyslog\n");
394 } else if(strcmp(key
, "ILoveCandy") == 0) {
396 pm_printf(ALPM_LOG_DEBUG
, "config: chomp\n");
397 } else if(strcmp(key
, "VerbosePkgLists") == 0) {
398 config
->verbosepkglists
= 1;
399 pm_printf(ALPM_LOG_DEBUG
, "config: verbosepkglists\n");
400 } else if(strcmp(key
, "UseDelta") == 0) {
401 config
->deltaratio
= 0.7;
402 pm_printf(ALPM_LOG_DEBUG
, "config: usedelta (default 0.7)\n");
403 } else if(strcmp(key
, "TotalDownload") == 0) {
404 config
->totaldownload
= 1;
405 pm_printf(ALPM_LOG_DEBUG
, "config: totaldownload\n");
406 } else if(strcmp(key
, "CheckSpace") == 0) {
407 config
->checkspace
= 1;
409 pm_printf(ALPM_LOG_WARNING
,
410 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
411 file
, linenum
, key
, "options");
414 /* options with settings */
415 if(strcmp(key
, "NoUpgrade") == 0) {
416 setrepeatingoption(value
, "NoUpgrade", &(config
->noupgrade
));
417 } else if(strcmp(key
, "NoExtract") == 0) {
418 setrepeatingoption(value
, "NoExtract", &(config
->noextract
));
419 } else if(strcmp(key
, "IgnorePkg") == 0) {
420 setrepeatingoption(value
, "IgnorePkg", &(config
->ignorepkg
));
421 } else if(strcmp(key
, "IgnoreGroup") == 0) {
422 setrepeatingoption(value
, "IgnoreGroup", &(config
->ignoregrp
));
423 } else if(strcmp(key
, "HoldPkg") == 0) {
424 setrepeatingoption(value
, "HoldPkg", &(config
->holdpkg
));
425 } else if(strcmp(key
, "SyncFirst") == 0) {
426 setrepeatingoption(value
, "SyncFirst", &(config
->syncfirst
));
427 } else if(strcmp(key
, "CacheDir") == 0) {
428 setrepeatingoption(value
, "CacheDir", &(config
->cachedirs
));
429 } else if(strcmp(key
, "Architecture") == 0) {
431 config_set_arch(value
);
433 } else if(strcmp(key
, "UseDelta") == 0) {
436 ratio
= strtod(value
, &endptr
);
437 if(*endptr
!= '\0' || ratio
< 0.0 || ratio
> 2.0) {
438 pm_printf(ALPM_LOG_ERROR
,
439 _("config file %s, line %d: invalid value for '%s' : '%s'\n"),
440 file
, linenum
, "UseDelta", value
);
443 config
->deltaratio
= ratio
;
444 pm_printf(ALPM_LOG_DEBUG
, "config: usedelta = %f\n", ratio
);
445 } else if(strcmp(key
, "DBPath") == 0) {
446 /* don't overwrite a path specified on the command line */
447 if(!config
->dbpath
) {
448 config
->dbpath
= strdup(value
);
449 pm_printf(ALPM_LOG_DEBUG
, "config: dbpath: %s\n", value
);
451 } else if(strcmp(key
, "RootDir") == 0) {
452 /* don't overwrite a path specified on the command line */
453 if(!config
->rootdir
) {
454 config
->rootdir
= strdup(value
);
455 pm_printf(ALPM_LOG_DEBUG
, "config: rootdir: %s\n", value
);
457 } else if(strcmp(key
, "GPGDir") == 0) {
458 if(!config
->gpgdir
) {
459 config
->gpgdir
= strdup(value
);
460 pm_printf(ALPM_LOG_DEBUG
, "config: gpgdir: %s\n", value
);
462 } else if(strcmp(key
, "LogFile") == 0) {
463 if(!config
->logfile
) {
464 config
->logfile
= strdup(value
);
465 pm_printf(ALPM_LOG_DEBUG
, "config: logfile: %s\n", value
);
467 } else if(strcmp(key
, "XferCommand") == 0) {
468 config
->xfercommand
= strdup(value
);
469 pm_printf(ALPM_LOG_DEBUG
, "config: xfercommand: %s\n", value
);
470 } else if(strcmp(key
, "CleanMethod") == 0) {
471 alpm_list_t
*methods
= NULL
;
472 setrepeatingoption(value
, "CleanMethod", &methods
);
473 if(process_cleanmethods(methods
, file
, linenum
)) {
478 } else if(strcmp(key
, "SigLevel") == 0) {
479 alpm_list_t
*values
= NULL
;
480 setrepeatingoption(value
, "SigLevel", &values
);
481 if(process_siglevel(values
, &config
->siglevel
, file
, linenum
)) {
487 pm_printf(ALPM_LOG_WARNING
,
488 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
489 file
, linenum
, key
, "options");
496 static int _add_mirror(alpm_db_t
*db
, char *value
)
498 const char *dbname
= alpm_db_get_name(db
);
499 /* let's attempt a replacement for the current repo */
500 char *temp
= strreplace(value
, "$repo", dbname
);
501 /* let's attempt a replacement for the arch */
502 const char *arch
= config
->arch
;
505 server
= strreplace(temp
, "$arch", arch
);
508 if(strstr(temp
, "$arch")) {
510 pm_printf(ALPM_LOG_ERROR
,
511 _("mirror '%s' contains the '%s' variable, but no '%s' is defined.\n"),
512 value
, "$arch", "Architecture");
518 if(alpm_db_add_server(db
, server
) != 0) {
519 /* pm_errno is set by alpm_db_setserver */
520 pm_printf(ALPM_LOG_ERROR
, _("could not add server URL to database '%s': %s (%s)\n"),
521 dbname
, server
, alpm_strerror(alpm_errno(config
->handle
)));
530 /** Sets up libalpm global stuff in one go. Called after the command line
531 * and inital config file parsing. Once this is complete, we can see if any
532 * paths were defined. If a rootdir was defined and nothing else, we want all
533 * of our paths to live under the rootdir that was specified. Safe to call
534 * multiple times (will only do anything the first time).
536 static int setup_libalpm(void)
540 alpm_handle_t
*handle
;
542 pm_printf(ALPM_LOG_DEBUG
, "setup_libalpm called\n");
544 /* Configure root path first. If it is set and dbpath/logfile were not
545 * set, then set those as well to reside under the root. */
546 if(config
->rootdir
) {
548 if(!config
->dbpath
) {
549 snprintf(path
, PATH_MAX
, "%s/%s", config
->rootdir
, DBPATH
+ 1);
550 config
->dbpath
= strdup(path
);
552 if(!config
->logfile
) {
553 snprintf(path
, PATH_MAX
, "%s/%s", config
->rootdir
, LOGFILE
+ 1);
554 config
->logfile
= strdup(path
);
557 config
->rootdir
= strdup(ROOTDIR
);
558 if(!config
->dbpath
) {
559 config
->dbpath
= strdup(DBPATH
);
563 /* initialize library */
564 handle
= alpm_initialize(config
->rootdir
, config
->dbpath
, &err
);
566 pm_printf(ALPM_LOG_ERROR
, _("failed to initialize alpm library (%s)\n"),
568 if(err
== ALPM_ERR_DB_VERSION
) {
569 pm_printf(ALPM_LOG_ERROR
, _(" try running pacman-db-upgrade\n"));
573 config
->handle
= handle
;
575 alpm_option_set_logcb(handle
, cb_log
);
576 alpm_option_set_dlcb(handle
, cb_dl_progress
);
577 alpm_option_set_eventcb(handle
, cb_event
);
578 alpm_option_set_questioncb(handle
, cb_question
);
579 alpm_option_set_progresscb(handle
, cb_progress
);
581 config
->logfile
= config
->logfile
? config
->logfile
: strdup(LOGFILE
);
582 ret
= alpm_option_set_logfile(handle
, config
->logfile
);
584 pm_printf(ALPM_LOG_ERROR
, _("problem setting logfile '%s' (%s)\n"),
585 config
->logfile
, alpm_strerror(alpm_errno(handle
)));
589 /* Set GnuPG's home directory. This is not relative to rootdir, even if
590 * rootdir is defined. Reasoning: gpgdir contains configuration data. */
591 config
->gpgdir
= config
->gpgdir
? config
->gpgdir
: strdup(GPGDIR
);
592 ret
= alpm_option_set_gpgdir(handle
, config
->gpgdir
);
594 pm_printf(ALPM_LOG_ERROR
, _("problem setting gpgdir '%s' (%s)\n"),
595 config
->gpgdir
, alpm_strerror(alpm_errno(handle
)));
599 /* add a default cachedir if one wasn't specified */
600 if(config
->cachedirs
== NULL
) {
601 alpm_option_add_cachedir(handle
, CACHEDIR
);
603 alpm_option_set_cachedirs(handle
, config
->cachedirs
);
606 alpm_option_set_default_siglevel(handle
, config
->siglevel
);
608 if(config
->xfercommand
) {
609 alpm_option_set_fetchcb(handle
, download_with_xfercommand
);
610 } else if(!(alpm_capabilities() & ALPM_CAPABILITY_DOWNLOADER
)) {
611 pm_printf(ALPM_LOG_WARNING
, _("no '%s' configured"), "XferCommand");
614 if(config
->totaldownload
) {
615 alpm_option_set_totaldlcb(handle
, cb_dl_total
);
618 alpm_option_set_arch(handle
, config
->arch
);
619 alpm_option_set_checkspace(handle
, config
->checkspace
);
620 alpm_option_set_usesyslog(handle
, config
->usesyslog
);
621 alpm_option_set_deltaratio(handle
, config
->deltaratio
);
623 alpm_option_set_ignorepkgs(handle
, config
->ignorepkg
);
624 alpm_option_set_ignoregroups(handle
, config
->ignoregrp
);
625 alpm_option_set_noupgrades(handle
, config
->noupgrade
);
626 alpm_option_set_noextracts(handle
, config
->noextract
);
632 * Allows parsing in advance of an entire config section before we start
633 * calling library methods.
636 /* useful for all sections */
639 /* db section option gathering */
640 alpm_siglevel_t siglevel
;
641 alpm_list_t
*servers
;
645 * Wrap up a section once we have reached the end of it. This should be called
646 * when a subsequent section is encountered, or when we have reached the end of
647 * the root config file. Once called, all existing saved config pieces on the
648 * section struct are freed.
649 * @param section the current parsed and saved section data
650 * @param parse_options whether we are parsing options or repo data
651 * @return 0 on success, 1 on failure
653 static int finish_section(struct section_t
*section
, int parse_options
)
659 pm_printf(ALPM_LOG_DEBUG
, "config: finish section '%s'\n", section
->name
);
661 /* parsing options (or nothing)- nothing to do except free the pieces */
662 if(!section
->name
|| parse_options
|| section
->is_options
) {
666 /* if we are not looking at options sections only, register a db */
667 db
= alpm_register_syncdb(config
->handle
, section
->name
, section
->siglevel
);
669 pm_printf(ALPM_LOG_ERROR
, _("could not register '%s' database (%s)\n"),
670 section
->name
, alpm_strerror(alpm_errno(config
->handle
)));
675 for(i
= section
->servers
; i
; i
= alpm_list_next(i
)) {
676 char *value
= i
->data
;
677 if(_add_mirror(db
, value
) != 0) {
678 pm_printf(ALPM_LOG_ERROR
,
679 _("could not add mirror '%s' to database '%s' (%s)\n"),
680 value
, section
->name
, alpm_strerror(alpm_errno(config
->handle
)));
688 alpm_list_free(section
->servers
);
689 section
->servers
= NULL
;
690 section
->siglevel
= ALPM_SIG_USE_DEFAULT
;
692 section
->name
= NULL
;
696 /** The "real" parseconfig. Each "Include" directive will recall this method so
697 * recursion and stack depth are limited to 10 levels. The publicly visible
698 * parseconfig calls this with a NULL section argument so we can recall from
699 * within ourself on an include.
700 * @param file path to the config file
701 * @param section the current active section
702 * @param parse_options whether to parse and call methods for the options
703 * section; if 0, parse and call methods for the repos sections
704 * @param depth the current recursion depth
705 * @return 0 on success, 1 on failure
707 static int _parseconfig(const char *file
, struct section_t
*section
,
708 int parse_options
, int depth
)
714 const int max_depth
= 10;
716 if(depth
>= max_depth
) {
717 pm_printf(ALPM_LOG_ERROR
,
718 _("config parsing exceeded max recursion depth of %d.\n"), max_depth
);
723 pm_printf(ALPM_LOG_DEBUG
, "config: attempting to read file %s\n", file
);
724 fp
= fopen(file
, "r");
726 pm_printf(ALPM_LOG_ERROR
, _("config file %s could not be read.\n"), file
);
731 while(fgets(line
, PATH_MAX
, fp
)) {
732 char *key
, *value
, *ptr
;
737 /* ignore whole line and end of line comments */
738 if((ptr
= strchr(line
, '#'))) {
742 line_len
= strtrim(line
);
748 if(line
[0] == '[' && line
[line_len
- 1] == ']') {
750 /* only possibility here is a line == '[]' */
752 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: bad section name.\n"),
757 /* new config section, skip the '[' */
758 name
= strdup(line
+ 1);
759 name
[line_len
- 2] = '\0';
760 /* we're at a new section; perform any post-actions for the prior */
761 if(finish_section(section
, parse_options
)) {
765 pm_printf(ALPM_LOG_DEBUG
, "config: new section '%s'\n", name
);
766 section
->name
= name
;
767 section
->is_options
= (strcmp(name
, "options") == 0);
772 /* strsep modifies the 'line' string: 'key \0 value' */
780 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: syntax error in config file- missing key.\n"),
785 /* For each directive, compare to the camelcase string. */
786 if(section
->name
== NULL
) {
787 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: All directives must belong to a section.\n"),
792 /* Include is allowed in both options and repo sections */
793 if(strcmp(key
, "Include") == 0) {
799 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: directive '%s' needs a value\n"),
804 /* Ignore include failures... assume non-critical */
805 globret
= glob(value
, GLOB_NOCHECK
, NULL
, &globbuf
);
808 pm_printf(ALPM_LOG_DEBUG
,
809 "config file %s, line %d: include globbing out of space\n",
813 pm_printf(ALPM_LOG_DEBUG
,
814 "config file %s, line %d: include globbing read error for %s\n",
815 file
, linenum
, value
);
818 pm_printf(ALPM_LOG_DEBUG
,
819 "config file %s, line %d: no include found for %s\n",
820 file
, linenum
, value
);
823 for(gindex
= 0; gindex
< globbuf
.gl_pathc
; gindex
++) {
824 pm_printf(ALPM_LOG_DEBUG
, "config file %s, line %d: including %s\n",
825 file
, linenum
, globbuf
.gl_pathv
[gindex
]);
826 _parseconfig(globbuf
.gl_pathv
[gindex
], section
, parse_options
, depth
+ 1);
833 if(parse_options
&& section
->is_options
) {
834 /* we are either in options ... */
835 if((ret
= _parse_options(key
, value
, file
, linenum
)) != 0) {
838 } else if(!parse_options
&& !section
->is_options
) {
839 /* ... or in a repo section */
840 if(strcmp(key
, "Server") == 0) {
842 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: directive '%s' needs a value\n"),
847 section
->servers
= alpm_list_add(section
->servers
, strdup(value
));
848 } else if(strcmp(key
, "SigLevel") == 0) {
849 alpm_list_t
*values
= NULL
;
850 setrepeatingoption(value
, "SigLevel", &values
);
852 if(section
->siglevel
== ALPM_SIG_USE_DEFAULT
) {
853 section
->siglevel
= config
->siglevel
;
855 if(process_siglevel(values
, §ion
->siglevel
, file
, linenum
)) {
863 pm_printf(ALPM_LOG_WARNING
,
864 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
865 file
, linenum
, key
, section
->name
);
871 ret
= finish_section(section
, parse_options
);
878 pm_printf(ALPM_LOG_DEBUG
, "config: finished parsing %s\n", file
);
882 /** Parse a configuration file.
883 * @param file path to the config file
884 * @return 0 on success, non-zero on error
886 int parseconfig(const char *file
)
889 struct section_t section
;
890 memset(§ion
, 0, sizeof(struct section_t
));
891 section
.siglevel
= ALPM_SIG_USE_DEFAULT
;
892 /* the config parse is a two-pass affair. We first parse the entire thing for
893 * the [options] section so we can get all default and path options set.
894 * Next, we go back and parse everything but [options]. */
896 /* call the real parseconfig function with a null section & db argument */
897 pm_printf(ALPM_LOG_DEBUG
, "parseconfig: options pass\n");
898 if((ret
= _parseconfig(file
, §ion
, 1, 0))) {
901 if((ret
= setup_libalpm())) {
904 /* second pass, repo section parsing */
905 pm_printf(ALPM_LOG_DEBUG
, "parseconfig: repo pass\n");
906 return _parseconfig(file
, §ion
, 0, 0);
909 /* vim: set ts=2 sw=2 noet: */