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