LCOV - code coverage report
Current view: top level - src - clean.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 0 159 0.0 %
Date: 2015-08-15 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       3             :  * Copyright (c) 2013-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             : #ifdef HAVE_CONFIG_H
      30             : #include "pkg_config.h"
      31             : #endif
      32             : 
      33             : #include <sys/stat.h>
      34             : /* For MIN */
      35             : #include <sys/param.h>
      36             : 
      37             : #include <assert.h>
      38             : #include <err.h>
      39             : #include <fts.h>
      40             : #include <getopt.h>
      41             : #ifdef HAVE_LIBUTIL_H
      42             : #include <libutil.h>
      43             : #endif
      44             : #include <pkg.h>
      45             : #include <stdbool.h>
      46             : #include <string.h>
      47             : #include <sysexits.h>
      48             : #include <unistd.h>
      49             : #include <khash.h>
      50             : #include <kvec.h>
      51             : 
      52             : #include <bsd_compat.h>
      53             : 
      54             : #include "pkgcli.h"
      55             : 
      56           0 : KHASH_MAP_INIT_STR(sum, char *);
      57             : typedef kvec_t(char *) dl_list;
      58             : 
      59             : #define OUT_OF_DATE     (1U<<0)
      60             : #define REMOVED         (1U<<1)
      61             : #define CKSUM_MISMATCH  (1U<<2)
      62             : #define SIZE_MISMATCH   (1U<<3)
      63             : #define ALL             (1U<<4)
      64             : 
      65             : static int
      66           0 : add_to_dellist(dl_list *dl,  const char *path)
      67             : {
      68             :         static bool first_entry = true;
      69             :         char *store_path;
      70             : 
      71           0 :         assert(path != NULL);
      72             : 
      73           0 :         store_path = strdup(path);
      74             : 
      75           0 :         if (!quiet) {
      76           0 :                 if (first_entry) {
      77           0 :                         first_entry = false;
      78           0 :                         printf("The following package files will be deleted:"
      79             :                             "\n");
      80             :                 }
      81           0 :                 printf("\t%s\n", store_path);
      82             :         }
      83             : 
      84           0 :         kv_push(char *, *dl, store_path);
      85             : 
      86           0 :         return (EPKG_OK);
      87             : }
      88             : 
      89             : static void
      90           0 : free_dellist(dl_list *dl)
      91             : {
      92             :         unsigned int i;
      93             : 
      94           0 :         for (i = 0; i < kv_size(*dl); i++)
      95           0 :                 free(kv_A(*dl, i));
      96           0 :         kv_destroy(*dl);
      97           0 : }
      98             : 
      99             : static int
     100           0 : delete_dellist(dl_list *dl, int total)
     101             : {
     102           0 :         int retcode = EX_OK;
     103           0 :         unsigned int count = 0, processed = 0;
     104             :         char *file;
     105             : 
     106           0 :         count = kv_size(*dl);
     107           0 :         progressbar_start("Deleting files");
     108           0 :         while (kv_size(*dl) > 0) {
     109           0 :                 file = kv_pop(*dl);
     110           0 :                 if (unlink(file) != 0) {
     111           0 :                         warn("unlink(%s)", file);
     112           0 :                         retcode = EX_SOFTWARE;
     113             :                 }
     114           0 :                 free(file);
     115           0 :                 ++processed;
     116           0 :                 progressbar_tick(processed, total);
     117             :         }
     118           0 :         progressbar_tick(processed, total);
     119             : 
     120           0 :         if (!quiet) {
     121           0 :                 if (retcode == EX_OK)
     122           0 :                         printf("All done\n");
     123             :                 else
     124           0 :                         printf("%d package%s could not be deleted\n",
     125             :                               count, count > 1 ? "s" : "");
     126             :         }
     127           0 :         return (retcode);
     128             : }
     129             : 
     130             : /*
     131             :  * Extract hash from filename in format <name>-<version>-<hash>.txz
     132             :  */
     133             : static bool
     134           0 : extract_filename_sum(const char *fname, char sum[])
     135             : {
     136             :         const char *dash_pos, *dot_pos;
     137             : 
     138           0 :         dot_pos = strrchr(fname, '.');
     139           0 :         if (dot_pos == NULL)
     140           0 :                 dot_pos = fname + strlen(fname);
     141             : 
     142           0 :         dash_pos = strrchr(fname, '-');
     143           0 :         if (dash_pos == NULL)
     144           0 :                 return (false);
     145           0 :         else if (dot_pos < dash_pos)
     146           0 :                 dot_pos = fname + strlen(fname);
     147             : 
     148           0 :         if (dot_pos - dash_pos != PKG_FILE_CKSUM_CHARS + 1)
     149           0 :                 return (false);
     150             : 
     151           0 :         strlcpy(sum, dash_pos + 1, PKG_FILE_CKSUM_CHARS + 1);
     152           0 :         return (true);
     153             : }
     154             : 
     155             : void
     156           0 : usage_clean(void)
     157             : {
     158           0 :         fprintf(stderr, "Usage: pkg clean [-anqy]\n\n");
     159           0 :         fprintf(stderr, "For more information see 'pkg help clean'.\n");
     160           0 : }
     161             : 
     162             : int
     163           0 : exec_clean(int argc, char **argv)
     164             : {
     165           0 :         struct pkgdb    *db = NULL;
     166           0 :         struct pkgdb_it *it = NULL;
     167           0 :         struct pkg      *p = NULL;
     168           0 :         kh_sum_t        *sumlist = NULL;
     169           0 :         FTS             *fts = NULL;
     170           0 :         FTSENT          *ent = NULL;
     171             :         dl_list          dl;
     172             :         const char      *cachedir, *sum, *name;
     173             :         char            *paths[2], csum[PKG_FILE_CKSUM_CHARS + 1],
     174             :                         link_buf[MAXPATHLEN];
     175           0 :         bool             all = false;
     176             :         int              retcode, ret;
     177           0 :         int              ch, cnt = 0;
     178           0 :         size_t           total = 0, slen;
     179             :         ssize_t          link_len;
     180             :         char             size[8];
     181             :         char            *cksum;
     182             :         khint_t         k;
     183           0 :         struct pkg_manifest_key *keys = NULL;
     184             : 
     185           0 :         struct option longopts[] = {
     186             :                 { "all",      no_argument,    NULL,   'a' },
     187             :                 { "dry-run",  no_argument,    NULL,   'n' },
     188             :                 { "quiet",    no_argument,    NULL,   'q' },
     189             :                 { "yes",      no_argument,    NULL,   'y' },
     190             :                 { NULL,         0,              NULL,   0   },
     191             :         };
     192             : 
     193           0 :         while ((ch = getopt_long(argc, argv, "+anqy", longopts, NULL)) != -1) {
     194           0 :                 switch (ch) {
     195             :                 case 'a':
     196           0 :                         all = true;
     197           0 :                         break;
     198             :                 case 'n':
     199           0 :                         dry_run = true;
     200           0 :                         break;
     201             :                 case 'q':
     202           0 :                         quiet = true;
     203           0 :                         break;
     204             :                 case 'y':
     205           0 :                         yes = true;
     206           0 :                         break;
     207             :                 default:
     208           0 :                         usage_clean();
     209           0 :                         return (EX_USAGE);
     210             :                 }
     211             :         }
     212           0 :         argc -= optind;
     213           0 :         argv += optind;
     214             : 
     215           0 :         cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
     216             : 
     217           0 :         paths[0] = __DECONST(char*, cachedir);
     218           0 :         paths[1] = NULL;
     219             : 
     220           0 :         retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_REPO);
     221             : 
     222           0 :         if (retcode == EPKG_ENOACCESS) {
     223           0 :                 warnx("Insufficient privileges to clean old packages");
     224           0 :                 return (EX_NOPERM);
     225           0 :         } else if (retcode == EPKG_ENODB) {
     226           0 :                 warnx("No package database installed.  Nothing to do!");
     227           0 :                 return (EX_OK);
     228           0 :         } else if (retcode != EPKG_OK) {
     229           0 :                 warnx("Error accessing the package database");
     230           0 :                 return (EX_SOFTWARE);
     231             :         }
     232             : 
     233           0 :         retcode = EX_SOFTWARE;
     234             : 
     235           0 :         if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK)
     236           0 :                 return (EX_IOERR);
     237             : 
     238           0 :         if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
     239           0 :                 pkgdb_close(db);
     240           0 :                 warnx("Cannot get a read lock on a database, it is locked by another process");
     241           0 :                 return (EX_TEMPFAIL);
     242             :         }
     243             : 
     244           0 :         kv_init(dl);
     245           0 :         if ((fts = fts_open(paths, FTS_PHYSICAL, NULL)) == NULL) {
     246           0 :                 warn("fts_open(%s)", cachedir);
     247           0 :                 goto cleanup;
     248             :         }
     249             : 
     250             :         /* Build the list of out-of-date or obsolete packages */
     251             : 
     252           0 :         pkg_manifest_keys_new(&keys);
     253           0 :         while ((ent = fts_read(fts)) != NULL) {
     254           0 :                 if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL)
     255           0 :                         continue;
     256             : 
     257           0 :                 if (all) {
     258           0 :                         retcode = add_to_dellist(&dl, ent->fts_path);
     259           0 :                         if (retcode == EPKG_OK) {
     260           0 :                                 total += ent->fts_statp->st_size;
     261           0 :                                 ++cnt;
     262             :                         }
     263           0 :                         continue;
     264             :                 }
     265             : 
     266           0 :                 if (sumlist == NULL) {
     267           0 :                         sumlist = kh_init_sum();
     268           0 :                         it = pkgdb_repo_search(db, "*", MATCH_GLOB, FIELD_NAME, FIELD_NONE, NULL);
     269           0 :                         while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) {
     270           0 :                                 pkg_get(p, PKG_CKSUM, &sum);
     271           0 :                                 slen = MIN(strlen(sum), PKG_FILE_CKSUM_CHARS);
     272           0 :                                 cksum = strndup(sum, slen);
     273           0 :                                 k = kh_put_sum(sumlist, cksum, &ret);
     274           0 :                                 if (ret != 0)
     275           0 :                                         kh_value(sumlist, k) = cksum;
     276             :                         }
     277             :                 }
     278             : 
     279           0 :                 if (ent->fts_info == FTS_SL) {
     280             :                         /* Dereference the symlink and check it for being
     281             :                          * recognized checksum file, or delete the symlink
     282             :                          * later. */
     283           0 :                         if ((link_len = readlink(ent->fts_name, link_buf,
     284             :                             sizeof(link_buf))) == -1)
     285           0 :                                 continue;
     286           0 :                         link_buf[link_len] = '\0';
     287           0 :                         name = link_buf;
     288             :                 } else
     289           0 :                         name = ent->fts_name;
     290             : 
     291           0 :                 k = kh_end(sumlist);
     292           0 :                 if (extract_filename_sum(name, csum))
     293           0 :                         k = kh_get_sum(sumlist, csum);
     294           0 :                 if (k == kh_end(sumlist)) {
     295           0 :                         retcode = add_to_dellist(&dl, ent->fts_path);
     296           0 :                         if (retcode == EPKG_OK) {
     297           0 :                                 total += ent->fts_statp->st_size;
     298           0 :                                 ++cnt;
     299             :                         }
     300           0 :                         continue;
     301             :                 }
     302             :         }
     303           0 :         if (sumlist != NULL) {
     304           0 :                 kh_foreach_value(sumlist, cksum, free(cksum));
     305           0 :                 kh_destroy_sum(sumlist);
     306             :         }
     307             : 
     308           0 :         if (kv_size(dl) == 0) {
     309           0 :                 if (!quiet)
     310           0 :                         printf("Nothing to do.\n");
     311           0 :                 retcode = EX_OK;
     312           0 :                 goto cleanup;
     313             :         }
     314             : 
     315           0 :         humanize_number(size, sizeof(size), total, "B",
     316             :             HN_AUTOSCALE, HN_IEC_PREFIXES);
     317             : 
     318           0 :         if (!quiet)
     319           0 :                 printf("The cleanup will free %s\n", size);
     320           0 :         if (!dry_run) {
     321           0 :                         if (query_yesno(false,
     322             :                           "\nProceed with cleaning the cache? ")) {
     323           0 :                                 retcode = delete_dellist(&dl, cnt);
     324             :                         }
     325             :         } else {
     326           0 :                 retcode = EX_OK;
     327             :         }
     328             : 
     329             : cleanup:
     330           0 :         pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
     331           0 :         pkgdb_close(db);
     332           0 :         pkg_manifest_keys_free(keys);
     333           0 :         free_dellist(&dl);
     334             : 
     335           0 :         if (fts != NULL)
     336           0 :                 fts_close(fts);
     337             : 
     338           0 :         return (retcode);
     339             : }

Generated by: LCOV version 1.10