LCOV - code coverage report
Current view: top level - src - info.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 79 282 28.0 %
Date: 2015-08-15 Functions: 1 2 50.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2014 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
       5             :  * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
       6             :  * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
       7             :  * All rights reserved.
       8             :  * 
       9             :  * Redistribution and use in source and binary forms, with or without
      10             :  * modification, are permitted provided that the following conditions
      11             :  * are met:
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer
      14             :  *    in this position and unchanged.
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  * 
      19             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      20             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      21             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      22             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      23             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      24             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      25             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      26             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      28             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29             :  */
      30             : 
      31             : #ifdef HAVE_CONFIG_H
      32             : #include "pkg_config.h"
      33             : #endif
      34             : 
      35             : #ifdef HAVE_CAPSICUM
      36             : #include <sys/capability.h>
      37             : #endif
      38             : 
      39             : #include <err.h>
      40             : #include <errno.h>
      41             : #include <fcntl.h>
      42             : #include <getopt.h>
      43             : #include <pkg.h>
      44             : #include <stdbool.h>
      45             : #include <stdio.h>
      46             : #include <string.h>
      47             : #include <sysexits.h>
      48             : #include <unistd.h>
      49             : 
      50             : #include "pkgcli.h"
      51             : 
      52             : enum sign {
      53             :         LT,
      54             :         LE,
      55             :         GT,
      56             :         GE,
      57             :         EQ
      58             : };
      59             : 
      60             : void
      61           0 : usage_info(void)
      62             : {
      63           0 :         fprintf(stderr, "Usage: pkg info <pkg-name>\n");
      64           0 :         fprintf(stderr, "       pkg info -a\n");
      65           0 :         fprintf(stderr, "       pkg info [-AbBDdefIklOqRrs] [-Cgix] <pkg-name>\n");
      66           0 :         fprintf(stderr, "       pkg info [-AbBDdfIlqRrs] -F <pkg-file>\n\n");
      67           0 :         fprintf(stderr, "For more information see 'pkg help info'.\n");
      68           0 : }
      69             : 
      70             : /*
      71             :  * list of options
      72             :  * -S <type> : show scripts, type can be pre-install etc: TODO
      73             :  */
      74             : 
      75             : int
      76           7 : exec_info(int argc, char **argv)
      77             : {
      78           7 :         struct pkgdb *db = NULL;
      79           7 :         struct pkgdb_it *it = NULL;
      80             :         int query_flags;
      81           7 :         struct pkg *pkg = NULL;
      82           7 :         uint64_t opt = INFO_TAG_NAMEVER;
      83           7 :         match_t match = MATCH_GLOB;
      84             :         char *pkgname;
      85           7 :         char *pkgversion = NULL, *pkgversion2 = NULL;
      86           7 :         const char *file = NULL;
      87             :         int ch, fd;
      88           7 :         int ret = EPKG_OK;
      89           7 :         int retcode = 0;
      90           7 :         bool gotone = false;
      91             :         int i, j;
      92           7 :         int sign = 0;
      93           7 :         int sign2 = 0;
      94           7 :         int open_flags = 0;
      95           7 :         bool pkg_exists = false;
      96           7 :         bool origin_search = false;
      97           7 :         bool e_flag = false;
      98           7 :         struct pkg_manifest_key *keys = NULL;
      99             : #ifdef HAVE_CAPSICUM
     100             :         cap_rights_t rights;
     101             : #endif
     102             : 
     103           7 :         struct option longopts[] = {
     104             :                 { "all",              no_argument,            NULL,   'a' },
     105             :                 { "annotations",      no_argument,            NULL,   'A' },
     106             :                 { "provided-shlibs",  no_argument,            NULL,   'b' },
     107             :                 { "required-shlibs",  no_argument,            NULL,   'B' },
     108             :                 { "case-sensitive",   no_argument,            NULL,   'C' },
     109             :                 { "dependencies",     no_argument,            NULL,   'd' },
     110             :                 { "pkg-message",      no_argument,            NULL,   'D' },
     111             :                 { "exists",           no_argument,            NULL,   'e' },
     112             :                 { "show-name-only",   no_argument,            NULL,   'E' },
     113             :                 { "full",             no_argument,            NULL,   'f' },
     114             :                 { "file",             required_argument,      NULL,   'F' },
     115             :                 { "glob",             no_argument,            NULL,   'g' },
     116             :                 { "case-insensitive", no_argument,            NULL,   'i' },
     117             :                 { "comment",          no_argument,            NULL,   'I' },
     118             :                 { "locked",           no_argument,            NULL,   'k' },
     119             :                 { "list-files",               no_argument,            NULL,   'l' },
     120             :                 { "origin",           no_argument,            NULL,   'o' },
     121             :                 { "by-origin",                no_argument,            NULL,   'O' },
     122             :                 { "prefix",           no_argument,            NULL,   'p' },
     123             :                 { "quiet",            no_argument,            NULL,   'q' },
     124             :                 { "required-by",      no_argument,            NULL,   'r' },
     125             :                 { "raw",              no_argument,            NULL,   'R' },
     126             :                 { "size",             no_argument,            NULL,   's' },
     127             :                 { "regex",            no_argument,            NULL,   'x' },
     128             :                 { "raw-format",               required_argument,      NULL,   1   },
     129             :                 { NULL,                 0,                      NULL,   0   },
     130             :         };
     131             : 
     132             :         /* TODO: exclusive opts ? */
     133          22 :         while ((ch = getopt_long(argc, argv, "+aAbBCdDeEfF:giIkloOpqrRsx", longopts, NULL)) != -1) {
     134           8 :                 switch (ch) {
     135             :                 case 'a':
     136           0 :                         match = MATCH_ALL;
     137           0 :                         break;
     138             :                 case 'A':
     139           5 :                         opt |= INFO_ANNOTATIONS;
     140           5 :                         break;
     141             :                 case 'b':
     142           0 :                         opt |= INFO_SHLIBS_PROVIDED;
     143           0 :                         break;
     144             :                 case 'B':
     145           0 :                         opt |= INFO_SHLIBS_REQUIRED;
     146           0 :                         break;
     147             :                 case 'C':
     148           0 :                         pkgdb_set_case_sensitivity(true);
     149           0 :                         break;
     150             :                 case 'd':
     151           0 :                         opt |= INFO_DEPS;
     152           0 :                         break;
     153             :                 case 'D':
     154           0 :                         opt |= INFO_MESSAGE;
     155           0 :                         break;
     156             :                 case 'e':
     157           0 :                         pkg_exists = true;;
     158           0 :                         retcode = 1;
     159           0 :                         break;
     160             :                 case 'E': /* ports compatibility */
     161           0 :                         e_flag = true;
     162           0 :                         break;
     163             :                 case 'f':
     164           0 :                         opt |= INFO_FULL;
     165           0 :                         break;
     166             :                 case 'F':
     167           0 :                         file = optarg;
     168           0 :                         break;
     169             :                 case 'g':
     170           0 :                         match = MATCH_GLOB;
     171           0 :                         break;
     172             :                 case 'i':
     173           0 :                         pkgdb_set_case_sensitivity(false);
     174           0 :                         break;
     175             :                 case 'I':
     176           0 :                         opt |= INFO_COMMENT;
     177           0 :                         break;
     178             :                 case 'k':
     179           0 :                         opt |= INFO_LOCKED;
     180           0 :                         break;
     181             :                 case 'l':
     182           0 :                         opt |= INFO_FILES;
     183           0 :                         break;
     184             :                 case 'o':
     185           1 :                         opt |= INFO_ORIGIN;
     186           1 :                         break;
     187             :                 case 'O':
     188           0 :                         origin_search = true;  /* only for ports compat */
     189           0 :                         break;
     190             :                 case 'p':
     191           0 :                         opt |= INFO_PREFIX;
     192           0 :                         break;
     193             :                 case 'q':
     194           2 :                         quiet = true;
     195           2 :                         break;
     196             :                 case 'r':
     197           0 :                         opt |= INFO_RDEPS;
     198           0 :                         break;
     199             :                 case 'R':
     200           0 :                         opt |= INFO_RAW;
     201           0 :                         break;
     202             :                 case 's':
     203           0 :                         opt |= INFO_FLATSIZE;
     204           0 :                         break;
     205             :                 case 'x':
     206           0 :                         match = MATCH_REGEX;
     207           0 :                         break;
     208             :                 case 1:
     209           0 :                         if (strcasecmp(optarg, "json") == 0)
     210           0 :                                 opt |= INFO_RAW_JSON;
     211           0 :                         else if (strcasecmp(optarg, "json-compact") == 0)
     212           0 :                                 opt |= INFO_RAW_JSON_COMPACT;
     213           0 :                         else if (strcasecmp(optarg, "yaml") == 0)
     214           0 :                                 opt |= INFO_RAW_YAML;
     215           0 :                         else if (strcasecmp(optarg, "ucl") == 0)
     216           0 :                                 opt |= INFO_RAW_UCL;
     217             :                         else
     218           0 :                                 errx(EX_USAGE, "Invalid format '%s' for the "
     219             :                                     "raw output, expecting json, json-compact "
     220             :                                     "or yaml", optarg);
     221           0 :                         break;
     222             :                 default:
     223           0 :                         usage_info();
     224           0 :                         return(EX_USAGE);
     225             :                 }
     226             :         }
     227             : 
     228           7 :         if (argc == 1 || (argc == 2 && quiet))
     229           2 :                 match = MATCH_ALL;
     230             : 
     231           7 :         argc -= optind;
     232           7 :         argv += optind;
     233             : 
     234           7 :         if (argc == 0 && file == NULL && match != MATCH_ALL) {
     235             :                 /* which -O bsd.*.mk always execpt clean output */
     236           0 :                 if (origin_search)
     237           0 :                         return (EX_OK);
     238           0 :                 usage_info();
     239           0 :                 return (EX_USAGE);
     240             :         }
     241             : 
     242             :         /* When no other data is requested, default is to print
     243             :          * 'name-ver comment' For -O, just print name-ver */
     244           8 :         if (!origin_search && (opt & INFO_ALL) == 0 && match == MATCH_ALL &&
     245           1 :             !quiet)
     246           0 :                 opt |= INFO_COMMENT;
     247             : 
     248             :         /* Special compatibility: handle -O and -q -O */
     249           7 :         if (origin_search) {
     250           0 :                 if (quiet) {
     251           0 :                         opt = INFO_TAG_NAMEVER;
     252           0 :                         quiet = false;
     253             :                 } else {
     254           0 :                         opt = INFO_TAG_NAMEVER|INFO_COMMENT;
     255             :                 }
     256             :         }
     257             : 
     258           7 :         if (match == MATCH_ALL && opt == INFO_TAG_NAMEVER)
     259           1 :                 quiet = false;
     260             : 
     261           7 :         if (file != NULL) {
     262           0 :                 if ((fd = open(file, O_RDONLY)) == -1) {
     263           0 :                         warn("Unable to open %s", file);
     264           0 :                         return (EX_IOERR);
     265             :                 }
     266             : 
     267             : #ifdef HAVE_CAPSICUM
     268           0 :                 cap_rights_init(&rights, CAP_READ, CAP_FSTAT);
     269           0 :                 if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS ) {
     270           0 :                         warn("cap_rights_limit() failed");
     271           0 :                         return (EX_SOFTWARE);
     272             :                 }
     273             : 
     274           0 :                 if (cap_enter() < 0 && errno != ENOSYS) {
     275           0 :                         warn("cap_enter() failed");
     276           0 :                         close(fd);
     277           0 :                         return (EX_SOFTWARE);
     278             :                 }
     279             : #endif
     280           0 :                 if (opt == INFO_TAG_NAMEVER)
     281           0 :                         opt |= INFO_FULL;
     282           0 :                 pkg_manifest_keys_new(&keys);
     283           0 :                 if (opt & INFO_RAW) {
     284           0 :                         if ((opt & (INFO_RAW_JSON|INFO_RAW_JSON_COMPACT)) == 0)
     285           0 :                                 opt |= INFO_RAW_YAML;
     286             :                 }
     287             : 
     288           0 :                 if ((opt & (INFO_RAW | INFO_FILES |
     289             :                                 INFO_DIRS)) == 0)
     290           0 :                         open_flags = PKG_OPEN_MANIFEST_COMPACT;
     291             : 
     292           0 :                 if (pkg_open_fd(&pkg, fd, keys, open_flags) != EPKG_OK) {
     293           0 :                         close(fd);
     294           0 :                         return (1);
     295             :                 }
     296           0 :                 pkg_manifest_keys_free(keys);
     297           0 :                 print_info(pkg, opt);
     298           0 :                 close(fd);
     299           0 :                 pkg_free(pkg);
     300           0 :                 return (EX_OK);
     301             :         }
     302             : 
     303           7 :         ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
     304           7 :         if (ret == EPKG_ENOACCESS) {
     305           0 :                 warnx("Insufficient privileges to query the package database");
     306           0 :                 return (EX_NOPERM);
     307           7 :         } else if (ret == EPKG_ENODB) {
     308           0 :                 if (match == MATCH_ALL)
     309           0 :                         return (EX_OK);
     310           0 :                 if (origin_search)
     311           0 :                         return (EX_OK);
     312           0 :                 if (!quiet)
     313           0 :                         warnx("No packages installed");
     314           0 :                 return (EX_UNAVAILABLE);
     315           7 :         } else if (ret != EPKG_OK)
     316           0 :                 return (EX_IOERR);
     317             :                 
     318           7 :         ret = pkgdb_open(&db, PKGDB_DEFAULT);
     319           7 :         if (ret != EPKG_OK)
     320           0 :                 return (EX_IOERR);
     321             : 
     322           7 :         if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
     323           0 :                 pkgdb_close(db);
     324           0 :                 warnx("Cannot get a read lock on a database, it is locked by another process");
     325           0 :                 return (EX_TEMPFAIL);
     326             :         }
     327             : 
     328           7 :         i = 0;
     329             :         do {
     330           7 :                 gotone = false;
     331           7 :                 pkgname = argv[i];
     332             : 
     333             :                 /*
     334             :                  * allow to search for origin with a trailing /
     335             :                  * likes audio/linux-vsound depending on ${PORTSDIR}/audio/sox/
     336             :                  */
     337           7 :                 if (argc > 0 && pkgname[strlen(pkgname) -1] == '/')
     338           0 :                         pkgname[strlen(pkgname) -1] = '\0';
     339             : 
     340           7 :                 if (argc > 0) {
     341           5 :                         j=0;
     342          25 :                         while (pkgname[j] != '\0') {
     343          15 :                                 if (pkgname[j] == '<') {
     344           0 :                                         if (pkgversion) {
     345           0 :                                                 pkgversion2 = pkgname + j;
     346           0 :                                                 sign2 = LT;
     347           0 :                                                 pkgversion2[0] = '\0';
     348           0 :                                                 pkgversion2++;
     349           0 :                                                 if (pkgversion2[0] == '=') {
     350           0 :                                                         pkgversion2++;
     351           0 :                                                         sign=LE;
     352           0 :                                                         j++;
     353             :                                                 }
     354             :                                         } else {
     355           0 :                                                 pkgversion = pkgname + j;
     356           0 :                                                 sign = LT;
     357           0 :                                                 pkgversion[0] = '\0';
     358           0 :                                                 pkgversion++;
     359           0 :                                                 if (pkgversion[0] == '=') {
     360           0 :                                                         pkgversion++;
     361           0 :                                                         sign=LE;
     362           0 :                                                         j++;
     363             :                                                 }
     364             :                                         }
     365          15 :                                 } else if (pkgname[j] == '>') {
     366           0 :                                         if (pkgversion) {
     367           0 :                                                 pkgversion2 = pkgname + j;
     368           0 :                                                 sign2 = GT;
     369           0 :                                                 pkgversion2[0] = '\0';
     370           0 :                                                 pkgversion2++;
     371           0 :                                                 if (pkgversion2[0] == '=') {
     372           0 :                                                         pkgversion2++;
     373           0 :                                                         sign=GE;
     374           0 :                                                         j++;
     375             :                                                 }
     376             :                                         } else {
     377           0 :                                                 pkgversion = pkgname + j;
     378           0 :                                                 sign = GT;
     379           0 :                                                 pkgversion[0] = '\0';
     380           0 :                                                 pkgversion++;
     381           0 :                                                 if (pkgversion[0] == '=') {
     382           0 :                                                         pkgversion++;
     383           0 :                                                         sign=GE;
     384           0 :                                                         j++;
     385             :                                                 }
     386             :                                         }
     387          15 :                                 } else if (pkgname[j] == '=') {
     388           0 :                                         if (pkgversion) {
     389           0 :                                                 pkgversion2 = pkgname + j;
     390           0 :                                                 sign2 = EQ;
     391           0 :                                                 pkgversion2[0] = '\0';
     392           0 :                                                 pkgversion2++;
     393           0 :                                                 if (pkgversion2[0] == '=') {
     394           0 :                                                         pkgversion2++;
     395           0 :                                                         sign=EQ;
     396           0 :                                                         j++;
     397             :                                                 }
     398             :                                         } else {
     399           0 :                                                 pkgversion = pkgname + j;
     400           0 :                                                 sign = EQ;
     401           0 :                                                 pkgversion[0] = '\0';
     402           0 :                                                 pkgversion++;
     403           0 :                                                 if (pkgversion[0] == '=') {
     404           0 :                                                         pkgversion++;
     405           0 :                                                         sign=EQ;
     406           0 :                                                         j++;
     407             :                                                 }
     408             :                                         }
     409             :                                 }
     410          15 :                                 j++;
     411             :                         }
     412             :                 }
     413             : 
     414           7 :                 if (match != MATCH_ALL && pkgname[0] == '\0') {
     415           0 :                         fprintf(stderr, "Pattern must not be empty.\n");
     416           0 :                         i++;
     417           0 :                         continue;
     418             :                 }
     419             : 
     420           7 :                 if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
     421           0 :                         goto cleanup;
     422             :                 }
     423             : 
     424             :                 /* this is place for compatibility hacks */
     425             : 
     426             :                 /* ports infrastructure expects pkg info -q -O to
     427             :                  * always return 0 even if the ports doesn't exists */
     428             : 
     429           7 :                 if (origin_search)
     430           0 :                         gotone = true;
     431             : 
     432             :                 /* end of compatibility hacks */
     433             : 
     434             :                 /*
     435             :                  * only show full version in case of match glob with a
     436             :                  * single argument specified which does not contains
     437             :                  * any glob pattern
     438             :                  */
     439           7 :                 if (argc == 1 && !origin_search && !quiet && !e_flag &&
     440           5 :                     match == MATCH_GLOB &&
     441          10 :                     strcspn(pkgname, "*[]{}()") == strlen(pkgname) &&
     442             :                     opt == INFO_TAG_NAMEVER)
     443           0 :                         opt |= INFO_FULL;
     444             : 
     445           7 :                 query_flags = info_flags(opt, false);
     446          21 :                 while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
     447           7 :                         gotone = true;
     448             :                         const char *version;
     449             : 
     450           7 :                         pkg_get(pkg, PKG_VERSION, &version);
     451           7 :                         if (pkgversion != NULL) {
     452           0 :                                 switch (pkg_version_cmp(version, pkgversion)) {
     453             :                                 case -1:
     454           0 :                                         if (sign != LT && sign != LE) {
     455           0 :                                                 gotone = false;
     456           0 :                                                 continue;
     457             :                                         }
     458           0 :                                         break;
     459             :                                 case 0:
     460           0 :                                         if (sign != LE &&
     461           0 :                                             sign != GE &&
     462             :                                             sign != EQ) {
     463           0 :                                                 gotone = false;
     464           0 :                                                 continue;
     465             :                                         }
     466           0 :                                         break;
     467             :                                 case 1:
     468           0 :                                         if (sign != GT && sign != GE) {
     469           0 :                                                 gotone = false;
     470           0 :                                                 continue;
     471             :                                         }
     472           0 :                                         break;
     473             :                                 }
     474             :                         }
     475           7 :                         if (pkgversion2 != NULL) {
     476           0 :                                 switch (pkg_version_cmp(version, pkgversion2)) {
     477             :                                 case -1:
     478           0 :                                         if (sign2 != LT && sign2 != LE) {
     479           0 :                                                 gotone = false;
     480           0 :                                                 continue;
     481             :                                         }
     482           0 :                                         break;
     483             :                                 case 0:
     484           0 :                                         if (sign2 != LE &&
     485           0 :                                             sign2 != GE &&
     486             :                                             sign2 != EQ) {
     487           0 :                                                 gotone = false;
     488           0 :                                                 continue;
     489             :                                         }
     490           0 :                                         break;
     491             :                                 case 1:
     492           0 :                                         if (sign2 != GT && sign2 != GE) {
     493           0 :                                                 gotone = false;
     494           0 :                                                 continue;
     495             :                                         }
     496           0 :                                         break;
     497             :                                 }
     498             :                         }
     499           7 :                         if (pkg_exists)
     500           0 :                                 retcode = EX_OK;
     501             :                         else
     502           7 :                                 print_info(pkg, opt);
     503             :                 }
     504           7 :                 if (ret != EPKG_END) {
     505           0 :                         retcode = EX_IOERR;
     506             :                 }
     507             : 
     508           7 :                 if (retcode == EX_OK && !gotone && match != MATCH_ALL) {
     509           0 :                         if (!quiet)
     510           0 :                                 warnx("No package(s) matching %s", argv[i]);
     511           0 :                         retcode = EX_SOFTWARE;
     512             :                 }
     513             : 
     514           7 :                 pkgdb_it_free(it);
     515             : 
     516           7 :                 i++;
     517           7 :         } while (i < argc);
     518             : 
     519             : cleanup:
     520           7 :         pkg_free(pkg);
     521             : 
     522           7 :         pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
     523           7 :         pkgdb_close(db);
     524             : 
     525           7 :         return (retcode);
     526             : }

Generated by: LCOV version 1.10