LCOV - code coverage report
Current view: top level - src - set.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 101 164 61.6 %
Date: 2015-08-15 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2012 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
       4             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       5             :  * All rights reserved.
       6             :  * 
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer
      12             :  *    in this position and unchanged.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      18             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      21             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : 
      29             : #include <err.h>
      30             : #include <getopt.h>
      31             : #include <stdio.h>
      32             : #include <stdbool.h>
      33             : #include <string.h>
      34             : #include <sysexits.h>
      35             : #include <unistd.h>
      36             : 
      37             : #include <pkg.h>
      38             : 
      39             : #include <bsd_compat.h>
      40             : 
      41             : #include "pkgcli.h"
      42             : 
      43             : #define AUTOMATIC 1U<<0
      44             : #define ORIGIN 1U<<1
      45             : #define NAME 1U<<2
      46             : 
      47             : void
      48           0 : usage_set(void)
      49             : {
      50           0 :         fprintf(stderr, "Usage: pkg set [-a] [-A [01]] [-o <oldorigin>:<neworigin>] [-n <oldname>:<newname>] [-y] [-Cgix] <pkg-name>\n\n");
      51           0 :         fprintf(stderr, "For more information see 'pkg help set'. \n");
      52           0 : }
      53             : 
      54             : static bool
      55           2 : check_change_values(const char *opt, char **oldv, char **newv, char guard)
      56             : {
      57             :         const char *semicolon;
      58             : 
      59           2 :         if (opt == NULL)
      60           0 :                 return (false);
      61             : 
      62           2 :         semicolon = strrchr(opt, ':');
      63             : 
      64           2 :         if (semicolon == NULL)
      65           0 :                 return (false);
      66             : 
      67           2 :         *oldv = malloc(semicolon - opt + 1);
      68           2 :         strlcpy(*oldv, opt, semicolon - opt + 1);
      69           2 :         *newv = strdup(semicolon + 1);
      70             : 
      71           2 :         if (guard != '\0') {
      72             :                 /* Check guard symbol in both new and old values */
      73           2 :                 if (strrchr(*oldv, guard) == NULL ||
      74           1 :                         strrchr(*newv, guard) == NULL) {
      75           0 :                         free(*oldv);
      76           0 :                         free(*newv);
      77           0 :                         *oldv = NULL;
      78           0 :                         *newv = NULL;
      79             : 
      80           0 :                         return (false);
      81             :                 }
      82             :         }
      83             : 
      84           2 :         return (true);
      85             : }
      86             : 
      87             : int
      88           4 : exec_set(int argc, char **argv)
      89             : {
      90           4 :         struct pkgdb    *db = NULL;
      91           4 :         struct pkgdb_it *it = NULL;
      92           4 :         struct pkg      *pkg = NULL;
      93             :         int              ch;
      94             :         int              i;
      95           4 :         match_t          match = MATCH_EXACT;
      96           4 :         int64_t          newautomatic = -1;
      97           4 :         bool             automatic = false;
      98           4 :         bool             rc = false;
      99           4 :         const char      *changed = NULL;
     100           4 :         char            *newvalue = NULL;
     101           4 :         char            *oldvalue = NULL;
     102           4 :         unsigned int     loads = PKG_LOAD_BASIC;
     103           4 :         unsigned int     sets = 0;
     104           4 :         unsigned int     field = 0, depfield = 0;
     105             :         int              retcode;
     106             : 
     107           4 :         struct option longopts[] = {
     108             :                 { "automatic",                required_argument,      NULL,   'A' },
     109             :                 { "all",              no_argument,            NULL,   'a' },
     110             :                 { "case-sensitive",   no_argument,            NULL,   'C' },
     111             :                 { "glob",             no_argument,            NULL,   'g' },
     112             :                 { "case-insensitive", no_argument,            NULL,   'i' },
     113             :                 { "change-origin",    required_argument,      NULL,   'o' },
     114             :                 { "change-name",      required_argument,      NULL,   'n' },
     115             :                 { "regex",            no_argument,            NULL,   'x' },
     116             :                 { "yes",              no_argument,            NULL,   'y' },
     117             :                 { NULL,                 0,                      NULL,   0   },
     118             :         };
     119             : 
     120          16 :         while ((ch = getopt_long(argc, argv, "+A:aCgio:xyn:", longopts, NULL)) != -1) {
     121           8 :                 switch (ch) {
     122             :                 case 'A':
     123           2 :                         sets |= AUTOMATIC;
     124           2 :                         newautomatic = optarg[0] - '0';
     125           2 :                         if (newautomatic != 0 && newautomatic != 1)
     126           0 :                                 errx(EX_USAGE, "Wrong value for -A. "
     127             :                                     "Expecting 0 or 1, got: %s",
     128             :                                     optarg);
     129           2 :                         break;
     130             :                 case 'a':
     131           0 :                         match = MATCH_ALL;
     132           0 :                         break;
     133             :                 case 'C':
     134           0 :                         pkgdb_set_case_sensitivity(true);
     135           0 :                         break;
     136             :                 case 'g':
     137           0 :                         match = MATCH_GLOB;
     138           0 :                         break;
     139             :                 case 'i':
     140           0 :                         pkgdb_set_case_sensitivity(false);
     141           0 :                         break;
     142             :                 case 'o':
     143           1 :                         sets |= ORIGIN;
     144           1 :                         loads |= PKG_LOAD_DEPS;
     145           1 :                         match = MATCH_ALL;
     146           1 :                         changed = "origin";
     147           1 :                         if (!check_change_values(optarg, &oldvalue, &newvalue, '/')) {
     148           0 :                                  errx(EX_USAGE, "Wrong format for -o. "
     149             :                                          "Expecting oldorigin:neworigin, got: %s",
     150             :                                          optarg);
     151             :                         }
     152           1 :                         break;
     153             :                 case 'n':
     154           1 :                         sets |= NAME;
     155           1 :                         loads |= PKG_LOAD_DEPS;
     156           1 :                         match = MATCH_ALL;
     157           1 :                         changed = "name";
     158           1 :                         if (!check_change_values(optarg, &oldvalue, &newvalue, '\0')) {
     159           0 :                                  errx(EX_USAGE, "Wrong format for -n. "
     160             :                                          "Expecting oldname:newname, got: %s",
     161             :                                          optarg);
     162             :                         }
     163           1 :                         break;
     164             :                 case 'x':
     165           0 :                         match = MATCH_REGEX;
     166           0 :                         break;
     167             :                 case 'y':
     168           4 :                         yes = true;
     169           4 :                         break;
     170             :                 default:
     171           0 :                         free(oldvalue);
     172             :                         
     173           0 :                         usage_set();
     174           0 :                         return (EX_USAGE);
     175             :                 }
     176             :         }
     177             : 
     178           4 :         argc -= optind;
     179           4 :         argv += optind;
     180             : 
     181           4 :         if ((argc < 1 && match != MATCH_ALL) ||
     182           6 :                 (newautomatic == -1 && newvalue == NULL) ||
     183           4 :                 (sets & (NAME|ORIGIN)) == (NAME|ORIGIN)) {
     184           0 :                 usage_set();
     185           0 :                 return (EX_USAGE);
     186             :         }
     187             : 
     188           4 :         if (sets & NAME) {
     189           1 :                 field = PKG_SET_NAME;
     190           1 :                 depfield = PKG_SET_DEPNAME;
     191             :         }
     192           3 :         else if (sets & ORIGIN) {
     193           1 :                 field = PKG_SET_ORIGIN;
     194           1 :                 depfield = PKG_SET_DEPORIGIN;
     195             :         }
     196             : 
     197           4 :         retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
     198             :                                PKGDB_DB_LOCAL);
     199           4 :         if (retcode == EPKG_ENODB) {
     200           0 :                 if (match == MATCH_ALL)
     201           0 :                         return (EX_OK);
     202           0 :                 if (!quiet)
     203           0 :                         warnx("No packages installed.  Nothing to do!");
     204           0 :                 return (EX_OK);
     205           4 :         } else if (retcode == EPKG_ENOACCESS) {
     206           0 :                 warnx("Insufficient privileges to modify the package database");
     207           0 :                 return (EX_NOPERM);
     208           4 :         } else if (retcode != EPKG_OK) {
     209           0 :                 warnx("Error accessing package database");
     210           0 :                 return (EX_SOFTWARE);
     211             :         }
     212             : 
     213           4 :         if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
     214           0 :                 free(newvalue);
     215           0 :                 return (EX_IOERR);
     216             :         }
     217             : 
     218           4 :         if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
     219           0 :                 pkgdb_close(db);
     220           0 :                 free(newvalue);
     221           0 :                 warnx("Cannot get an exclusive lock on a database, it is locked by another process");
     222           0 :                 return (EX_TEMPFAIL);
     223             :         }
     224             : 
     225           4 :         if (pkgdb_transaction_begin(db, NULL) != EPKG_OK) {
     226           0 :                 pkgdb_close(db);
     227           0 :                 free(newvalue);
     228           0 :                 warnx("Cannot start transaction for update");
     229           0 :                 return (EX_TEMPFAIL);
     230             :         }
     231             : 
     232             :  
     233           4 :         if (oldvalue != NULL) {
     234           2 :                 match = MATCH_ALL;
     235           2 :                 if ((it = pkgdb_query(db, oldvalue, MATCH_EXACT)) == NULL) {
     236           0 :                         retcode = EX_IOERR;
     237           0 :                         goto cleanup;
     238             :                 }
     239             : 
     240           2 :                 if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
     241           0 :                         pkg = NULL;
     242             : /*                      fprintf(stderr, "%s not installed\n", oldorigin);
     243             :                         free(oldorigin);
     244             :                         pkgdb_it_free(it);
     245             :                         pkgdb_close(db);
     246             :                         return (EX_SOFTWARE);*/
     247             :                 }
     248             : 
     249           2 :                 rc = yes;
     250           2 :                 if (!yes) {
     251           0 :                         if (pkg != NULL)
     252           0 :                                 rc = query_yesno(false, "Change %S from %S to %S for %n-%v? ",
     253             :                                                 changed, oldvalue, newvalue, pkg, pkg);
     254             :                         else
     255           0 :                                 rc = query_yesno(false, "Change %S from %S to %S for all dependencies? ",
     256             :                                                 changed, oldvalue, newvalue);
     257             :                 }
     258           2 :                 if (pkg != NULL && rc) {
     259           2 :                         if (pkgdb_set(db, pkg, field, newvalue) != EPKG_OK) {
     260           0 :                                 retcode = EX_IOERR;
     261           0 :                                 goto cleanup;
     262             :                         }
     263             :                 }
     264           2 :                 pkgdb_it_free(it);
     265             :         }
     266           4 :         i = 0;
     267             :         do {
     268           4 :                 bool saved_rc = rc;
     269             : 
     270           4 :                 if ((it = pkgdb_query(db, argv[i], match)) == NULL) {
     271           0 :                         retcode = EX_IOERR;
     272           0 :                         goto cleanup;
     273             :                 }
     274             : 
     275          12 :                 while (pkgdb_it_next(it, &pkg, loads) == EPKG_OK) {
     276           4 :                         if ((sets & AUTOMATIC) == AUTOMATIC) {
     277           2 :                                 pkg_get(pkg, PKG_AUTOMATIC, &automatic);
     278           2 :                                 if (automatic == newautomatic)
     279           0 :                                         continue;
     280           2 :                                 if (!rc) {
     281           2 :                                         if (newautomatic)
     282           1 :                                                 rc = query_yesno(false,
     283             :                                                                 "Mark %n-%v as automatically installed? ",
     284             :                                                                 pkg, pkg);
     285             :                                         else
     286           1 :                                                 rc = query_yesno(false,
     287             :                                                                 "Mark %n-%v as not automatically installed? ",
     288             :                                                                 pkg, pkg);
     289             :                                 }
     290           2 :                                 if (rc)
     291           2 :                                         pkgdb_set(db, pkg, PKG_SET_AUTOMATIC, (int)newautomatic);
     292           2 :                                 rc = saved_rc;
     293             :                         }
     294           4 :                         if (sets & (ORIGIN|NAME)) {
     295           2 :                                 struct pkg_dep *d = NULL;
     296           4 :                                 while (pkg_deps(pkg, &d) == EPKG_OK) {
     297             :                                         /*
     298             :                                          * Do not query user when he has already
     299             :                                          * been queried.
     300             :                                          */
     301           0 :                                         if (pkgdb_set(db, pkg, depfield, oldvalue, newvalue) != EPKG_OK) {
     302           0 :                                                 retcode = EX_IOERR;
     303           0 :                                                 goto cleanup;
     304             :                                         }
     305             :                                 }
     306             :                         }
     307             :                 }
     308           4 :                 pkgdb_it_free(it);
     309           4 :                 i++;
     310           4 :         } while (i < argc);
     311             : 
     312             : cleanup:
     313           4 :         free(oldvalue);
     314           4 :         free(newvalue);
     315           4 :         pkg_free(pkg);
     316             : 
     317           4 :         if (retcode == 0) {
     318           4 :                 pkgdb_transaction_commit(db, NULL);
     319             :         }
     320             :         else {
     321           0 :                 pkgdb_transaction_rollback(db, NULL);
     322             :         }
     323             : 
     324           4 :         pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
     325           4 :         pkgdb_close(db);
     326             : 
     327           4 :         return (retcode);
     328             : }

Generated by: LCOV version 1.10