Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/annotate.c
2646 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
while ((ch = getopt_long(argc, argv, "+aACDgiMqSxy", longopts, NULL))
225
!= -1) {
226
switch (ch) {
227
case 'a':
228
match = MATCH_ALL;
229
break;
230
case 'A':
231
action = ADD;
232
break;
233
case 'C':
234
pkgdb_set_case_sensitivity(true);
235
break;
236
case 'D':
237
action = DELETE;
238
break;
239
case 'g':
240
match = MATCH_GLOB;
241
break;
242
case 'i':
243
pkgdb_set_case_sensitivity(false);
244
break;
245
case 'M':
246
action = MODIFY;
247
break;
248
case 'q':
249
quiet = true;
250
break;
251
case 'S':
252
action = SHOW;
253
lock_type = PKGDB_LOCK_READONLY;
254
flags |= PKG_LOAD_ANNOTATIONS;
255
break;
256
case 'x':
257
match = MATCH_REGEX;
258
break;
259
case 'y':
260
yes = true;
261
break;
262
default:
263
usage_annotate();
264
return (EXIT_FAILURE);
265
}
266
}
267
argc -= optind;
268
argv += optind;
269
270
if (action == NONE ||
271
(match == MATCH_ALL && argc < 1) ||
272
(match != MATCH_ALL && argc < 2)) {
273
usage_annotate();
274
return (EXIT_FAILURE);
275
}
276
277
if (match == MATCH_ALL) {
278
pkgname = NULL;
279
tag = argv[0];
280
value = (argc > 1) ? argv[1] : NULL;
281
} else {
282
pkgname = argv[0];
283
tag = argv[1];
284
value = (argc > 2) ? argv[2] : NULL;
285
}
286
287
if ((action == ADD || action == MODIFY) && value == NULL) {
288
/* try and read data for the value from stdin. */
289
value = input = read_input();
290
}
291
292
if (lock_type == PKGDB_LOCK_EXCLUSIVE)
293
mode |= PKGDB_MODE_WRITE;
294
retcode = pkgdb_access(mode, PKGDB_DB_LOCAL);
295
if (retcode == EPKG_ENODB) {
296
if (match == MATCH_ALL) {
297
exitcode = EXIT_SUCCESS;
298
goto cleanup;
299
}
300
if (!quiet)
301
warnx("No packages installed. Nothing to do!");
302
exitcode = EXIT_SUCCESS;
303
goto cleanup;
304
} else if (retcode == EPKG_ENOACCESS) {
305
warnx("Insufficient privileges to modify the package database");
306
exitcode = EXIT_FAILURE;
307
goto cleanup;
308
} else if (retcode != EPKG_OK) {
309
warnx("Error accessing the package database");
310
exitcode = EXIT_FAILURE;
311
goto cleanup;
312
}
313
314
retcode = pkgdb_open(&db, PKGDB_DEFAULT);
315
if (retcode != EPKG_OK) {
316
free(input);
317
return (EXIT_FAILURE);
318
}
319
320
if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) {
321
pkgdb_close(db);
322
warnx("Cannot get an exclusive lock on a database, it is locked by another process");
323
return (EXIT_FAILURE);
324
}
325
326
if ((it = pkgdb_query(db, pkgname, match)) == NULL) {
327
exitcode = EXIT_FAILURE;
328
goto cleanup;
329
}
330
331
while ((retcode = pkgdb_it_next(it, &pkg, flags)) == EPKG_OK) {
332
333
switch(action) {
334
case NONE: /* Should never happen */
335
usage_annotate();
336
exitcode = EXIT_FAILURE;
337
break;
338
case ADD:
339
retcode = do_add(db, pkg, tag, value);
340
break;
341
case MODIFY:
342
retcode = do_modify(db, pkg, tag, value);
343
break;
344
case DELETE:
345
retcode = do_delete(db, pkg, tag);
346
break;
347
case SHOW:
348
retcode = do_show(pkg, tag);
349
break;
350
}
351
352
if (retcode == EPKG_WARN)
353
exitcode = EXIT_FAILURE;
354
355
if (retcode != EPKG_OK && retcode != EPKG_WARN) {
356
exitcode = EXIT_FAILURE;
357
goto cleanup;
358
}
359
}
360
361
cleanup:
362
pkg_free(pkg);
363
pkgdb_it_free(it);
364
365
pkgdb_release_lock(db, lock_type);
366
pkgdb_close(db);
367
free(input);
368
369
return (exitcode);
370
}
371
372