Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/annotate.c
2065 views
1
/*-
2
* Copyright (c) 2013-2014 Matthew Seaman <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer
10
* in this position and unchanged.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
*/
26
27
#ifdef HAVE_CONFIG_H
28
#include "pkg_config.h"
29
#endif
30
31
#include <sys/types.h>
32
33
#include <err.h>
34
#include <getopt.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
40
#include <pkg.h>
41
42
#include "pkgcli.h"
43
44
enum action {
45
NONE,
46
ADD,
47
MODIFY,
48
DELETE,
49
SHOW,
50
};
51
52
void
53
usage_annotate(void)
54
{
55
fprintf(stderr,
56
"Usage: pkg annotate [-Cgiqxy] [-A|M] <pkg-name> <tag> [<value>]\n");
57
fprintf(stderr,
58
" pkg annotate [-Cgiqxy] [-S|D] <pkg-name> <tag>\n");
59
fprintf(stderr,
60
" pkg annotate [-qy] -a [-A|M] <tag> [<value>]\n");
61
fprintf(stderr,
62
" pkg annotate [-qy] -a [-S|D] <tag>\n\n");
63
fprintf(stderr,
64
"For more information see 'pkg help annotate'.\n");
65
}
66
67
static int
68
do_add(struct pkgdb *db, struct pkg *pkg, const char *tag, const char *value)
69
{
70
int ret = EPKG_OK;
71
72
73
if (yes || query_tty_yesno(false, "%n-%v: Add annotation tagged: %S with "
74
"value: %S? ", pkg, pkg, tag, value)) {
75
76
ret = pkgdb_add_annotation(db, pkg, tag, value);
77
if (ret == EPKG_OK) {
78
if (!quiet)
79
pkg_printf("%n-%v: added annotation tagged:"
80
" %S\n", pkg, pkg, tag);
81
} else if (ret == EPKG_WARN) {
82
if (!quiet) {
83
pkg_warnx("%n-%v: Cannot add annotation tagged:"
84
" %S\n", pkg, pkg, tag);
85
}
86
} else {
87
pkg_warnx("%n-%v: Failed to add annotation tagged:"
88
" %S\n", pkg, pkg, tag);
89
}
90
}
91
return (ret);
92
}
93
94
static int
95
do_modify(struct pkgdb *db, struct pkg *pkg, const char *tag, const char *value)
96
{
97
int ret = EPKG_OK;
98
99
100
if (yes || query_tty_yesno(false, "%n-%v: Change annotation tagged: %S to "
101
"new value: %S? ", pkg, pkg, tag, value)) {
102
ret = pkgdb_modify_annotation(db, pkg, tag, value);
103
if (ret == EPKG_OK || ret == EPKG_WARN) {
104
if (!quiet)
105
pkg_printf("%n-%v: Modified annotation "
106
"tagged: %S\n", pkg, pkg, tag);
107
} else {
108
pkg_warnx("%n-%v: Failed to modify annotation tagged:"
109
" %S", pkg, pkg, tag);
110
}
111
}
112
return (ret);
113
}
114
115
static int
116
do_delete(struct pkgdb *db, struct pkg *pkg, const char *tag)
117
{
118
int ret = EPKG_OK;
119
120
if (yes || query_tty_yesno(false, "%n-%v: Delete annotation tagged: %S? ",
121
pkg, pkg, tag)) {
122
ret = pkgdb_delete_annotation(db, pkg, tag);
123
if (ret == EPKG_OK) {
124
if (!quiet)
125
pkg_printf("%n-%v: Deleted annotation "
126
"tagged: %S\n", pkg, pkg, tag);
127
} else if (ret == EPKG_WARN) {
128
if (!quiet) {
129
pkg_warnx("%n-%v: Cannot delete annotation "
130
"tagged: %S -- because there is none\n",
131
pkg, pkg, tag);
132
}
133
} else {
134
pkg_warnx("%n-%v: Failed to delete annotation tagged: %S\n",
135
pkg, pkg, tag);
136
}
137
}
138
return (ret);
139
}
140
141
static int
142
do_show(struct pkg *pkg, const char *tag)
143
{
144
struct pkg_kvlist_iterator *kit;
145
struct pkg_kvlist *kl = NULL;
146
struct pkg_kv *note;
147
int ret = EPKG_OK;
148
149
pkg_get(pkg, PKG_ATTR_ANNOTATIONS, &kl);
150
kit = pkg_kvlist_iterator(kl);
151
while ((note = pkg_kvlist_next(kit))) {
152
if (STREQ(tag, note->key)) {
153
if (quiet)
154
printf("%s\n", note->value);
155
else
156
pkg_printf("%n-%v: Tag: %S Value: %S\n",
157
pkg, pkg, note->key, note->value);
158
return (EPKG_OK);
159
}
160
}
161
free(kit);
162
free(kl);
163
164
return (ret);
165
}
166
167
168
static char *
169
read_input(void)
170
{
171
xstring *input;
172
int ch;
173
174
input = xstring_new();
175
176
for (;;) {
177
ch = getc(stdin);
178
if (ch == EOF) {
179
if (feof(stdin))
180
break;
181
if (ferror(stdin))
182
err(EXIT_FAILURE, "Failed to read stdin");
183
}
184
fputc(ch, input->fp);
185
}
186
187
return (xstring_get(input));
188
}
189
190
int
191
exec_annotate(int argc, char **argv)
192
{
193
struct pkgdb *db = NULL;
194
struct pkgdb_it *it = NULL;
195
struct pkg *pkg = NULL;
196
enum action action = NONE;
197
const char *tag;
198
const char *value;
199
const char *pkgname;
200
char *input = NULL;
201
int ch;
202
int match = MATCH_EXACT;
203
int retcode;
204
int exitcode = EXIT_SUCCESS;
205
int flags = 0;
206
int lock_type = PKGDB_LOCK_EXCLUSIVE;
207
int mode = PKGDB_MODE_READ;
208
209
struct option longopts[] = {
210
{ "all", no_argument, NULL, 'a' },
211
{ "add", no_argument, NULL, 'A' },
212
{ "case-insensitive", no_argument, NULL, 'C' },
213
{ "delete", no_argument, NULL, 'D' },
214
{ "glob", no_argument, NULL, 'g' },
215
{ "case-insensitive", no_argument, NULL, 'i' },
216
{ "modify", no_argument, NULL, 'M' },
217
{ "quiet", no_argument, NULL, 'q' },
218
{ "show", no_argument, NULL, 'S' },
219
{ "regex", no_argument, NULL, 'x' },
220
{ "yes", no_argument, NULL, 'y' },
221
{ NULL, 0, NULL, 0 },
222
};
223
224
/* Set default case sensitivity for searching */
225
pkgdb_set_case_sensitivity(
226
pkg_object_bool(pkg_config_get("CASE_SENSITIVE_MATCH"))
227
);
228
229
while ((ch = getopt_long(argc, argv, "+aACDgiMqSxy", longopts, NULL))
230
!= -1) {
231
switch (ch) {
232
case 'a':
233
match = MATCH_ALL;
234
break;
235
case 'A':
236
action = ADD;
237
break;
238
case 'C':
239
pkgdb_set_case_sensitivity(true);
240
break;
241
case 'D':
242
action = DELETE;
243
break;
244
case 'g':
245
match = MATCH_GLOB;
246
break;
247
case 'i':
248
pkgdb_set_case_sensitivity(false);
249
break;
250
case 'M':
251
action = MODIFY;
252
break;
253
case 'q':
254
quiet = true;
255
break;
256
case 'S':
257
action = SHOW;
258
lock_type = PKGDB_LOCK_READONLY;
259
flags |= PKG_LOAD_ANNOTATIONS;
260
break;
261
case 'x':
262
match = MATCH_REGEX;
263
break;
264
case 'y':
265
yes = true;
266
break;
267
default:
268
usage_annotate();
269
return (EXIT_FAILURE);
270
}
271
}
272
argc -= optind;
273
argv += optind;
274
275
if (action == NONE ||
276
(match == MATCH_ALL && argc < 1) ||
277
(match != MATCH_ALL && argc < 2)) {
278
usage_annotate();
279
return (EXIT_FAILURE);
280
}
281
282
if (match == MATCH_ALL) {
283
pkgname = NULL;
284
tag = argv[0];
285
value = (argc > 1) ? argv[1] : NULL;
286
} else {
287
pkgname = argv[0];
288
tag = argv[1];
289
value = (argc > 2) ? argv[2] : NULL;
290
}
291
292
if ((action == ADD || action == MODIFY) && value == NULL) {
293
/* try and read data for the value from stdin. */
294
value = input = read_input();
295
}
296
297
if (lock_type == PKGDB_LOCK_EXCLUSIVE)
298
mode |= PKGDB_MODE_WRITE;
299
retcode = pkgdb_access(mode, PKGDB_DB_LOCAL);
300
if (retcode == EPKG_ENODB) {
301
if (match == MATCH_ALL) {
302
exitcode = EXIT_SUCCESS;
303
goto cleanup;
304
}
305
if (!quiet)
306
warnx("No packages installed. Nothing to do!");
307
exitcode = EXIT_SUCCESS;
308
goto cleanup;
309
} else if (retcode == EPKG_ENOACCESS) {
310
warnx("Insufficient privileges to modify the package database");
311
exitcode = EXIT_FAILURE;
312
goto cleanup;
313
} else if (retcode != EPKG_OK) {
314
warnx("Error accessing the package database");
315
exitcode = EXIT_FAILURE;
316
goto cleanup;
317
}
318
319
retcode = pkgdb_open(&db, PKGDB_DEFAULT);
320
if (retcode != EPKG_OK) {
321
free(input);
322
return (EXIT_FAILURE);
323
}
324
325
if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) {
326
pkgdb_close(db);
327
warnx("Cannot get an exclusive lock on a database, it is locked by another process");
328
return (EXIT_FAILURE);
329
}
330
331
if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
332
exitcode = EXIT_FAILURE;
333
goto cleanup;
334
}
335
336
while ((retcode = pkgdb_it_next(it, &pkg, flags)) == EPKG_OK) {
337
338
switch(action) {
339
case NONE: /* Should never happen */
340
usage_annotate();
341
exitcode = EXIT_FAILURE;
342
break;
343
case ADD:
344
retcode = do_add(db, pkg, tag, value);
345
break;
346
case MODIFY:
347
retcode = do_modify(db, pkg, tag, value);
348
break;
349
case DELETE:
350
retcode = do_delete(db, pkg, tag);
351
break;
352
case SHOW:
353
retcode = do_show(pkg, tag);
354
break;
355
}
356
357
if (retcode == EPKG_WARN)
358
exitcode = EXIT_FAILURE;
359
360
if (retcode != EPKG_OK && retcode != EPKG_WARN) {
361
exitcode = EXIT_FAILURE;
362
goto cleanup;
363
}
364
}
365
366
cleanup:
367
pkg_free(pkg);
368
pkgdb_it_free(it);
369
370
pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
371
pkgdb_close(db);
372
free(input);
373
374
return (exitcode);
375
}
376
377