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