1/*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include "lint.h"
27#include "file64.h"
28#include "mtlib.h"
29#include "thr_uberdata.h"
30#include <sys/types.h>
31#include <err.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdarg.h>
35#include <string.h>
36#include <errno.h>
37#include <dlfcn.h>
38#include "stdiom.h"
39
40/* Function exit/warning functions and global variables. */
41
42const char *__progname;		/* GNU/Linux/BSD compatibility */
43
44#define	PROGNAMESIZE	128	/* buffer size for __progname */
45
46const char *
47getprogname(void)
48{
49	return (__progname);
50}
51
52void
53setprogname(const char *argv0)
54{
55	uberdata_t *udp = curthread->ul_uberdata;
56	const char *progname;
57
58	if ((progname = strrchr(argv0, '/')) == NULL)
59		progname = argv0;
60	else
61		progname++;
62
63	if (udp->progname == NULL)
64		udp->progname = lmalloc(PROGNAMESIZE);
65	(void) strlcpy(udp->progname, progname, PROGNAMESIZE);
66	__progname = udp->progname;
67}
68
69/* called only from libc_init() */
70void
71init_progname(void)
72{
73	Dl_argsinfo_t args;
74	const char *argv0;
75
76	if (dlinfo(RTLD_SELF, RTLD_DI_ARGSINFO, &args) < 0 ||
77	    args.dla_argc <= 0 ||
78	    (argv0 = args.dla_argv[0]) == NULL)
79		argv0 = "UNKNOWN";
80
81	setprogname(argv0);
82}
83
84/*
85 * warncore() is the workhorse of these functions.  Everything else has
86 * a warncore() component in it.
87 */
88static rmutex_t *
89warncore(FILE *fp, const char *fmt, va_list args)
90{
91	rmutex_t *lk;
92
93	FLOCKFILE(lk, fp);
94
95	if (__progname != NULL)
96		(void) fprintf(fp, "%s: ", __progname);
97
98	if (fmt != NULL) {
99		(void) vfprintf(fp, fmt, args);
100	}
101
102	return (lk);
103}
104
105/* Finish a warning with a newline and a flush of stderr. */
106static void
107warnfinish(FILE *fp, rmutex_t *lk)
108{
109	(void) fputc('\n', fp);
110	(void) fflush(fp);
111	FUNLOCKFILE(lk);
112}
113
114void
115_vwarnxfp(FILE *fp, const char *fmt, va_list args)
116{
117	rmutex_t *lk;
118
119	lk = warncore(fp, fmt, args);
120	warnfinish(fp, lk);
121}
122
123void
124vwarnx(const char *fmt, va_list args)
125{
126	_vwarnxfp(stderr, fmt, args);
127}
128
129void
130_vwarnfp(FILE *fp, const char *fmt, va_list args)
131{
132	int tmperr = errno;	/* Capture errno now. */
133	rmutex_t *lk;
134
135	lk = warncore(fp, fmt, args);
136	if (fmt != NULL) {
137		(void) fputc(':', fp);
138		(void) fputc(' ', fp);
139	}
140	(void) fputs(strerror(tmperr), fp);
141	warnfinish(fp, lk);
142}
143
144void
145vwarn(const char *fmt, va_list args)
146{
147	_vwarnfp(stderr, fmt, args);
148}
149
150/* PRINTFLIKE1 */
151void
152warnx(const char *fmt, ...)
153{
154	va_list args;
155
156	va_start(args, fmt);
157	vwarnx(fmt, args);
158	va_end(args);
159}
160
161void
162_warnfp(FILE *fp, const char *fmt, ...)
163{
164	va_list args;
165
166	va_start(args, fmt);
167	_vwarnfp(fp, fmt, args);
168	va_end(args);
169}
170
171void
172_warnxfp(FILE *fp, const char *fmt, ...)
173{
174	va_list args;
175
176	va_start(args, fmt);
177	_vwarnxfp(fp, fmt, args);
178	va_end(args);
179}
180
181/* PRINTFLIKE1 */
182void
183warn(const char *fmt, ...)
184{
185	va_list args;
186
187	va_start(args, fmt);
188	vwarn(fmt, args);
189	va_end(args);
190}
191
192/* PRINTFLIKE2 */
193void
194err(int status, const char *fmt, ...)
195{
196	va_list args;
197
198	va_start(args, fmt);
199	vwarn(fmt, args);
200	va_end(args);
201	exit(status);
202}
203
204void
205_errfp(FILE *fp, int status, const char *fmt, ...)
206{
207	va_list args;
208
209	va_start(args, fmt);
210	_vwarnfp(fp, fmt, args);
211	va_end(args);
212	exit(status);
213}
214
215void
216verr(int status, const char *fmt, va_list args)
217{
218	vwarn(fmt, args);
219	exit(status);
220}
221
222void
223_verrfp(FILE *fp, int status, const char *fmt, va_list args)
224{
225	_vwarnfp(fp, fmt, args);
226	exit(status);
227}
228
229/* PRINTFLIKE2 */
230void
231errx(int status, const char *fmt, ...)
232{
233	va_list args;
234
235	va_start(args, fmt);
236	vwarnx(fmt, args);
237	va_end(args);
238	exit(status);
239}
240
241void
242_errxfp(FILE *fp, int status, const char *fmt, ...)
243{
244	va_list args;
245
246	va_start(args, fmt);
247	_vwarnxfp(fp, fmt, args);
248	va_end(args);
249	exit(status);
250}
251
252void
253verrx(int status, const char *fmt, va_list args)
254{
255	vwarnx(fmt, args);
256	exit(status);
257}
258
259void
260_verrxfp(FILE *fp, int status, const char *fmt, va_list args)
261{
262	_vwarnxfp(fp, fmt, args);
263	exit(status);
264}
265