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