Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * pkg-format.c - customizable package formatting
4 : : *
5 : : * Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
6 : : * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
7 : : *
8 : : * This is free software; you can redistribute it and/or modify
9 : : * it under the terms of the GNU General Public License as published by
10 : : * the Free Software Foundation; either version 2 of the License, or
11 : : * (at your option) any later version.
12 : : *
13 : : * This is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <config.h>
23 : : #include <compat.h>
24 : :
25 : : #include <sys/types.h>
26 : : #include <sys/stat.h>
27 : :
28 : : #include <errno.h>
29 : : #include <limits.h>
30 : : #include <string.h>
31 : : #include <stdlib.h>
32 : : #include <stdio.h>
33 : : #include <unistd.h>
34 : :
35 : : #include <dpkg/i18n.h>
36 : : #include <dpkg/error.h>
37 : : #include <dpkg/dpkg.h>
38 : : #include <dpkg/dpkg-db.h>
39 : : #include <dpkg/db-ctrl.h>
40 : : #include <dpkg/db-fsys.h>
41 : : #include <dpkg/parsedump.h>
42 : : #include <dpkg/pkg-show.h>
43 : : #include <dpkg/pkg-format.h>
44 : :
45 : : enum pkg_format_type {
46 : : PKG_FORMAT_INVALID,
47 : : PKG_FORMAT_STRING,
48 : : PKG_FORMAT_FIELD,
49 : : };
50 : :
51 : : struct pkg_format_node {
52 : : struct pkg_format_node *next;
53 : : enum pkg_format_type type;
54 : : int width;
55 : : char *data;
56 : : };
57 : :
58 : :
59 : : static struct pkg_format_node *
60 : 28 : pkg_format_node_new(void)
61 : : {
62 : : struct pkg_format_node *buf;
63 : :
64 : 28 : buf = m_malloc(sizeof(*buf));
65 : 28 : buf->type = PKG_FORMAT_INVALID;
66 : 28 : buf->next = NULL;
67 : 28 : buf->data = NULL;
68 : 28 : buf->width = 0;
69 : :
70 : 28 : return buf;
71 : : }
72 : :
73 : : static bool
74 : 18 : parsefield(struct pkg_format_node *node, const char *fmt, const char *fmtend,
75 : : struct dpkg_error *err)
76 : : {
77 : : int len;
78 : : const char *ws;
79 : :
80 : 18 : len = fmtend - fmt + 1;
81 : :
82 : 18 : ws = memchr(fmt, ';', len);
83 [ - + ]: 18 : if (ws) {
84 : : char *endptr;
85 : : long w;
86 : :
87 : 0 : errno = 0;
88 : 0 : w = strtol(ws + 1, &endptr, 0);
89 [ # # ]: 0 : if (endptr[0] != '}') {
90 : 0 : dpkg_put_error(err,
91 : 0 : _("invalid character '%c' in field width"),
92 : 0 : *endptr);
93 : 0 : return false;
94 : : }
95 [ # # # # : 0 : if (w < INT_MIN || w > INT_MAX || errno == ERANGE) {
# # ]
96 : 0 : dpkg_put_error(err, _("field width is out of range"));
97 : 0 : return false;
98 : : }
99 : :
100 : 0 : node->width = w;
101 : :
102 : 0 : len = ws - fmt;
103 : : }
104 : :
105 : 18 : node->type = PKG_FORMAT_FIELD;
106 : 18 : node->data = m_malloc(len + 1);
107 : 18 : memcpy(node->data, fmt, len);
108 : 18 : node->data[len] = '\0';
109 : :
110 : 18 : return true;
111 : : }
112 : :
113 : : static bool
114 : 10 : parsestring(struct pkg_format_node *node, const char *fmt, const char *fmtend,
115 : : struct dpkg_error *err)
116 : : {
117 : : int len;
118 : : char *write;
119 : :
120 : 10 : len = fmtend - fmt + 1;
121 : :
122 : 10 : node->type = PKG_FORMAT_STRING;
123 : 10 : node->data = write = m_malloc(len + 1);
124 [ + + ]: 44 : while (fmt <= fmtend) {
125 [ - + ]: 34 : if (*fmt == '\\') {
126 : 0 : fmt++;
127 [ # # # # ]: 0 : switch (*fmt) {
128 : 0 : case 'n':
129 : 0 : *write = '\n';
130 : 0 : break;
131 : 0 : case 't':
132 : 0 : *write = '\t';
133 : 0 : break;
134 : 0 : case 'r':
135 : 0 : *write = '\r';
136 : 0 : break;
137 : 0 : case '\\':
138 : : default:
139 : 0 : *write = *fmt;
140 : 0 : break;
141 : : }
142 : : } else
143 : 34 : *write = *fmt;
144 : 34 : write++;
145 : 34 : fmt++;
146 : : }
147 : 10 : *write = '\0';
148 : :
149 : 10 : return true;
150 : : }
151 : :
152 : : void
153 : 12 : pkg_format_free(struct pkg_format_node *head)
154 : : {
155 : : struct pkg_format_node *node;
156 : :
157 [ + + ]: 40 : while (head) {
158 : 28 : node = head;
159 : 28 : head = node->next;
160 : :
161 : 28 : free(node->data);
162 : 28 : free(node);
163 : : }
164 : 12 : }
165 : :
166 : : struct pkg_format_node *
167 : 12 : pkg_format_parse(const char *fmt, struct dpkg_error *err)
168 : : {
169 : : struct pkg_format_node *head, *node;
170 : : const char *fmtend;
171 : :
172 : 12 : head = node = NULL;
173 : :
174 [ + + ]: 40 : while (*fmt) {
175 [ + + ]: 28 : if (node)
176 : 16 : node = node->next = pkg_format_node_new();
177 : : else
178 : 12 : head = node = pkg_format_node_new();
179 : :
180 [ + + + - ]: 28 : if (fmt[0] == '$' && fmt[1] == '{') {
181 : 18 : fmtend = strchr(fmt, '}');
182 [ - + ]: 18 : if (!fmtend) {
183 : 0 : dpkg_put_error(err, _("missing closing brace"));
184 : 0 : pkg_format_free(head);
185 : 0 : return NULL;
186 : : }
187 : :
188 [ - + ]: 18 : if (!parsefield(node, fmt + 2, fmtend - 1, err)) {
189 : 0 : pkg_format_free(head);
190 : 0 : return NULL;
191 : : }
192 : 18 : fmt = fmtend + 1;
193 : : } else {
194 : 10 : fmtend = fmt;
195 : : do {
196 : 10 : fmtend += 1;
197 : 10 : fmtend = strchrnul(fmtend, '$');
198 [ + + - + ]: 10 : } while (fmtend[0] && fmtend[1] != '{');
199 : :
200 [ - + ]: 10 : if (!parsestring(node, fmt, fmtend - 1, err)) {
201 : 0 : pkg_format_free(head);
202 : 0 : return NULL;
203 : : }
204 : 10 : fmt = fmtend;
205 : : }
206 : : }
207 : :
208 [ - + ]: 12 : if (!head)
209 : 0 : dpkg_put_error(err, _("may not be empty string"));
210 : :
211 : 12 : return head;
212 : : }
213 : :
214 : : static void
215 : 0 : virt_package(struct varbuf *vb,
216 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
217 : : enum fwriteflags flags, const struct fieldinfo *fip)
218 : : {
219 : 0 : varbuf_add_pkgbin_name(vb, pkg, pkgbin, pnaw_nonambig);
220 : 0 : }
221 : :
222 : : static void
223 : 0 : virt_status_abbrev(struct varbuf *vb,
224 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
225 : : enum fwriteflags flags, const struct fieldinfo *fip)
226 : : {
227 [ # # ]: 0 : if (pkgbin != &pkg->installed)
228 : 0 : return;
229 : :
230 : 0 : varbuf_add_char(vb, pkg_abbrev_want(pkg));
231 : 0 : varbuf_add_char(vb, pkg_abbrev_status(pkg));
232 : 0 : varbuf_add_char(vb, pkg_abbrev_eflag(pkg));
233 : : }
234 : :
235 : : static void
236 : 0 : virt_status_want(struct varbuf *vb,
237 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
238 : : enum fwriteflags flags, const struct fieldinfo *fip)
239 : : {
240 [ # # ]: 0 : if (pkgbin != &pkg->installed)
241 : 0 : return;
242 : :
243 : 0 : varbuf_add_str(vb, pkg_want_name(pkg));
244 : : }
245 : :
246 : : static void
247 : 0 : virt_status_status(struct varbuf *vb,
248 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
249 : : enum fwriteflags flags, const struct fieldinfo *fip)
250 : : {
251 [ # # ]: 0 : if (pkgbin != &pkg->installed)
252 : 0 : return;
253 : :
254 : 0 : varbuf_add_str(vb, pkg_status_name(pkg));
255 : : }
256 : :
257 : : static void
258 : 0 : virt_status_eflag(struct varbuf *vb,
259 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
260 : : enum fwriteflags flags, const struct fieldinfo *fip)
261 : : {
262 [ # # ]: 0 : if (pkgbin != &pkg->installed)
263 : 0 : return;
264 : :
265 : 0 : varbuf_add_str(vb, pkg_eflag_name(pkg));
266 : : }
267 : :
268 : : static void
269 : 2 : virt_synopsis(struct varbuf *vb,
270 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
271 : : enum fwriteflags flags, const struct fieldinfo *fip)
272 : : {
273 : : const char *desc;
274 : : int len;
275 : :
276 : 2 : desc = pkgbin_synopsis(pkg, pkgbin, &len);
277 : :
278 : 2 : varbuf_add_buf(vb, desc, len);
279 : 2 : }
280 : :
281 : : static void
282 : 0 : virt_fsys_last_modified(struct varbuf *vb,
283 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
284 : : enum fwriteflags flags, const struct fieldinfo *fip)
285 : : {
286 : : const char *listfile;
287 : : struct stat st;
288 : : intmax_t mtime;
289 : :
290 [ # # ]: 0 : if (pkg->status == PKG_STAT_NOTINSTALLED)
291 : 0 : return;
292 : :
293 : 0 : listfile = pkg_infodb_get_file(pkg, pkgbin, LISTFILE);
294 : :
295 [ # # ]: 0 : if (stat(listfile, &st) < 0) {
296 [ # # ]: 0 : if (errno == ENOENT)
297 : 0 : return;
298 : :
299 : 0 : ohshite(_("cannot get package %s filesystem last modification time"),
300 : : pkgbin_name_const(pkg, pkgbin, pnaw_nonambig));
301 : : }
302 : :
303 : 0 : mtime = st.st_mtime;
304 : 0 : varbuf_printf(vb, "%jd", mtime);
305 : : }
306 : :
307 : : /*
308 : : * This function requires the caller to have loaded the package fsys metadata,
309 : : * otherwise it will do nothing.
310 : : */
311 : : static void
312 : 0 : virt_fsys_files(struct varbuf *vb,
313 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
314 : : enum fwriteflags flags, const struct fieldinfo *fip)
315 : : {
316 : : struct fsys_namenode_list *node;
317 : :
318 [ # # ]: 0 : if (!pkg->files_list_valid)
319 : 0 : return;
320 : :
321 [ # # ]: 0 : for (node = pkg->files; node; node = node->next) {
322 : 0 : varbuf_add_char(vb, ' ');
323 : 0 : varbuf_add_str(vb, node->namenode->name);
324 : 0 : varbuf_add_char(vb, '\n');
325 : : }
326 : : }
327 : :
328 : : static void
329 : 4 : virt_source_package(struct varbuf *vb,
330 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
331 : : enum fwriteflags flags, const struct fieldinfo *fip)
332 : : {
333 : : const char *name;
334 : : size_t len;
335 : :
336 : 4 : name = pkgbin->source;
337 [ + + ]: 4 : if (name == NULL)
338 : 2 : name = pkg->set->name;
339 : :
340 : 4 : len = strcspn(name, " ");
341 : :
342 : 4 : varbuf_add_buf(vb, name, len);
343 : 4 : }
344 : :
345 : : static void
346 : 4 : virt_source_version(struct varbuf *vb,
347 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
348 : : enum fwriteflags flags, const struct fieldinfo *fip)
349 : : {
350 : 4 : varbuf_add_source_version(vb, pkg, pkgbin);
351 : 4 : }
352 : :
353 : : static void
354 : 3 : virt_source_upstream_version(struct varbuf *vb,
355 : : const struct pkginfo *pkg, const struct pkgbin *pkgbin,
356 : : enum fwriteflags flags, const struct fieldinfo *fip)
357 : : {
358 : : struct dpkg_version version;
359 : :
360 : 3 : pkg_source_version(&version, pkg, pkgbin);
361 : :
362 [ + + ]: 3 : if (version.version)
363 : 2 : varbuf_add_str(vb, version.version);
364 : 3 : }
365 : :
366 : : static const struct fieldinfo virtinfos[] = {
367 : : { FIELD("binary:Package"), NULL, virt_package },
368 : : { FIELD("binary:Synopsis"), NULL, virt_synopsis },
369 : : { FIELD("binary:Summary"), NULL, virt_synopsis },
370 : : { FIELD("db:Status-Abbrev"), NULL, virt_status_abbrev },
371 : : { FIELD("db:Status-Want"), NULL, virt_status_want },
372 : : { FIELD("db:Status-Status"), NULL, virt_status_status },
373 : : { FIELD("db:Status-Eflag"), NULL, virt_status_eflag },
374 : : { FIELD("db-fsys:Files"), NULL, virt_fsys_files },
375 : : { FIELD("db-fsys:Last-Modified"), NULL, virt_fsys_last_modified },
376 : : { FIELD("source:Package"), NULL, virt_source_package },
377 : : { FIELD("source:Version"), NULL, virt_source_version },
378 : : { FIELD("source:Upstream-Version"), NULL, virt_source_upstream_version },
379 : : { NULL },
380 : : };
381 : :
382 : : bool
383 : 2 : pkg_format_needs_db_fsys(const struct pkg_format_node *head)
384 : : {
385 : : const struct pkg_format_node *node;
386 : :
387 [ + + ]: 6 : for (node = head; node; node = node->next) {
388 [ + + ]: 5 : if (node->type != PKG_FORMAT_FIELD)
389 : 3 : continue;
390 [ + + ]: 2 : if (strcmp(node->data, "db-fsys:Files") == 0)
391 : 1 : return true;
392 : : }
393 : :
394 : 1 : return false;
395 : : }
396 : :
397 : : static void
398 : 22 : pkg_format_item(struct varbuf *vb,
399 : : const struct pkg_format_node *node, const char *str)
400 : : {
401 [ + - ]: 22 : if (node->width == 0)
402 : 22 : varbuf_add_str(vb, str);
403 : : else
404 : 0 : varbuf_printf(vb, "%*s", node->width, str);
405 : 22 : }
406 : :
407 : : void
408 : 10 : pkg_format_print(struct varbuf *vb, const struct pkg_format_node *head,
409 : : struct pkginfo *pkg, struct pkgbin *pkgbin)
410 : : {
411 : : const struct pkg_format_node *node;
412 : 10 : struct varbuf fb = VARBUF_INIT, wb = VARBUF_INIT;
413 : :
414 [ + + ]: 32 : for (node = head; node; node = node->next) {
415 : 22 : bool ok = false;
416 : :
417 [ + + ]: 22 : if (node->type == PKG_FORMAT_STRING) {
418 : 6 : pkg_format_item(&fb, node, node->data);
419 : 6 : ok = true;
420 [ + - ]: 16 : } else if (node->type == PKG_FORMAT_FIELD) {
421 : : const struct fieldinfo *fip;
422 : :
423 : 16 : fip = find_field_info(fieldinfos, node->data);
424 [ + + ]: 16 : if (fip == NULL)
425 : 13 : fip = find_field_info(virtinfos, node->data);
426 : :
427 [ + - ]: 16 : if (fip) {
428 : 16 : fip->wcall(&wb, pkg, pkgbin, 0, fip);
429 : :
430 : 16 : pkg_format_item(&fb, node, varbuf_str(&wb));
431 : 16 : varbuf_reset(&wb);
432 : 16 : ok = true;
433 : : } else {
434 : : const struct arbitraryfield *afp;
435 : :
436 : 0 : afp = find_arbfield_info(pkgbin->arbs, node->data);
437 [ # # ]: 0 : if (afp) {
438 : 0 : pkg_format_item(&fb, node, afp->value);
439 : 0 : ok = true;
440 : : }
441 : : }
442 : : }
443 : :
444 [ + - ]: 22 : if (ok) {
445 : 22 : size_t len = fb.used;
446 : 22 : size_t width = abs(node->width);
447 : :
448 [ - + - - ]: 22 : if ((width != 0) && (len > width))
449 : 0 : len = width;
450 : 22 : varbuf_add_buf(vb, varbuf_str(&fb), len);
451 : : }
452 : :
453 : 22 : varbuf_reset(&fb);
454 : : }
455 : :
456 : 10 : varbuf_destroy(&wb);
457 : 10 : varbuf_destroy(&fb);
458 : 10 : }
459 : :
460 : : void
461 : 0 : pkg_format_show(const struct pkg_format_node *head,
462 : : struct pkginfo *pkg, struct pkgbin *pkgbin)
463 : : {
464 : 0 : struct varbuf vb = VARBUF_INIT;
465 : :
466 : 0 : pkg_format_print(&vb, head, pkg, pkgbin);
467 : :
468 [ # # ]: 0 : if (vb.buf)
469 : 0 : fputs(vb.buf, stdout);
470 : :
471 : 0 : varbuf_destroy(&vb);
472 : 0 : }
|