show.c revision 228990
1/*
2 * FreeBSD install - a package for the installation and maintenance
3 * of non-core utilities.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * Jordan K. Hubbard
15 * 23 Aug 1993
16 *
17 * Various display routines for the info module.
18 *
19 */
20
21#include <sys/cdefs.h>
22__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/info/show.c 228990 2011-12-30 10:58:14Z uqs $");
23
24#include "lib.h"
25#include "info.h"
26#include <err.h>
27#include <stdlib.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <md5.h>
31
32void
33show_file(const char *title, const char *fname)
34{
35    FILE *fp;
36    char line[1024];
37    int n;
38
39    if (!Quiet)
40	printf("%s%s", InfoPrefix, title);
41    fp = fopen(fname, "r");
42    if (fp == (FILE *) NULL)
43	printf("ERROR: show_file: Can't open '%s' for reading!\n", fname);
44    else {
45	int append_nl = 0;
46	while ((n = fread(line, 1, 1024, fp)) != 0)
47	    fwrite(line, 1, n, stdout);
48	fclose(fp);
49	append_nl = (line[n - 1] != '\n');	/* Do we have a trailing \n ? */
50	if (append_nl)
51	   printf("\n");
52    }
53    printf("\n");	/* just in case */
54}
55
56void
57show_index(const char *title, const char *fname)
58{
59    FILE *fp;
60    char line[MAXINDEXSIZE+2];
61
62    strlcpy(line, "???\n", sizeof(line));
63
64    if (!Quiet)
65        printf("%s%s", InfoPrefix, title);
66    fp = fopen(fname, "r");
67    if (fp == (FILE *) NULL) {
68        warnx("show_file: can't open '%s' for reading", fname);
69    } else {
70    	if(fgets(line, MAXINDEXSIZE + 1, fp)) {
71		size_t line_length = strlen(line);
72
73		if (line[line_length - 1] != '\n') {	/* Do we have a trailing \n ? */
74			line[line_length] = '\n';	/* Add a trailing \n */
75			line[line_length + 1] = '\0';	/* Terminate string */
76		}
77	}
78	fclose(fp);
79    }
80    fputs(line, stdout);
81}
82
83/* Show a packing list item type.  If showall is TRUE, show all */
84void
85show_plist(const char *title, Package *plist, plist_t type, Boolean showall)
86{
87    PackingList p;
88    Boolean ign = FALSE;
89    char *prefix = NULL;
90
91    if (!Quiet)
92	printf("%s%s", InfoPrefix, title);
93    p = plist->head;
94    while (p) {
95	if (p->type != type && showall != TRUE) {
96	    p = p->next;
97	    continue;
98	}
99	switch(p->type) {
100	case PLIST_FILE:
101	    if (ign) {
102		printf(Quiet ? "%s\n" : "File: %s (ignored)\n", p->name);
103		ign = FALSE;
104	    }
105	    else
106		printf(Quiet ? "%s\n" : "File: %s\n", p->name);
107	    break;
108
109	case PLIST_CWD:
110	    if (!prefix)
111		prefix = p->name;
112	    printf(Quiet ? "@cwd %s\n" : "\tCWD to %s\n", (p->name == NULL) ? prefix : p->name);
113	    break;
114
115	case PLIST_SRC:
116	    printf(Quiet ? "@srcdir %s\n" : "\tSRCDIR to %s\n", p->name);
117	    break;
118
119	case PLIST_CMD:
120	    printf(Quiet ? "@exec %s\n" : "\tEXEC '%s'\n", p->name);
121	    break;
122
123	case PLIST_UNEXEC:
124	    printf(Quiet ? "@unexec %s\n" : "\tUNEXEC '%s'\n", p->name);
125	    break;
126
127	case PLIST_CHMOD:
128	    printf(Quiet ? "@chmod %s\n" : "\tCHMOD to %s\n",
129		   p->name ? p->name : "(clear default)");
130	    break;
131
132	case PLIST_CHOWN:
133	    printf(Quiet ? "@chown %s\n" : "\tCHOWN to %s\n",
134		   p->name ? p->name : "(clear default)");
135	    break;
136
137	case PLIST_CHGRP:
138	    printf(Quiet ? "@chgrp %s\n" : "\tCHGRP to %s\n",
139		   p->name ? p->name : "(clear default)");
140	    break;
141
142	case PLIST_COMMENT:
143	    printf(Quiet ? "@comment %s\n" : "\tComment: %s\n", p->name);
144	    break;
145
146	case PLIST_NOINST:
147	    printf(Quiet ? "@noinst %s\n" : "\tNot installed: %s\n", p->name);
148	    break;
149
150	case PLIST_IGNORE:
151	    ign = TRUE;
152	    break;
153
154	case PLIST_IGNORE_INST:
155	    printf(Quiet ? "@ignore_inst ??? doesn't belong here.\n" :
156		   "\tIgnore next file installation directive (doesn't belong)\n");
157	    ign = TRUE;
158	    break;
159
160	case PLIST_NAME:
161	    printf(Quiet ? "@name %s\n" : "\tPackage name: %s\n", p->name);
162	    break;
163
164	case PLIST_DISPLAY:
165	    printf(Quiet ? "@display %s\n" : "\tInstall message file: %s\n", p->name);
166	    break;
167
168	case PLIST_PKGDEP:
169	    printf(Quiet ? "@pkgdep %s\n" : "Dependency: %s\n", p->name);
170	    break;
171
172	case PLIST_DEPORIGIN:
173	    printf(Quiet ? "@comment DEPORIGIN:%s\n" :
174		"\tdependency origin: %s\n", p->name);
175	    break;
176
177	case PLIST_CONFLICTS:
178	    printf(Quiet ? "@conflicts %s\n" : "Conflicts: %s\n", p->name);
179	    break;
180
181	case PLIST_MTREE:
182	    printf(Quiet ? "@mtree %s\n" : "\tPackage mtree file: %s\n", p->name);
183	    break;
184
185	case PLIST_DIR_RM:
186	    printf(Quiet ? "@dirrm %s\n" : "\tDeinstall directory remove: %s\n", p->name);
187	    break;
188
189	case PLIST_OPTION:
190	    printf(Quiet ? "@option %s\n" :
191		"\tOption \"%s\" controlling package installation behaviour\n",
192		p->name);
193	    break;
194
195	case PLIST_ORIGIN:
196	    printf(Quiet ? "@comment ORIGIN:%s\n" :
197		"\tPackage origin: %s\n", p->name);
198	    break;
199
200	default:
201	    cleanup(0);
202	    errx(2, "%s: unknown command type %d (%s)",
203		__func__, p->type, p->name);
204	    break;
205	}
206	p = p->next;
207    }
208}
209
210static const char *
211elide_root(const char *dir)
212{
213    if (strcmp(dir, "/") == 0)
214	return "";
215    return dir;
216}
217
218/* Show all files in the packing list (except ignored ones) */
219void
220show_files(const char *title, Package *plist)
221{
222    PackingList p;
223    Boolean ign = FALSE;
224    char *prefix = NULL;
225    const char *dir = ".";
226
227    if (!Quiet)
228	printf("%s%s", InfoPrefix, title);
229    p = plist->head;
230    while (p) {
231	switch(p->type) {
232	case PLIST_FILE:
233	    if (!ign)
234		printf("%s/%s\n", elide_root(dir), p->name);
235	    ign = FALSE;
236	    break;
237
238	case PLIST_CWD:
239	    if (!prefix)
240		prefix = p->name;
241	    if (p->name == NULL)
242		dir = prefix;
243	    else
244		dir = p->name;
245	    break;
246
247	case PLIST_IGNORE:
248	    ign = TRUE;
249	    break;
250
251        /* Silence GCC in the -Wall mode */
252	default:
253	    break;
254	}
255	p = p->next;
256    }
257}
258
259/* Calculate and show size of all installed package files (except ignored ones) */
260void
261show_size(const char *title, Package *plist)
262{
263    PackingList p;
264    Boolean ign = FALSE;
265    const char *dir = ".";
266    struct stat sb;
267    char tmp[FILENAME_MAX];
268    unsigned long size = 0;
269    long blksize;
270    int headerlen;
271    char *descr;
272    char *prefix = NULL;
273
274    descr = getbsize(&headerlen, &blksize);
275    if (!Quiet)
276	printf("%s%s", InfoPrefix, title);
277    for (p = plist->head; p != NULL; p = p->next) {
278	switch (p->type) {
279	case PLIST_FILE:
280	    if (!ign) {
281		snprintf(tmp, FILENAME_MAX, "%s/%s", elide_root(dir), p->name);
282		if (!lstat(tmp, &sb)) {
283		    size += sb.st_size;
284		    if (Verbose)
285			printf("%lu\t%s\n", (unsigned long) howmany(sb.st_size, blksize), tmp);
286		}
287	    }
288	    ign = FALSE;
289	    break;
290
291	case PLIST_CWD:
292	    if (!prefix)
293		prefix = p->name;
294	    if (p->name == NULL)
295		dir = prefix;
296	    else
297		dir = p->name;
298	    break;
299
300	case PLIST_IGNORE:
301	    ign = TRUE;
302	    break;
303
304	/* Silence GCC in the -Wall mode */
305	default:
306	    break;
307	}
308    }
309    if (!Quiet)
310	printf("%lu\t(%s)\n", howmany(size, blksize), descr);
311    else
312	if (UseBlkSz)
313		printf("%lu\n", howmany(size, blksize));
314	else
315		printf("%lu\n", size);
316}
317
318/* Show files that don't match the recorded checksum */
319void
320show_cksum(const char *title, Package *plist)
321{
322    PackingList p;
323    const char *dir = ".";
324    char *prefix = NULL;
325    char tmp[FILENAME_MAX];
326
327    if (!Quiet)
328	printf("%s%s", InfoPrefix, title);
329
330    for (p = plist->head; p != NULL; p = p->next)
331	if (p->type == PLIST_CWD) {
332	    if (!prefix)
333		prefix = p->name;
334	    if (p->name == NULL)
335		dir = prefix;
336	    else
337		dir = p->name;
338	} else if (p->type == PLIST_FILE) {
339	    snprintf(tmp, FILENAME_MAX, "%s/%s", elide_root(dir), p->name);
340	    if (!fexists(tmp))
341		warnx("%s doesn't exist", tmp);
342	    else if (p->next && p->next->type == PLIST_COMMENT &&
343	             (strncmp(p->next->name, "MD5:", 4) == 0)) {
344		char *cp = NULL, buf[33];
345
346		/*
347		 * For packing lists whose version is 1.1 or greater, the md5
348		 * hash for a symlink is calculated on the string returned
349		 * by readlink().
350		 */
351		if (issymlink(tmp) && verscmp(plist, 1, 0) > 0) {
352		    int len;
353		    char linkbuf[FILENAME_MAX];
354
355		    if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
356			cp = MD5Data((unsigned char *)linkbuf, len, buf);
357		} else if (isfile(tmp) || verscmp(plist, 1, 1) < 0)
358		    cp = MD5File(tmp, buf);
359
360		if (cp != NULL) {
361		    /* Mismatch? */
362		    if (strcmp(cp, p->next->name + 4))
363			printf("%s fails the original MD5 checksum\n", tmp);
364		    else if (Verbose)
365			printf("%s matched the original MD5 checksum\n", tmp);
366		}
367	    }
368	}
369}
370
371/* Show an "origin" path (usually category/portname) */
372void
373show_origin(const char *title, Package *plist)
374{
375
376    if (!Quiet)
377	printf("%s%s", InfoPrefix, title);
378    printf("%s\n", plist->origin != NULL ? plist->origin : "");
379}
380
381/* Show revision number of the packing list */
382void
383show_fmtrev(const char *title, Package *plist)
384{
385
386    if (!Quiet)
387	printf("%s%s", InfoPrefix, title);
388    printf("%d.%d\n", plist->fmtver_maj, plist->fmtver_mnr);
389}
390