Line data Source code
1 : /*-
2 : * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3 : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
5 : * Copyright (c) 2012-2015 Matthew Seaman <matthew@FreeBSD.org>
6 : * Copyright (c) 2013-2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
7 : * All rights reserved.
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions
11 : * are met:
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer
14 : * in this position and unchanged.
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
20 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
23 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : */
30 :
31 : #ifdef HAVE_CONFIG_H
32 : #include "pkg_config.h"
33 : #endif
34 :
35 : #include <sys/param.h>
36 : #include <sys/stat.h>
37 :
38 : #include <err.h>
39 : #include <fcntl.h>
40 : #include <inttypes.h>
41 : #ifdef HAVE_LIBUTIL_H
42 : #include <libutil.h>
43 : #endif
44 : #include <string.h>
45 : #include <unistd.h>
46 : #include <stdarg.h>
47 : #include <paths.h>
48 : #define _WITH_GETLINE
49 : #include <stdio.h>
50 : #include <errno.h>
51 : #include <pkg.h>
52 :
53 : #include <bsd_compat.h>
54 :
55 : #include "utlist.h"
56 : #include "pkgcli.h"
57 :
58 : bool
59 0 : query_tty_yesno(bool r, const char *msg, ...)
60 : {
61 : int c;
62 : va_list ap;
63 : int tty_fd;
64 : FILE *tty;
65 0 : int tty_flags = O_RDWR;
66 : char yesnomsg[1024];
67 :
68 : #ifdef O_TTY_INIT
69 0 : tty_flags |= O_TTY_INIT;
70 : #endif
71 0 : tty_fd = open(_PATH_TTY, tty_flags);
72 0 : if (tty_fd == -1) {
73 : /* No ctty -- return the default answer */
74 0 : if (default_yes)
75 0 : return (true);
76 0 : return (r);
77 : }
78 :
79 0 : tty = fdopen(tty_fd, "r+");
80 :
81 0 : strlcpy(yesnomsg, msg, sizeof(yesnomsg));
82 0 : if (default_yes || r)
83 0 : strlcat(yesnomsg, "[Y/n]: ", sizeof(yesnomsg));
84 : else
85 0 : strlcat(yesnomsg, "[y/N]: ", sizeof(yesnomsg));
86 :
87 0 : va_start(ap, msg);
88 0 : pkg_vfprintf(tty, yesnomsg, ap);
89 0 : va_end(ap);
90 :
91 0 : c = getc(tty);
92 0 : if (c == 'y' || c == 'Y')
93 0 : r = true;
94 0 : else if (c == 'n' || c == 'N')
95 0 : r = false;
96 0 : else if (c == '\n' || c == EOF) {
97 0 : if (default_yes)
98 0 : r = true;
99 : /* Else, r is not modified. It's default value is kept. */
100 0 : goto cleanup;
101 : }
102 :
103 0 : while ((c = getc(tty)) != '\n' && c != EOF)
104 0 : continue;
105 :
106 : cleanup:
107 0 : fclose(tty);
108 :
109 0 : return (r);
110 : }
111 :
112 : static bool
113 16 : vquery_yesno(bool deft, const char *msg, va_list ap)
114 : {
115 16 : char *line = NULL;
116 : char *out;
117 16 : size_t linecap = 0;
118 : int linelen;
119 16 : bool r = deft;
120 : char yesnomsg[1024];
121 :
122 : /* We use default value of yes or default in case of quiet mode */
123 16 : if (quiet)
124 0 : return (yes || default_yes || r);
125 :
126 16 : if (dry_run)
127 0 : return (yes || default_yes || r );
128 :
129 : /* Do not query user if we have specified yes flag */
130 16 : if (yes)
131 16 : return (true);
132 :
133 0 : strlcpy(yesnomsg, msg, sizeof(yesnomsg));
134 0 : if (default_yes || r)
135 0 : strlcat(yesnomsg, "[Y/n]: ", sizeof(yesnomsg));
136 : else
137 0 : strlcat(yesnomsg, "[y/N]: ", sizeof(yesnomsg));
138 :
139 0 : pkg_vasprintf(&out, yesnomsg, ap);
140 0 : printf("%s", out);
141 :
142 : for (;;) {
143 0 : if ((linelen = getline(&line, &linecap, stdin)) != -1) {
144 :
145 0 : if (linelen == 1 && line[0] == '\n') {
146 0 : if (default_yes)
147 0 : r = true;
148 0 : break;
149 : }
150 0 : else if (linelen == 2) {
151 0 : if (line[0] == 'y' || line[0] == 'Y') {
152 0 : r = true;
153 0 : break;
154 : }
155 0 : else if (line[0] == 'n' || line[0] == 'N') {
156 0 : r = false;
157 0 : break;
158 : }
159 : }
160 : else {
161 0 : if (strcasecmp(line, "yes\n") == 0) {
162 0 : r = true;
163 0 : break;
164 : }
165 0 : else if (strcasecmp(line, "no\n") == 0) {
166 0 : r = false;
167 0 : break;
168 : }
169 : }
170 0 : printf("Please type 'Y[es]' or 'N[o]' to make selection\n");
171 0 : printf("%s", out);
172 : }
173 : else {
174 0 : if (errno == EINTR) {
175 0 : continue;
176 : }
177 : else {
178 0 : if (default_yes)
179 0 : r = true;
180 : /* Else, assume EOF as false */
181 0 : r = false;
182 0 : break;
183 : }
184 : }
185 0 : }
186 :
187 0 : free(out);
188 :
189 0 : return (r);
190 : }
191 :
192 : bool
193 16 : query_yesno(bool deft, const char *msg, ...)
194 : {
195 : va_list ap;
196 : bool r;
197 :
198 16 : va_start(ap, msg);
199 16 : r = vquery_yesno(deft, msg, ap);
200 16 : va_end(ap);
201 :
202 16 : return (r);
203 : }
204 :
205 : int
206 0 : query_select(const char *msg, const char **opts, int ncnt, int deft)
207 : {
208 : int i;
209 0 : char *str = NULL;
210 0 : char *endpntr = NULL;
211 0 : size_t n = 0;
212 :
213 0 : printf("%s\n", msg);
214 0 : for (i = 0; i < ncnt; i++) {
215 0 : if (i + 1 == deft)
216 : {
217 0 : printf("*[%d] %s\n",
218 0 : i + 1, opts[i]);
219 : } else {
220 0 : printf(" [%d] %s\n",
221 0 : i + 1, opts[i]);
222 : }
223 : }
224 :
225 0 : i = deft;
226 0 : while (getline(&str, &n, stdin) == -1) {
227 0 : if (errno == EINTR)
228 0 : continue;
229 : else
230 0 : goto cleanup;
231 : }
232 0 : i = (int) strtoul(str, &endpntr, 10);
233 :
234 0 : if (endpntr == NULL || *endpntr == '\0') {
235 0 : i = deft;
236 0 : } else if (*endpntr == '\n' || *endpntr == '\r') {
237 0 : if (i > ncnt || i < 1)
238 0 : i = deft;
239 : } else
240 0 : i = -1;
241 :
242 : cleanup:
243 0 : free(str);
244 0 : return (i);
245 : }
246 :
247 : /* what the pkg needs to load in order to display the requested info */
248 : int
249 7 : info_flags(uint64_t opt, bool remote)
250 : {
251 7 : int flags = PKG_LOAD_BASIC;
252 :
253 7 : if (opt & INFO_CATEGORIES)
254 0 : flags |= PKG_LOAD_CATEGORIES;
255 7 : if (opt & INFO_LICENSES)
256 0 : flags |= PKG_LOAD_LICENSES;
257 7 : if (opt & (INFO_OPTIONS|INFO_OPTION_DEFAULTS|INFO_OPTION_DESCRIPTIONS))
258 0 : flags |= PKG_LOAD_OPTIONS;
259 7 : if (opt & INFO_SHLIBS_REQUIRED)
260 0 : flags |= PKG_LOAD_SHLIBS_REQUIRED;
261 7 : if (opt & INFO_SHLIBS_PROVIDED)
262 0 : flags |= PKG_LOAD_SHLIBS_PROVIDED;
263 7 : if (opt & INFO_PROVIDED)
264 0 : flags |= PKG_LOAD_PROVIDES;
265 7 : if (opt & INFO_REQUIRED)
266 0 : flags |= PKG_LOAD_REQUIRES;
267 7 : if (opt & INFO_ANNOTATIONS)
268 5 : flags |= PKG_LOAD_ANNOTATIONS;
269 7 : if (opt & INFO_DEPS)
270 0 : flags |= PKG_LOAD_DEPS;
271 7 : if (opt & INFO_RDEPS)
272 0 : flags |= PKG_LOAD_RDEPS;
273 7 : if (opt & INFO_FILES)
274 0 : flags |= PKG_LOAD_FILES;
275 7 : if (opt & INFO_DIRS)
276 0 : flags |= PKG_LOAD_DIRS;
277 7 : if (opt & INFO_USERS)
278 0 : flags |= PKG_LOAD_USERS;
279 7 : if (opt & INFO_GROUPS)
280 0 : flags |= PKG_LOAD_GROUPS;
281 7 : if (opt & INFO_RAW) {
282 0 : flags |= PKG_LOAD_CATEGORIES |
283 : PKG_LOAD_LICENSES |
284 : PKG_LOAD_OPTIONS |
285 : PKG_LOAD_SHLIBS_REQUIRED |
286 : PKG_LOAD_SHLIBS_PROVIDED |
287 : PKG_LOAD_PROVIDES |
288 : PKG_LOAD_REQUIRES |
289 : PKG_LOAD_ANNOTATIONS |
290 : PKG_LOAD_DEPS;
291 0 : if (!remote) {
292 0 : flags |= PKG_LOAD_FILES |
293 : PKG_LOAD_DIRS |
294 : PKG_LOAD_USERS |
295 : PKG_LOAD_GROUPS |
296 : PKG_LOAD_SCRIPTS;
297 : }
298 : }
299 :
300 7 : return flags;
301 : }
302 :
303 : void
304 7 : print_info(struct pkg * const pkg, uint64_t options)
305 : {
306 7 : bool print_tag = false;
307 7 : bool show_locks = false;
308 : const char *repourl;
309 : unsigned opt;
310 : int64_t flatsize, oldflatsize, pkgsize;
311 7 : int cout = 0; /* Number of characters output */
312 : int info_num; /* Number of different data items to print */
313 7 : int outflags = 0;
314 :
315 7 : pkg_get(pkg,
316 : PKG_REPOURL, &repourl,
317 : PKG_FLATSIZE, &flatsize,
318 : PKG_OLD_FLATSIZE, &oldflatsize,
319 : PKG_PKGSIZE, &pkgsize);
320 :
321 7 : if (options & INFO_RAW) {
322 0 : switch (options & (INFO_RAW_YAML|INFO_RAW_JSON|INFO_RAW_JSON_COMPACT|INFO_RAW_UCL)) {
323 : case INFO_RAW_YAML:
324 0 : outflags |= PKG_MANIFEST_EMIT_PRETTY;
325 0 : break;
326 : case INFO_RAW_UCL:
327 0 : outflags |= PKG_MANIFEST_EMIT_UCL;
328 0 : break;
329 : case INFO_RAW_JSON:
330 0 : outflags |= PKG_MANIFEST_EMIT_JSON;
331 : case INFO_RAW_JSON_COMPACT:
332 0 : break;
333 : }
334 0 : if (pkg_type(pkg) == PKG_REMOTE)
335 0 : outflags |= PKG_MANIFEST_EMIT_COMPACT;
336 :
337 0 : pkg_emit_manifest_file(pkg, stdout, outflags, NULL);
338 :
339 0 : return;
340 : }
341 :
342 : /* Show locking status when requested to display it and the
343 : package is locally installed */
344 7 : if (pkg_type(pkg) == PKG_INSTALLED && (options & INFO_LOCKED) != 0)
345 0 : show_locks = true;
346 :
347 7 : if (!quiet) {
348 : /* Print a tag-line identifying the package -- either
349 : NAMEVER, ORIGIN or NAME (in that order of
350 : preference). This may be the only output from this
351 : function */
352 :
353 6 : if (options & INFO_TAG_NAMEVER)
354 6 : cout = pkg_printf("%n-%v", pkg, pkg);
355 0 : else if (options & INFO_TAG_ORIGIN)
356 0 : cout = pkg_printf("%o", pkg);
357 0 : else if (options & INFO_TAG_NAME)
358 0 : cout = pkg_printf("%n", pkg);
359 : }
360 :
361 : /* If we printed a tag, and there are no other items to print,
362 : then just return now. If there's only one single-line item
363 : to print, show it at column 32 on the same line. If there's
364 : one multi-line item to print, start a new line. If there is
365 : more than one item to print per pkg, use 'key : value'
366 : style to show on a new line. */
367 :
368 7 : info_num = 0;
369 217 : for (opt = 0x1U; opt <= INFO_LASTFIELD; opt <<= 1)
370 210 : if ((opt & options) != 0)
371 6 : info_num++;
372 :
373 7 : if (info_num == 0 && cout > 0) {
374 1 : printf("\n");
375 1 : return;
376 : }
377 :
378 6 : if (info_num == 1) {
379 : /* Only one item to print */
380 6 : print_tag = false;
381 6 : if (!quiet) {
382 5 : if (options & INFO_MULTILINE)
383 5 : printf(":\n");
384 : else {
385 0 : if (cout < 31)
386 0 : cout = 31 - cout;
387 : else
388 0 : cout = 1;
389 0 : printf("%*s", cout, " ");
390 : }
391 : }
392 : } else {
393 : /* Several items to print */
394 0 : print_tag = true;
395 0 : if (!quiet)
396 0 : printf("\n");
397 : }
398 :
399 186 : for (opt = 0x1; opt <= INFO_LASTFIELD; opt <<= 1) {
400 180 : if ((opt & options) == 0)
401 174 : continue;
402 :
403 6 : switch (opt) {
404 : case INFO_NAME:
405 0 : if (print_tag)
406 0 : printf("%-15s: ", "Name");
407 0 : pkg_printf("%n\n", pkg);
408 0 : break;
409 : case INFO_INSTALLED:
410 0 : if (pkg_type(pkg) != PKG_REMOTE) {
411 0 : if (print_tag) {
412 0 : printf("%-15s: ", "Installed on");
413 0 : pkg_printf("%t%{%+%}\n", pkg);
414 : }
415 0 : } else if (!print_tag)
416 0 : printf("\n");
417 0 : break;
418 : case INFO_VERSION:
419 0 : if (print_tag)
420 0 : printf("%-15s: ", "Version");
421 0 : pkg_printf("%v\n", pkg);
422 0 : break;
423 : case INFO_ORIGIN:
424 1 : if (print_tag)
425 0 : printf("%-15s: ", "Origin");
426 1 : pkg_printf("%o\n", pkg);
427 1 : break;
428 : case INFO_PREFIX:
429 0 : if (print_tag)
430 0 : printf("%-15s: ", "Prefix");
431 0 : pkg_printf("%p\n", pkg);
432 0 : break;
433 : case INFO_REPOSITORY:
434 0 : if (pkg_type(pkg) == PKG_REMOTE &&
435 0 : repourl != NULL && repourl[0] != '\0') {
436 0 : if (print_tag)
437 0 : printf("%-15s: ", "Repository");
438 0 : pkg_printf("%N [%S]\n", pkg, repourl);
439 0 : } else if (!print_tag)
440 0 : printf("\n");
441 0 : break;
442 : case INFO_CATEGORIES:
443 0 : if (print_tag)
444 0 : printf("%-15s: ", "Categories");
445 0 : pkg_printf("%C%{%Cn%| %}\n", pkg);
446 0 : break;
447 : case INFO_LICENSES:
448 0 : if (print_tag)
449 0 : printf("%-15s: ", "Licenses");
450 0 : pkg_printf("%L%{%Ln%| %l %}\n", pkg);
451 0 : break;
452 : case INFO_MAINTAINER:
453 0 : if (print_tag)
454 0 : printf("%-15s: ", "Maintainer");
455 0 : pkg_printf("%m\n", pkg);
456 0 : break;
457 : case INFO_WWW:
458 0 : if (print_tag)
459 0 : printf("%-15s: ", "WWW");
460 0 : pkg_printf("%w\n", pkg);
461 0 : break;
462 : case INFO_COMMENT:
463 0 : if (print_tag)
464 0 : printf("%-15s: ", "Comment");
465 0 : pkg_printf("%c\n", pkg);
466 0 : break;
467 : case INFO_OPTIONS:
468 0 : if (pkg_list_count(pkg, PKG_OPTIONS) > 0) {
469 0 : if (print_tag)
470 0 : printf("%-15s:\n", "Options");
471 0 : if (quiet)
472 0 : pkg_printf("%O%{%-15On: %Ov\n%|%}", pkg);
473 : else
474 0 : pkg_printf("%O%{\t%-15On: %Ov\n%|%}", pkg);
475 : }
476 0 : break;
477 : case INFO_SHLIBS_REQUIRED:
478 0 : if (pkg_list_count(pkg, PKG_SHLIBS_REQUIRED) > 0) {
479 0 : if (print_tag)
480 0 : printf("%-15s:\n", "Shared Libs required");
481 0 : if (quiet)
482 0 : pkg_printf("%B%{%Bn\n%|%}", pkg);
483 : else
484 0 : pkg_printf("%B%{\t%Bn\n%|%}", pkg);
485 : }
486 0 : break;
487 : case INFO_SHLIBS_PROVIDED:
488 0 : if (pkg_list_count(pkg, PKG_SHLIBS_PROVIDED) > 0) {
489 0 : if (print_tag)
490 0 : printf("%-15s:\n", "Shared Libs provided");
491 0 : if (quiet)
492 0 : pkg_printf("%b%{%bn\n%|%}", pkg);
493 : else
494 0 : pkg_printf("%b%{\t%bn\n%|%}", pkg);
495 : }
496 0 : break;
497 : case INFO_REQUIRED:
498 0 : if (pkg_list_count(pkg, PKG_REQUIRES) > 0) {
499 0 : if (print_tag)
500 0 : printf("%-15s:\n", "Requires");
501 0 : if (quiet)
502 0 : pkg_printf("%Y%{%Yn\n%|%}", pkg);
503 : else
504 0 : pkg_printf("%Y%{\t%Yn\n%|%}", pkg);
505 : }
506 0 : break;
507 : case INFO_PROVIDED:
508 0 : if (pkg_list_count(pkg, PKG_PROVIDES) > 0) {
509 0 : if (print_tag)
510 0 : printf("%-15s:\n", "Provides");
511 0 : if (quiet)
512 0 : pkg_printf("%y%{%yn\n%|%}", pkg);
513 : else
514 0 : pkg_printf("%y%{\t%yn\n%|%}", pkg);
515 : }
516 0 : break;
517 : case INFO_ANNOTATIONS:
518 5 : if (print_tag)
519 0 : printf("%-15s:\n", "Annotations");
520 5 : if (quiet)
521 0 : pkg_printf("%A%{%-15An: %Av\n%|%}", pkg);
522 : else
523 5 : pkg_printf("%A%{\t%-15An: %Av\n%|%}", pkg);
524 5 : break;
525 : case INFO_FLATSIZE:
526 0 : if (print_tag)
527 0 : printf("%-15s: ", "Flat size");
528 0 : pkg_printf("%#sB\n", pkg);
529 0 : break;
530 : case INFO_PKGSIZE: /* Remote pkgs only */
531 0 : if (pkg_type(pkg) == PKG_REMOTE) {
532 0 : if (print_tag)
533 0 : printf("%-15s: ", "Pkg size");
534 0 : pkg_printf("%#xB\n", pkg);
535 0 : } else if (!print_tag)
536 0 : printf("\n");
537 0 : break;
538 : case INFO_DESCR:
539 0 : if (print_tag)
540 0 : printf("%-15s:\n", "Description");
541 0 : pkg_printf("%e\n", pkg);
542 0 : break;
543 : case INFO_MESSAGE:
544 0 : if (print_tag)
545 0 : printf("%-15s:\n", "Message");
546 0 : if (pkg_has_message(pkg))
547 0 : pkg_printf("%M\n", pkg);
548 0 : break;
549 : case INFO_DEPS:
550 0 : if (pkg_list_count(pkg, PKG_DEPS) > 0) {
551 0 : if (print_tag)
552 0 : printf("%-15s:\n", "Depends on");
553 0 : if (quiet) {
554 0 : if (show_locks)
555 0 : pkg_printf("%d%{%dn-%dv%#dk\n%|%}", pkg);
556 : else
557 0 : pkg_printf("%d%{%dn-%dv\n%|%}", pkg);
558 : } else {
559 0 : if (show_locks)
560 0 : pkg_printf("%d%{\t%dn-%dv%#dk\n%|%}", pkg);
561 : else
562 0 : pkg_printf("%d%{\t%dn-%dv\n%|%}", pkg);
563 : }
564 : }
565 0 : break;
566 : case INFO_RDEPS:
567 0 : if (pkg_list_count(pkg, PKG_RDEPS) > 0) {
568 0 : if (print_tag)
569 0 : printf("%-15s:\n", "Required by");
570 0 : if (quiet) {
571 0 : if (show_locks)
572 0 : pkg_printf("%r%{%rn-%rv%#rk\n%|%}", pkg);
573 : else
574 0 : pkg_printf("%r%{%rn-%rv\n%|%}", pkg);
575 : } else {
576 0 : if (show_locks)
577 0 : pkg_printf("%r%{\t%rn-%rv%#rk\n%|%}", pkg);
578 : else
579 0 : pkg_printf("%r%{\t%rn-%rv\n%|%}", pkg);
580 : }
581 : }
582 0 : break;
583 : case INFO_FILES: /* Installed pkgs only */
584 0 : if (pkg_type(pkg) != PKG_REMOTE &&
585 0 : pkg_list_count(pkg, PKG_FILES) > 0) {
586 0 : if (print_tag)
587 0 : printf("%-15s:\n", "Files");
588 0 : if (quiet)
589 0 : pkg_printf("%F%{%Fn\n%|%}", pkg);
590 : else
591 0 : pkg_printf("%F%{\t%Fn\n%|%}", pkg);
592 : }
593 0 : break;
594 : case INFO_DIRS: /* Installed pkgs only */
595 0 : if (pkg_type(pkg) != PKG_REMOTE &&
596 0 : pkg_list_count(pkg, PKG_DIRS) > 0) {
597 0 : if (print_tag)
598 0 : printf("%-15s:\n", "Directories");
599 0 : if (quiet)
600 0 : pkg_printf("%D%{%Dn\n%|%}", pkg);
601 : else
602 0 : pkg_printf("%D%{\t%Dn\n%|%}", pkg);
603 : }
604 0 : break;
605 : case INFO_USERS: /* Installed pkgs only */
606 0 : if (pkg_type(pkg) != PKG_REMOTE &&
607 0 : pkg_list_count(pkg, PKG_USERS) > 0) {
608 0 : if (print_tag)
609 0 : printf("%-15s: ", "Users");
610 0 : pkg_printf("%U%{%Un%| %}\n", pkg);
611 : }
612 0 : break;
613 : case INFO_GROUPS: /* Installed pkgs only */
614 0 : if (pkg_type(pkg) != PKG_REMOTE &&
615 0 : pkg_list_count(pkg, PKG_GROUPS) > 0) {
616 0 : if (print_tag)
617 0 : printf("%-15s: ", "Groups");
618 0 : pkg_printf("%G%{%Gn%| %}\n", pkg);
619 : }
620 0 : break;
621 : case INFO_ARCH:
622 0 : if (print_tag)
623 0 : printf("%-15s: ", "Architecture");
624 0 : pkg_printf("%q\n", pkg);
625 0 : break;
626 : case INFO_REPOURL:
627 0 : if (pkg_type(pkg) == PKG_REMOTE &&
628 0 : repourl != NULL && repourl[0] != '\0') {
629 0 : if (print_tag)
630 0 : printf("%-15s: ", "Pkg URL");
631 0 : if (repourl[strlen(repourl) -1] == '/')
632 0 : pkg_printf("%S%R\n", repourl, pkg);
633 : else
634 0 : pkg_printf("%S/%R\n", repourl, pkg);
635 0 : } else if (!print_tag)
636 0 : printf("\n");
637 0 : break;
638 : case INFO_LOCKED:
639 0 : if (print_tag)
640 0 : printf("%-15s: ", "Locked");
641 0 : pkg_printf("%?k\n", pkg);
642 0 : break;
643 : }
644 : }
645 : }
646 :
647 : enum pkg_display_type {
648 : PKG_DISPLAY_LOCKED = 0,
649 : PKG_DISPLAY_DELETE,
650 : PKG_DISPLAY_INSTALL,
651 : PKG_DISPLAY_UPGRADE,
652 : PKG_DISPLAY_DOWNGRADE,
653 : PKG_DISPLAY_REINSTALL,
654 : PKG_DISPLAY_FETCH,
655 : PKG_DISPLAY_MAX
656 : };
657 : struct pkg_solved_display_item {
658 : struct pkg *new, *old;
659 : enum pkg_display_type display_type;
660 : pkg_solved_t solved_type;
661 : struct pkg_solved_display_item *prev, *next;
662 : };
663 :
664 : static void
665 32 : set_jobs_summary_pkg(struct pkg_jobs *jobs,
666 : struct pkg *new_pkg, struct pkg *old_pkg,
667 : pkg_solved_t type, int64_t *oldsize,
668 : int64_t *newsize, int64_t *dlsize,
669 : struct pkg_solved_display_item **disp)
670 : {
671 : const char *oldversion, *repopath, *destdir;
672 : char path[MAXPATHLEN];
673 : int ret;
674 : struct stat st;
675 : int64_t flatsize, oldflatsize, pkgsize;
676 : struct pkg_solved_display_item *it;
677 :
678 32 : flatsize = oldflatsize = pkgsize = 0;
679 32 : oldversion = NULL;
680 :
681 32 : pkg_get(new_pkg, PKG_FLATSIZE, &flatsize, PKG_PKGSIZE, &pkgsize,
682 : PKG_REPOPATH, &repopath);
683 32 : if (old_pkg != NULL)
684 11 : pkg_get(old_pkg, PKG_VERSION, &oldversion, PKG_FLATSIZE, &oldflatsize);
685 :
686 32 : it = malloc(sizeof (*it));
687 32 : if (it == NULL) {
688 0 : fprintf(stderr, "malloc failed for "
689 0 : "pkg_solved_display_item: %s", strerror (errno));
690 0 : return;
691 : }
692 32 : it->new = new_pkg;
693 32 : it->old = old_pkg;
694 32 : it->solved_type = type;
695 :
696 32 : if (old_pkg != NULL && pkg_is_locked(old_pkg)) {
697 0 : it->display_type = PKG_DISPLAY_LOCKED;
698 0 : DL_APPEND(disp[it->display_type], it);
699 0 : return;
700 : }
701 :
702 32 : destdir = pkg_jobs_destdir(jobs);
703 :
704 32 : switch (type) {
705 : case PKG_SOLVED_INSTALL:
706 : case PKG_SOLVED_UPGRADE:
707 26 : ret = EPKG_FATAL;
708 :
709 26 : if (destdir == NULL)
710 26 : ret = pkg_repo_cached_name(new_pkg, path, sizeof(path));
711 0 : else if (repopath != NULL) {
712 0 : snprintf(path, sizeof(path), "%s/%s", destdir, repopath);
713 0 : ret = EPKG_OK;
714 : }
715 :
716 26 : if ((ret == EPKG_OK || ret == EPKG_FATAL) && (stat(path, &st) == -1 || pkgsize != st.st_size))
717 : /* file looks corrupted (wrong size),
718 : assume a checksum mismatch will
719 : occur later and the file will be
720 : fetched from remote again */
721 0 : *dlsize += pkgsize;
722 :
723 26 : if (old_pkg != NULL) {
724 11 : switch (pkg_version_change_between(new_pkg, old_pkg)) {
725 : case PKG_DOWNGRADE:
726 0 : it->display_type = PKG_DISPLAY_DOWNGRADE;
727 0 : break;
728 : case PKG_REINSTALL:
729 6 : it->display_type = PKG_DISPLAY_REINSTALL;
730 :
731 6 : break;
732 : case PKG_UPGRADE:
733 5 : it->display_type = PKG_DISPLAY_UPGRADE;
734 :
735 5 : break;
736 : }
737 11 : *oldsize += oldflatsize;
738 11 : *newsize += flatsize;
739 : } else {
740 15 : it->display_type = PKG_DISPLAY_INSTALL;
741 15 : *newsize += flatsize;
742 : }
743 26 : break;
744 : case PKG_SOLVED_DELETE:
745 6 : *oldsize += flatsize;
746 6 : it->display_type = PKG_DISPLAY_DELETE;
747 :
748 6 : break;
749 : case PKG_SOLVED_UPGRADE_REMOVE:
750 : /* Ignore split-upgrade packages for display */
751 0 : free(it);
752 0 : return;
753 : break;
754 :
755 : case PKG_SOLVED_FETCH:
756 0 : *newsize += pkgsize;
757 0 : it->display_type = PKG_DISPLAY_FETCH;
758 :
759 0 : if (destdir == NULL)
760 0 : pkg_repo_cached_name(new_pkg, path, sizeof(path));
761 : else
762 0 : snprintf(path, sizeof(path), "%s/%s", destdir, repopath);
763 :
764 0 : if (stat(path, &st) != -1) {
765 0 : *oldsize += st.st_size;
766 :
767 0 : if (pkgsize != st.st_size)
768 0 : *dlsize += pkgsize;
769 : else {
770 0 : free(it);
771 0 : return;
772 : }
773 : }
774 : else
775 0 : *dlsize += pkgsize;
776 :
777 0 : break;
778 : }
779 32 : DL_APPEND(disp[it->display_type], it);
780 : }
781 :
782 : static void
783 32 : display_summary_item(struct pkg_solved_display_item *it, int64_t dlsize)
784 : {
785 : const char *why;
786 : int64_t pkgsize;
787 : char size[8], tlsize[8];
788 :
789 32 : pkg_get(it->new, PKG_PKGSIZE, &pkgsize);
790 :
791 32 : switch (it->display_type) {
792 : case PKG_DISPLAY_LOCKED:
793 0 : pkg_printf("\tPackage %n-%v is locked ", it->old, it->old);
794 0 : switch (it->solved_type) {
795 : case PKG_SOLVED_INSTALL:
796 : case PKG_SOLVED_UPGRADE:
797 : /* If it's a new install, then it
798 : * cannot have been locked yet. */
799 0 : pkg_printf("and may not be upgraded to version %v\n", it->new);
800 0 : break;
801 : case PKG_SOLVED_DELETE:
802 : case PKG_SOLVED_UPGRADE_REMOVE:
803 0 : printf("and may not be deinstalled\n");
804 32 : return;
805 : break;
806 : case PKG_SOLVED_FETCH:
807 0 : printf("but a new package can still be fetched\n");
808 0 : break;
809 : }
810 0 : break;
811 : case PKG_DISPLAY_DELETE:
812 6 : pkg_get(it->new, PKG_REASON, &why);
813 6 : pkg_printf("\t%n-%v", it->new, it->new);
814 6 : if (why != NULL)
815 0 : printf(" (%s)", why);
816 6 : printf("\n");
817 6 : break;
818 : case PKG_DISPLAY_INSTALL:
819 15 : pkg_printf("\t%n: %v", it->new, it->new);
820 15 : if (pkg_repos_total_count() > 1)
821 0 : pkg_printf(" [%N]", it->new);
822 15 : printf("\n");
823 15 : break;
824 : case PKG_DISPLAY_UPGRADE:
825 5 : pkg_printf("\t%n: %v -> %v", it->new, it->old, it->new);
826 5 : if (pkg_repos_total_count() > 1)
827 0 : pkg_printf(" [%N]", it->new);
828 5 : printf("\n");
829 5 : break;
830 : case PKG_DISPLAY_DOWNGRADE:
831 0 : pkg_printf("\t%n: %v -> %v", it->new, it->old, it->new);
832 0 : if (pkg_repos_total_count() > 1)
833 0 : pkg_printf(" [%N]", it->new);
834 0 : printf("\n");
835 0 : break;
836 : case PKG_DISPLAY_REINSTALL:
837 6 : pkg_get(it->new, PKG_REASON, &why);
838 6 : pkg_printf("\t%n-%v", it->new, it->new);
839 6 : if (pkg_repos_total_count() > 1)
840 0 : pkg_printf(" [%N]", it->new);
841 6 : if (why != NULL)
842 6 : printf(" (%s)", why);
843 6 : printf("\n");
844 6 : break;
845 : case PKG_DISPLAY_FETCH:
846 0 : humanize_number(size, sizeof(size), pkgsize, "B",
847 : HN_AUTOSCALE, HN_IEC_PREFIXES);
848 0 : humanize_number(tlsize, sizeof(size), dlsize, "B",
849 : HN_AUTOSCALE, HN_IEC_PREFIXES);
850 :
851 0 : pkg_printf("\t%n-%v ", it->new, it->new);
852 0 : printf("(%.2f%% of %s: %s)\n", ((double)100 * pkgsize) / (double)dlsize,
853 : tlsize, size);
854 0 : break;
855 : default:
856 0 : break;
857 : }
858 : }
859 :
860 :
861 : static const char* pkg_display_messages[PKG_DISPLAY_MAX + 1] = {
862 : [PKG_DISPLAY_LOCKED] = "Installed packages LOCKED",
863 : [PKG_DISPLAY_DELETE] = "Installed packages to be REMOVED",
864 : [PKG_DISPLAY_INSTALL] = "New packages to be INSTALLED",
865 : [PKG_DISPLAY_UPGRADE] = "Installed packages to be UPGRADED",
866 : [PKG_DISPLAY_DOWNGRADE] = "Installed packages to be DOWNGRADED",
867 : [PKG_DISPLAY_REINSTALL] = "Installed packages to be REINSTALLED",
868 : [PKG_DISPLAY_FETCH] = "New packages to be FETCHED",
869 : [PKG_DISPLAY_MAX] = NULL
870 : };
871 :
872 : int
873 12 : print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...)
874 : {
875 : struct pkg *new_pkg, *old_pkg;
876 12 : void *iter = NULL;
877 : char size[8];
878 : va_list ap;
879 12 : int type, displayed = 0;
880 : int64_t dlsize, oldsize, newsize;
881 : struct pkg_solved_display_item *disp[PKG_DISPLAY_MAX], *cur, *tmp;
882 12 : bool first = true;
883 :
884 12 : dlsize = oldsize = newsize = 0;
885 12 : type = pkg_jobs_type(jobs);
886 12 : memset(disp, 0, sizeof (disp));
887 :
888 56 : while (pkg_jobs_iter(jobs, &iter, &new_pkg, &old_pkg, &type))
889 32 : set_jobs_summary_pkg(jobs, new_pkg, old_pkg, type, &oldsize,
890 : &newsize, &dlsize, disp);
891 :
892 96 : for (type = 0; type < PKG_DISPLAY_MAX; type ++) {
893 84 : if (disp[type] != NULL) {
894 : /* Space between each section. */
895 20 : if (!first)
896 8 : puts("");
897 : else
898 12 : first = false;
899 20 : if (msg != NULL) {
900 12 : va_start(ap, msg);
901 12 : vprintf(msg, ap);
902 12 : va_end(ap);
903 12 : fflush(stdout);
904 12 : msg = NULL;
905 : }
906 20 : printf("%s:\n", pkg_display_messages[type]);
907 52 : DL_FOREACH_SAFE(disp[type], cur, tmp) {
908 32 : display_summary_item(cur, dlsize);
909 32 : displayed ++;
910 32 : free(cur);
911 : }
912 : }
913 : }
914 :
915 : /* Add an extra line before the size output. */
916 12 : if (oldsize != newsize || dlsize)
917 0 : puts("");
918 :
919 12 : if (oldsize > newsize) {
920 0 : humanize_number(size, sizeof(size), oldsize - newsize, "B",
921 : HN_AUTOSCALE, HN_IEC_PREFIXES);
922 0 : printf("The operation will free %s.\n", size);
923 12 : } else if (newsize > oldsize) {
924 0 : humanize_number(size, sizeof(size), newsize - oldsize, "B",
925 : HN_AUTOSCALE, HN_IEC_PREFIXES);
926 0 : printf("The process will require %s more space.\n", size);
927 : }
928 :
929 12 : if (dlsize > 0) {
930 0 : humanize_number(size, sizeof(size), dlsize, "B",
931 : HN_AUTOSCALE, HN_IEC_PREFIXES);
932 0 : printf("%s to be downloaded.\n", size);
933 : }
934 :
935 12 : return (displayed);
936 : }
937 :
938 : void
939 0 : sbuf_flush(struct sbuf *buf)
940 : {
941 0 : sbuf_finish(buf);
942 0 : printf("%s", sbuf_data(buf));
943 0 : sbuf_clear(buf);
944 0 : }
|