Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/set.c
2065 views
1
/*-
2
* Copyright (c) 2012 Baptiste Daroussin <[email protected]>
3
* Copyright (c) 2014 Matthew Seaman <[email protected]>
4
* Copyright (c) 2014 Vsevolod Stakhov <[email protected]>
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 <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#include <pkg.h>
38
39
#include <xmalloc.h>
40
41
#include <bsd_compat.h>
42
43
#include "pkgcli.h"
44
45
#define AUTOMATIC 1U<<0
46
#define ORIGIN 1U<<1
47
#define NAME 1U<<2
48
#define VITAL 1U<<3
49
50
void
51
usage_set(void)
52
{
53
fprintf(stderr, "Usage: pkg set [-a] [-A 0|1] [-o <oldorigin>:<neworigin>] [-n <oldname>:<newname>] [-y] [-Cgix] [-v 0|1] <pkg-name>\n\n");
54
fprintf(stderr, "For more information see 'pkg help set'. \n");
55
}
56
57
static bool
58
check_change_values(const char *opt, char **oldv, char **newv, char guard)
59
{
60
const char *semicolon;
61
62
if (opt == NULL)
63
return (false);
64
65
semicolon = strrchr(opt, ':');
66
67
if (semicolon == NULL)
68
return (false);
69
70
*oldv = xmalloc(semicolon - opt + 1);
71
strlcpy(*oldv, opt, semicolon - opt + 1);
72
*newv = xstrdup(semicolon + 1);
73
74
if (guard != '\0') {
75
/* Check guard symbol in both new and old values */
76
if (strrchr(*oldv, guard) == NULL ||
77
strrchr(*newv, guard) == NULL) {
78
free(*oldv);
79
free(*newv);
80
*oldv = NULL;
81
*newv = NULL;
82
83
return (false);
84
}
85
}
86
87
return (true);
88
}
89
90
int
91
exec_set(int argc, char **argv)
92
{
93
struct pkgdb *db = NULL;
94
struct pkgdb_it *it = NULL;
95
struct pkg *pkg = NULL;
96
int ch;
97
int i;
98
match_t match = MATCH_EXACT;
99
int64_t newautomatic = -1;
100
int64_t newvital = -1;
101
bool automatic = false;
102
bool rc = false;
103
bool vital = false;
104
const char *changed = NULL;
105
char *newvalue = NULL;
106
char *oldvalue = NULL;
107
unsigned int loads = PKG_LOAD_BASIC;
108
unsigned int sets = 0;
109
unsigned int field = 0, depfield = 0;
110
int retcode;
111
bool partial = false;
112
113
struct option longopts[] = {
114
{ "automatic", required_argument, NULL, 'A' },
115
{ "all", no_argument, NULL, 'a' },
116
{ "case-sensitive", no_argument, NULL, 'C' },
117
{ "glob", no_argument, NULL, 'g' },
118
{ "case-insensitive", no_argument, NULL, 'i' },
119
{ "change-origin", required_argument, NULL, 'o' },
120
{ "partial", no_argument, NULL, 'p' },
121
{ "change-name", required_argument, NULL, 'n' },
122
{ "regex", no_argument, NULL, 'x' },
123
{ "vital", required_argument, NULL, 'v' },
124
{ "yes", no_argument, NULL, 'y' },
125
{ NULL, 0, NULL, 0 },
126
};
127
128
while ((ch = getopt_long(argc, argv, "+A:aCgio:pxyn:v:", longopts, NULL)) != -1) {
129
switch (ch) {
130
case 'A':
131
sets |= AUTOMATIC;
132
newautomatic = optarg[0] - '0';
133
if (newautomatic != 0 && newautomatic != 1)
134
errx(EXIT_FAILURE, "Wrong value for -A. "
135
"Expecting 0 or 1, got: %s",
136
optarg);
137
break;
138
case 'a':
139
match = MATCH_ALL;
140
break;
141
case 'C':
142
pkgdb_set_case_sensitivity(true);
143
break;
144
case 'g':
145
match = MATCH_GLOB;
146
break;
147
case 'i':
148
pkgdb_set_case_sensitivity(false);
149
break;
150
case 'o':
151
sets |= ORIGIN;
152
loads |= PKG_LOAD_DEPS;
153
match = MATCH_ALL;
154
changed = "origin";
155
if (!check_change_values(optarg, &oldvalue, &newvalue, '\0')) {
156
errx(EXIT_FAILURE, "Wrong format for -o. "
157
"Expecting oldorigin:neworigin, got: %s",
158
optarg);
159
}
160
break;
161
case 'n':
162
sets |= NAME;
163
loads |= PKG_LOAD_DEPS;
164
match = MATCH_ALL;
165
changed = "name";
166
if (!check_change_values(optarg, &oldvalue, &newvalue, '\0')) {
167
errx(EXIT_FAILURE, "Wrong format for -n. "
168
"Expecting oldname:newname, got: %s",
169
optarg);
170
}
171
break;
172
case 'x':
173
match = MATCH_REGEX;
174
break;
175
case 'v':
176
sets |= VITAL;
177
newvital = optarg[0] - '0';
178
if (newvital != 0 && newvital != 1)
179
errx(EXIT_FAILURE, "Wrong value for -v. "
180
"Expecting 0 or 1, got: %s",
181
optarg);
182
break;
183
case 'y':
184
yes = true;
185
break;
186
case 'p':
187
partial = true;
188
break;
189
default:
190
free(oldvalue);
191
free(newvalue);
192
usage_set();
193
return (EXIT_FAILURE);
194
}
195
}
196
197
argc -= optind;
198
argv += optind;
199
200
if ((argc < 1 && match != MATCH_ALL) ||
201
(newautomatic == -1 && newvital == -1 && newvalue == NULL) ||
202
(sets & (NAME|ORIGIN)) == (NAME|ORIGIN)) {
203
free(newvalue);
204
usage_set();
205
return (EXIT_FAILURE);
206
}
207
208
if (sets & NAME) {
209
field = PKG_SET_NAME;
210
depfield = PKG_SET_DEPNAME;
211
}
212
else if (sets & ORIGIN) {
213
field = PKG_SET_ORIGIN;
214
depfield = PKG_SET_DEPORIGIN;
215
}
216
if (partial && ((sets & (NAME|ORIGIN)) == 0)) {
217
warnx("-p requires either -o or -n option)");
218
usage_set();
219
return (EXIT_FAILURE);
220
}
221
222
retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
223
PKGDB_DB_LOCAL);
224
if (retcode == EPKG_ENODB) {
225
free(newvalue);
226
if (match == MATCH_ALL)
227
return (EXIT_SUCCESS);
228
if (!quiet)
229
warnx("No packages installed. Nothing to do!");
230
return (EXIT_SUCCESS);
231
} else if (retcode == EPKG_ENOACCESS) {
232
free(newvalue);
233
warnx("Insufficient privileges to modify the package database");
234
return (EXIT_FAILURE);
235
} else if (retcode != EPKG_OK) {
236
warnx("Error accessing package database");
237
free(newvalue);
238
return (EXIT_FAILURE);
239
}
240
241
if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
242
free(newvalue);
243
return (EXIT_FAILURE);
244
}
245
246
if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
247
pkgdb_close(db);
248
free(newvalue);
249
warnx("Cannot get an exclusive lock on a database, it is locked by another process");
250
return (EXIT_FAILURE);
251
}
252
253
if (pkgdb_transaction_begin(db, NULL) != EPKG_OK) {
254
pkgdb_close(db);
255
free(newvalue);
256
warnx("Cannot start transaction for update");
257
return (EXIT_FAILURE);
258
}
259
260
if (partial) {
261
int cnt, cntdep;
262
rc = yes;
263
if (!yes)
264
rc = query_yesno(false, "Do you want to batch replace '%S' in package %S with '%S'?",
265
oldvalue, changed, newvalue);
266
if (!rc) {
267
retcode = EXIT_SUCCESS;
268
goto cleanup;
269
}
270
cnt = pkgdb_replace(db, field, oldvalue, newvalue);
271
if (cnt < 0) {
272
retcode = EXIT_FAILURE;
273
goto cleanup;
274
} else if (cnt == 0) {
275
if (!quiet)
276
warnx("No packages renamed.");
277
retcode = EXIT_FAILURE;
278
goto cleanup;
279
}
280
cntdep = pkgdb_replace(db, depfield, oldvalue, newvalue);
281
if (cntdep < 0) {
282
retcode = EXIT_FAILURE;
283
goto cleanup;
284
}
285
if (!quiet)
286
printf("%d packages have been renamed.\n", cnt);
287
retcode = EXIT_SUCCESS;
288
goto cleanup;
289
}
290
291
if (oldvalue != NULL) {
292
match = MATCH_ALL;
293
if ((it = pkgdb_query(db, oldvalue, MATCH_EXACT)) == NULL) {
294
retcode = EXIT_FAILURE;
295
goto cleanup;
296
}
297
298
if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) {
299
pkg = NULL;
300
/* fprintf(stderr, "%s not installed\n", oldorigin);
301
free(oldorigin);
302
pkgdb_it_free(it);
303
pkgdb_close(db);
304
return (EXIT_FAILURE);*/
305
}
306
307
rc = yes;
308
if (!yes) {
309
if (pkg != NULL)
310
rc = query_yesno(false, "Change %S from %S to %S for %n-%v? ",
311
changed, oldvalue, newvalue, pkg, pkg);
312
else
313
rc = query_yesno(false, "Change %S from %S to %S for all dependencies? ",
314
changed, oldvalue, newvalue);
315
}
316
if (pkg != NULL && rc) {
317
if (pkgdb_set(db, pkg, field, newvalue) != EPKG_OK) {
318
retcode = EXIT_FAILURE;
319
goto cleanup;
320
}
321
}
322
pkgdb_it_free(it);
323
}
324
i = 0;
325
do {
326
bool saved_rc = rc;
327
bool gotone = false;
328
329
if ((it = pkgdb_query(db, argv[i], match)) == NULL) {
330
retcode = EXIT_FAILURE;
331
goto cleanup;
332
}
333
334
while (pkgdb_it_next(it, &pkg, loads) == EPKG_OK) {
335
gotone = true;
336
if ((sets & AUTOMATIC) == AUTOMATIC) {
337
pkg_get(pkg, PKG_ATTR_AUTOMATIC, &automatic);
338
if (automatic == newautomatic)
339
continue;
340
if (!rc) {
341
if (newautomatic)
342
rc = query_yesno(false,
343
"Mark %n-%v as automatically installed? ",
344
pkg, pkg);
345
else
346
rc = query_yesno(false,
347
"Mark %n-%v as not automatically installed? ",
348
pkg, pkg);
349
}
350
if (rc)
351
pkgdb_set(db, pkg, PKG_SET_AUTOMATIC, (int)newautomatic);
352
rc = saved_rc;
353
}
354
if ((sets & VITAL) == VITAL) {
355
pkg_get(pkg, PKG_ATTR_VITAL, &vital);
356
if (vital == newvital)
357
continue;
358
if (!rc) {
359
if (newvital)
360
rc = query_yesno(false,
361
"Mark %n-%v as vital? ",
362
pkg, pkg);
363
else
364
rc = query_yesno(false,
365
"Mark %n-%v as not vital? ",
366
pkg, pkg);
367
}
368
if (rc)
369
pkgdb_set(db, pkg, PKG_SET_VITAL, (int)newvital);
370
rc = saved_rc;
371
}
372
if (sets & (ORIGIN|NAME)) {
373
struct pkg_dep *d = NULL;
374
while (pkg_deps(pkg, &d) == EPKG_OK) {
375
/*
376
* Do not query user when he has already
377
* been queried.
378
*/
379
if (pkgdb_set(db, pkg, depfield, oldvalue, newvalue) != EPKG_OK) {
380
retcode = EXIT_FAILURE;
381
goto cleanup;
382
}
383
}
384
}
385
}
386
if (!gotone) {
387
warnx("No package(s) matching %s", argv[i]);
388
retcode = EXIT_FAILURE;
389
}
390
pkgdb_it_free(it);
391
i++;
392
} while (i < argc);
393
394
cleanup:
395
free(oldvalue);
396
free(newvalue);
397
pkg_free(pkg);
398
399
if (retcode == 0) {
400
pkgdb_transaction_commit(db, NULL);
401
}
402
else {
403
pkgdb_transaction_rollback(db, NULL);
404
}
405
406
pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
407
pkgdb_close(db);
408
409
return (retcode);
410
}
411
412