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