xref: /titanic_44/usr/src/tools/findunref/findunref.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Finds all unreferenced files in a source tree that do not match a list of
31*7c478bd9Sstevel@tonic-gate  * permitted pathnames.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <ctype.h>
35*7c478bd9Sstevel@tonic-gate #include <errno.h>
36*7c478bd9Sstevel@tonic-gate #include <fnmatch.h>
37*7c478bd9Sstevel@tonic-gate #include <ftw.h>
38*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
39*7c478bd9Sstevel@tonic-gate #include <stdio.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include <string.h>
42*7c478bd9Sstevel@tonic-gate #include <time.h>
43*7c478bd9Sstevel@tonic-gate #include <unistd.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * Pathname set: a simple datatype for storing pathname pattern globs and
50*7c478bd9Sstevel@tonic-gate  * for checking whether a given pathname is matched by a pattern glob in
51*7c478bd9Sstevel@tonic-gate  * the set.
52*7c478bd9Sstevel@tonic-gate  */
53*7c478bd9Sstevel@tonic-gate typedef struct {
54*7c478bd9Sstevel@tonic-gate 	char		**paths;
55*7c478bd9Sstevel@tonic-gate 	unsigned int	npath;
56*7c478bd9Sstevel@tonic-gate 	unsigned int	maxpaths;
57*7c478bd9Sstevel@tonic-gate } pnset_t;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static int	pnset_add(pnset_t *, const char *);
60*7c478bd9Sstevel@tonic-gate static int	pnset_check(const pnset_t *, const char *);
61*7c478bd9Sstevel@tonic-gate static void	pnset_empty(pnset_t *);
62*7c478bd9Sstevel@tonic-gate static int	checkpath(const char *, const struct stat *, int, struct FTW *);
63*7c478bd9Sstevel@tonic-gate static pnset_t	*make_exset(const char *);
64*7c478bd9Sstevel@tonic-gate static void	warn(const char *, ...);
65*7c478bd9Sstevel@tonic-gate static void	die(const char *, ...);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static time_t		tstamp;		/* timestamp to compare files to */
68*7c478bd9Sstevel@tonic-gate static pnset_t		*exsetp;	/* pathname globs to ignore */
69*7c478bd9Sstevel@tonic-gate static const char	*progname;
70*7c478bd9Sstevel@tonic-gate static boolean_t	allfiles = B_FALSE;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate int
73*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
74*7c478bd9Sstevel@tonic-gate {
75*7c478bd9Sstevel@tonic-gate 	int c;
76*7c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
77*7c478bd9Sstevel@tonic-gate 	char subtree[MAXPATHLEN] = "./";
78*7c478bd9Sstevel@tonic-gate 	char *tstampfile = ".build.tstamp";
79*7c478bd9Sstevel@tonic-gate 	struct stat tsstat;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	progname = strrchr(argv[0], '/');
82*7c478bd9Sstevel@tonic-gate 	if (progname == NULL)
83*7c478bd9Sstevel@tonic-gate 		progname = argv[0];
84*7c478bd9Sstevel@tonic-gate 	else
85*7c478bd9Sstevel@tonic-gate 		progname++;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "as:t:")) != EOF) {
88*7c478bd9Sstevel@tonic-gate 		switch (c) {
89*7c478bd9Sstevel@tonic-gate 		case 'a':
90*7c478bd9Sstevel@tonic-gate 			allfiles = B_TRUE;
91*7c478bd9Sstevel@tonic-gate 			break;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 		case 's':
94*7c478bd9Sstevel@tonic-gate 			(void) strlcat(subtree, optarg, MAXPATHLEN);
95*7c478bd9Sstevel@tonic-gate 			break;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 		case 't':
98*7c478bd9Sstevel@tonic-gate 			tstampfile = optarg;
99*7c478bd9Sstevel@tonic-gate 			break;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 		default:
102*7c478bd9Sstevel@tonic-gate 		case '?':
103*7c478bd9Sstevel@tonic-gate 			goto usage;
104*7c478bd9Sstevel@tonic-gate 		}
105*7c478bd9Sstevel@tonic-gate 	}
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	argc -= optind;
108*7c478bd9Sstevel@tonic-gate 	argv += optind;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	if (argc != 2) {
111*7c478bd9Sstevel@tonic-gate usage:		(void) fprintf(stderr, "usage: %s [-a] [-s subtree] "
112*7c478bd9Sstevel@tonic-gate 		    "[-t tstampfile] srcroot exceptfile\n", progname);
113*7c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	/*
117*7c478bd9Sstevel@tonic-gate 	 * Interpret a relative timestamp path as relative to srcroot.
118*7c478bd9Sstevel@tonic-gate 	 */
119*7c478bd9Sstevel@tonic-gate 	if (tstampfile[0] == '/')
120*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(path, tstampfile, MAXPATHLEN);
121*7c478bd9Sstevel@tonic-gate 	else
122*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s/%s", argv[0], tstampfile);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	if (stat(path, &tsstat) == -1)
125*7c478bd9Sstevel@tonic-gate 		die("cannot stat timestamp file \"%s\"", path);
126*7c478bd9Sstevel@tonic-gate 	tstamp = tsstat.st_mtime;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	/*
129*7c478bd9Sstevel@tonic-gate 	 * Create the exception pathname set.
130*7c478bd9Sstevel@tonic-gate 	 */
131*7c478bd9Sstevel@tonic-gate 	exsetp = make_exset(argv[1]);
132*7c478bd9Sstevel@tonic-gate 	if (exsetp == NULL)
133*7c478bd9Sstevel@tonic-gate 		die("cannot make exception pathname set\n");
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	/*
136*7c478bd9Sstevel@tonic-gate 	 * Walk the specified subtree of the tree rooted at argv[0].
137*7c478bd9Sstevel@tonic-gate 	 */
138*7c478bd9Sstevel@tonic-gate 	(void) chdir(argv[0]);
139*7c478bd9Sstevel@tonic-gate 	if (nftw(subtree, checkpath, 100, FTW_PHYS) != 0)
140*7c478bd9Sstevel@tonic-gate 		die("cannot walk tree rooted at \"%s\"\n", argv[0]);
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	pnset_empty(exsetp);
143*7c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
144*7c478bd9Sstevel@tonic-gate }
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate  * Using `exceptfile' and a built-in list of exceptions, build and return a
148*7c478bd9Sstevel@tonic-gate  * pnset_t consisting of all of the pathnames globs which are allowed to be
149*7c478bd9Sstevel@tonic-gate  * unreferenced in the source tree.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate static pnset_t *
152*7c478bd9Sstevel@tonic-gate make_exset(const char *exceptfile)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	FILE		*fp;
155*7c478bd9Sstevel@tonic-gate 	char		line[MAXPATHLEN];
156*7c478bd9Sstevel@tonic-gate 	char		*newline;
157*7c478bd9Sstevel@tonic-gate 	pnset_t		*pnsetp;
158*7c478bd9Sstevel@tonic-gate 	unsigned int	i;
159*7c478bd9Sstevel@tonic-gate 	char		*builtin[] = { "*/SCCS", "*/.del-*", "*/.make.*",
160*7c478bd9Sstevel@tonic-gate 			    "*.flg", NULL };
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	pnsetp = calloc(sizeof (pnset_t), 1);
163*7c478bd9Sstevel@tonic-gate 	if (pnsetp == NULL)
164*7c478bd9Sstevel@tonic-gate 		return (NULL);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	/*
167*7c478bd9Sstevel@tonic-gate 	 * Add the built-in exceptions.
168*7c478bd9Sstevel@tonic-gate 	 */
169*7c478bd9Sstevel@tonic-gate 	for (i = 0; builtin[i] != NULL; i++) {
170*7c478bd9Sstevel@tonic-gate 		if (pnset_add(pnsetp, builtin[i]) == 0)
171*7c478bd9Sstevel@tonic-gate 			goto fail;
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	/*
175*7c478bd9Sstevel@tonic-gate 	 * Add any exceptions from the file.
176*7c478bd9Sstevel@tonic-gate 	 */
177*7c478bd9Sstevel@tonic-gate 	fp = fopen(exceptfile, "r");
178*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
179*7c478bd9Sstevel@tonic-gate 		warn("cannot open exception file \"%s\"", exceptfile);
180*7c478bd9Sstevel@tonic-gate 		goto fail;
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != NULL) {
184*7c478bd9Sstevel@tonic-gate 		newline = strrchr(line, '\n');
185*7c478bd9Sstevel@tonic-gate 		if (newline != NULL)
186*7c478bd9Sstevel@tonic-gate 			*newline = '\0';
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 		for (i = 0; isspace(line[i]); i++)
189*7c478bd9Sstevel@tonic-gate 			;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 		if (line[i] == '#' || line[i] == '\0')
192*7c478bd9Sstevel@tonic-gate 			continue;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 		if (pnset_add(pnsetp, line) == 0) {
195*7c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
196*7c478bd9Sstevel@tonic-gate 			goto fail;
197*7c478bd9Sstevel@tonic-gate 		}
198*7c478bd9Sstevel@tonic-gate 	}
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
201*7c478bd9Sstevel@tonic-gate 	return (pnsetp);
202*7c478bd9Sstevel@tonic-gate fail:
203*7c478bd9Sstevel@tonic-gate 	pnset_empty(pnsetp);
204*7c478bd9Sstevel@tonic-gate 	free(pnsetp);
205*7c478bd9Sstevel@tonic-gate 	return (NULL);
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate /*
209*7c478bd9Sstevel@tonic-gate  * FTW callback: print `path' if it's older than `tstamp' and not in `exsetp'.
210*7c478bd9Sstevel@tonic-gate  */
211*7c478bd9Sstevel@tonic-gate static int
212*7c478bd9Sstevel@tonic-gate checkpath(const char *path, const struct stat *statp, int type,
213*7c478bd9Sstevel@tonic-gate     struct FTW *ftwp)
214*7c478bd9Sstevel@tonic-gate {
215*7c478bd9Sstevel@tonic-gate 	char sccspath[MAXPATHLEN];
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	switch (type) {
218*7c478bd9Sstevel@tonic-gate 	case FTW_F:
219*7c478bd9Sstevel@tonic-gate 		/*
220*7c478bd9Sstevel@tonic-gate 		 * Skip if the file is referenced or in the exception list.
221*7c478bd9Sstevel@tonic-gate 		 */
222*7c478bd9Sstevel@tonic-gate 		if (statp->st_atime >= tstamp || pnset_check(exsetp, path))
223*7c478bd9Sstevel@tonic-gate 			return (0);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 		/*
226*7c478bd9Sstevel@tonic-gate 		 * If not explicitly checking all files, restrict ourselves
227*7c478bd9Sstevel@tonic-gate 		 * to unreferenced files under SCCS control.
228*7c478bd9Sstevel@tonic-gate 		 */
229*7c478bd9Sstevel@tonic-gate 		if (!allfiles) {
230*7c478bd9Sstevel@tonic-gate 			(void) snprintf(sccspath, MAXPATHLEN, "%.*s/SCCS/s.%s",
231*7c478bd9Sstevel@tonic-gate 			    ftwp->base, path, path + ftwp->base);
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 			if (access(sccspath, F_OK) == -1)
234*7c478bd9Sstevel@tonic-gate 				return (0);
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 		(void) puts(path);
238*7c478bd9Sstevel@tonic-gate 		return (0);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	case FTW_D:
241*7c478bd9Sstevel@tonic-gate 		/*
242*7c478bd9Sstevel@tonic-gate 		 * Prune any directories in the exception list.
243*7c478bd9Sstevel@tonic-gate 		 */
244*7c478bd9Sstevel@tonic-gate 		if (pnset_check(exsetp, path))
245*7c478bd9Sstevel@tonic-gate 			ftwp->quit = FTW_PRUNE;
246*7c478bd9Sstevel@tonic-gate 		return (0);
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	case FTW_DNR:
249*7c478bd9Sstevel@tonic-gate 		warn("cannot read \"%s\"", path);
250*7c478bd9Sstevel@tonic-gate 		return (0);
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	case FTW_NS:
253*7c478bd9Sstevel@tonic-gate 		warn("cannot stat \"%s\"", path);
254*7c478bd9Sstevel@tonic-gate 		return (0);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	default:
257*7c478bd9Sstevel@tonic-gate 		break;
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	return (0);
261*7c478bd9Sstevel@tonic-gate }
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate /*
264*7c478bd9Sstevel@tonic-gate  * Add `path' to the pnset_t pointed to by `pnsetp'.
265*7c478bd9Sstevel@tonic-gate  */
266*7c478bd9Sstevel@tonic-gate static int
267*7c478bd9Sstevel@tonic-gate pnset_add(pnset_t *pnsetp, const char *path)
268*7c478bd9Sstevel@tonic-gate {
269*7c478bd9Sstevel@tonic-gate 	char **newpaths;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	if (pnsetp->npath == pnsetp->maxpaths) {
272*7c478bd9Sstevel@tonic-gate 		newpaths = realloc(pnsetp->paths, sizeof (const char *) *
273*7c478bd9Sstevel@tonic-gate 		    (pnsetp->maxpaths + 15));
274*7c478bd9Sstevel@tonic-gate 		if (newpaths == NULL)
275*7c478bd9Sstevel@tonic-gate 			return (0);
276*7c478bd9Sstevel@tonic-gate 		pnsetp->paths = newpaths;
277*7c478bd9Sstevel@tonic-gate 		pnsetp->maxpaths += 15;
278*7c478bd9Sstevel@tonic-gate 	}
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	pnsetp->paths[pnsetp->npath] = strdup(path);
281*7c478bd9Sstevel@tonic-gate 	if (pnsetp->paths[pnsetp->npath] == NULL)
282*7c478bd9Sstevel@tonic-gate 		return (0);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	pnsetp->npath++;
285*7c478bd9Sstevel@tonic-gate 	return (1);
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * Check `path' against the pnset_t pointed to by `pnsetp'.
290*7c478bd9Sstevel@tonic-gate  */
291*7c478bd9Sstevel@tonic-gate static int
292*7c478bd9Sstevel@tonic-gate pnset_check(const pnset_t *pnsetp, const char *path)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	unsigned int i;
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < pnsetp->npath; i++) {
297*7c478bd9Sstevel@tonic-gate 		if (fnmatch(pnsetp->paths[i], path, 0) == 0)
298*7c478bd9Sstevel@tonic-gate 			return (1);
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 	return (0);
301*7c478bd9Sstevel@tonic-gate }
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate /*
304*7c478bd9Sstevel@tonic-gate  * Empty the pnset_t pointed to by `pnsetp'.
305*7c478bd9Sstevel@tonic-gate  */
306*7c478bd9Sstevel@tonic-gate static void
307*7c478bd9Sstevel@tonic-gate pnset_empty(pnset_t *pnsetp)
308*7c478bd9Sstevel@tonic-gate {
309*7c478bd9Sstevel@tonic-gate 	while (pnsetp->npath-- != 0)
310*7c478bd9Sstevel@tonic-gate 		free(pnsetp->paths[pnsetp->npath]);
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	free(pnsetp->paths);
313*7c478bd9Sstevel@tonic-gate 	pnsetp->maxpaths = 0;
314*7c478bd9Sstevel@tonic-gate }
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */
317*7c478bd9Sstevel@tonic-gate static void
318*7c478bd9Sstevel@tonic-gate warn(const char *format, ...)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	va_list alist;
321*7c478bd9Sstevel@tonic-gate 	char *errstr = strerror(errno);
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	if (errstr == NULL)
324*7c478bd9Sstevel@tonic-gate 		errstr = "<unknown error>";
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", progname);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	va_start(alist, format);
329*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, format, alist);
330*7c478bd9Sstevel@tonic-gate 	va_end(alist);
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	if (strrchr(format, '\n') == NULL)
333*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, ": %s\n", errstr);
334*7c478bd9Sstevel@tonic-gate }
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */
337*7c478bd9Sstevel@tonic-gate static void
338*7c478bd9Sstevel@tonic-gate die(const char *format, ...)
339*7c478bd9Sstevel@tonic-gate {
340*7c478bd9Sstevel@tonic-gate 	va_list alist;
341*7c478bd9Sstevel@tonic-gate 	char *errstr = strerror(errno);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	if (errstr == NULL)
344*7c478bd9Sstevel@tonic-gate 		errstr = "<unknown error>";
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: fatal: ", progname);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	va_start(alist, format);
349*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, format, alist);
350*7c478bd9Sstevel@tonic-gate 	va_end(alist);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	if (strrchr(format, '\n') == NULL)
353*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, ": %s\n", errstr);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
356*7c478bd9Sstevel@tonic-gate }
357