pacman.c: Remove redundant strdup() in parsearg_global()
[pacman-ng.git] / src / pacman / pacman.c
blobd285a055c0f0ed9f0ef14c0fdda532fc97fbabb1
1 /*
2 * pacman.c
4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 /* special handling of package version for GIT */
24 #if defined(GIT_VERSION)
25 #undef PACKAGE_VERSION
26 #define PACKAGE_VERSION GIT_VERSION
27 #endif
29 #include <ctype.h> /* isspace */
30 #include <stdlib.h> /* atoi */
31 #include <stdio.h>
32 #include <ctype.h> /* isspace */
33 #include <limits.h>
34 #include <getopt.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/utsname.h> /* uname */
40 #include <locale.h> /* setlocale */
41 #include <errno.h>
42 #if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H)
43 #include <mcheck.h> /* debug tracing (mtrace) */
44 #endif
46 /* alpm */
47 #include <alpm.h>
48 #include <alpm_list.h>
50 /* pacman */
51 #include "pacman.h"
52 #include "util.h"
53 #include "conf.h"
55 /* list of targets specified on command line */
56 static alpm_list_t *pm_targets;
58 /* Used to sort the options in --help */
59 static int options_cmp(const void *p1, const void *p2)
61 const char *s1 = p1;
62 const char *s2 = p2;
64 if(s1 == s2) return 0;
65 if(!s1) return -1;
66 if(!s2) return 1;
67 /* First skip all spaces in both strings */
68 while(isspace((unsigned char)*s1)) {
69 s1++;
71 while(isspace((unsigned char)*s2)) {
72 s2++;
74 /* If we compare a long option (--abcd) and a short one (-a),
75 * the short one always wins */
76 if(*s1 == '-' && *s2 == '-') {
77 s1++;
78 s2++;
79 if(*s1 == '-' && *s2 == '-') {
80 /* two long -> strcmp */
81 s1++;
82 s2++;
83 } else if(*s2 == '-') {
84 /* s1 short, s2 long */
85 return -1;
86 } else if(*s1 == '-') {
87 /* s1 long, s2 short */
88 return 1;
90 /* two short -> strcmp */
93 return strcmp(s1, s2);
96 /** Display usage/syntax for the specified operation.
97 * @param op the operation code requested
98 * @param myname basename(argv[0])
100 static void usage(int op, const char * const myname)
102 #define addlist(s) (list = alpm_list_add(list, s))
103 alpm_list_t *list = NULL, *i;
104 /* prefetch some strings for usage below, which moves a lot of calls
105 * out of gettext. */
106 char const * const str_opt = _("options");
107 char const * const str_file = _("file(s)");
108 char const * const str_pkg = _("package(s)");
109 char const * const str_usg = _("usage");
110 char const * const str_opr = _("operation");
112 /* please limit your strings to 80 characters in width */
113 if(op == PM_OP_MAIN) {
114 printf("%s: %s <%s> [...]\n", str_usg, myname, str_opr);
115 printf(_("operations:\n"));
116 printf(" %s {-h --help}\n", myname);
117 printf(" %s {-V --version}\n", myname);
118 printf(" %s {-D --database} <%s> <%s>\n", myname, str_opt, str_pkg);
119 printf(" %s {-Q --query} [%s] [%s]\n", myname, str_opt, str_pkg);
120 printf(" %s {-R --remove} [%s] <%s>\n", myname, str_opt, str_pkg);
121 printf(" %s {-S --sync} [%s] [%s]\n", myname, str_opt, str_pkg);
122 printf(" %s {-T --deptest} [%s] [%s]\n", myname, str_opt, str_pkg);
123 printf(" %s {-U --upgrade} [%s] <%s>\n", myname, str_opt, str_file);
124 printf(_("\nuse '%s {-h --help}' with an operation for available options\n"),
125 myname);
126 } else {
127 if(op == PM_OP_REMOVE) {
128 printf("%s: %s {-R --remove} [%s] <%s>\n", str_usg, myname, str_opt, str_pkg);
129 printf("%s:\n", str_opt);
130 addlist(_(" -c, --cascade remove packages and all packages that depend on them\n"));
131 addlist(_(" -n, --nosave remove configuration files\n"));
132 addlist(_(" -s, --recursive remove unnecessary dependencies\n"
133 " (-ss includes explicitly installed dependencies)\n"));
134 addlist(_(" -u, --unneeded remove unneeded packages\n"));
135 } else if(op == PM_OP_UPGRADE) {
136 printf("%s: %s {-U --upgrade} [%s] <%s>\n", str_usg, myname, str_opt, str_file);
137 addlist(_(" --needed do not reinstall up to date packages\n"));
138 addlist(_(" --recursive reinstall all dependencies of target packages\n"));
139 printf("%s:\n", str_opt);
140 } else if(op == PM_OP_QUERY) {
141 printf("%s: %s {-Q --query} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);
142 printf("%s:\n", str_opt);
143 addlist(_(" -c, --changelog view the changelog of a package\n"));
144 addlist(_(" -d, --deps list packages installed as dependencies [filter]\n"));
145 addlist(_(" -e, --explicit list packages explicitly installed [filter]\n"));
146 addlist(_(" -g, --groups view all members of a package group\n"));
147 addlist(_(" -i, --info view package information (-ii for backup files)\n"));
148 addlist(_(" -k, --check check that the files owned by the package(s) are present\n"));
149 addlist(_(" -l, --list list the contents of the queried package\n"));
150 addlist(_(" -m, --foreign list installed packages not found in sync db(s) [filter]\n"));
151 addlist(_(" -o, --owns <file> query the package that owns <file>\n"));
152 addlist(_(" -p, --file <package> query a package file instead of the database\n"));
153 addlist(_(" -q, --quiet show less information for query and search\n"));
154 addlist(_(" -s, --search <regex> search locally-installed packages for matching strings\n"));
155 addlist(_(" -t, --unrequired list packages not required by any package [filter]\n"));
156 addlist(_(" -u, --upgrades list outdated packages [filter]\n"));
157 } else if(op == PM_OP_SYNC) {
158 printf("%s: %s {-S --sync} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);
159 printf("%s:\n", str_opt);
160 addlist(_(" -c, --clean remove old packages from cache directory (-cc for all)\n"));
161 addlist(_(" -g, --groups view all members of a package group\n"));
162 addlist(_(" -i, --info view package information\n"));
163 addlist(_(" -l, --list <repo> view a list of packages in a repo\n"));
164 addlist(_(" -q, --quiet show less information for query and search\n"));
165 addlist(_(" -s, --search <regex> search remote repositories for matching strings\n"));
166 addlist(_(" -u, --sysupgrade upgrade installed packages (-uu allows downgrade)\n"));
167 addlist(_(" -w, --downloadonly download packages but do not install/upgrade anything\n"));
168 addlist(_(" -y, --refresh download fresh package databases from the server\n"));
169 addlist(_(" --needed do not reinstall up to date packages\n"));
170 addlist(_(" --recursive reinstall all dependencies of target packages\n"));
171 } else if(op == PM_OP_DATABASE) {
172 printf("%s: %s {-D --database} <%s> <%s>\n", str_usg, myname, str_opt, str_pkg);
173 printf("%s:\n", str_opt);
174 addlist(_(" --asdeps mark packages as non-explicitly installed\n"));
175 addlist(_(" --asexplicit mark packages as explicitly installed\n"));
176 } else if(op == PM_OP_DEPTEST) {
177 printf("%s: %s {-T --deptest} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);
178 printf("%s:\n", str_opt);
180 switch(op) {
181 case PM_OP_SYNC:
182 case PM_OP_UPGRADE:
183 addlist(_(" -f, --force force install, overwrite conflicting files\n"));
184 addlist(_(" --asdeps install packages as non-explicitly installed\n"));
185 addlist(_(" --asexplicit install packages as explicitly installed\n"));
186 addlist(_(" --ignore <pkg> ignore a package upgrade (can be used more than once)\n"));
187 addlist(_(" --ignoregroup <grp>\n"
188 " ignore a group upgrade (can be used more than once)\n"));
189 /* pass through */
190 case PM_OP_REMOVE:
191 addlist(_(" -d, --nodeps skip dependency version checks (-dd to skip all checks)\n"));
192 addlist(_(" --dbonly only modify database entries, not package files\n"));
193 addlist(_(" --noprogressbar do not show a progress bar when downloading files\n"));
194 addlist(_(" --noscriptlet do not execute the install scriptlet if one exists\n"));
195 addlist(_(" --print print the targets instead of performing the operation\n"));
196 addlist(_(" --print-format <string>\n"
197 " specify how the targets should be printed\n"));
198 break;
201 addlist(_(" -b, --dbpath <path> set an alternate database location\n"));
202 addlist(_(" -r, --root <path> set an alternate installation root\n"));
203 addlist(_(" -v, --verbose be verbose\n"));
204 addlist(_(" --arch <arch> set an alternate architecture\n"));
205 addlist(_(" --cachedir <dir> set an alternate package cache location\n"));
206 addlist(_(" --config <path> set an alternate configuration file\n"));
207 addlist(_(" --debug display debug messages\n"));
208 addlist(_(" --gpgdir <path> set an alternate home directory for GnuPG\n"));
209 addlist(_(" --logfile <path> set an alternate log file\n"));
210 addlist(_(" --noconfirm do not ask for any confirmation\n"));
212 list = alpm_list_msort(list, alpm_list_count(list), options_cmp);
213 for (i = list; i; i = alpm_list_next(i)) {
214 printf("%s", (char *)alpm_list_getdata(i));
216 alpm_list_free(list);
217 #undef addlist
220 /** Output pacman version and copyright.
222 static void version(void)
224 printf("\n");
225 printf(" .--. Pacman v%s - libalpm v%s\n", PACKAGE_VERSION, alpm_version());
226 printf("/ _.-' .-. .-. .-. Copyright (C) 2006-2011 Pacman Development Team\n");
227 printf("\\ '-. '-' '-' '-' Copyright (C) 2002-2006 Judd Vinet\n");
228 printf(" '--'\n");
229 printf(_(" This program may be freely redistributed under\n"
230 " the terms of the GNU General Public License.\n"));
231 printf("\n");
234 /** Sets up gettext localization. Safe to call multiple times.
236 /* Inspired by the monotone function localize_monotone. */
237 #if defined(ENABLE_NLS)
238 static void localize(void)
240 static int init = 0;
241 if(!init) {
242 setlocale(LC_ALL, "");
243 bindtextdomain(PACKAGE, LOCALEDIR);
244 textdomain(PACKAGE);
245 init = 1;
248 #endif
250 /** Set user agent environment variable.
252 static void setuseragent(void)
254 char agent[101];
255 struct utsname un;
257 uname(&un);
258 snprintf(agent, 100, "pacman/%s (%s %s) libalpm/%s",
259 PACKAGE_VERSION, un.sysname, un.machine, alpm_version());
260 setenv("HTTP_USER_AGENT", agent, 0);
263 /** Free the resources.
265 * @param ret the return value
267 static void cleanup(int ret) {
268 /* free alpm library resources */
269 if(config->handle && alpm_release(config->handle) == -1) {
270 pm_printf(ALPM_LOG_ERROR, "error releasing alpm library\n");
273 /* free memory */
274 FREELIST(pm_targets);
275 if(config) {
276 config_free(config);
277 config = NULL;
280 exit(ret);
283 /** Write function that correctly handles EINTR.
285 static ssize_t xwrite(int fd, const void *buf, size_t count)
287 ssize_t ret;
288 do {
289 ret = write(fd, buf, count);
290 } while(ret == -1 && errno == EINTR);
291 return ret;
294 /** Catches thrown signals. Performs necessary cleanup to ensure database is
295 * in a consistant state.
296 * @param signum the thrown signal
298 static void handler(int signum)
300 int out = fileno(stdout);
301 int err = fileno(stderr);
302 if(signum == SIGSEGV) {
303 const char *msg1 = "error: segmentation fault\n";
304 const char *msg2 = "Internal pacman error: Segmentation fault.\n"
305 "Please submit a full bug report with --debug if appropriate.\n";
306 /* write a error message to out, the rest to err */
307 xwrite(out, msg1, strlen(msg1));
308 xwrite(err, msg2, strlen(msg2));
309 exit(signum);
310 } else if(signum == SIGINT) {
311 const char *msg = "\nInterrupt signal received\n";
312 xwrite(err, msg, strlen(msg));
313 if(alpm_trans_interrupt(config->handle) == 0) {
314 /* a transaction is being interrupted, don't exit pacman yet. */
315 return;
317 /* no commiting transaction, we can release it now and then exit pacman */
318 alpm_trans_release(config->handle);
319 /* output a newline to be sure we clear any line we may be on */
320 xwrite(out, "\n", 1);
322 cleanup(128 + signum);
325 #define check_optarg() if(!optarg) { return 1; }
327 static int parsearg_util_addlist(alpm_list_t **list)
329 alpm_list_t *split, *item;
331 check_optarg();
332 split = strsplit(optarg, ',');
333 for(item = split; item; item = alpm_list_next(item)) {
334 *list = alpm_list_add(*list, item->data);
336 alpm_list_free(split);
337 return 0;
340 /** Helper function for parsing operation from command-line arguments.
341 * @param opt Keycode returned by getopt_long
342 * @param dryrun If nonzero, application state is NOT changed
343 * @return 0 if opt was handled, 1 if it was not handled
345 static int parsearg_op(int opt, int dryrun)
347 switch(opt) {
348 /* operations */
349 case 'D':
350 if(dryrun) break;
351 config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DATABASE); break;
352 case 'Q':
353 if(dryrun) break;
354 config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break;
355 case 'R':
356 if(dryrun) break;
357 config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break;
358 case 'S':
359 if(dryrun) break;
360 config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break;
361 case 'T':
362 if(dryrun) break;
363 config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); break;
364 case 'U':
365 if(dryrun) break;
366 config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); break;
367 case 'V':
368 if(dryrun) break;
369 config->version = 1; break;
370 case 'h':
371 if(dryrun) break;
372 config->help = 1; break;
373 default:
374 return 1;
376 return 0;
379 /** Helper functions for parsing command-line arguments.
380 * @param opt Keycode returned by getopt_long
381 * @return 0 on success, 1 on failure
383 static int parsearg_global(int opt)
385 switch(opt) {
386 case OP_ARCH:
387 check_optarg();
388 config_set_arch(optarg);
389 break;
390 case OP_ASK:
391 check_optarg();
392 config->noask = 1;
393 config->ask = (unsigned int)atoi(optarg);
394 break;
395 case OP_CACHEDIR:
396 check_optarg();
397 config->cachedirs = alpm_list_add(config->cachedirs, strdup(optarg));
398 break;
399 case OP_CONFIG:
400 check_optarg();
401 if(config->configfile) {
402 free(config->configfile);
404 config->configfile = strndup(optarg, PATH_MAX);
405 break;
406 case OP_DEBUG:
407 /* debug levels are made more 'human readable' than using a raw logmask
408 * here, error and warning are set in config_new, though perhaps a
409 * --quiet option will remove these later */
410 if(optarg) {
411 unsigned short debug = (unsigned short)atoi(optarg);
412 switch(debug) {
413 case 2:
414 config->logmask |= ALPM_LOG_FUNCTION; /* fall through */
415 case 1:
416 config->logmask |= ALPM_LOG_DEBUG;
417 break;
418 default:
419 pm_printf(ALPM_LOG_ERROR, _("'%s' is not a valid debug level\n"),
420 optarg);
421 return 1;
423 } else {
424 config->logmask |= ALPM_LOG_DEBUG;
426 /* progress bars get wonky with debug on, shut them off */
427 config->noprogressbar = 1;
428 break;
429 case OP_GPGDIR:
430 config->gpgdir = strdup(optarg);
431 break;
432 case OP_LOGFILE:
433 check_optarg();
434 config->logfile = strndup(optarg, PATH_MAX);
435 break;
436 case OP_NOCONFIRM: config->noconfirm = 1; break;
437 case 'b':
438 check_optarg();
439 config->dbpath = strdup(optarg);
440 break;
441 case 'r': check_optarg(); config->rootdir = strdup(optarg); break;
442 case 'v': (config->verbose)++; break;
443 default: return 1;
445 return 0;
448 static int parsearg_database(int opt)
450 switch(opt) {
451 case OP_ASDEPS: config->flags |= ALPM_TRANS_FLAG_ALLDEPS; break;
452 case OP_ASEXPLICIT: config->flags |= ALPM_TRANS_FLAG_ALLEXPLICIT; break;
453 default: return 1;
455 return 0;
458 static int parsearg_query(int opt)
460 switch(opt) {
461 case 'c': config->op_q_changelog = 1; break;
462 case 'd': config->op_q_deps = 1; break;
463 case 'e': config->op_q_explicit = 1; break;
464 case 'g': (config->group)++; break;
465 case 'i': (config->op_q_info)++; break;
466 case 'k': config->op_q_check = 1; break;
467 case 'l': config->op_q_list = 1; break;
468 case 'm': config->op_q_foreign = 1; break;
469 case 'o': config->op_q_owns = 1; break;
470 case 'p': config->op_q_isfile = 1; break;
471 case 'q': config->quiet = 1; break;
472 case 's': config->op_q_search = 1; break;
473 case 't': config->op_q_unrequired = 1; break;
474 case 'u': config->op_q_upgrade = 1; break;
475 default: return 1;
477 return 0;
480 /* options common to -S -R -U */
481 static int parsearg_trans(int opt)
483 switch(opt) {
484 case 'd':
485 if(config->flags & ALPM_TRANS_FLAG_NODEPVERSION) {
486 config->flags |= ALPM_TRANS_FLAG_NODEPS;
487 } else {
488 config->flags |= ALPM_TRANS_FLAG_NODEPVERSION;
490 break;
491 case OP_DBONLY: config->flags |= ALPM_TRANS_FLAG_DBONLY; break;
492 case OP_NOPROGRESSBAR: config->noprogressbar = 1; break;
493 case OP_NOSCRIPTLET: config->flags |= ALPM_TRANS_FLAG_NOSCRIPTLET; break;
494 case 'p': config->print = 1; break;
495 case OP_PRINTFORMAT:
496 check_optarg();
497 config->print_format = strdup(optarg);
498 break;
499 default: return 1;
501 return 0;
504 static int parsearg_remove(int opt)
506 if(parsearg_trans(opt) == 0)
507 return 0;
508 switch(opt) {
509 case 'c': config->flags |= ALPM_TRANS_FLAG_CASCADE; break;
510 case 'n': config->flags |= ALPM_TRANS_FLAG_NOSAVE; break;
511 case 's':
512 case OP_RECURSIVE:
513 /* 's' is the legacy flag here, but since recursive is used in -S without
514 * a shortopt, we need to do funky tricks */
515 if(config->flags & ALPM_TRANS_FLAG_RECURSE) {
516 config->flags |= ALPM_TRANS_FLAG_RECURSEALL;
517 } else {
518 config->flags |= ALPM_TRANS_FLAG_RECURSE;
520 break;
521 case 'u': config->flags |= ALPM_TRANS_FLAG_UNNEEDED; break;
522 default: return 1;
524 return 0;
527 /* options common to -S -U */
528 static int parsearg_upgrade(int opt)
530 if(parsearg_trans(opt) == 0)
531 return 0;
532 switch(opt) {
533 case 'f': config->flags |= ALPM_TRANS_FLAG_FORCE; break;
534 case OP_ASDEPS: config->flags |= ALPM_TRANS_FLAG_ALLDEPS; break;
535 case OP_ASEXPLICIT: config->flags |= ALPM_TRANS_FLAG_ALLEXPLICIT; break;
536 case OP_NEEDED: config->flags |= ALPM_TRANS_FLAG_NEEDED; break;
537 case OP_RECURSIVE: config->flags |= ALPM_TRANS_FLAG_RECURSE; break;
538 case OP_IGNORE:
539 parsearg_util_addlist(&(config->ignorepkg));
540 break;
541 case OP_IGNOREGROUP:
542 parsearg_util_addlist(&(config->ignoregrp));
543 break;
544 default: return 1;
546 return 0;
549 static int parsearg_sync(int opt)
551 if(parsearg_upgrade(opt) == 0)
552 return 0;
553 switch(opt) {
554 case 'c': (config->op_s_clean)++; break;
555 case 'g': (config->group)++; break;
556 case 'i': (config->op_s_info)++; break;
557 case 'l': config->op_q_list = 1; break;
558 case 'q': config->quiet = 1; break;
559 case 's': config->op_s_search = 1; break;
560 case 'u': (config->op_s_upgrade)++; break;
561 case 'w':
562 config->op_s_downloadonly = 1;
563 config->flags |= ALPM_TRANS_FLAG_DOWNLOADONLY;
564 config->flags |= ALPM_TRANS_FLAG_NOCONFLICTS;
565 break;
566 case 'y': (config->op_s_sync)++; break;
567 default: return 1;
569 return 0;
572 /** Parse command-line arguments for each operation.
573 * @param argc argc
574 * @param argv argv
575 * @return 0 on success, 1 on error
577 static int parseargs(int argc, char *argv[])
579 int opt;
580 int option_index = 0;
581 int result;
582 const char *optstring = "DQRSTUVb:cdefghiklmnopqr:stuvwy";
583 static const struct option opts[] =
585 {"database", no_argument, 0, 'D'},
586 {"query", no_argument, 0, 'Q'},
587 {"remove", no_argument, 0, 'R'},
588 {"sync", no_argument, 0, 'S'},
589 {"deptest", no_argument, 0, 'T'}, /* used by makepkg */
590 {"upgrade", no_argument, 0, 'U'},
591 {"version", no_argument, 0, 'V'},
592 {"dbpath", required_argument, 0, 'b'},
593 {"cascade", no_argument, 0, 'c'},
594 {"changelog", no_argument, 0, 'c'},
595 {"clean", no_argument, 0, 'c'},
596 {"nodeps", no_argument, 0, 'd'},
597 {"deps", no_argument, 0, 'd'},
598 {"explicit", no_argument, 0, 'e'},
599 {"force", no_argument, 0, 'f'},
600 {"groups", no_argument, 0, 'g'},
601 {"help", no_argument, 0, 'h'},
602 {"info", no_argument, 0, 'i'},
603 {"check", no_argument, 0, 'k'},
604 {"list", no_argument, 0, 'l'},
605 {"foreign", no_argument, 0, 'm'},
606 {"nosave", no_argument, 0, 'n'},
607 {"owns", no_argument, 0, 'o'},
608 {"file", no_argument, 0, 'p'},
609 {"print", no_argument, 0, 'p'},
610 {"quiet", no_argument, 0, 'q'},
611 {"root", required_argument, 0, 'r'},
612 {"search", no_argument, 0, 's'},
613 {"unrequired", no_argument, 0, 't'},
614 {"upgrades", no_argument, 0, 'u'},
615 {"sysupgrade", no_argument, 0, 'u'},
616 {"unneeded", no_argument, 0, 'u'},
617 {"verbose", no_argument, 0, 'v'},
618 {"downloadonly", no_argument, 0, 'w'},
619 {"refresh", no_argument, 0, 'y'},
621 {"noconfirm", no_argument, 0, OP_NOCONFIRM},
622 {"config", required_argument, 0, OP_CONFIG},
623 {"ignore", required_argument, 0, OP_IGNORE},
624 {"debug", optional_argument, 0, OP_DEBUG},
625 {"noprogressbar", no_argument, 0, OP_NOPROGRESSBAR},
626 {"noscriptlet", no_argument, 0, OP_NOSCRIPTLET},
627 {"ask", required_argument, 0, OP_ASK},
628 {"cachedir", required_argument, 0, OP_CACHEDIR},
629 {"asdeps", no_argument, 0, OP_ASDEPS},
630 {"logfile", required_argument, 0, OP_LOGFILE},
631 {"ignoregroup", required_argument, 0, OP_IGNOREGROUP},
632 {"needed", no_argument, 0, OP_NEEDED},
633 {"asexplicit", no_argument, 0, OP_ASEXPLICIT},
634 {"arch", required_argument, 0, OP_ARCH},
635 {"print-format", required_argument, 0, OP_PRINTFORMAT},
636 {"gpgdir", required_argument, 0, OP_GPGDIR},
637 {"recursive", no_argument, 0, OP_RECURSIVE},
638 {"dbonly", no_argument, 0, OP_DBONLY},
639 {0, 0, 0, 0}
642 /* parse operation */
643 while((opt = getopt_long(argc, argv, optstring, opts, &option_index))) {
644 if(opt < 0) {
645 break;
646 } else if(opt == 0) {
647 continue;
648 } else if(opt == '?') {
649 /* unknown option, getopt printed an error */
650 return 1;
652 parsearg_op(opt, 0);
655 if(config->op == 0) {
656 pm_printf(ALPM_LOG_ERROR, _("only one operation may be used at a time\n"));
657 return 1;
659 if(config->help) {
660 usage(config->op, mbasename(argv[0]));
661 return 2;
663 if(config->version) {
664 version();
665 return 2;
668 /* parse all other options */
669 optind = 1;
670 while((opt = getopt_long(argc, argv, optstring, opts, &option_index))) {
671 if(opt < 0) {
672 break;
673 } else if(opt == 0) {
674 continue;
675 } else if(opt == '?') {
676 /* this should have failed during first pass already */
677 return 1;
678 } else if(parsearg_op(opt, 1) == 0) {
679 /* opt is an operation */
680 continue;
683 switch(config->op) {
684 case PM_OP_DATABASE:
685 result = parsearg_database(opt);
686 break;
687 case PM_OP_QUERY:
688 result = parsearg_query(opt);
689 break;
690 case PM_OP_REMOVE:
691 result = parsearg_remove(opt);
692 break;
693 case PM_OP_SYNC:
694 result = parsearg_sync(opt);
695 break;
696 case PM_OP_UPGRADE:
697 result = parsearg_upgrade(opt);
698 break;
699 case PM_OP_DEPTEST:
700 default:
701 result = 1;
702 break;
704 if(result == 0) {
705 continue;
708 /* fall back to global options */
709 result = parsearg_global(opt);
710 if(result != 0) {
711 /* global option parsing failed, abort */
712 pm_printf(ALPM_LOG_ERROR, _("invalid option\n"));
713 return result;
717 while(optind < argc) {
718 /* add the target to our target array */
719 pm_targets = alpm_list_add(pm_targets, strdup(argv[optind]));
720 optind++;
723 return 0;
726 /** print commandline to logfile
728 static void cl_to_log(int argc, char* argv[])
730 size_t size = 0;
731 int i;
732 for(i = 0; i < argc; i++) {
733 size += strlen(argv[i]) + 1;
735 if(!size) {
736 return;
738 char *cl_text = malloc(size);
739 if(!cl_text) {
740 return;
742 char *p = cl_text;
743 for(i = 0; i < argc - 1; i++) {
744 strcpy(p, argv[i]);
745 p += strlen(argv[i]);
746 *p++ = ' ';
748 strcpy(p, argv[i]);
749 alpm_logaction(config->handle, "Running '%s'\n", cl_text);
750 free(cl_text);
753 /** Main function.
754 * @param argc argc
755 * @param argv argv
756 * @return A return code indicating success, failure, etc.
758 int main(int argc, char *argv[])
760 int ret = 0;
761 struct sigaction new_action, old_action;
762 #if defined(HAVE_GETEUID) && !defined(CYGWIN)
763 /* geteuid undefined in CYGWIN */
764 uid_t myuid = geteuid();
765 #endif
767 #if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H)
768 /*setenv("MALLOC_TRACE","pacman.mtrace", 0);*/
769 mtrace();
770 #endif
772 /* Set signal handlers */
773 /* Set up the structure to specify the new action. */
774 new_action.sa_handler = handler;
775 sigemptyset(&new_action.sa_mask);
776 new_action.sa_flags = 0;
778 sigaction(SIGINT, NULL, &old_action);
779 if(old_action.sa_handler != SIG_IGN) {
780 sigaction(SIGINT, &new_action, NULL);
782 sigaction(SIGTERM, NULL, &old_action);
783 if(old_action.sa_handler != SIG_IGN) {
784 sigaction(SIGTERM, &new_action, NULL);
786 sigaction(SIGSEGV, NULL, &old_action);
787 if(old_action.sa_handler != SIG_IGN) {
788 sigaction(SIGSEGV, &new_action, NULL);
791 /* i18n init */
792 #if defined(ENABLE_NLS)
793 localize();
794 #endif
796 /* set user agent for downloading */
797 setuseragent();
799 /* init config data */
800 config = config_new();
802 /* disable progressbar if the output is redirected */
803 if(!isatty(1)) {
804 config->noprogressbar = 1;
807 /* Priority of options:
808 * 1. command line
809 * 2. config file
810 * 3. compiled-in defaults
811 * However, we have to parse the command line first because a config file
812 * location can be specified here, so we need to make sure we prefer these
813 * options over the config file coming second.
816 /* parse the command line */
817 ret = parseargs(argc, argv);
818 if(ret != 0) {
819 cleanup(ret);
822 /* we support reading targets from stdin if a cmdline parameter is '-' */
823 if(!isatty(fileno(stdin)) && alpm_list_find_str(pm_targets, "-")) {
824 char line[PATH_MAX];
825 int i = 0;
827 /* remove the '-' from the list */
828 pm_targets = alpm_list_remove_str(pm_targets, "-", NULL);
830 while(i < PATH_MAX && (line[i] = (char)fgetc(stdin)) != EOF) {
831 if(isspace((unsigned char)line[i])) {
832 /* avoid adding zero length arg when multiple spaces separate args */
833 if(i > 0) {
834 line[i] = '\0';
835 pm_targets = alpm_list_add(pm_targets, strdup(line));
836 i = 0;
838 } else {
839 i++;
842 /* check for buffer overflow */
843 if(i >= PATH_MAX) {
844 pm_printf(ALPM_LOG_ERROR, _("buffer overflow detected in arg parsing\n"));
845 cleanup(EXIT_FAILURE);
848 /* end of stream -- check for data still in line buffer */
849 if(i > 0) {
850 line[i] = '\0';
851 pm_targets = alpm_list_add(pm_targets, strdup(line));
853 if(!freopen(ctermid(NULL), "r", stdin)) {
854 pm_printf(ALPM_LOG_ERROR, _("failed to reopen stdin for reading: (%s)\n"),
855 strerror(errno));
859 /* parse the config file */
860 ret = parseconfig(config->configfile);
861 if(ret != 0) {
862 cleanup(ret);
865 /* noask is meant to be non-interactive */
866 if(config->noask) {
867 config->noconfirm = 1;
870 /* set up the print operations */
871 if(config->print && !config->op_s_clean) {
872 config->noconfirm = 1;
873 config->flags |= ALPM_TRANS_FLAG_NOCONFLICTS;
874 config->flags |= ALPM_TRANS_FLAG_NOLOCK;
875 /* Display only errors */
876 config->logmask &= ~ALPM_LOG_WARNING;
879 #if defined(HAVE_GETEUID) && !defined(CYGWIN)
880 /* check if we have sufficient permission for the requested operation */
881 if(myuid > 0 && needs_root()) {
882 pm_printf(ALPM_LOG_ERROR, _("you cannot perform this operation unless you are root.\n"));
883 cleanup(EXIT_FAILURE);
885 #endif
887 if(config->verbose > 0) {
888 alpm_list_t *i;
889 printf("Root : %s\n", alpm_option_get_root(config->handle));
890 printf("Conf File : %s\n", config->configfile);
891 printf("DB Path : %s\n", alpm_option_get_dbpath(config->handle));
892 printf("Cache Dirs: ");
893 for(i = alpm_option_get_cachedirs(config->handle); i; i = alpm_list_next(i)) {
894 printf("%s ", (char *)alpm_list_getdata(i));
896 printf("\n");
897 printf("Lock File : %s\n", alpm_option_get_lockfile(config->handle));
898 printf("Log File : %s\n", alpm_option_get_logfile(config->handle));
899 printf("GPG Dir : %s\n", alpm_option_get_gpgdir(config->handle));
900 list_display("Targets :", pm_targets);
903 /* Log commandline */
904 if(needs_root()) {
905 cl_to_log(argc, argv);
908 /* start the requested operation */
909 switch(config->op) {
910 case PM_OP_DATABASE:
911 ret = pacman_database(pm_targets);
912 break;
913 case PM_OP_REMOVE:
914 ret = pacman_remove(pm_targets);
915 break;
916 case PM_OP_UPGRADE:
917 ret = pacman_upgrade(pm_targets);
918 break;
919 case PM_OP_QUERY:
920 ret = pacman_query(pm_targets);
921 break;
922 case PM_OP_SYNC:
923 ret = pacman_sync(pm_targets);
924 break;
925 case PM_OP_DEPTEST:
926 ret = pacman_deptest(pm_targets);
927 break;
928 default:
929 pm_printf(ALPM_LOG_ERROR, _("no operation specified (use -h for help)\n"));
930 ret = EXIT_FAILURE;
933 cleanup(ret);
934 /* not reached */
935 return EXIT_SUCCESS;
938 /* vim: set ts=2 sw=2 noet: */