Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2016 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
5 : : * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
6 : : * Copyright (c) 2012-2013 Bryan Drewery <bdrewery@FreeBSD.org>
7 : : * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
8 : : * All rights reserved.
9 : : *
10 : : * Redistribution and use in source and binary forms, with or without
11 : : * modification, are permitted provided that the following conditions
12 : : * are met:
13 : : * 1. Redistributions of source code must retain the above copyright
14 : : * notice, this list of conditions and the following disclaimer
15 : : * in this position and unchanged.
16 : : * 2. Redistributions in binary form must reproduce the above copyright
17 : : * notice, this list of conditions and the following disclaimer in the
18 : : * documentation and/or other materials provided with the distribution.
19 : : *
20 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
21 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : : */
31 : :
32 : : #include <sys/types.h>
33 : :
34 : : #include <err.h>
35 : : #include <getopt.h>
36 : : #include <libgen.h>
37 : : #include <stdbool.h>
38 : : #include <stdio.h>
39 : : #include <string.h>
40 : : #include <unistd.h>
41 : :
42 : : #include <pkg.h>
43 : :
44 : : #include "pkgcli.h"
45 : :
46 : : void
47 : 0 : usage_install(void)
48 : : {
49 : 0 : fprintf(stderr,
50 : : "Usage: pkg install [-AfInFMqRUy] [-r reponame] [-Cgix] <pkg-name> ...\n\n");
51 : 0 : fprintf(stderr, "For more information see 'pkg help install'.\n");
52 : 0 : }
53 : :
54 : : int
55 : 94 : exec_install(int argc, char **argv)
56 : : {
57 : 94 : struct pkgdb *db = NULL;
58 : 94 : struct pkg_jobs *jobs = NULL;
59 : : int retcode;
60 : : int status;
61 : 94 : int updcode = EPKG_OK;
62 : : int ch;
63 : : int mode, repo_type;
64 : 94 : int done = 0;
65 : 94 : int lock_type = PKGDB_LOCK_ADVISORY;
66 : 94 : bool rc = true;
67 : 94 : bool local_only = false;
68 : 94 : match_t match = MATCH_EXACT;
69 : 94 : pkg_flags f = PKG_FLAG_NONE | PKG_FLAG_PKG_VERSION_TEST;
70 : : c_charv_t reponames;
71 : :
72 : 94 : struct option longopts[] = {
73 : : { "automatic", no_argument, NULL, 'A' },
74 : : { "case-sensitive", no_argument, NULL, 'C' },
75 : : { "force", no_argument, NULL, 'f' },
76 : : { "fetch-only", no_argument, NULL, 'F' },
77 : : { "glob", no_argument, NULL, 'g' },
78 : : { "case-insensitive", no_argument, NULL, 'i' },
79 : : { "no-scripts", no_argument, NULL, 'I' },
80 : : { "local-only", no_argument, NULL, 'l' },
81 : : { "ignore-missing", no_argument, NULL, 'M' },
82 : : { "dry-run", no_argument, NULL, 'n' },
83 : : { "quiet", no_argument, NULL, 'q' },
84 : : { "repository", required_argument, NULL, 'r' },
85 : : { "recursive", no_argument, NULL, 'R' },
86 : : { "no-repo-update", no_argument, NULL, 'U' },
87 : : { "regex", no_argument, NULL, 'x' },
88 : : { "yes", no_argument, NULL, 'y' },
89 : : { NULL, 0, NULL, 0 },
90 : : };
91 : :
92 : 94 : nbactions = nbdone = 0;
93 : :
94 [ + - ]: 94 : if (STREQ(argv[0], "add")) {
95 : 0 : auto_update = false;
96 : 0 : local_only = true;
97 : 0 : yes = true;
98 : 0 : quiet = true;
99 : 0 : }
100 : :
101 : 94 : pkgvec_init(&reponames);
102 [ + + ]: 299 : while ((ch = getopt_long(argc, argv, "+ACfFgiIlMnqr:RUxy", longopts, NULL)) != -1) {
103 [ - - + - : 205 : switch (ch) {
- - - - -
+ + - + +
- + - ]
104 : : case 'A':
105 : 0 : f |= PKG_FLAG_AUTOMATIC;
106 : 0 : break;
107 : : case 'C':
108 : 0 : pkgdb_set_case_sensitivity(true);
109 : 0 : break;
110 : : case 'f':
111 : 46 : f |= PKG_FLAG_FORCE;
112 : 46 : break;
113 : : case 'F':
114 : 0 : f |= PKG_FLAG_SKIP_INSTALL;
115 : 0 : lock_type = PKGDB_LOCK_READONLY;
116 : 0 : break;
117 : : case 'g':
118 : 0 : match = MATCH_GLOB;
119 : 0 : break;
120 : : case 'i':
121 : 0 : pkgdb_set_case_sensitivity(false);
122 : 0 : break;
123 : : case 'I':
124 : 0 : f |= PKG_FLAG_NOSCRIPT;
125 : 0 : break;
126 : : case 'l':
127 : 0 : local_only = true;
128 : 0 : auto_update = false;
129 : 0 : break;
130 : : case 'M':
131 : 0 : f |= PKG_FLAG_FORCE_MISSING;
132 : 0 : break;
133 : : case 'n':
134 : 3 : f |= PKG_FLAG_DRY_RUN;
135 : 3 : lock_type = PKGDB_LOCK_READONLY;
136 : 3 : dry_run = true;
137 : 3 : break;
138 : : case 'q':
139 : 56 : quiet = true;
140 : 56 : break;
141 : : case 'r':
142 [ - + - + : 1 : pkgvec_push(&reponames, optarg);
+ - ]
143 : 1 : break;
144 : : case 'R':
145 : 0 : f |= PKG_FLAG_RECURSIVE;
146 : 0 : break;
147 : : case 'U':
148 : 8 : auto_update = false;
149 : 8 : break;
150 : : case 'x':
151 : 0 : match = MATCH_REGEX;
152 : 0 : break;
153 : : case 'y':
154 : 91 : yes = true;
155 : 91 : break;
156 : : default:
157 : 0 : usage_install();
158 : 0 : return (EXIT_FAILURE);
159 : : }
160 : : }
161 : 94 : argc -= optind;
162 : 94 : argv += optind;
163 : :
164 [ + - ]: 94 : if (argc < 1) {
165 : 0 : usage_install();
166 : 0 : return (EXIT_FAILURE);
167 : : }
168 : :
169 [ + + + - ]: 94 : if (dry_run && !auto_update)
170 : 0 : mode = PKGDB_MODE_READ;
171 : : else
172 : 94 : mode = PKGDB_MODE_READ |
173 : : PKGDB_MODE_WRITE |
174 : : PKGDB_MODE_CREATE;
175 [ - + ]: 94 : if (local_only)
176 : 0 : repo_type = PKGDB_DB_LOCAL;
177 : : else
178 : 94 : repo_type = PKGDB_DB_LOCAL|PKGDB_DB_REPO;
179 : :
180 : : /* It is safe to use both `reponame` and `NULL` here */
181 : 94 : retcode = pkgdb_access2(mode, repo_type, &reponames);
182 : :
183 [ - + # # ]: 94 : if (retcode == EPKG_ENOACCESS && dry_run) {
184 : 0 : auto_update = false;
185 : 0 : retcode = pkgdb_access2(PKGDB_MODE_READ,
186 : 0 : repo_type, &reponames);
187 : 0 : }
188 : :
189 [ - + ]: 94 : if (retcode == EPKG_ENOACCESS) {
190 : 0 : warnx("Insufficient privileges to install packages");
191 : 0 : return (EXIT_FAILURE);
192 [ - + ]: 94 : } else if (retcode != EPKG_OK)
193 : 0 : return (EXIT_FAILURE);
194 : :
195 : : /* first update the remote repositories if needed */
196 [ + + + + : 94 : if (auto_update && pkg_repos_total_count() > 0 &&
+ - ]
197 : 32 : (updcode = pkgcli_update(false, false, &reponames)) != EPKG_OK)
198 : 0 : return (updcode);
199 : :
200 [ - + - + ]: 188 : if (pkgdb_open_all2(&db,
201 : 94 : local_only ? PKGDB_DEFAULT : PKGDB_MAYBE_REMOTE,
202 : 94 : &reponames) != EPKG_OK)
203 : 0 : return (EXIT_FAILURE);
204 : :
205 [ - + ]: 94 : if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) {
206 : 0 : pkgdb_close(db);
207 : 0 : warnx("Cannot get an advisory lock on a database, it is locked by another process");
208 : 0 : return (EXIT_FAILURE);
209 : : }
210 : :
211 : 94 : status = EXIT_FAILURE;
212 [ - + ]: 94 : if (pkg_jobs_new(&jobs, PKG_JOBS_INSTALL, db) != EPKG_OK)
213 : 0 : goto cleanup;
214 : :
215 [ + - + + : 94 : if (!local_only && reponames.len > 0 &&
+ - ]
216 : 1 : pkg_jobs_set_repositories(jobs, &reponames) != EPKG_OK)
217 : 0 : goto cleanup;
218 : :
219 : 94 : pkg_jobs_set_flags(jobs, f);
220 : :
221 [ - + ]: 94 : if (pkg_jobs_add(jobs, match, argv, argc) == EPKG_FATAL)
222 : 0 : goto cleanup;
223 : :
224 [ + + ]: 94 : if (pkg_jobs_solve(jobs) != EPKG_OK)
225 : 1 : goto cleanup;
226 : :
227 : 93 : status = EXIT_SUCCESS;
228 [ + + ]: 93 : while ((nbactions = pkg_jobs_count(jobs)) > 0) {
229 : 92 : rc = yes;
230 : : /* print a summary before applying the jobs */
231 [ + + - + ]: 92 : if (!quiet || dry_run) {
232 : 72 : print_jobs_summary(jobs,
233 : : "The following %d package(s) will be affected (of %d checked):\n\n",
234 : 36 : nbactions, pkg_jobs_total(jobs));
235 : 36 : }
236 [ + + ]: 92 : if (dry_run)
237 : 3 : break;
238 : :
239 [ + + ]: 89 : if (!quiet) {
240 : 33 : rc = query_yesno(false,
241 : : "\nProceed with this action? ");
242 : 33 : }
243 : :
244 [ - + ]: 89 : if (rc) {
245 : 89 : retcode = pkg_jobs_apply(jobs);
246 : 89 : done = 1;
247 [ - + ]: 89 : if (retcode == EPKG_CONFLICT) {
248 : 0 : printf("Conflicts with the existing packages "
249 : : "have been found.\nOne more solver "
250 : : "iteration is needed to resolve them.\n");
251 : 0 : continue;
252 : : }
253 [ + + ]: 89 : else if (retcode != EPKG_OK) {
254 : 1 : status = retcode;
255 : 1 : goto cleanup;
256 : : }
257 : 88 : }
258 : :
259 [ + + ]: 88 : if (messages != NULL) {
260 : 8 : fflush(messages->fp);
261 : 8 : printf("%s", messages->buf);
262 : 8 : }
263 : 88 : break;
264 : : }
265 : :
266 [ + + + + ]: 92 : if (done == 0 && rc)
267 : 1 : printf("The most recent versions of packages are already installed\n");
268 : :
269 [ + + ]: 95 : if (!rc)
270 : 3 : status = EXIT_FAILURE;
271 : :
272 : : cleanup:
273 : 94 : pkgdb_release_lock(db, lock_type);
274 : 94 : pkg_jobs_free(jobs);
275 : 94 : pkgdb_close(db);
276 : :
277 [ + + ]: 94 : if (!dry_run)
278 : 91 : pkg_cache_full_clean();
279 : :
280 [ + + + - ]: 94 : if (!rc && newpkgversion)
281 : 0 : newpkgversion = false;
282 : :
283 : 94 : return (status);
284 : 94 : }
|