4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2017 Peter Tribble.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
35 #define __EXTENTIONS__
46 #include <sys/param.h>
50 #include <sys/types.h>
52 #include <sys/param.h>
60 #include <instzones_api.h>
65 extern int pkginfofind(char *path
, char *pkg_dir
, char *pkginst
);
67 #define ERR_USAGE "usage:\n" \
68 "%s [-q] [-pi] [-x|l] [options] [pkg ...]\n" \
69 "%s -d device [-q] [-x|l] [options] [pkg ...]\n" \
72 " -p #select partially installed packages\n" \
73 " -i #select completely installed packages\n" \
74 " -x #extracted listing\n" \
75 " -l #long listing\n" \
76 " -r #relocation base \n" \
77 "and options may include:\n" \
78 " -c category, [category...]\n" \
79 " -a architecture\n" \
82 #define ERR_INCOMP0 "-L and -l/-x/-r flags are incompatible"
83 #define ERR_INCOMP1 "-l and -x/-r flags are not compatible"
84 #define ERR_INCOMP2 "-x and -l/-r flags are not compatible"
85 #define ERR_INCOMP3 "-r and -x/-x flags are not compatible"
86 #define ERR_NOINFO "ERROR: information for \"%s\" was not found"
87 #define ERR_NOPINFO "ERROR: No partial information for \"%s\" was found"
88 #define ERR_BADINFO "pkginfo file is corrupt or missing"
89 #define ERR_ROOT_SET "Could not set install root from the environment."
90 #define ERR_ROOT_CMD "Command line install root contends with environment."
92 /* Format for dumping package attributes in dumpinfo() */
93 #define FMT "%10s: %s\n"
94 #define SFMT "%-11.11s %-*.*s %s\n"
96 #define XFMT "%-*.*s %s\n"
98 #define nblock(size) ((size + (DEV_BSIZE - 1)) / DEV_BSIZE)
101 static char *device
= NULL
;
102 static char *parmlst
[] = {
103 "DESC", "PSTAMP", "INSTDATE", "VSTOCK", "SERIALNUM", "HOTLINE",
107 static int errflg
= 0;
108 static int qflag
= 0;
109 static int iflag
= -1;
110 static int pflag
= -1;
111 static int lflag
= 0;
112 static int Lflag
= 0;
113 static int Nflag
= 0;
114 static int xflag
= 0;
115 static int rflag
= 0; /* bug # 1081606 */
116 static struct cfent entry
;
117 static char **pkg
= NULL
;
118 static int pkgcnt
= 0;
119 static char *ckcatg
[MAXCATG
] = {NULL
};
120 static int ncatg
= 0;
121 static char *ckvers
= NULL
;
122 static char *ckarch
= NULL
;
124 static struct cfstat
{
138 static struct pkginfo info
;
140 static struct cfstat
*fpkg(char *pkginst
);
141 static int iscatg(char *list
);
142 static int selectp(char *p
);
143 static void usage(void), look_for_installed(void),
144 report(void), rdcontents(void);
145 static void pkgusage(struct cfstat
*dp
, struct cfent
*pentry
);
146 static void getinfo(struct cfstat
*dp
);
147 static void dumpinfo(struct cfstat
*dp
, int pkgLngth
);
150 main(int argc
, char **argv
)
157 /* initialize locale mechanism */
159 (void) setlocale(LC_ALL
, "");
161 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
162 #define TEXT_DOMAIN "SYS_TEST"
164 (void) textdomain(TEXT_DOMAIN
);
166 /* determine program name */
168 (void) set_prog_name(argv
[0]);
170 /* tell spmi zones interface how to access package output functions */
172 z_set_output_functions(echo
, echoDebug
, progerr
);
174 /* establish installation root directory */
176 if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
177 progerr(gettext(ERR_ROOT_SET
));
181 while ((c
= getopt(argc
, argv
, "LNR:xv:a:d:qrpilc:?")) != EOF
) {
192 /* -d could specify stream or mountable device */
193 device
= flex_device(optarg
, 1);
219 if (xflag
|| lflag
|| rflag
) {
220 progerr(gettext(ERR_INCOMP0
));
227 if (xflag
|| rflag
) {
228 progerr(gettext(ERR_INCOMP1
));
236 if (lflag
|| rflag
) {
237 progerr(gettext(ERR_INCOMP2
));
244 if (lflag
|| xflag
|| Lflag
) {
245 progerr(gettext(ERR_INCOMP0
));
252 ckcatg
[ncatg
++] = strtok(optarg
, " \t\n, ");
253 while (ckcatg
[ncatg
] = strtok(NULL
, " \t\n, "))
257 /* added for newroot functions */
259 if (!set_inst_root(optarg
)) {
260 progerr(gettext(ERR_ROOT_CMD
));
271 * implement the newroot option
273 set_PKGpaths(get_inst_root()); /* set up /var... directories */
276 * Open the install DB, if one exists.
280 pkgcnt
= (argc
- optind
);
282 if (pkg
[0] && strcmp(pkg
[0], "all") == NULL
) {
288 pkgdir
= get_PKGLOC(); /* we need this later */
290 /* convert device appropriately */
295 * If we are to inspect a spooled package we are only interested in
296 * the pkginfo file in the spooled pkg. We have a spooled pkg if
297 * device is not NULL.
300 look_for_installed();
302 if (lflag
&& strcmp(pkgdir
, get_PKGLOC()) == 0) {
303 /* look at contents file */
309 * If we are to inspect a spooled package we are only interested in
310 * the pkginfo file in the spooled pkg so we skip any Reg 4 DB
311 * lookups and use the old algorithm. We have a spooled pkg if
312 * device is not NULL.
317 (void) pkghead(NULL
);
319 return (errflg
? 1 : 0);
325 struct cfstat
*dp
, *choice
;
329 boolean_t output
= B_FALSE
;
332 choice
= (struct cfstat
*)0;
333 for (dp
= data
; dp
; dp
= dp
->next
) {
334 pkgLgth
= strlen(dp
->pkginst
);
335 if (pkgLgth
> longestPkg
)
336 longestPkg
= pkgLgth
;
338 for (dp
= data
; dp
; dp
= dp
->next
) {
339 /* get information about this package */
340 if (dp
->installed
< 0)
341 continue; /* already used */
342 if (Lflag
&& pkgcnt
) {
345 } else if (!choice
||
346 (strcmp(choice
->pkginst
, dp
->pkginst
) > 0))
350 break; /* no more packages */
352 if (pkginfo(&info
, choice
->pkginst
, ckarch
, ckvers
)) {
353 choice
->installed
= (-1);
358 * Confirm that the pkginfo file contains the
359 * required information.
361 if (info
.name
== NULL
|| *(info
.name
) == NULL
||
362 info
.arch
== NULL
|| *(info
.arch
) == NULL
||
363 info
.version
== NULL
|| *(info
.version
) == NULL
||
364 info
.catg
== NULL
|| *(info
.catg
) == NULL
) {
365 progerr(gettext(ERR_BADINFO
));
370 /* is it in an appropriate catgory? */
371 if (iscatg(info
.catg
)) {
372 choice
->installed
= (-1);
377 (choice
->partial
|| (info
.status
== PI_PARTIAL
) ||
378 (info
.status
== PI_UNKNOWN
))) {
379 /* don't include partially installed packages */
380 choice
->installed
= (-1);
384 if (!iflag
&& (info
.status
== PI_INSTALLED
)) {
385 /* don't include completely installed packages */
386 choice
->installed
= (-1);
391 dumpinfo(choice
, longestPkg
);
392 choice
->installed
= (-1);
394 i
= selectp(choice
->pkginst
);
406 /* If no package matched and no output produced set error flag */
410 /* verify that each package listed on command line was output */
411 for (i
= 0; i
< pkgcnt
; ++i
) {
416 logerr(gettext(ERR_NOPINFO
), pkg
[i
]);
418 logerr(gettext(ERR_NOINFO
), pkg
[i
]);
423 (void) pkginfo(&info
, NULL
); /* free up all memory and open fds */
427 dumpinfo(struct cfstat
*dp
, int pkgLngth
)
434 return; /* print nothing */
438 (void) puts((info
.basedir
) ? info
.basedir
: "none");
443 (void) puts(info
.pkginst
);
446 (void) printf(XFMT
, pkgLngth
, pkgLngth
, info
.pkginst
,
449 if (info
.arch
|| info
.version
) {
450 (void) printf(CFMT
, pkgLngth
, pkgLngth
, "");
452 (void) printf("(%s) ", info
.arch
);
454 (void) printf("%s", info
.version
);
460 (void) sscanf(info
.catg
, "%[^, \t\n]", category
);
462 (void) strcpy(category
, "(unknown)");
464 (void) printf(SFMT
, category
, pkgLngth
, pkgLngth
, info
.pkginst
,
469 (void) printf(FMT
, "PKGINST", info
.pkginst
);
471 (void) printf(FMT
, "NAME", info
.name
);
472 if (lflag
&& info
.catg
)
473 (void) printf(FMT
, "CATEGORY", info
.catg
);
474 if (lflag
&& info
.arch
)
475 (void) printf(FMT
, "ARCH", info
.arch
);
477 (void) printf(FMT
, "VERSION", info
.version
);
479 (void) printf(FMT
, "BASEDIR", info
.basedir
);
481 (void) printf(FMT
, "VENDOR", info
.vendor
);
483 for (i
= 0; parmlst
[i
]; ++i
) {
484 if ((pt
= pkgparam(info
.pkginst
, parmlst
[i
])) != NULL
&& *pt
)
485 (void) printf(FMT
, parmlst
[i
], pt
);
487 if (info
.status
== PI_SPOOLED
)
488 (void) printf(FMT
, "STATUS", gettext("spooled"));
489 else if (info
.status
== PI_PARTIAL
)
490 (void) printf(FMT
, "STATUS",
491 gettext("partially installed"));
492 else if (info
.status
== PI_INSTALLED
)
493 (void) printf(FMT
, "STATUS",
494 gettext("completely installed"));
496 (void) printf(FMT
, "STATUS", gettext("(unknown)"));
498 (void) pkgparam(NULL
, NULL
);
501 (void) putchar('\n');
505 if (strcmp(pkgdir
, get_PKGLOC()))
509 (void) printf(gettext("%10s: %7ld spooled pathnames\n"),
510 "FILES", dp
->spooled
);
512 (void) printf(gettext("%10s: %7ld installed pathnames\n"),
513 "FILES", dp
->installed
);
515 (void) printf(gettext("%20d partially installed pathnames\n"),
518 (void) printf(gettext("%20d shared pathnames\n"), dp
->shared
);
520 (void) printf(gettext("%20d linked files\n"), dp
->link
);
522 (void) printf(gettext("%20d directories\n"), dp
->dirs
);
524 (void) printf(gettext("%20d executables\n"), dp
->exec
);
526 (void) printf(gettext("%20d setuid/setgid executables\n"),
529 (void) printf(gettext("%20d package information files\n"),
530 dp
->info
+1); /* pkgmap counts! */
533 (void) printf(gettext("%20ld blocks used (approx)\n"),
536 (void) putchar('\n');
539 static struct cfstat
*
542 struct cfstat
*dp
, *last
;
545 last
= (struct cfstat
*)0;
547 if (strcmp(dp
->pkginst
, pkginst
) == NULL
)
552 dp
= (struct cfstat
*)calloc(1, sizeof (struct cfstat
));
554 progerr(gettext("no memory, malloc() failed"));
560 last
->next
= dp
; /* link list */
561 (void) strcpy(dp
->pkginst
, pkginst
);
575 return (0); /* no specification implies all packages */
578 return (1); /* no category specified in pkginfo is a bug */
582 if (pt
= strchr(list
, ','))
585 for (i
= 0; ckcatg
[i
]; /* void */) {
587 if (!strcasecmp(list
, ckcatg
[i
++])) {
597 list
= pt
; /* points to next one */
603 look_for_installed(void)
609 if ((dirfp
= opendir(pkgdir
)) == NULL
)
612 while (drp
= readdir(dirfp
)) {
613 if (drp
->d_name
[0] == '.')
616 if (pkgcnt
&& (selectp(drp
->d_name
) < 0))
619 if (!pkginfofind(path
, pkgdir
, drp
->d_name
))
620 continue; /* doesn't appear to be a package */
622 (void) fpkg(drp
->d_name
);
624 (void) closedir(dirfp
);
632 for (i
= 0; i
< pkgcnt
; ++i
) {
633 if (pkg
[i
] && pkgnmchk(p
, pkg
[i
], 1) == 0)
647 if (!socfile(&server
, B_TRUE
) ||
648 pkgopenfilter(server
, pkgcnt
== 1 ? pkg
[0] : NULL
) != 0)
651 /* check the contents file to look for referenced packages */
652 while ((n
= srchcfile(&entry
, "*", server
)) > 0) {
653 for (pinfo
= entry
.pinfo
; pinfo
; pinfo
= pinfo
->next
) {
654 /* see if entry is used by indicated packaged */
655 if (pkgcnt
&& (selectp(pinfo
->pkg
) < 0))
658 dp
= fpkg(pinfo
->pkg
);
659 pkgusage(dp
, &entry
);
665 * Only objects specifically tagged with '!' event
666 * character are considered "partial", everything
667 * else is considered "installed" (even server
670 switch (pinfo
->status
) {
681 char *errstr
= getErrstr();
682 progerr(gettext("bad entry read in contents file"));
683 logerr(gettext("pathname: %s"),
684 (entry
.path
&& *entry
.path
) ? entry
.path
: "Unknown");
685 logerr(gettext("problem: %s"),
686 (errstr
&& *errstr
) ? errstr
: "Unknown");
689 pkgcloseserver(server
);
693 getinfo(struct cfstat
*dp
)
696 char pkgmap
[MAXPATHLEN
];
699 (void) snprintf(pkgmap
, sizeof (pkgmap
),
700 "%s/%s/pkgmap", pkgdir
, dp
->pkginst
);
702 if (vfpOpen(&vfp
, pkgmap
, "r", VFP_NEEDNOW
) != 0) {
703 progerr(gettext("unable open \"%s\" for reading"), pkgmap
);
707 dp
->spooled
= 1; /* pkgmap counts! */
709 while ((n
= gpkgmapvfp(&entry
, vfp
)) > 0) {
711 pkgusage(dp
, &entry
);
715 char *errstr
= getErrstr();
716 progerr(gettext("bad entry read in pkgmap file"));
717 logerr(gettext("pathname: %s"),
718 (entry
.path
&& *entry
.path
) ? entry
.path
: "Unknown");
719 logerr(gettext("problem: %s"),
720 (errstr
&& *errstr
) ? errstr
: "Unknown");
724 (void) vfpClose(&vfp
);
728 pkgusage(struct cfstat
*dp
, struct cfent
*pentry
)
730 if (pentry
->ftype
== 'i') {
733 } else if (pentry
->ftype
== 'l') {
736 if ((pentry
->ftype
== 'd') || (pentry
->ftype
== 'x'))
739 /* Only collect mode stats if they would be meaningful. */
740 if (pentry
->ainfo
.mode
!= BADMODE
) {
741 if (pentry
->ainfo
.mode
& 06000)
743 if (!strchr("dxcbp", pentry
->ftype
) &&
744 (pentry
->ainfo
.mode
& 0111))
749 if (strchr("ifve", pentry
->ftype
))
750 dp
->tblks
+= nblock(pentry
->cinfo
.size
);
756 char *prog
= get_prog_name();
759 (void) fprintf(stderr
, gettext(ERR_USAGE
), prog
, prog
);