4 * Copyright (c) 2006-2009 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 /* special handling of package version for GIT */
24 #if defined(GIT_VERSION)
25 #undef PACKAGE_VERSION
26 #define PACKAGE_VERSION GIT_VERSION
29 #include <stdlib.h> /* atoi */
36 #include <sys/types.h>
37 #include <sys/utsname.h> /* uname */
38 #include <locale.h> /* setlocale */
39 #include <time.h> /* time_t */
41 #if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H)
42 #include <mcheck.h> /* debug tracing (mtrace) */
47 #include <alpm_list.h>
57 /* list of targets specified on command line */
58 static alpm_list_t
*pm_targets
;
60 /** Display usage/syntax for the specified operation.
61 * @param op the operation code requested
62 * @param myname basename(argv[0])
64 static void usage(int op
, const char * const myname
)
66 /* prefetch some strings for usage below, which moves a lot of calls
68 char const * const str_opt
= _("options");
69 char const * const str_file
= _("file(s)");
70 char const * const str_pkg
= _("package(s)");
71 char const * const str_usg
= _("usage");
72 char const * const str_opr
= _("operation");
74 if(op
== PM_OP_MAIN
) {
75 printf("%s: %s <%s> [...]\n", str_usg
, myname
, str_opr
);
76 printf(_("operations:\n"));
77 printf(" %s {-h --help}\n", myname
);
78 printf(" %s {-V --version}\n", myname
);
79 printf(" %s {-Q --query} [%s] [%s]\n", myname
, str_opt
, str_pkg
);
80 printf(" %s {-R --remove} [%s] <%s>\n", myname
, str_opt
, str_pkg
);
81 printf(" %s {-S --sync} [%s] [%s]\n", myname
, str_opt
, str_pkg
);
82 printf(" %s {-U --upgrade} [%s] <%s>\n", myname
, str_opt
, str_file
);
83 printf(_("\nuse '%s {-h --help}' with an operation for available options\n"),
86 if(op
== PM_OP_REMOVE
) {
87 printf("%s: %s {-R --remove} [%s] <%s>\n", str_usg
, myname
, str_opt
, str_pkg
);
88 printf("%s:\n", str_opt
);
89 printf(_(" -c, --cascade remove packages and all packages that depend on them\n"));
90 printf(_(" -d, --nodeps skip dependency checks\n"));
91 printf(_(" -k, --dbonly only remove database entry, do not remove files\n"));
92 printf(_(" -n, --nosave remove configuration files as well\n"));
93 printf(_(" -s, --recursive remove dependencies also (that won't break packages)\n"
94 " (-ss includes explicitly installed dependencies too)\n"));
95 printf(_(" -u, --unneeded remove unneeded packages (that won't break packages)\n"));
96 } else if(op
== PM_OP_UPGRADE
) {
97 printf("%s: %s {-U --upgrade} [%s] <%s>\n", str_usg
, myname
, str_opt
, str_file
);
98 printf("%s:\n", str_opt
);
99 printf(_(" --asdeps install packages as non-explicitly installed\n"));
100 printf(_(" --asexplicit install packages as explicitly installed\n"));
101 printf(_(" -d, --nodeps skip dependency checks\n"));
102 printf(_(" -f, --force force install, overwrite conflicting files\n"));
103 } else if(op
== PM_OP_QUERY
) {
104 printf("%s: %s {-Q --query} [%s] [%s]\n", str_usg
, myname
, str_opt
, str_pkg
);
105 printf("%s:\n", str_opt
);
106 printf(_(" -c, --changelog view the changelog of a package\n"));
107 printf(_(" -d, --deps list packages installed as dependencies [filter]\n"));
108 printf(_(" -e, --explicit list packages explicitly installed [filter]\n"));
109 printf(_(" -g, --groups view all members of a package group\n"));
110 printf(_(" -i, --info view package information (-ii for backup files)\n"));
111 printf(_(" -k, --check check that the files owned by the package(s) are present\n"));
112 printf(_(" -l, --list list the contents of the queried package\n"));
113 printf(_(" -m, --foreign list installed packages not found in sync db(s) [filter]\n"));
114 printf(_(" -o, --owns <file> query the package that owns <file>\n"));
115 printf(_(" -p, --file <package> query a package file instead of the database\n"));
116 printf(_(" -s, --search <regex> search locally-installed packages for matching strings\n"));
117 printf(_(" -t, --unrequired list packages not required by any package [filter]\n"));
118 printf(_(" -u, --upgrades list outdated packages [filter]\n"));
119 printf(_(" -q, --quiet show less information for query and search\n"));
120 } else if(op
== PM_OP_SYNC
) {
121 printf("%s: %s {-S --sync} [%s] [%s]\n", str_usg
, myname
, str_opt
, str_pkg
);
122 printf("%s:\n", str_opt
);
123 printf(_(" --asdeps install packages as non-explicitly installed\n"));
124 printf(_(" --asexplicit install packages as explicitly installed\n"));
125 printf(_(" -c, --clean remove old packages from cache directory (-cc for all)\n"));
126 printf(_(" -d, --nodeps skip dependency checks\n"));
127 printf(_(" -f, --force force install, overwrite conflicting files\n"));
128 printf(_(" -g, --groups view all members of a package group\n"));
129 printf(_(" -i, --info view package information\n"));
130 printf(_(" -l, --list <repo> view a list of packages in a repo\n"));
131 printf(_(" -p, --print-uris print out URIs for given packages and their dependencies\n"));
132 printf(_(" -s, --search <regex> search remote repositories for matching strings\n"));
133 printf(_(" -u, --sysupgrade upgrade all outdated packages (-uu enables downgrade)\n"));
134 printf(_(" -w, --downloadonly download packages but do not install/upgrade anything\n"));
135 printf(_(" -y, --refresh download fresh package databases from the server\n"));
136 printf(_(" --needed don't reinstall up to date packages\n"));
137 printf(_(" --ignore <pkg> ignore a package upgrade (can be used more than once)\n"));
138 printf(_(" --ignoregroup <grp>\n"
139 " ignore a group upgrade (can be used more than once)\n"));
140 printf(_(" -q, --quiet show less information for query and search\n"));
142 printf(_(" --config <path> set an alternate configuration file\n"));
143 printf(_(" --logfile <path> set an alternate log file\n"));
144 printf(_(" --noconfirm do not ask for any confirmation\n"));
145 printf(_(" --noprogressbar do not show a progress bar when downloading files\n"));
146 printf(_(" --noscriptlet do not execute the install scriptlet if one exists\n"));
147 printf(_(" -v, --verbose be verbose\n"));
148 printf(_(" --debug display debug messages\n"));
149 printf(_(" -r, --root <path> set an alternate installation root\n"));
150 printf(_(" -b, --dbpath <path> set an alternate database location\n"));
151 printf(_(" --cachedir <dir> set an alternate package cache location\n"));
155 /** Output pacman version and copyright.
157 static void version(void)
160 printf(" .--. Pacman v%s - libalpm v%s\n", PACKAGE_VERSION
, alpm_version());
161 printf("/ _.-' .-. .-. .-. Copyright (C) 2006-2009 Pacman Development Team\n");
162 printf("\\ '-. '-' '-' '-' Copyright (C) 2002-2006 Judd Vinet\n");
164 printf(_(" This program may be freely redistributed under\n"
165 " the terms of the GNU General Public License.\n"));
169 /** Sets up gettext localization. Safe to call multiple times.
171 /* Inspired by the monotone function localize_monotone. */
172 #if defined(ENABLE_NLS)
173 static void localize(void)
177 setlocale(LC_ALL
, "");
178 bindtextdomain(PACKAGE
, LOCALEDIR
);
185 /** Set user agent environment variable.
187 static void setuseragent(void)
193 snprintf(agent
, 100, "pacman/%s (%s %s) libalpm/%s",
194 PACKAGE_VERSION
, un
.sysname
, un
.machine
, alpm_version());
195 setenv("HTTP_USER_AGENT", agent
, 0);
198 /** Free the resources.
200 * @param ret the return value
202 static void cleanup(int ret
) {
203 /* free alpm library resources */
204 if(alpm_release() == -1) {
205 pm_printf(PM_LOG_ERROR
, alpm_strerrorlast());
209 FREELIST(pm_targets
);
218 /** Write function that correctly handles EINTR.
220 static ssize_t
xwrite(int fd
, const void *buf
, size_t count
)
223 while((ret
= write(fd
, buf
, count
)) == -1 && errno
== EINTR
);
227 /** Catches thrown signals. Performs necessary cleanup to ensure database is
228 * in a consistant state.
229 * @param signum the thrown signal
231 static RETSIGTYPE
handler(int signum
)
233 int out
= fileno(stdout
);
234 int err
= fileno(stderr
);
235 if(signum
== SIGSEGV
) {
236 const char *msg1
= "error: segmentation fault\n";
237 const char *msg2
= "Internal pacman error: Segmentation fault.\n"
238 "Please submit a full bug report with --debug if appropriate.\n";
239 /* write a error message to out, the rest to err */
240 xwrite(out
, msg1
, strlen(msg1
));
241 xwrite(err
, msg2
, strlen(msg2
));
243 } else if((signum
== SIGINT
)) {
244 const char *msg
= "\nInterrupt signal received\n";
245 xwrite(err
, msg
, strlen(msg
));
246 if(alpm_trans_interrupt() == 0) {
247 /* a transaction is being interrupted, don't exit pacman yet. */
250 /* no commiting transaction, we can release it now and then exit pacman */
251 alpm_trans_release();
252 /* output a newline to be sure we clear any line we may be on */
253 xwrite(out
, "\n", 1);
258 /** Sets all libalpm required paths in one go. Called after the command line
259 * and inital config file parsing. Once this is complete, we can see if any
260 * paths were defined. If a rootdir was defined and nothing else, we want all
261 * of our paths to live under the rootdir that was specified. Safe to call
262 * multiple times (will only do anything the first time).
264 static void setlibpaths(void)
270 pm_printf(PM_LOG_DEBUG
, "setlibpaths() called\n");
271 /* Configure root path first. If it is set and dbpath/logfile were not
272 * set, then set those as well to reside under the root. */
273 if(config
->rootdir
) {
275 ret
= alpm_option_set_root(config
->rootdir
);
277 pm_printf(PM_LOG_ERROR
, _("problem setting rootdir '%s' (%s)\n"),
278 config
->rootdir
, alpm_strerrorlast());
281 if(!config
->dbpath
) {
282 /* omit leading slash from our static DBPATH, root handles it */
283 snprintf(path
, PATH_MAX
, "%s%s", alpm_option_get_root(), DBPATH
+ 1);
284 config
->dbpath
= strdup(path
);
286 if(!config
->logfile
) {
287 /* omit leading slash from our static LOGFILE path, root handles it */
288 snprintf(path
, PATH_MAX
, "%s%s", alpm_option_get_root(), LOGFILE
+ 1);
289 config
->logfile
= strdup(path
);
292 /* Set other paths if they were configured. Note that unless rootdir
293 * was left undefined, these two paths (dbpath and logfile) will have
294 * been set locally above, so the if cases below will now trigger. */
296 ret
= alpm_option_set_dbpath(config
->dbpath
);
298 pm_printf(PM_LOG_ERROR
, _("problem setting dbpath '%s' (%s)\n"),
299 config
->dbpath
, alpm_strerrorlast());
303 if(config
->logfile
) {
304 ret
= alpm_option_set_logfile(config
->logfile
);
306 pm_printf(PM_LOG_ERROR
, _("problem setting logfile '%s' (%s)\n"),
307 config
->logfile
, alpm_strerrorlast());
312 /* add a default cachedir if one wasn't specified */
313 if(alpm_option_get_cachedirs() == NULL
) {
314 alpm_option_add_cachedir(CACHEDIR
);
320 /** Parse command-line arguments for each operation.
323 * @return 0 on success, 1 on error
325 static int parseargs(int argc
, char *argv
[])
328 int option_index
= 0;
329 static struct option opts
[] =
331 {"query", no_argument
, 0, 'Q'},
332 {"remove", no_argument
, 0, 'R'},
333 {"sync", no_argument
, 0, 'S'},
334 {"deptest", no_argument
, 0, 'T'}, /* used by makepkg */
335 {"upgrade", no_argument
, 0, 'U'},
336 {"version", no_argument
, 0, 'V'},
337 {"dbpath", required_argument
, 0, 'b'},
338 {"cascade", no_argument
, 0, 'c'},
339 {"changelog", no_argument
, 0, 'c'},
340 {"clean", no_argument
, 0, 'c'},
341 {"nodeps", no_argument
, 0, 'd'},
342 {"deps", no_argument
, 0, 'd'},
343 {"explicit", no_argument
, 0, 'e'},
344 {"force", no_argument
, 0, 'f'},
345 {"groups", no_argument
, 0, 'g'},
346 {"help", no_argument
, 0, 'h'},
347 {"info", no_argument
, 0, 'i'},
348 {"dbonly", no_argument
, 0, 'k'},
349 {"check", no_argument
, 0, 'k'},
350 {"list", no_argument
, 0, 'l'},
351 {"foreign", no_argument
, 0, 'm'},
352 {"nosave", no_argument
, 0, 'n'},
353 {"owns", no_argument
, 0, 'o'},
354 {"file", no_argument
, 0, 'p'},
355 {"print-uris", no_argument
, 0, 'p'},
356 {"quiet", no_argument
, 0, 'q'},
357 {"root", required_argument
, 0, 'r'},
358 {"recursive", no_argument
, 0, 's'},
359 {"search", no_argument
, 0, 's'},
360 {"unrequired", no_argument
, 0, 't'},
361 {"upgrades", no_argument
, 0, 'u'},
362 {"sysupgrade", no_argument
, 0, 'u'},
363 {"unneeded", no_argument
, 0, 'u'},
364 {"verbose", no_argument
, 0, 'v'},
365 {"downloadonly", no_argument
, 0, 'w'},
366 {"refresh", no_argument
, 0, 'y'},
367 {"noconfirm", no_argument
, 0, 1000},
368 {"config", required_argument
, 0, 1001},
369 {"ignore", required_argument
, 0, 1002},
370 {"debug", optional_argument
, 0, 1003},
371 {"noprogressbar", no_argument
, 0, 1004},
372 {"noscriptlet", no_argument
, 0, 1005},
373 {"cachedir", required_argument
, 0, 1007},
374 {"asdeps", no_argument
, 0, 1008},
375 {"logfile", required_argument
, 0, 1009},
376 {"ignoregroup", required_argument
, 0, 1010},
377 {"needed", no_argument
, 0, 1011},
378 {"asexplicit", no_argument
, 0, 1012},
382 while((opt
= getopt_long(argc
, argv
, "RUFQSTr:b:vkhscVfmnoldepqituwygz", opts
, &option_index
))) {
383 alpm_list_t
*list
= NULL
, *item
= NULL
; /* lists for splitting strings */
390 case 1000: config
->noconfirm
= 1; break;
392 if(config
->configfile
) {
393 free(config
->configfile
);
395 config
->configfile
= strndup(optarg
, PATH_MAX
);
398 list
= strsplit(optarg
, ',');
399 for(item
= list
; item
; item
= alpm_list_next(item
)) {
400 alpm_option_add_ignorepkg((char *)alpm_list_getdata(item
));
405 /* debug levels are made more 'human readable' than using a raw logmask
406 * here, error and warning are set in config_new, though perhaps a
407 * --quiet option will remove these later */
409 unsigned short debug
= atoi(optarg
);
412 config
->logmask
|= PM_LOG_FUNCTION
; /* fall through */
414 config
->logmask
|= PM_LOG_DEBUG
;
417 pm_printf(PM_LOG_ERROR
, _("'%s' is not a valid debug level\n"),
422 config
->logmask
|= PM_LOG_DEBUG
;
424 /* progress bars get wonky with debug on, shut them off */
425 config
->noprogressbar
= 1;
427 case 1004: config
->noprogressbar
= 1; break;
428 case 1005: config
->flags
|= PM_TRANS_FLAG_NOSCRIPTLET
; break;
430 if(alpm_option_add_cachedir(optarg
) != 0) {
431 pm_printf(PM_LOG_ERROR
, _("problem adding cachedir '%s' (%s)\n"),
432 optarg
, alpm_strerrorlast());
437 config
->flags
|= PM_TRANS_FLAG_ALLDEPS
;
440 config
->logfile
= strdup(optarg
);
443 list
= strsplit(optarg
, ',');
444 for(item
= list
; item
; item
= alpm_list_next(item
)) {
445 alpm_option_add_ignoregrp((char *)alpm_list_getdata(item
));
449 case 1011: config
->flags
|= PM_TRANS_FLAG_NEEDED
; break;
451 config
->flags
|= PM_TRANS_FLAG_ALLEXPLICIT
;
453 case 'Q': config
->op
= (config
->op
!= PM_OP_MAIN
? 0 : PM_OP_QUERY
); break;
454 case 'R': config
->op
= (config
->op
!= PM_OP_MAIN
? 0 : PM_OP_REMOVE
); break;
455 case 'S': config
->op
= (config
->op
!= PM_OP_MAIN
? 0 : PM_OP_SYNC
); break;
456 case 'T': config
->op
= (config
->op
!= PM_OP_MAIN
? 0 : PM_OP_DEPTEST
); break;
457 case 'U': config
->op
= (config
->op
!= PM_OP_MAIN
? 0 : PM_OP_UPGRADE
); break;
458 case 'V': config
->version
= 1; break;
460 config
->dbpath
= strdup(optarg
);
463 (config
->op_s_clean
)++;
464 config
->flags
|= PM_TRANS_FLAG_CASCADE
;
465 config
->op_q_changelog
= 1;
468 config
->op_q_deps
= 1;
469 config
->flags
|= PM_TRANS_FLAG_NODEPS
;
472 config
->op_q_explicit
= 1;
474 case 'f': config
->flags
|= PM_TRANS_FLAG_FORCE
; break;
475 case 'g': (config
->group
)++; break;
476 case 'h': config
->help
= 1; break;
477 case 'i': (config
->op_q_info
)++; (config
->op_s_info
)++; break;
479 config
->flags
|= PM_TRANS_FLAG_DBONLY
;
480 config
->op_q_check
= 1;
482 case 'l': config
->op_q_list
= 1; break;
483 case 'm': config
->op_q_foreign
= 1; break;
484 case 'n': config
->flags
|= PM_TRANS_FLAG_NOSAVE
; break;
485 case 'o': config
->op_q_owns
= 1; break;
487 config
->op_q_isfile
= 1;
488 config
->op_s_printuris
= 1;
489 config
->flags
|= PM_TRANS_FLAG_NOCONFLICTS
;
490 config
->flags
|= PM_TRANS_FLAG_NOLOCK
;
496 config
->rootdir
= strdup(optarg
);
499 config
->op_s_search
= 1;
500 config
->op_q_search
= 1;
501 if(config
->flags
& PM_TRANS_FLAG_RECURSE
) {
502 config
->flags
|= PM_TRANS_FLAG_RECURSEALL
;
504 config
->flags
|= PM_TRANS_FLAG_RECURSE
;
508 config
->op_q_unrequired
= 1;
511 (config
->op_s_upgrade
)++;
512 config
->op_q_upgrade
= 1;
513 config
->flags
|= PM_TRANS_FLAG_UNNEEDED
;
515 case 'v': (config
->verbose
)++; break;
517 config
->op_s_downloadonly
= 1;
518 config
->flags
|= PM_TRANS_FLAG_DOWNLOADONLY
;
519 config
->flags
|= PM_TRANS_FLAG_NOCONFLICTS
;
521 case 'y': (config
->op_s_sync
)++; break;
527 if(config
->op
== 0) {
528 pm_printf(PM_LOG_ERROR
, _("only one operation may be used at a time\n"));
533 usage(config
->op
, mbasename(argv
[0]));
536 if(config
->version
) {
541 while(optind
< argc
) {
542 /* add the target to our target array */
543 pm_targets
= alpm_list_add(pm_targets
, strdup(argv
[optind
]));
550 /* helper for being used with setrepeatingoption */
551 static void option_add_holdpkg(const char *name
) {
552 config
->holdpkg
= alpm_list_add(config
->holdpkg
, strdup(name
));
555 /* helper for being used with setrepeatingoption */
556 static void option_add_syncfirst(const char *name
) {
557 config
->syncfirst
= alpm_list_add(config
->syncfirst
, strdup(name
));
560 /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
561 * settings. Refactored out of the parseconfig code since all of them did
562 * the exact same thing and duplicated code.
563 * @param ptr a pointer to the start of the multiple options
564 * @param option the string (friendly) name of the option, used for messages
565 * @param optionfunc a function pointer to an alpm_option_add_* function
567 static void setrepeatingoption(const char *ptr
, const char *option
,
568 void (*optionfunc
)(const char*))
570 char *p
= (char*)ptr
;
573 while((q
= strchr(p
, ' '))) {
576 pm_printf(PM_LOG_DEBUG
, "config: %s: %s\n", option
, p
);
581 pm_printf(PM_LOG_DEBUG
, "config: %s: %s\n", option
, p
);
584 static char *get_filename(const char *url
) {
585 char *filename
= strrchr(url
, '/');
586 if(filename
!= NULL
) {
592 static char *get_destfile(const char *path
, const char *filename
) {
594 /* len = localpath len + filename len + null */
595 int len
= strlen(path
) + strlen(filename
) + 1;
596 destfile
= calloc(len
, sizeof(char));
597 snprintf(destfile
, len
, "%s%s", path
, filename
);
602 static char *get_tempfile(const char *path
, const char *filename
) {
604 /* len = localpath len + filename len + '.part' len + null */
605 int len
= strlen(path
) + strlen(filename
) + 6;
606 tempfile
= calloc(len
, sizeof(char));
607 snprintf(tempfile
, len
, "%s%s.part", path
, filename
);
612 /** External fetch callback */
613 int download_with_xfercommand(const char *url
, const char *localpath
,
614 time_t mtimeold
, time_t *mtimenew
) {
619 char origCmd
[PATH_MAX
];
620 char parsedCmd
[PATH_MAX
] = "";
622 char *destfile
, *tempfile
, *filename
;
624 if(!config
->xfercommand
) {
628 filename
= get_filename(url
);
632 destfile
= get_destfile(localpath
, filename
);
633 tempfile
= get_tempfile(localpath
, filename
);
635 strncpy(origCmd
, config
->xfercommand
, sizeof(origCmd
));
636 /* replace all occurrences of %o with fn.part */
638 while((ptr2
= strstr(ptr1
, "%o"))) {
641 strcat(parsedCmd
, ptr1
);
642 strcat(parsedCmd
, tempfile
);
645 strcat(parsedCmd
, ptr1
);
646 /* replace all occurrences of %u with the download URL */
647 strncpy(origCmd
, parsedCmd
, sizeof(origCmd
));
650 while((ptr2
= strstr(ptr1
, "%u"))) {
652 strcat(parsedCmd
, ptr1
);
653 strcat(parsedCmd
, url
);
656 strcat(parsedCmd
, ptr1
);
657 /* cwd to the download directory */
658 getcwd(cwd
, PATH_MAX
);
659 if(chdir(localpath
)) {
660 pm_printf(PM_LOG_WARNING
, "could not chdir to %s\n", localpath
);
664 /* execute the parsed command via /bin/sh -c */
665 pm_printf(PM_LOG_DEBUG
, "running command: %s\n", parsedCmd
);
666 retval
= system(parsedCmd
);
669 pm_printf(PM_LOG_WARNING
, "running XferCommand: fork failed!\n");
671 } else if(retval
!= 0) {
672 /* download failed */
673 pm_printf(PM_LOG_DEBUG
, "XferCommand command returned non-zero status "
674 "code (%d)\n", retval
);
677 /* download was successful */
679 rename(tempfile
, destfile
);
687 /* hack to let an user the time to cancel a download */
696 /* The real parseconfig. Called with a null section argument by the publicly
697 * visible parseconfig so we can recall from within ourself on an include */
698 static int _parseconfig(const char *file
, const char *givensection
,
699 pmdb_t
* const givendb
)
702 char line
[PATH_MAX
+1];
704 char *ptr
, *section
= NULL
;
708 pm_printf(PM_LOG_DEBUG
, "config: attempting to read file %s\n", file
);
709 fp
= fopen(file
, "r");
711 pm_printf(PM_LOG_ERROR
, _("config file %s could not be read.\n"), file
);
715 /* if we are passed a section, use it as our starting point */
716 if(givensection
!= NULL
) {
717 section
= strdup(givensection
);
719 /* if we are passed a db, use it as our starting point */
720 if(givendb
!= NULL
) {
724 while(fgets(line
, PATH_MAX
, fp
)) {
728 /* ignore whole line and end of line comments */
729 if(strlen(line
) == 0 || line
[0] == '#') {
732 if((ptr
= strchr(line
, '#'))) {
736 if(line
[0] == '[' && line
[strlen(line
)-1] == ']') {
737 /* new config section, skip the '[' */
743 section
= strdup(ptr
);
744 section
[strlen(section
)-1] = '\0';
745 pm_printf(PM_LOG_DEBUG
, "config: new section '%s'\n", section
);
746 if(!strlen(section
)) {
747 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: bad section name.\n"),
752 /* if we are not looking at the options section, register a db */
753 if(strcmp(section
, "options") != 0) {
754 db
= alpm_db_register_sync(section
);
756 pm_printf(PM_LOG_ERROR
, _("could not register '%s' database (%s)\n"),
757 section
, alpm_strerrorlast());
765 /* strsep modifies the 'line' string: 'key \0 ptr' */
773 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: syntax error in config file- missing key.\n"),
778 /* For each directive, compare to the camelcase string. */
779 if(section
== NULL
) {
780 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: All directives must belong to a section.\n"),
785 if(ptr
== NULL
&& strcmp(section
, "options") == 0) {
786 /* directives without settings, all in [options] */
787 if(strcmp(key
, "NoPassiveFtp") == 0) {
788 alpm_option_set_nopassiveftp(1);
789 pm_printf(PM_LOG_DEBUG
, "config: nopassiveftp\n");
790 } else if(strcmp(key
, "UseSyslog") == 0) {
791 alpm_option_set_usesyslog(1);
792 pm_printf(PM_LOG_DEBUG
, "config: usesyslog\n");
793 } else if(strcmp(key
, "ILoveCandy") == 0) {
795 pm_printf(PM_LOG_DEBUG
, "config: chomp\n");
796 } else if(strcmp(key
, "ShowSize") == 0) {
797 config
->showsize
= 1;
798 pm_printf(PM_LOG_DEBUG
, "config: showsize\n");
799 } else if(strcmp(key
, "UseDelta") == 0) {
800 alpm_option_set_usedelta(1);
801 pm_printf(PM_LOG_DEBUG
, "config: usedelta\n");
802 } else if(strcmp(key
, "TotalDownload") == 0) {
803 config
->totaldownload
= 1;
804 pm_printf(PM_LOG_DEBUG
, "config: totaldownload\n");
806 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: directive '%s' not recognized.\n"),
812 /* directives with settings */
813 if(strcmp(key
, "Include") == 0) {
814 pm_printf(PM_LOG_DEBUG
, "config: including %s\n", ptr
);
815 _parseconfig(ptr
, section
, db
);
816 /* Ignore include failures... assume non-critical */
817 } else if(strcmp(section
, "options") == 0) {
818 if(strcmp(key
, "NoUpgrade") == 0) {
819 setrepeatingoption(ptr
, "NoUpgrade", alpm_option_add_noupgrade
);
820 } else if(strcmp(key
, "NoExtract") == 0) {
821 setrepeatingoption(ptr
, "NoExtract", alpm_option_add_noextract
);
822 } else if(strcmp(key
, "IgnorePkg") == 0) {
823 setrepeatingoption(ptr
, "IgnorePkg", alpm_option_add_ignorepkg
);
824 } else if(strcmp(key
, "IgnoreGroup") == 0) {
825 setrepeatingoption(ptr
, "IgnoreGroup", alpm_option_add_ignoregrp
);
826 } else if(strcmp(key
, "HoldPkg") == 0) {
827 setrepeatingoption(ptr
, "HoldPkg", option_add_holdpkg
);
828 } else if(strcmp(key
, "SyncFirst") == 0) {
829 setrepeatingoption(ptr
, "SyncFirst", option_add_syncfirst
);
830 } else if(strcmp(key
, "DBPath") == 0) {
831 /* don't overwrite a path specified on the command line */
832 if(!config
->dbpath
) {
833 config
->dbpath
= strdup(ptr
);
834 pm_printf(PM_LOG_DEBUG
, "config: dbpath: %s\n", ptr
);
836 } else if(strcmp(key
, "CacheDir") == 0) {
837 if(alpm_option_add_cachedir(ptr
) != 0) {
838 pm_printf(PM_LOG_ERROR
, _("problem adding cachedir '%s' (%s)\n"),
839 ptr
, alpm_strerrorlast());
843 pm_printf(PM_LOG_DEBUG
, "config: cachedir: %s\n", ptr
);
844 } else if(strcmp(key
, "RootDir") == 0) {
845 /* don't overwrite a path specified on the command line */
846 if(!config
->rootdir
) {
847 config
->rootdir
= strdup(ptr
);
848 pm_printf(PM_LOG_DEBUG
, "config: rootdir: %s\n", ptr
);
850 } else if (strcmp(key
, "LogFile") == 0) {
851 if(!config
->logfile
) {
852 config
->logfile
= strdup(ptr
);
853 pm_printf(PM_LOG_DEBUG
, "config: logfile: %s\n", ptr
);
855 } else if (strcmp(key
, "XferCommand") == 0) {
856 config
->xfercommand
= strdup(ptr
);
857 alpm_option_set_fetchcb(download_with_xfercommand
);
858 pm_printf(PM_LOG_DEBUG
, "config: xfercommand: %s\n", ptr
);
859 } else if (strcmp(key
, "CleanMethod") == 0) {
860 if (strcmp(ptr
, "KeepInstalled") == 0) {
861 config
->cleanmethod
= PM_CLEAN_KEEPINST
;
862 } else if (strcmp(ptr
, "KeepCurrent") == 0) {
863 config
->cleanmethod
= PM_CLEAN_KEEPCUR
;
865 pm_printf(PM_LOG_ERROR
, _("invalid value for 'CleanMethod' : '%s'\n"), ptr
);
869 pm_printf(PM_LOG_DEBUG
, "config: cleanmethod: %s\n", ptr
);
871 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: directive '%s' not recognized.\n"),
876 } else if(strcmp(key
, "Server") == 0) {
877 /* let's attempt a replacement for the current repo */
878 char *server
= strreplace(ptr
, "$repo", section
);
880 if(alpm_db_setserver(db
, server
) != 0) {
881 /* pm_errno is set by alpm_db_setserver */
882 pm_printf(PM_LOG_ERROR
, _("could not add server URL to database '%s': %s (%s)\n"),
883 alpm_db_get_name(db
), server
, alpm_strerrorlast());
891 pm_printf(PM_LOG_ERROR
, _("config file %s, line %d: directive '%s' not recognized.\n"),
907 /* call setlibpaths here to ensure we have called it at least once */
909 pm_printf(PM_LOG_DEBUG
, "config: finished parsing %s\n", file
);
913 /** Parse a configuration file.
914 * @param file path to the config file.
915 * @return 0 on success, non-zero on error
917 static int parseconfig(const char *file
)
919 /* call the real parseconfig function with a null section & db argument */
920 return(_parseconfig(file
, NULL
, NULL
));
926 * @return A return code indicating success, failure, etc.
928 int main(int argc
, char *argv
[])
931 struct sigaction new_action
, old_action
;
932 #if defined(HAVE_GETEUID) && !defined(CYGWIN)
933 /* geteuid undefined in CYGWIN */
934 uid_t myuid
= geteuid();
937 #if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H)
938 /*setenv("MALLOC_TRACE","pacman.mtrace", 0);*/
942 /* Set signal handlers */
943 /* Set up the structure to specify the new action. */
944 new_action
.sa_handler
= handler
;
945 sigemptyset(&new_action
.sa_mask
);
946 new_action
.sa_flags
= 0;
948 sigaction(SIGINT
, NULL
, &old_action
);
949 if(old_action
.sa_handler
!= SIG_IGN
) {
950 sigaction(SIGINT
, &new_action
, NULL
);
952 sigaction(SIGTERM
, NULL
, &old_action
);
953 if(old_action
.sa_handler
!= SIG_IGN
) {
954 sigaction(SIGTERM
, &new_action
, NULL
);
956 sigaction(SIGSEGV
, NULL
, &old_action
);
957 if(old_action
.sa_handler
!= SIG_IGN
) {
958 sigaction(SIGSEGV
, &new_action
, NULL
);
962 #if defined(ENABLE_NLS)
966 /* set user agent for downloading */
969 /* init config data */
970 config
= config_new();
972 /* disable progressbar if the output is redirected */
974 config
->noprogressbar
= 1;
977 /* initialize library */
978 if(alpm_initialize() == -1) {
979 pm_printf(PM_LOG_ERROR
, _("failed to initialize alpm library (%s)\n"),
980 alpm_strerrorlast());
981 cleanup(EXIT_FAILURE
);
984 /* Setup logging as soon as possible, to print out maximum debugging info */
985 alpm_option_set_logcb(cb_log
);
986 alpm_option_set_dlcb(cb_dl_progress
);
987 /* define paths to reasonable defaults */
988 alpm_option_set_root(ROOTDIR
);
989 alpm_option_set_dbpath(DBPATH
);
990 alpm_option_set_logfile(LOGFILE
);
992 /* Priority of options:
995 * 3. compiled-in defaults
996 * However, we have to parse the command line first because a config file
997 * location can be specified here, so we need to make sure we prefer these
998 * options over the config file coming second.
1001 /* parse the command line */
1002 ret
= parseargs(argc
, argv
);
1007 /* parse the config file */
1008 ret
= parseconfig(config
->configfile
);
1013 /* set TotalDownload callback if option enabled */
1014 if(config
->totaldownload
) {
1015 alpm_option_set_totaldlcb(cb_dl_total
);
1018 #if defined(HAVE_GETEUID) && !defined(CYGWIN)
1019 /* check if we have sufficient permission for the requested operation */
1020 if(myuid
> 0 && needs_root()) {
1021 pm_printf(PM_LOG_ERROR
, _("you cannot perform this operation unless you are root.\n"));
1022 cleanup(EXIT_FAILURE
);
1026 if(config
->verbose
> 0) {
1028 printf("Root : %s\n", alpm_option_get_root());
1029 printf("Conf File : %s\n", config
->configfile
);
1030 printf("DB Path : %s\n", alpm_option_get_dbpath());
1031 printf("Cache Dirs: ");
1032 for(i
= alpm_option_get_cachedirs(); i
; i
= alpm_list_next(i
)) {
1033 printf("%s ", (char*)alpm_list_getdata(i
));
1036 printf("Lock File : %s\n", alpm_option_get_lockfile());
1037 printf("Log File : %s\n", alpm_option_get_logfile());
1038 list_display("Targets :", pm_targets
);
1041 /* Opening local database */
1042 db_local
= alpm_db_register_local();
1043 if(db_local
== NULL
) {
1044 pm_printf(PM_LOG_ERROR
, _("could not register 'local' database (%s)\n"),
1045 alpm_strerrorlast());
1046 cleanup(EXIT_FAILURE
);
1049 /* start the requested operation */
1050 switch(config
->op
) {
1052 ret
= pacman_remove(pm_targets
);
1055 ret
= pacman_upgrade(pm_targets
);
1058 ret
= pacman_query(pm_targets
);
1061 ret
= pacman_sync(pm_targets
);
1064 ret
= pacman_deptest(pm_targets
);
1067 pm_printf(PM_LOG_ERROR
, _("no operation specified (use -h for help)\n"));
1073 return(EXIT_SUCCESS
);
1076 /* vim: set ts=2 sw=2 noet: */