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/>.
28 #include <string.h> /* strdup */
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_fprintf(stderr
, PM_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
= PM_LOG_ERROR
| PM_LOG_WARNING
;
54 newconfig
->configfile
= strdup(CONFFILE
);
55 newconfig
->sigverify
= PM_PGP_VERIFY_UNKNOWN
;
60 int config_free(config_t
*oldconfig
)
62 if(oldconfig
== NULL
) {
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
);
87 /** Helper function for download_with_xfercommand() */
88 static char *get_filename(const char *url
) {
89 char *filename
= strrchr(url
, '/');
90 if(filename
!= NULL
) {
96 /** Helper function for download_with_xfercommand() */
97 static char *get_destfile(const char *path
, const char *filename
) {
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
);
107 /** Helper function for download_with_xfercommand() */
108 static char *get_tempfile(const char *path
, const char *filename
) {
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
);
118 /** External fetch callback */
119 static int download_with_xfercommand(const char *url
, const char *localpath
,
125 char *parsedcmd
,*tempcmd
;
128 char *destfile
, *tempfile
, *filename
;
130 if(!config
->xfercommand
) {
134 filename
= get_filename(url
);
138 destfile
= get_destfile(localpath
, filename
);
139 tempfile
= get_tempfile(localpath
, filename
);
141 if(force
&& stat(tempfile
, &st
) == 0) {
144 if(force
&& stat(destfile
, &st
) == 0) {
148 tempcmd
= strdup(config
->xfercommand
);
149 /* replace all occurrences of %o with fn.part */
150 if(strstr(tempcmd
, "%o")) {
152 parsedcmd
= strreplace(tempcmd
, "%o", tempfile
);
156 /* replace all occurrences of %u with the download URL */
157 parsedcmd
= strreplace(tempcmd
, "%u", url
);
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"));
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
);
173 /* execute the parsed command via /bin/sh -c */
174 pm_printf(PM_LOG_DEBUG
, "running command: %s\n", parsedcmd
);
175 retval
= system(parsedcmd
);
178 pm_printf(PM_LOG_WARNING
, _("running XferCommand: fork failed!\n"));
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
);
186 /* download was successful */
188 rename(tempfile
, destfile
);
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
));
201 /* hack to let an user the time to cancel a download */
212 int config_set_arch(const char *arch
)
214 if(strcmp(arch
, "auto") == 0) {
217 config
->arch
= strdup(un
.machine
);
219 config
->arch
= strdup(arch
);
221 pm_printf(PM_LOG_DEBUG
, "config: arch: %s\n", config
->arch
);
225 static pgp_verify_t
option_verifysig(const char *value
)
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
;
235 level
= PM_PGP_VERIFY_UNKNOWN
;
237 pm_printf(PM_LOG_DEBUG
, "config: VerifySig = %s (%d)\n", value
, level
);
241 static int process_cleanmethods(alpm_list_t
*values
) {
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
;
250 pm_printf(PM_LOG_ERROR
, _("invalid value for 'CleanMethod' : '%s'\n"),
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
,
270 while((q
= strchr(ptr
, ' '))) {
272 *list
= alpm_list_add(*list
, strdup(ptr
));
273 pm_printf(PM_LOG_DEBUG
, "config: %s: %s\n", option
, 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
)
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) {
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;
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");
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) {
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
)) {
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
;
366 pm_printf(PM_LOG_ERROR
,
367 _("config file %s, line %d: directive '%s' has invalid value '%s'\n"),
368 file
, linenum
, key
, value
);
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");
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
;
390 server
= strreplace(temp
, "$arch", arch
);
393 if(strstr(temp
, "$arch")) {
395 pm_printf(PM_LOG_ERROR
, _("The mirror '%s' contains the $arch"
396 " variable, but no Architecture is defined.\n"), value
);
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
)));
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)
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
) {
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
);
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
);
450 pm_printf(PM_LOG_ERROR
, _("failed to initialize alpm library (%s)\n"),
452 if(err
== PM_ERR_DB_VERSION
) {
453 pm_printf(PM_LOG_ERROR
, _(" try running pacman-db-upgrade\n"));
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
);
465 pm_printf(PM_LOG_ERROR
, _("problem setting logfile '%s' (%s)\n"),
466 config
->logfile
, alpm_strerror(alpm_errno(handle
)));
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
);
475 pm_printf(PM_LOG_ERROR
, _("problem setting gpgdir '%s' (%s)\n"),
476 config
->gpgdir
, alpm_strerror(alpm_errno(handle
)));
480 /* add a default cachedir if one wasn't specified */
481 if(config
->cachedirs
== NULL
) {
482 alpm_option_add_cachedir(handle
, CACHEDIR
);
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
);
513 * Allows parsing in advance of an entire config section before we start
514 * calling library methods.
517 /* useful for all sections */
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
)
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
) {
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
);
550 pm_printf(PM_LOG_ERROR
, _("could not register '%s' database (%s)\n"),
551 section
->name
, alpm_strerror(alpm_errno(config
->handle
)));
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
)));
569 alpm_list_free(section
->servers
);
570 section
->servers
= NULL
;
571 section
->sigverify
= 0;
573 section
->name
= NULL
;
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
)
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
);
604 pm_printf(PM_LOG_DEBUG
, "config: attempting to read file %s\n", file
);
605 fp
= fopen(file
, "r");
607 pm_printf(PM_LOG_ERROR
, _("config file %s could not be read.\n"), file
);
612 while(fgets(line
, PATH_MAX
, fp
)) {
613 char *key
, *value
, *ptr
;
618 line_len
= strlen(line
);
620 /* ignore whole line and end of line comments */
621 if(line_len
== 0 || line
[0] == '#') {
624 if((ptr
= strchr(line
, '#'))) {
628 if(line
[0] == '[' && line
[line_len
- 1] == ']') {
630 /* only possibility here is a line == '[]' */
632 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: bad section name.\n"),
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
)) {
645 pm_printf(PM_LOG_DEBUG
, "config: new section '%s'\n", name
);
646 section
->name
= name
;
647 section
->is_options
= (strcmp(name
, "options") == 0);
652 /* strsep modifies the 'line' string: 'key \0 value' */
660 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: syntax error in config file- missing key.\n"),
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"),
672 /* Include is allowed in both options and repo sections */
673 if(strcmp(key
, "Include") == 0) {
679 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: directive '%s' needs a value\n"),
684 /* Ignore include failures... assume non-critical */
685 globret
= glob(value
, GLOB_NOCHECK
, NULL
, &globbuf
);
688 pm_printf(PM_LOG_DEBUG
,
689 "config file %s, line %d: include globbing out of space\n",
693 pm_printf(PM_LOG_DEBUG
,
694 "config file %s, line %d: include globbing read error for %s\n",
695 file
, linenum
, value
);
698 pm_printf(PM_LOG_DEBUG
,
699 "config file %s, line %d: no include found for %s\n",
700 file
, linenum
, value
);
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);
713 if(parse_options
&& section
->is_options
) {
714 /* we are either in options ... */
715 if((ret
= _parse_options(key
, value
, file
, linenum
)) != 0) {
718 } else if (!parse_options
&& !section
->is_options
) {
719 /* ... or in a repo section */
720 if(strcmp(key
, "Server") == 0) {
722 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: directive '%s' needs a value\n"),
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
;
733 pm_printf(PM_LOG_ERROR
,
734 _("config file %s, line %d: directive '%s' has invalid value '%s'\n"),
735 file
, linenum
, key
, value
);
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
);
748 ret
= finish_section(section
, parse_options
);
753 pm_printf(PM_LOG_DEBUG
, "config: finished parsing %s\n", file
);
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
)
764 struct section_t section
;
765 memset(§ion
, 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
, §ion
, 1, 0))) {
775 if((ret
= setup_libalpm())) {
778 /* second pass, repo section parsing */
779 pm_printf(PM_LOG_DEBUG
, "parseconfig: repo pass\n");
780 return _parseconfig(file
, §ion
, 0, 0);
783 /* vim: set ts=2 sw=2 noet: */