4 * Copyright (c) 2006-2013 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/>.
23 #include <locale.h> /* setlocale */
24 #include <fcntl.h> /* open */
27 #include <string.h> /* strdup */
29 #include <sys/types.h>
30 #include <sys/utsname.h> /* uname */
40 /* global config variable */
41 config_t
*config
= NULL
;
43 #define NOCOLOR "\033[0m"
45 #define BOLD "\033[0;1m"
47 #define BLACK "\033[0;30m"
48 #define RED "\033[0;31m"
49 #define GREEN "\033[0;32m"
50 #define YELLOW "\033[0;33m"
51 #define BLUE "\033[0;34m"
52 #define MAGENTA "\033[0;35m"
53 #define CYAN "\033[0;36m"
54 #define WHITE "\033[0;37m"
56 #define BOLDBLACK "\033[1;30m"
57 #define BOLDRED "\033[1;31m"
58 #define BOLDGREEN "\033[1;32m"
59 #define BOLDYELLOW "\033[1;33m"
60 #define BOLDBLUE "\033[1;34m"
61 #define BOLDMAGENTA "\033[1;35m"
62 #define BOLDCYAN "\033[1;36m"
63 #define BOLDWHITE "\033[1;37m"
65 void enable_colors(int colors
)
67 colstr_t
*colstr
= &config
->colstr
;
69 if(colors
== PM_COLOR_ON
) {
70 colstr
->colon
= BOLDBLUE
"::" BOLD
" ";
72 colstr
->repo
= BOLDMAGENTA
;
73 colstr
->version
= BOLDGREEN
;
74 colstr
->groups
= BOLDBLUE
;
75 colstr
->meta
= BOLDCYAN
;
76 colstr
->warn
= BOLDYELLOW
;
77 colstr
->err
= BOLDRED
;
78 colstr
->nocolor
= NOCOLOR
;
82 config_t
*config_new(void)
84 config_t
*newconfig
= calloc(1, sizeof(config_t
));
86 pm_printf(ALPM_LOG_ERROR
,
87 _("malloc failure: could not allocate %zd bytes\n"),
91 /* defaults which may get overridden later */
92 newconfig
->op
= PM_OP_MAIN
;
93 newconfig
->logmask
= ALPM_LOG_ERROR
| ALPM_LOG_WARNING
;
94 newconfig
->configfile
= strdup(CONFFILE
);
95 newconfig
->deltaratio
= 0.0;
96 if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES
) {
97 newconfig
->siglevel
= ALPM_SIG_PACKAGE
| ALPM_SIG_PACKAGE_OPTIONAL
|
98 ALPM_SIG_DATABASE
| ALPM_SIG_DATABASE_OPTIONAL
;
99 newconfig
->localfilesiglevel
= ALPM_SIG_USE_DEFAULT
;
100 newconfig
->remotefilesiglevel
= ALPM_SIG_USE_DEFAULT
;
103 newconfig
->colstr
.colon
= ":: ";
104 newconfig
->colstr
.title
= "";
105 newconfig
->colstr
.repo
= "";
106 newconfig
->colstr
.version
= "";
107 newconfig
->colstr
.groups
= "";
108 newconfig
->colstr
.meta
= "";
109 newconfig
->colstr
.warn
= "";
110 newconfig
->colstr
.err
= "";
111 newconfig
->colstr
.nocolor
= "";
116 int config_free(config_t
*oldconfig
)
118 if(oldconfig
== NULL
) {
122 alpm_list_free(oldconfig
->explicit_adds
);
123 alpm_list_free(oldconfig
->explicit_removes
);
125 FREELIST(oldconfig
->holdpkg
);
126 FREELIST(oldconfig
->ignorepkg
);
127 FREELIST(oldconfig
->ignoregrp
);
128 FREELIST(oldconfig
->noupgrade
);
129 FREELIST(oldconfig
->noextract
);
130 free(oldconfig
->configfile
);
131 free(oldconfig
->rootdir
);
132 free(oldconfig
->dbpath
);
133 free(oldconfig
->logfile
);
134 free(oldconfig
->gpgdir
);
135 FREELIST(oldconfig
->cachedirs
);
136 free(oldconfig
->xfercommand
);
137 free(oldconfig
->print_format
);
138 free(oldconfig
->arch
);
144 /** Helper function for download_with_xfercommand() */
145 static char *get_filename(const char *url
)
147 char *filename
= strrchr(url
, '/');
148 if(filename
!= NULL
) {
154 /** Helper function for download_with_xfercommand() */
155 static char *get_destfile(const char *path
, const char *filename
)
158 /* len = localpath len + filename len + null */
159 size_t len
= strlen(path
) + strlen(filename
) + 1;
160 destfile
= calloc(len
, sizeof(char));
161 snprintf(destfile
, len
, "%s%s", path
, filename
);
166 /** Helper function for download_with_xfercommand() */
167 static char *get_tempfile(const char *path
, const char *filename
)
170 /* len = localpath len + filename len + '.part' len + null */
171 size_t len
= strlen(path
) + strlen(filename
) + 6;
172 tempfile
= calloc(len
, sizeof(char));
173 snprintf(tempfile
, len
, "%s%s.part", path
, filename
);
178 /** External fetch callback */
179 static int download_with_xfercommand(const char *url
, const char *localpath
,
186 char *parsedcmd
, *tempcmd
;
187 char *destfile
, *tempfile
, *filename
;
189 if(!config
->xfercommand
) {
193 filename
= get_filename(url
);
197 destfile
= get_destfile(localpath
, filename
);
198 tempfile
= get_tempfile(localpath
, filename
);
200 if(force
&& stat(tempfile
, &st
) == 0) {
203 if(force
&& stat(destfile
, &st
) == 0) {
207 tempcmd
= strdup(config
->xfercommand
);
208 /* replace all occurrences of %o with fn.part */
209 if(strstr(tempcmd
, "%o")) {
211 parsedcmd
= strreplace(tempcmd
, "%o", tempfile
);
215 /* replace all occurrences of %u with the download URL */
216 parsedcmd
= strreplace(tempcmd
, "%u", url
);
219 /* save the cwd so we can restore it later */
221 cwdfd
= open(".", O_RDONLY
);
222 } while(cwdfd
== -1 && errno
== EINTR
);
224 pm_printf(ALPM_LOG_ERROR
, _("could not get current working directory\n"));
227 /* cwd to the download directory */
228 if(chdir(localpath
)) {
229 pm_printf(ALPM_LOG_WARNING
, _("could not chdir to download directory %s\n"), localpath
);
233 /* execute the parsed command via /bin/sh -c */
234 pm_printf(ALPM_LOG_DEBUG
, "running command: %s\n", parsedcmd
);
235 retval
= system(parsedcmd
);
238 pm_printf(ALPM_LOG_WARNING
, _("running XferCommand: fork failed!\n"));
240 } else if(retval
!= 0) {
241 /* download failed */
242 pm_printf(ALPM_LOG_DEBUG
, "XferCommand command returned non-zero status "
243 "code (%d)\n", retval
);
246 /* download was successful */
249 if(rename(tempfile
, destfile
)) {
250 pm_printf(ALPM_LOG_ERROR
, _("could not rename %s to %s (%s)\n"),
251 tempfile
, destfile
, strerror(errno
));
258 /* restore the old cwd if we have it */
260 if(fchdir(cwdfd
) != 0) {
261 pm_printf(ALPM_LOG_ERROR
, _("could not restore working directory (%s)\n"),
268 /* hack to let an user the time to cancel a download */
279 int config_set_arch(const char *arch
)
281 if(strcmp(arch
, "auto") == 0) {
284 config
->arch
= strdup(un
.machine
);
286 config
->arch
= strdup(arch
);
288 pm_printf(ALPM_LOG_DEBUG
, "config: arch: %s\n", config
->arch
);
293 * Parse a signature verification level line.
294 * @param values the list of parsed option values
295 * @param storage location to store the derived signature level; any existing
296 * value here is used as a starting point
297 * @param file path to the config file
298 * @param linenum current line number in file
299 * @return 0 on success, 1 on any parsing error
301 static int process_siglevel(alpm_list_t
*values
, alpm_siglevel_t
*storage
,
302 const char *file
, int linenum
)
304 alpm_siglevel_t level
= *storage
;
308 /* Collapse the option names into a single bitmasked value */
309 for(i
= values
; i
; i
= alpm_list_next(i
)) {
310 const char *original
= i
->data
, *value
;
311 int package
= 0, database
= 0;
313 if(strncmp(original
, "Package", strlen("Package")) == 0) {
314 /* only packages are affected, don't flip flags for databases */
315 value
= original
+ strlen("Package");
317 } else if(strncmp(original
, "Database", strlen("Database")) == 0) {
318 /* only databases are affected, don't flip flags for packages */
319 value
= original
+ strlen("Database");
322 /* no prefix, so anything found will affect both packages and dbs */
324 package
= database
= 1;
327 /* now parse out and store actual flag if it is valid */
328 if(strcmp(value
, "Never") == 0) {
330 level
&= ~ALPM_SIG_PACKAGE
;
331 level
|= ALPM_SIG_PACKAGE_SET
;
334 level
&= ~ALPM_SIG_DATABASE
;
336 } else if(strcmp(value
, "Optional") == 0) {
338 level
|= ALPM_SIG_PACKAGE
;
339 level
|= ALPM_SIG_PACKAGE_OPTIONAL
;
340 level
|= ALPM_SIG_PACKAGE_SET
;
343 level
|= ALPM_SIG_DATABASE
;
344 level
|= ALPM_SIG_DATABASE_OPTIONAL
;
346 } else if(strcmp(value
, "Required") == 0) {
348 level
|= ALPM_SIG_PACKAGE
;
349 level
&= ~ALPM_SIG_PACKAGE_OPTIONAL
;
350 level
|= ALPM_SIG_PACKAGE_SET
;
353 level
|= ALPM_SIG_DATABASE
;
354 level
&= ~ALPM_SIG_DATABASE_OPTIONAL
;
356 } else if(strcmp(value
, "TrustedOnly") == 0) {
358 level
&= ~ALPM_SIG_PACKAGE_MARGINAL_OK
;
359 level
&= ~ALPM_SIG_PACKAGE_UNKNOWN_OK
;
360 level
|= ALPM_SIG_PACKAGE_TRUST_SET
;
363 level
&= ~ALPM_SIG_DATABASE_MARGINAL_OK
;
364 level
&= ~ALPM_SIG_DATABASE_UNKNOWN_OK
;
366 } else if(strcmp(value
, "TrustAll") == 0) {
368 level
|= ALPM_SIG_PACKAGE_MARGINAL_OK
;
369 level
|= ALPM_SIG_PACKAGE_UNKNOWN_OK
;
370 level
|= ALPM_SIG_PACKAGE_TRUST_SET
;
373 level
|= ALPM_SIG_DATABASE_MARGINAL_OK
;
374 level
|= ALPM_SIG_DATABASE_UNKNOWN_OK
;
377 pm_printf(ALPM_LOG_ERROR
,
378 _("config file %s, line %d: invalid value for '%s' : '%s'\n"),
379 file
, linenum
, "SigLevel", original
);
382 level
&= ~ALPM_SIG_USE_DEFAULT
;
385 /* ensure we have sig checking ability and are actually turning it on */
386 if(!(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES
) &&
387 level
& (ALPM_SIG_PACKAGE
| ALPM_SIG_DATABASE
)) {
388 pm_printf(ALPM_LOG_ERROR
,
389 _("config file %s, line %d: '%s' option invalid, no signature support\n"),
390 file
, linenum
, "SigLevel");
401 * Merge the package entires of two signature verification levels.
402 * @param base initial siglevel
403 * @param over overridden siglevel, derived value is stored here
405 static void merge_siglevel(alpm_siglevel_t
*base
, alpm_siglevel_t
*over
)
407 alpm_siglevel_t level
= *over
;
408 if(level
& ALPM_SIG_USE_DEFAULT
) {
411 if(!(level
& ALPM_SIG_PACKAGE_SET
)) {
412 level
|= *base
& ALPM_SIG_PACKAGE
;
413 level
|= *base
& ALPM_SIG_PACKAGE_OPTIONAL
;
415 if(!(level
& ALPM_SIG_PACKAGE_TRUST_SET
)) {
416 level
|= *base
& ALPM_SIG_PACKAGE_MARGINAL_OK
;
417 level
|= *base
& ALPM_SIG_PACKAGE_UNKNOWN_OK
;
424 static int process_cleanmethods(alpm_list_t
*values
,
425 const char *file
, int linenum
)
428 for(i
= values
; i
; i
= alpm_list_next(i
)) {
429 const char *value
= i
->data
;
430 if(strcmp(value
, "KeepInstalled") == 0) {
431 config
->cleanmethod
|= PM_CLEAN_KEEPINST
;
432 } else if(strcmp(value
, "KeepCurrent") == 0) {
433 config
->cleanmethod
|= PM_CLEAN_KEEPCUR
;
435 pm_printf(ALPM_LOG_ERROR
,
436 _("config file %s, line %d: invalid value for '%s' : '%s'\n"),
437 file
, linenum
, "CleanMethod", value
);
444 /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
445 * settings. Refactored out of the parseconfig code since all of them did
446 * the exact same thing and duplicated code.
447 * @param ptr a pointer to the start of the multiple options
448 * @param option the string (friendly) name of the option, used for messages
449 * @param list the list to add the option to
451 static void setrepeatingoption(char *ptr
, const char *option
,
456 val
= strtok_r(ptr
, " ", &saveptr
);
458 *list
= alpm_list_add(*list
, strdup(val
));
459 pm_printf(ALPM_LOG_DEBUG
, "config: %s: %s\n", option
, val
);
460 val
= strtok_r(NULL
, " ", &saveptr
);
464 static int _parse_options(const char *key
, char *value
,
465 const char *file
, int linenum
)
468 /* options without settings */
469 if(strcmp(key
, "UseSyslog") == 0) {
470 config
->usesyslog
= 1;
471 pm_printf(ALPM_LOG_DEBUG
, "config: usesyslog\n");
472 } else if(strcmp(key
, "ILoveCandy") == 0) {
474 pm_printf(ALPM_LOG_DEBUG
, "config: chomp\n");
475 } else if(strcmp(key
, "VerbosePkgLists") == 0) {
476 config
->verbosepkglists
= 1;
477 pm_printf(ALPM_LOG_DEBUG
, "config: verbosepkglists\n");
478 } else if(strcmp(key
, "UseDelta") == 0) {
479 config
->deltaratio
= 0.7;
480 pm_printf(ALPM_LOG_DEBUG
, "config: usedelta (default 0.7)\n");
481 } else if(strcmp(key
, "TotalDownload") == 0) {
482 config
->totaldownload
= 1;
483 pm_printf(ALPM_LOG_DEBUG
, "config: totaldownload\n");
484 } else if(strcmp(key
, "CheckSpace") == 0) {
485 config
->checkspace
= 1;
486 } else if(strcmp(key
, "Color") == 0) {
487 if(config
->color
== PM_COLOR_UNSET
) {
488 config
->color
= isatty(fileno(stdout
)) ? PM_COLOR_ON
: PM_COLOR_OFF
;
489 enable_colors(config
->color
);
492 pm_printf(ALPM_LOG_WARNING
,
493 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
494 file
, linenum
, key
, "options");
497 /* options with settings */
498 if(strcmp(key
, "NoUpgrade") == 0) {
499 setrepeatingoption(value
, "NoUpgrade", &(config
->noupgrade
));
500 } else if(strcmp(key
, "NoExtract") == 0) {
501 setrepeatingoption(value
, "NoExtract", &(config
->noextract
));
502 } else if(strcmp(key
, "IgnorePkg") == 0) {
503 setrepeatingoption(value
, "IgnorePkg", &(config
->ignorepkg
));
504 } else if(strcmp(key
, "IgnoreGroup") == 0) {
505 setrepeatingoption(value
, "IgnoreGroup", &(config
->ignoregrp
));
506 } else if(strcmp(key
, "HoldPkg") == 0) {
507 setrepeatingoption(value
, "HoldPkg", &(config
->holdpkg
));
508 } else if(strcmp(key
, "CacheDir") == 0) {
509 setrepeatingoption(value
, "CacheDir", &(config
->cachedirs
));
510 } else if(strcmp(key
, "Architecture") == 0) {
512 config_set_arch(value
);
514 } else if(strcmp(key
, "UseDelta") == 0) {
517 const char *oldlocale
;
519 /* set the locale to 'C' for consistent decimal parsing (0.7 and never
520 * 0,7) from config files, then restore old setting when we are done */
521 oldlocale
= setlocale(LC_NUMERIC
, NULL
);
522 setlocale(LC_NUMERIC
, "C");
523 ratio
= strtod(value
, &endptr
);
524 setlocale(LC_NUMERIC
, oldlocale
);
526 if(*endptr
!= '\0' || ratio
< 0.0 || ratio
> 2.0) {
527 pm_printf(ALPM_LOG_ERROR
,
528 _("config file %s, line %d: invalid value for '%s' : '%s'\n"),
529 file
, linenum
, "UseDelta", value
);
532 config
->deltaratio
= ratio
;
533 pm_printf(ALPM_LOG_DEBUG
, "config: usedelta = %f\n", ratio
);
534 } else if(strcmp(key
, "DBPath") == 0) {
535 /* don't overwrite a path specified on the command line */
536 if(!config
->dbpath
) {
537 config
->dbpath
= strdup(value
);
538 pm_printf(ALPM_LOG_DEBUG
, "config: dbpath: %s\n", value
);
540 } else if(strcmp(key
, "RootDir") == 0) {
541 /* don't overwrite a path specified on the command line */
542 if(!config
->rootdir
) {
543 config
->rootdir
= strdup(value
);
544 pm_printf(ALPM_LOG_DEBUG
, "config: rootdir: %s\n", value
);
546 } else if(strcmp(key
, "GPGDir") == 0) {
547 if(!config
->gpgdir
) {
548 config
->gpgdir
= strdup(value
);
549 pm_printf(ALPM_LOG_DEBUG
, "config: gpgdir: %s\n", value
);
551 } else if(strcmp(key
, "LogFile") == 0) {
552 if(!config
->logfile
) {
553 config
->logfile
= strdup(value
);
554 pm_printf(ALPM_LOG_DEBUG
, "config: logfile: %s\n", value
);
556 } else if(strcmp(key
, "XferCommand") == 0) {
557 config
->xfercommand
= strdup(value
);
558 pm_printf(ALPM_LOG_DEBUG
, "config: xfercommand: %s\n", value
);
559 } else if(strcmp(key
, "CleanMethod") == 0) {
560 alpm_list_t
*methods
= NULL
;
561 setrepeatingoption(value
, "CleanMethod", &methods
);
562 if(process_cleanmethods(methods
, file
, linenum
)) {
567 } else if(strcmp(key
, "SigLevel") == 0) {
568 alpm_list_t
*values
= NULL
;
569 setrepeatingoption(value
, "SigLevel", &values
);
570 if(process_siglevel(values
, &config
->siglevel
, file
, linenum
)) {
575 } else if(strcmp(key
, "LocalFileSigLevel") == 0) {
576 alpm_list_t
*values
= NULL
;
577 setrepeatingoption(value
, "LocalFileSigLevel", &values
);
578 if(process_siglevel(values
, &config
->localfilesiglevel
, file
, linenum
)) {
583 } else if(strcmp(key
, "RemoteFileSigLevel") == 0) {
584 alpm_list_t
*values
= NULL
;
585 setrepeatingoption(value
, "RemoteFileSigLevel", &values
);
586 if(process_siglevel(values
, &config
->remotefilesiglevel
, file
, linenum
)) {
592 pm_printf(ALPM_LOG_WARNING
,
593 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
594 file
, linenum
, key
, "options");
601 static int _add_mirror(alpm_db_t
*db
, char *value
)
603 const char *dbname
= alpm_db_get_name(db
);
604 /* let's attempt a replacement for the current repo */
605 char *temp
= strreplace(value
, "$repo", dbname
);
606 /* let's attempt a replacement for the arch */
607 const char *arch
= config
->arch
;
610 server
= strreplace(temp
, "$arch", arch
);
613 if(strstr(temp
, "$arch")) {
615 pm_printf(ALPM_LOG_ERROR
,
616 _("mirror '%s' contains the '%s' variable, but no '%s' is defined.\n"),
617 value
, "$arch", "Architecture");
623 if(alpm_db_add_server(db
, server
) != 0) {
624 /* pm_errno is set by alpm_db_setserver */
625 pm_printf(ALPM_LOG_ERROR
, _("could not add server URL to database '%s': %s (%s)\n"),
626 dbname
, server
, alpm_strerror(alpm_errno(config
->handle
)));
635 /** Sets up libalpm global stuff in one go. Called after the command line
636 * and initial config file parsing. Once this is complete, we can see if any
637 * paths were defined. If a rootdir was defined and nothing else, we want all
638 * of our paths to live under the rootdir that was specified. Safe to call
639 * multiple times (will only do anything the first time).
641 static int setup_libalpm(void)
645 alpm_handle_t
*handle
;
647 pm_printf(ALPM_LOG_DEBUG
, "setup_libalpm called\n");
649 /* Configure root path first. If it is set and dbpath/logfile were not
650 * set, then set those as well to reside under the root. */
651 if(config
->rootdir
) {
653 if(!config
->dbpath
) {
654 snprintf(path
, PATH_MAX
, "%s/%s", config
->rootdir
, DBPATH
+ 1);
655 config
->dbpath
= strdup(path
);
657 if(!config
->logfile
) {
658 snprintf(path
, PATH_MAX
, "%s/%s", config
->rootdir
, LOGFILE
+ 1);
659 config
->logfile
= strdup(path
);
662 config
->rootdir
= strdup(ROOTDIR
);
663 if(!config
->dbpath
) {
664 config
->dbpath
= strdup(DBPATH
);
668 /* initialize library */
669 handle
= alpm_initialize(config
->rootdir
, config
->dbpath
, &err
);
671 pm_printf(ALPM_LOG_ERROR
, _("failed to initialize alpm library\n(%s: %s)\n"),
672 alpm_strerror(err
), config
->dbpath
);
673 if(err
== ALPM_ERR_DB_VERSION
) {
674 pm_printf(ALPM_LOG_ERROR
, _(" try running pacman-db-upgrade\n"));
678 config
->handle
= handle
;
680 alpm_option_set_logcb(handle
, cb_log
);
681 alpm_option_set_dlcb(handle
, cb_dl_progress
);
682 alpm_option_set_eventcb(handle
, cb_event
);
683 alpm_option_set_questioncb(handle
, cb_question
);
684 alpm_option_set_progresscb(handle
, cb_progress
);
686 config
->logfile
= config
->logfile
? config
->logfile
: strdup(LOGFILE
);
687 ret
= alpm_option_set_logfile(handle
, config
->logfile
);
689 pm_printf(ALPM_LOG_ERROR
, _("problem setting logfile '%s' (%s)\n"),
690 config
->logfile
, alpm_strerror(alpm_errno(handle
)));
694 /* Set GnuPG's home directory. This is not relative to rootdir, even if
695 * rootdir is defined. Reasoning: gpgdir contains configuration data. */
696 config
->gpgdir
= config
->gpgdir
? config
->gpgdir
: strdup(GPGDIR
);
697 ret
= alpm_option_set_gpgdir(handle
, config
->gpgdir
);
699 pm_printf(ALPM_LOG_ERROR
, _("problem setting gpgdir '%s' (%s)\n"),
700 config
->gpgdir
, alpm_strerror(alpm_errno(handle
)));
704 /* add a default cachedir if one wasn't specified */
705 if(config
->cachedirs
== NULL
) {
706 alpm_option_add_cachedir(handle
, CACHEDIR
);
708 alpm_option_set_cachedirs(handle
, config
->cachedirs
);
711 alpm_option_set_default_siglevel(handle
, config
->siglevel
);
713 merge_siglevel(&config
->siglevel
, &config
->localfilesiglevel
);
714 merge_siglevel(&config
->siglevel
, &config
->remotefilesiglevel
);
715 alpm_option_set_local_file_siglevel(handle
, config
->localfilesiglevel
);
716 alpm_option_set_remote_file_siglevel(handle
, config
->remotefilesiglevel
);
718 if(config
->xfercommand
) {
719 alpm_option_set_fetchcb(handle
, download_with_xfercommand
);
720 } else if(!(alpm_capabilities() & ALPM_CAPABILITY_DOWNLOADER
)) {
721 pm_printf(ALPM_LOG_WARNING
, _("no '%s' configured"), "XferCommand");
724 if(config
->totaldownload
) {
725 alpm_option_set_totaldlcb(handle
, cb_dl_total
);
728 alpm_option_set_arch(handle
, config
->arch
);
729 alpm_option_set_checkspace(handle
, config
->checkspace
);
730 alpm_option_set_usesyslog(handle
, config
->usesyslog
);
731 alpm_option_set_deltaratio(handle
, config
->deltaratio
);
733 alpm_option_set_ignorepkgs(handle
, config
->ignorepkg
);
734 alpm_option_set_ignoregroups(handle
, config
->ignoregrp
);
735 alpm_option_set_noupgrades(handle
, config
->noupgrade
);
736 alpm_option_set_noextracts(handle
, config
->noextract
);
742 * Allows parsing in advance of an entire config section before we start
743 * calling library methods.
746 /* useful for all sections */
750 /* db section option gathering */
751 alpm_siglevel_t siglevel
;
752 alpm_list_t
*servers
;
753 alpm_db_usage_t usage
;
756 static int process_usage(alpm_list_t
*values
, alpm_db_usage_t
*usage
,
757 const char *file
, int linenum
)
760 alpm_db_usage_t level
= *usage
;
763 for(i
= values
; i
; i
= i
->next
) {
766 if(strcmp(key
, "Sync") == 0) {
767 level
|= ALPM_DB_USAGE_SYNC
;
768 } else if(strcmp(key
, "Search") == 0) {
769 level
|= ALPM_DB_USAGE_SEARCH
;
770 } else if(strcmp(key
, "Install") == 0) {
771 level
|= ALPM_DB_USAGE_INSTALL
;
772 } else if(strcmp(key
, "Upgrade") == 0) {
773 level
|= ALPM_DB_USAGE_UPGRADE
;
774 } else if(strcmp(key
, "All") == 0) {
775 level
|= ALPM_DB_USAGE_ALL
;
777 pm_printf(ALPM_LOG_ERROR
,
778 _("config file %s, line %d: '%s' option '%s' not recognized\n"),
779 file
, linenum
, "Usage", key
);
790 static int _parse_repo(const char *key
, char *value
, const char *file
,
791 int line
, struct section_t
*section
)
795 if(strcmp(key
, "Server") == 0) {
797 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: directive '%s' needs a value\n"),
801 section
->servers
= alpm_list_add(section
->servers
, strdup(value
));
803 } else if(strcmp(key
, "SigLevel") == 0) {
805 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: directive '%s' needs a value\n"),
808 alpm_list_t
*values
= NULL
;
809 setrepeatingoption(value
, "SigLevel", &values
);
811 if(section
->siglevel
== ALPM_SIG_USE_DEFAULT
) {
812 section
->siglevel
= config
->siglevel
;
814 ret
= process_siglevel(values
, §ion
->siglevel
, file
, line
);
818 } else if(strcmp(key
, "Usage") == 0) {
819 alpm_list_t
*values
= NULL
;
820 setrepeatingoption(value
, "Usage", &values
);
822 if(process_usage(values
, §ion
->usage
, file
, line
)) {
829 pm_printf(ALPM_LOG_WARNING
,
830 _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
831 file
, line
, key
, section
->name
);
838 * Wrap up a section once we have reached the end of it. This should be called
839 * when a subsequent section is encountered, or when we have reached the end of
840 * the root config file. Once called, all existing saved config pieces on the
841 * section struct are freed.
842 * @param section the current parsed and saved section data
843 * @param parse_options whether we are parsing options or repo data
844 * @return 0 on success, 1 on failure
846 static int finish_section(struct section_t
*section
)
852 pm_printf(ALPM_LOG_DEBUG
, "config: finish section '%s'\n", section
->name
);
854 /* parsing options (or nothing)- nothing to do except free the pieces */
855 if(!section
->name
|| section
->parse_options
|| section
->is_options
) {
859 /* if we are not looking at options sections only, register a db */
860 db
= alpm_register_syncdb(config
->handle
, section
->name
, section
->siglevel
);
862 pm_printf(ALPM_LOG_ERROR
, _("could not register '%s' database (%s)\n"),
863 section
->name
, alpm_strerror(alpm_errno(config
->handle
)));
868 pm_printf(ALPM_LOG_DEBUG
,
869 "setting usage of %d for %s repoistory\n",
870 section
->usage
== 0 ? ALPM_DB_USAGE_ALL
: section
->usage
,
872 alpm_db_set_usage(db
, section
->usage
== 0 ? ALPM_DB_USAGE_ALL
: section
->usage
);
874 for(i
= section
->servers
; i
; i
= alpm_list_next(i
)) {
875 char *value
= i
->data
;
876 if(_add_mirror(db
, value
) != 0) {
877 pm_printf(ALPM_LOG_ERROR
,
878 _("could not add mirror '%s' to database '%s' (%s)\n"),
879 value
, section
->name
, alpm_strerror(alpm_errno(config
->handle
)));
887 alpm_list_free(section
->servers
);
888 section
->servers
= NULL
;
889 section
->siglevel
= ALPM_SIG_USE_DEFAULT
;
890 section
->name
= NULL
;
895 static int _parse_directive(const char *file
, int linenum
, const char *name
,
896 char *key
, char *value
, void *data
)
898 struct section_t
*section
= data
;
900 int ret
= finish_section(section
);
901 pm_printf(ALPM_LOG_DEBUG
, "config: new section '%s'\n", name
);
902 section
->name
= name
;
903 if(name
&& strcmp(name
, "options") == 0) {
904 section
->is_options
= 1;
906 section
->is_options
= 0;
911 if(section
->name
== NULL
) {
912 pm_printf(ALPM_LOG_ERROR
, _("config file %s, line %d: All directives must belong to a section.\n"),
917 if(section
->parse_options
&& section
->is_options
) {
918 /* we are either in options ... */
919 return _parse_options(key
, value
, file
, linenum
);
920 } else if(!section
->parse_options
&& !section
->is_options
) {
921 /* ... or in a repo section */
922 return _parse_repo(key
, value
, file
, linenum
, section
);
928 /** Parse a configuration file.
929 * @param file path to the config file
930 * @return 0 on success, non-zero on error
932 int parseconfig(const char *file
)
935 struct section_t section
;
936 memset(§ion
, 0, sizeof(struct section_t
));
937 section
.siglevel
= ALPM_SIG_USE_DEFAULT
;
939 /* the config parse is a two-pass affair. We first parse the entire thing for
940 * the [options] section so we can get all default and path options set.
941 * Next, we go back and parse everything but [options]. */
943 /* call the real parseconfig function with a null section & db argument */
944 pm_printf(ALPM_LOG_DEBUG
, "parseconfig: options pass\n");
945 section
.parse_options
= 1;
946 if((ret
= parse_ini(file
, _parse_directive
, §ion
))) {
949 if((ret
= setup_libalpm())) {
952 /* second pass, repo section parsing */
953 pm_printf(ALPM_LOG_DEBUG
, "parseconfig: repo pass\n");
954 section
.parse_options
= 0;
955 return parse_ini(file
, _parse_directive
, §ion
);
958 /* vim: set ts=2 sw=2 noet: */