/ src / fetch.c
fetch.c
  1  /*-
  2   * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
  3   * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
  4   * Copyright (c) 2012-2013 Bryan Drewery <bdrewery@FreeBSD.org>
  5   * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
  6   * All rights reserved.
  7   *
  8   * Redistribution and use in source and binary forms, with or without
  9   * modification, are permitted provided that the following conditions
 10   * are met:
 11   * 1. Redistributions of source code must retain the above copyright
 12   *    notice, this list of conditions and the following disclaimer
 13   *    in this position and unchanged.
 14   * 2. Redistributions in binary form must reproduce the above copyright
 15   *    notice, this list of conditions and the following disclaimer in the
 16   *    documentation and/or other materials provided with the distribution.
 17   *
 18   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 19   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 20   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 21   * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 22   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 23   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 27   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28   */
 29  
 30  #include <sys/types.h>
 31  
 32  #include <err.h>
 33  #include <getopt.h>
 34  #include <libgen.h>
 35  #include <stdbool.h>
 36  #include <stdio.h>
 37  #include <string.h>
 38  #include <unistd.h>
 39  
 40  #include <pkg.h>
 41  
 42  #include "pkgcli.h"
 43  
 44  void
 45  usage_fetch(void)
 46  {
 47  	fprintf(stderr, "Usage: pkg fetch [-r reponame] [-o destdir] [-dqsUy] "
 48  					"[-Cgix] <pkg-name> <...>\n");
 49  	fprintf(stderr, "       pkg fetch [-r reponame] [-dqUy] -a\n");
 50  	fprintf(stderr, "       pkg fetch [-r reponame] [-dqUy] -u\n\n");
 51  	fprintf(stderr, "For more information see 'pkg help fetch'.\n");
 52  }
 53  
 54  int
 55  exec_fetch(int argc, char **argv)
 56  {
 57  	struct pkgdb	*db = NULL;
 58  	struct pkg_jobs	*jobs = NULL;
 59  	const char *destdir = NULL;
 60  	int		 ch;
 61  	int		 retcode;
 62  	int		 status = EXIT_FAILURE;
 63  	bool		 upgrades_for_installed = false, rc, csum_only = false;
 64  	unsigned	 mode;
 65  	match_t		 match = MATCH_EXACT;
 66  	pkg_flags	 f = PKG_FLAG_NONE;
 67  	c_charv_t	reponames = vec_init();
 68  
 69  	if (getenv("PKG_REPO_SYMLINK") != NULL)
 70  		f |= PKG_FLAG_FETCH_SYMLINK;
 71  
 72  	struct option longopts[] = {
 73  		{ "all",		no_argument,		NULL,	'a' },
 74  		{ "case-sensitive",	no_argument,		NULL,	'C' },
 75  		{ "dependencies",	no_argument,		NULL,	'd' },
 76  		{ "glob",		no_argument,		NULL,	'g' },
 77  		{ "case-insensitive",	no_argument,		NULL,	'i' },
 78  		{ "quiet",		no_argument,		NULL,	'q' },
 79  		{ "repository",		required_argument,	NULL,	'r' },
 80  		{ "symlink",		no_argument,		NULL,	's' },
 81  		{ "available-updates",	no_argument,		NULL,	'u' },
 82  		{ "no-repo-update",	no_argument,		NULL,	'U' },
 83  		{ "regex",		no_argument,		NULL,	'x' },
 84  		{ "yes",		no_argument,		NULL,	'y' },
 85  		{ "output",		required_argument,	NULL,	'o' },
 86  		{ NULL,			0,			NULL,	0   },
 87  	};
 88  
 89  	while ((ch = getopt_long(argc, argv, "+aCdgiqr:sUuxyo:", longopts, NULL)) != -1) {
 90  		switch (ch) {
 91  		case 'a':
 92  			match = MATCH_ALL;
 93  			break;
 94  		case 'C':
 95  			pkgdb_set_case_sensitivity(true);
 96  			break;
 97  		case 'd':
 98  			f |= PKG_FLAG_WITH_DEPS | PKG_FLAG_RECURSIVE;
 99  			break;
100  		case 'g':
101  			match = MATCH_GLOB;
102  			break;
103  		case 'i':
104  			pkgdb_set_case_sensitivity(false);
105  			break;
106  		case 'q':
107  			quiet = true;
108  			break;
109  		case 'r':
110  			vec_push(&reponames, optarg);
111  			break;
112  		case 's':
113  			f |= PKG_FLAG_FETCH_SYMLINK;
114  			break;
115  		case 'u':
116  			f |= PKG_FLAG_UPGRADES_FOR_INSTALLED;
117  			upgrades_for_installed = true;
118  			break;
119  		case 'U':
120  			auto_update = false;
121  			break;
122  		case 'x':
123  			match = MATCH_REGEX;
124  			break;
125  		case 'y':
126  			yes = true;
127  			break;
128  		case 'o':
129  			f |= PKG_FLAG_FETCH_MIRROR;
130  			destdir = optarg;
131  			break;
132  		default:
133  			usage_fetch();
134  			return (EXIT_FAILURE);
135  		}
136  	}
137  	argc -= optind;
138  	argv += optind;
139  
140  	if (argc < 1 && match != MATCH_ALL && !upgrades_for_installed) {
141  		usage_fetch();
142  		return (EXIT_FAILURE);
143  	}
144  
145          if (match == MATCH_ALL && upgrades_for_installed) {
146  		usage_fetch();
147  		return (EXIT_FAILURE);
148  	}
149  
150  	if (auto_update)
151  		mode = PKGDB_MODE_READ|PKGDB_MODE_WRITE|PKGDB_MODE_CREATE;
152  	else
153  		mode = PKGDB_MODE_READ;
154  
155  	retcode = pkgdb_access2(mode, PKGDB_DB_REPO, &reponames);
156  
157  	if (retcode == EPKG_ENOACCESS) {
158  		warnx("Insufficient privileges to access repo catalogue");
159  		return (EXIT_FAILURE);
160  	} else if (retcode != EPKG_OK)
161  		return (EXIT_FAILURE);
162  
163  	if (upgrades_for_installed) {
164  		retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
165  
166  		if (retcode == EPKG_ENOACCESS) {
167  			warnx("Insufficient privileges to access the package database");
168  			return (EXIT_FAILURE);
169  		} else if (retcode != EPKG_OK)
170  			return (EXIT_FAILURE);
171  	}
172  
173  	/* first update the remote repositories if needed */
174  	if (auto_update &&
175  	    (retcode = pkgcli_update(false, false, &reponames)) != EPKG_OK)
176  		return (retcode);
177  
178  	if (pkgdb_open_all2(&db, PKGDB_REMOTE, &reponames) != EPKG_OK)
179  		return (EXIT_FAILURE);
180  
181  	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
182  		pkgdb_close(db);
183  		warnx("Cannot get a read lock on a database, it is locked by another process");
184  		return (EXIT_FAILURE);
185  	}
186  
187  
188  	if (pkg_jobs_new(&jobs, PKG_JOBS_FETCH, db) != EPKG_OK)
189  		goto cleanup;
190  
191  	if (pkg_jobs_set_repositories(jobs, &reponames) != EPKG_OK)
192  		goto cleanup;
193  
194  	if (destdir != NULL && pkg_jobs_set_destdir(jobs, destdir) != EPKG_OK)
195  		goto cleanup;
196  
197  	pkg_jobs_set_flags(jobs, f);
198  
199  	if (!upgrades_for_installed &&
200  	    pkg_jobs_add(jobs, match, argv, argc) != EPKG_OK)
201  		goto cleanup;
202  
203  	if (pkg_jobs_solve(jobs) != EPKG_OK)
204  		goto cleanup;
205  
206  	if (pkg_jobs_count(jobs) == 0)
207  		goto cleanup;
208  
209  	if (!quiet) {
210  
211  		rc = print_jobs_summary(jobs,
212  		    "The following packages will be fetched:\n\n");
213  
214  		if (rc != 0) {
215  			rc = query_yesno(false, "\nProceed with fetching "
216  					"packages? ");
217  		} else {
218  			printf("No packages are required to be fetched.\n");
219  			rc = query_yesno(false, "Check the integrity of packages "
220  							"downloaded? ");
221  			csum_only = true;
222  		}
223  	}
224  	else {
225  		rc = true;
226  	}
227  
228  	if (!rc || (retcode = pkg_jobs_apply(jobs)) != EPKG_OK)
229  		goto cleanup;
230  
231  	if (csum_only && !quiet)
232  		printf("Integrity check was successful.\n");
233  
234  	status = EXIT_SUCCESS;
235  
236  cleanup:
237  	pkg_jobs_free(jobs);
238  	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
239  	pkgdb_close(db);
240  
241  	return (status);
242  }