Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/updating.c
2649 views
1
/*-
2
* Copyright (c) 2011-2025 Baptiste Daroussin <[email protected]>
3
* Copyright (c) 2014 Matthew Seaman <[email protected]>
4
*
5
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#if __has_include(<sys/capsicum.h>)
9
#include <sys/capsicum.h>
10
#define HAVE_CAPSICUM 1
11
#endif
12
13
#include <err.h>
14
#include <errno.h>
15
#include <getopt.h>
16
#include <pkg.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <string.h>
20
#include <unistd.h>
21
#include <ctype.h>
22
#include <regex.h>
23
24
#include "pkgcli.h"
25
26
struct regex_cache {
27
char *pattern;
28
regex_t reg;
29
};
30
31
static void
32
regex_cache_free(struct regex_cache *p)
33
{
34
if (!p)
35
return;
36
regfree(&p->reg);
37
free(p->pattern);
38
free(p);
39
}
40
41
void
42
usage_updating(void)
43
{
44
fprintf(stderr, "Usage: pkg updating [-i] [-d YYYYMMDD] [-f file] [portname ...]\n");
45
fprintf(stderr, "For more information see 'pkg help updating'.\n");
46
47
}
48
49
static char *
50
convert_re(const char *src)
51
{
52
const char *p;
53
char *q;
54
bool brace_flag = false;
55
size_t len = strlen(src);
56
char *buf = malloc(len*2+1);
57
if (buf == NULL)
58
return NULL;
59
60
for (p=src, q=buf; p < src+len; p++) {
61
switch (*p) {
62
case '*':
63
*q++ = '.';
64
*q++ = '*';
65
break;
66
case '?':
67
*q++ = '.';
68
break;
69
case '.':
70
*q++ = '\\';
71
*q++ = '.';
72
break;
73
case '{':
74
*q++='(';
75
brace_flag=true;
76
break;
77
case ',':
78
if (brace_flag)
79
*q++='|';
80
else
81
*q++=*p;
82
break;
83
case '}':
84
*q++=')';
85
brace_flag=false;
86
break;
87
default:
88
*q++ = *p;
89
}
90
}
91
*q ='\0';
92
return buf;
93
}
94
95
int
96
matcher(const char *affects, const char *origin, bool ignorecase)
97
{
98
int i, n, count, found, ret, rc;
99
bool was_spc;
100
size_t len;
101
char *re, *buf, *p, **words;
102
struct regex_cache *ent;
103
vec_t(struct regex_cache *) cache = vec_init();
104
105
len = strlen(affects);
106
buf = strdup(affects);
107
if (buf == NULL)
108
return 0;
109
110
for (count = 0, was_spc = true, p = buf; p < buf + len ; p++) {
111
if (isspace(*p)) {
112
if (!was_spc)
113
was_spc = true;
114
*p = '\0';
115
} else {
116
if (was_spc) {
117
count++;
118
was_spc = false;
119
}
120
}
121
}
122
123
words = malloc(sizeof(char*)*count);
124
if (words == NULL) {
125
free(buf);
126
return 0;
127
}
128
129
for (i = 0, was_spc = true, p = buf; p < buf + len ; p++) {
130
if (*p == '\0') {
131
if (!was_spc)
132
was_spc = true;
133
} else {
134
if (was_spc) {
135
words[i++] = p;
136
was_spc = false;
137
}
138
}
139
}
140
141
for(ret = 0, i = 0; i < count; i++) {
142
n = strlen(words[i]);
143
if (words[i][n-1] == ',') {
144
words[i][n-1] = '\0';
145
}
146
if (strpbrk(words[i],"^$*|?") == NULL &&
147
(strchr(words[i],'[') == NULL || strchr(words[i],']') == NULL) &&
148
(strchr(words[i],'{') == NULL || strchr(words[i],'}') == NULL) &&
149
(strchr(words[i],'(') == NULL || strchr(words[i],')') == NULL)) {
150
if (ignorecase) {
151
if (strcasecmp(words[i], origin) == 0) {
152
ret = 1;
153
break;
154
}
155
} else {
156
if (strcmp(words[i], origin) == 0) {
157
ret = 1;
158
break;
159
}
160
}
161
continue;
162
}
163
164
found = 0;
165
vec_foreach(cache, j) {
166
if (ignorecase)
167
rc = strcasecmp(words[i], cache.d[j]->pattern);
168
else
169
rc = strcmp(words[i], cache.d[j]->pattern);
170
if (rc == 0) {
171
found++;
172
if (regexec(&cache.d[j]->reg, origin, 0, NULL, 0) == 0) {
173
ret = 1;
174
break;
175
}
176
}
177
}
178
if (found == 0) {
179
if ((ent = malloc(sizeof(struct regex_cache))) == NULL) {
180
ret = 0;
181
goto out;
182
}
183
if ((ent->pattern = strdup(words[i])) == NULL) {
184
regex_cache_free(ent);
185
ret = 0;
186
goto out;
187
}
188
re = convert_re(words[i]);
189
if (re == NULL) {
190
regex_cache_free(ent);
191
ret = 0;
192
goto out;
193
}
194
regcomp(&ent->reg, re, (ignorecase) ? REG_ICASE|REG_EXTENDED : REG_EXTENDED);
195
free(re);
196
vec_push(&cache, ent);
197
if (regexec(&ent->reg, origin, 0, NULL, 0) == 0) {
198
ret = 1;
199
break;
200
}
201
}
202
}
203
204
out:
205
vec_free_and_free(&cache, regex_cache_free);
206
free(words);
207
free(buf);
208
return (ret);
209
}
210
211
int
212
exec_updating(int argc, char **argv)
213
{
214
char *date = NULL;
215
char *dateline = NULL;
216
char *updatingfile = NULL;
217
bool caseinsensitive = false;
218
charv_t origins = vec_init();
219
int ch;
220
char *line = NULL;
221
size_t linecap = 0;
222
char *tmp;
223
int head = 0;
224
int found = 0;
225
struct pkgdb *db = NULL;
226
struct pkg *pkg = NULL;
227
struct pkgdb_it *it = NULL;
228
FILE *fd;
229
int retcode = EXIT_SUCCESS;
230
#ifdef HAVE_CAPSICUM
231
cap_rights_t rights;
232
#endif
233
234
struct option longopts[] = {
235
{ "date", required_argument, NULL, 'd' },
236
{ "file", required_argument, NULL, 'f' },
237
{ "case-insensitive", no_argument, NULL, 'i' },
238
{ NULL, 0, NULL, 0 },
239
};
240
241
while ((ch = getopt_long(argc, argv, "+d:f:i", longopts, NULL)) != -1) {
242
switch (ch) {
243
case 'd':
244
date = optarg;
245
break;
246
case 'f':
247
updatingfile = optarg;
248
break;
249
case 'i':
250
caseinsensitive = true;
251
break;
252
default:
253
usage_updating();
254
return (EXIT_FAILURE);
255
}
256
}
257
argc -= optind;
258
argv += optind;
259
260
/* checking date format */
261
if (date != NULL)
262
if (strlen(date) != 8 || strspn(date, "0123456789") != 8)
263
err(EXIT_FAILURE, "Invalid date format");
264
265
if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
266
return (EXIT_FAILURE);
267
268
if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
269
pkgdb_close(db);
270
warnx("Cannot get a read lock on a database, it is locked by another process");
271
return (EXIT_FAILURE);
272
}
273
274
if (updatingfile == NULL) {
275
const char *portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
276
if (portsdir == NULL) {
277
retcode = EXIT_FAILURE;
278
goto cleanup;
279
}
280
asprintf(&updatingfile, "%s/UPDATING", portsdir);
281
}
282
283
fd = fopen(updatingfile, "r");
284
if (fd == NULL) {
285
warnx("Unable to open: %s", updatingfile);
286
goto cleanup;
287
}
288
289
#ifdef HAVE_CAPSICUM
290
cap_rights_init(&rights, CAP_READ);
291
if (cap_rights_limit(fileno(fd), &rights) < 0 && errno != ENOSYS ) {
292
warn("cap_rights_limit() failed");
293
fclose(fd);
294
return (EXIT_FAILURE);
295
}
296
297
#ifndef COVERAGE
298
if (cap_enter() < 0 && errno != ENOSYS) {
299
warn("cap_enter() failed");
300
fclose(fd);
301
return (EXIT_FAILURE);
302
}
303
#endif
304
#endif
305
306
if (argc == 0) {
307
if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) {
308
retcode = EXIT_FAILURE;
309
fclose(fd);
310
goto cleanup;
311
}
312
313
while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
314
char *orig;
315
pkg_asprintf(&orig, "%o", pkg);
316
vec_push(&origins, orig);
317
}
318
} else {
319
while (*argv) {
320
char *orig = strdup(*argv);
321
vec_push(&origins, orig);
322
argv++;
323
}
324
}
325
326
while (getline(&line, &linecap, fd) > 0) {
327
if (strspn(line, "0123456789:") == 9) {
328
free(dateline);
329
dateline = strdup(line);
330
found = 0;
331
head = 1;
332
} else if (head == 0) {
333
continue;
334
}
335
336
tmp = NULL;
337
if (found == 0) {
338
if (strstr(line, "AFFECTS") != NULL) {
339
vec_foreach(origins, i) {
340
if (matcher(line, origins.d[i], caseinsensitive) != 0) {
341
tmp = "";
342
break;
343
}
344
}
345
if (tmp == NULL)
346
tmp = strcasestr(line, "all users\n");
347
if (tmp == NULL)
348
tmp = strcasestr(line, "all ports users\n");
349
if (tmp != NULL) {
350
if ((date != NULL) && strncmp(dateline, date, 8) < 0) {
351
continue;
352
}
353
printf("%s%s",dateline, line);
354
found = 1;
355
}
356
}
357
} else {
358
printf("%s",line);
359
}
360
}
361
fclose(fd);
362
363
cleanup:
364
vec_free_and_free(&origins, free);
365
pkgdb_it_free(it);
366
pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
367
pkgdb_close(db);
368
pkg_free(pkg);
369
free(line);
370
free(dateline);
371
372
return (retcode);
373
}
374
375