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 : 320 : exec_install(int argc, char **argv)
56 : : {
57 : 320 : struct pkgdb *db = NULL;
58 : 320 : struct pkg_jobs *jobs = NULL;
59 : 320 : const char *reponame = NULL;
60 : : int retcode;
61 : : int status;
62 : 320 : int updcode = EPKG_OK;
63 : : int ch;
64 : : int mode, repo_type;
65 : 320 : int done = 0;
66 : 320 : int lock_type = PKGDB_LOCK_ADVISORY;
67 : 320 : bool rc = true;
68 : 320 : bool local_only = false;
69 : 320 : match_t match = MATCH_EXACT;
70 : 320 : pkg_flags f = PKG_FLAG_NONE | PKG_FLAG_PKG_VERSION_TEST;
71 : :
72 : 320 : 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 : 320 : nbactions = nbdone = 0;
93 : :
94 [ + - ]: 320 : if (strcmp(argv[0], "add") == 0) {
95 : 0 : auto_update = false;
96 : 0 : local_only = true;
97 : 0 : yes = true;
98 : 0 : quiet = true;
99 : 0 : }
100 : :
101 [ + + ]: 1041 : while ((ch = getopt_long(argc, argv, "+ACfFgiIlMnqr:RUxy", longopts, NULL)) != -1) {
102 [ - - + - : 721 : switch (ch) {
- - - - -
+ + + - -
- + - ]
103 : : case 'A':
104 : 0 : f |= PKG_FLAG_AUTOMATIC;
105 : 0 : break;
106 : : case 'C':
107 : 0 : pkgdb_set_case_sensitivity(true);
108 : 0 : break;
109 : : case 'f':
110 : 181 : f |= PKG_FLAG_FORCE;
111 : 181 : break;
112 : : case 'F':
113 : 0 : f |= PKG_FLAG_SKIP_INSTALL;
114 : 0 : lock_type = PKGDB_LOCK_READONLY;
115 : 0 : break;
116 : : case 'g':
117 : 0 : match = MATCH_GLOB;
118 : 0 : break;
119 : : case 'i':
120 : 0 : pkgdb_set_case_sensitivity(false);
121 : 0 : break;
122 : : case 'I':
123 : 0 : f |= PKG_FLAG_NOSCRIPT;
124 : 0 : break;
125 : : case 'l':
126 : 0 : local_only = true;
127 : 0 : auto_update = false;
128 : 0 : break;
129 : : case 'M':
130 : 0 : f |= PKG_FLAG_FORCE_MISSING;
131 : 0 : break;
132 : : case 'n':
133 : 8 : f |= PKG_FLAG_DRY_RUN;
134 : 8 : lock_type = PKGDB_LOCK_READONLY;
135 : 8 : dry_run = true;
136 : 8 : break;
137 : : case 'q':
138 : 215 : quiet = true;
139 : 215 : break;
140 : : case 'r':
141 : 5 : reponame = optarg;
142 : 5 : break;
143 : : case 'R':
144 : 0 : f |= PKG_FLAG_RECURSIVE;
145 : 0 : break;
146 : : case 'U':
147 : 0 : auto_update = false;
148 : 0 : break;
149 : : case 'x':
150 : 0 : match = MATCH_REGEX;
151 : 0 : break;
152 : : case 'y':
153 : 312 : yes = true;
154 : 312 : break;
155 : : default:
156 : 0 : usage_install();
157 : 0 : return (EXIT_FAILURE);
158 : : }
159 : : }
160 : 320 : argc -= optind;
161 : 320 : argv += optind;
162 : :
163 [ + - ]: 320 : if (argc < 1) {
164 : 0 : usage_install();
165 : 0 : return (EXIT_FAILURE);
166 : : }
167 : :
168 [ + + + - ]: 320 : if (dry_run && !auto_update)
169 : 0 : mode = PKGDB_MODE_READ;
170 : : else
171 : 320 : mode = PKGDB_MODE_READ |
172 : : PKGDB_MODE_WRITE |
173 : : PKGDB_MODE_CREATE;
174 [ - + ]: 320 : if (local_only)
175 : 0 : repo_type = PKGDB_DB_LOCAL;
176 : : else
177 : 320 : repo_type = PKGDB_DB_LOCAL|PKGDB_DB_REPO;
178 : :
179 : 320 : retcode = pkgdb_access(mode, repo_type);
180 : :
181 [ - + # # ]: 320 : if (retcode == EPKG_ENOACCESS && dry_run) {
182 : 0 : auto_update = false;
183 : 0 : retcode = pkgdb_access(PKGDB_MODE_READ,
184 : 0 : repo_type);
185 : 0 : }
186 : :
187 [ - + ]: 320 : if (retcode == EPKG_ENOACCESS) {
188 : 0 : warnx("Insufficient privileges to install packages");
189 : 0 : return (EXIT_FAILURE);
190 [ - + ]: 320 : } else if (retcode != EPKG_OK)
191 : 0 : return (EXIT_FAILURE);
192 : :
193 : : /* first update the remote repositories if needed */
194 [ + - + + : 320 : if (auto_update && pkg_repos_total_count() > 0 &&
+ - ]
195 : 108 : (updcode = pkgcli_update(false, false, reponame)) != EPKG_OK)
196 : 0 : return (updcode);
197 : :
198 [ - + - + ]: 640 : if (pkgdb_open_all(&db,
199 : 320 : local_only ? PKGDB_DEFAULT : PKGDB_MAYBE_REMOTE,
200 : 640 : reponame) != EPKG_OK)
201 : 0 : return (EXIT_FAILURE);
202 : :
203 [ - + ]: 320 : if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) {
204 : 0 : pkgdb_close(db);
205 : 0 : warnx("Cannot get an advisory lock on a database, it is locked by another process");
206 : 0 : return (EXIT_FAILURE);
207 : : }
208 : :
209 : 320 : status = EXIT_FAILURE;
210 [ - + ]: 320 : if (pkg_jobs_new(&jobs, PKG_JOBS_INSTALL, db) != EPKG_OK)
211 : 0 : goto cleanup;
212 : :
213 [ + - + + : 320 : if (!local_only && reponame != NULL &&
+ - ]
214 : 5 : pkg_jobs_set_repository(jobs, reponame) != EPKG_OK)
215 : 0 : goto cleanup;
216 : :
217 : 320 : pkg_jobs_set_flags(jobs, f);
218 : :
219 [ - + ]: 320 : if (pkg_jobs_add(jobs, match, argv, argc) == EPKG_FATAL)
220 : 0 : goto cleanup;
221 : :
222 [ + + ]: 320 : if (pkg_jobs_solve(jobs) != EPKG_OK)
223 : 4 : goto cleanup;
224 : :
225 : 316 : status = EXIT_SUCCESS;
226 [ + + ]: 316 : while ((nbactions = pkg_jobs_count(jobs)) > 0) {
227 : 312 : rc = yes;
228 : : /* print a summary before applying the jobs */
229 [ + + - + ]: 312 : if (!quiet || dry_run) {
230 : 194 : print_jobs_summary(jobs,
231 : : "The following %d package(s) will be affected (of %d checked):\n\n",
232 : 97 : nbactions, pkg_jobs_total(jobs));
233 : 97 : }
234 [ + + ]: 312 : if (dry_run)
235 : 8 : break;
236 : :
237 [ + + ]: 304 : if (!quiet) {
238 : 89 : rc = query_yesno(false,
239 : : "\nProceed with this action? ");
240 : 89 : }
241 : :
242 [ - + ]: 304 : if (rc) {
243 : 304 : retcode = pkg_jobs_apply(jobs);
244 : 304 : done = 1;
245 [ - + ]: 304 : if (retcode == EPKG_CONFLICT) {
246 : 0 : printf("Conflicts with the existing packages "
247 : : "have been found.\nOne more solver "
248 : : "iteration is needed to resolve them.\n");
249 : 0 : continue;
250 : : }
251 [ + + ]: 304 : else if (retcode != EPKG_OK) {
252 : 4 : status = retcode;
253 : 4 : goto cleanup;
254 : : }
255 : 300 : }
256 : :
257 [ + + ]: 300 : if (messages != NULL) {
258 : 32 : fflush(messages->fp);
259 : 32 : printf("%s", messages->buf);
260 : 32 : }
261 : 300 : break;
262 : : }
263 : :
264 [ + + + + ]: 312 : if (done == 0 && rc)
265 : 4 : printf("The most recent versions of packages are already installed\n");
266 : :
267 [ + + ]: 320 : if (!rc)
268 : 8 : status = EXIT_FAILURE;
269 : :
270 : : cleanup:
271 : 320 : pkgdb_release_lock(db, lock_type);
272 : 320 : pkg_jobs_free(jobs);
273 : 320 : pkgdb_close(db);
274 : :
275 [ + + ]: 320 : if (!dry_run)
276 : 312 : pkg_cache_full_clean();
277 : :
278 [ + + + - ]: 320 : if (!rc && newpkgversion)
279 : 0 : newpkgversion = false;
280 : :
281 : 320 : return (status);
282 : 320 : }
|