xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 69800)
122705Sdist /*
268839Seric  * Copyright (c) 1983, 1995 Eric P. Allman
362525Sbostic  * Copyright (c) 1988, 1993
462525Sbostic  *	The Regents of the University of California.  All rights reserved.
533729Sbostic  *
642826Sbostic  * %sccs.include.redist.c%
733729Sbostic  */
822705Sdist 
922705Sdist #ifndef lint
10*69800Seric static char sccsid[] = "@(#)err.c	8.35 (Berkeley) 06/05/95";
1133729Sbostic #endif /* not lint */
1222705Sdist 
133311Seric # include "sendmail.h"
1424943Seric # include <errno.h>
15295Seric 
16295Seric /*
171514Seric **  SYSERR -- Print error message.
18295Seric **
19295Seric **	Prints an error message via printf to the diagnostic
20295Seric **	output.  If LOG is defined, it logs it also.
21295Seric **
2258690Seric **	If the first character of the syserr message is `!' it will
2358690Seric **	log this as an ALERT message and exit immediately.  This can
2458690Seric **	leave queue files in an indeterminate state, so it should not
2558690Seric **	be used lightly.
2658690Seric **
27295Seric **	Parameters:
2867818Seric **		fmt -- the format string.  If it does not begin with
2967818Seric **			a three-digit SMTP reply code, either 554 or
3067818Seric **			451 is assumed depending on whether errno
3167818Seric **			is set.
3267818Seric **		(others) -- parameters
33295Seric **
34295Seric **	Returns:
354084Seric **		none
367762Seric **		Through TopFrame if QuickAbort is set.
37295Seric **
38295Seric **	Side Effects:
391514Seric **		increments Errors.
401514Seric **		sets ExitStat.
41295Seric */
42295Seric 
4368692Seric char	MsgBuf[BUFSIZ*2];		/* text of most recent message */
4468692Seric char	HeldMessageBuf[sizeof MsgBuf];	/* for held messages */
454084Seric 
4669748Seric extern void	putoutmsg __P((char *, bool, bool));
4769748Seric extern void	puterrmsg __P((char *));
4869748Seric static void	fmtmsg __P((char *, const char *, const char *, int, const char *, va_list));
4946928Sbostic 
5066334Seric #if NAMED_BIND && !defined(NO_DATA)
5163969Seric # define NO_DATA	NO_ADDRESS
5263969Seric #endif
5363969Seric 
5458824Seric void
55295Seric /*VARARGS1*/
5657642Seric #ifdef __STDC__
syserr(const char * fmt,...)5760094Seric syserr(const char *fmt, ...)
5857642Seric #else
5957642Seric syserr(fmt, va_alist)
6060094Seric 	const char *fmt;
6157642Seric 	va_dcl
6257642Seric #endif
63295Seric {
6416901Seric 	register char *p;
6516901Seric 	int olderrno = errno;
6658690Seric 	bool panic;
6766006Seric #ifdef LOG
6866006Seric 	char *uname;
6966006Seric 	struct passwd *pw;
7066006Seric 	char ubuf[80];
7166006Seric #endif
7256852Seric 	VA_LOCAL_DECL
73295Seric 
7458690Seric 	panic = *fmt == '!';
7558690Seric 	if (panic)
7658690Seric 		fmt++;
7758690Seric 
787525Seric 	/* format and output the error message */
7916901Seric 	if (olderrno == 0)
8058151Seric 		p = "554";
817957Seric 	else
8258151Seric 		p = "451";
8356852Seric 	VA_START(fmt);
8456852Seric 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
8556852Seric 	VA_END;
869389Seric 	puterrmsg(MsgBuf);
874063Seric 
8867818Seric 	/* save this message for mailq printing */
8967818Seric 	if (!panic)
9067818Seric 	{
9167818Seric 		if (CurEnv->e_message != NULL)
9267818Seric 			free(CurEnv->e_message);
9367818Seric 		CurEnv->e_message = newstr(MsgBuf + 4);
9467818Seric 	}
9567818Seric 
96295Seric 	/* determine exit status if not already set */
97295Seric 	if (ExitStat == EX_OK)
98295Seric 	{
9916901Seric 		if (olderrno == 0)
100295Seric 			ExitStat = EX_SOFTWARE;
101295Seric 		else
1021598Seric 			ExitStat = EX_OSERR;
10366323Seric 		if (tTd(54, 1))
10466323Seric 			printf("syserr: ExitStat = %d\n", ExitStat);
105295Seric 	}
106295Seric 
107295Seric # ifdef LOG
10868693Seric 	pw = sm_getpwuid(getuid());
10966006Seric 	if (pw != NULL)
11066006Seric 		uname = pw->pw_name;
11166006Seric 	else
11266006Seric 	{
11366006Seric 		uname = ubuf;
11466006Seric 		sprintf(ubuf, "UID%d", getuid());
11566006Seric 	}
11666006Seric 
1177674Seric 	if (LogLevel > 0)
11866006Seric 		syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %s",
11925277Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
12066006Seric 			uname, &MsgBuf[4]);
12156795Seric # endif /* LOG */
12264725Seric 	if (olderrno == EMFILE)
12364731Seric 	{
12464725Seric 		printopenfds(TRUE);
12564731Seric 		mci_dump_all(TRUE);
12664731Seric 	}
12758690Seric 	if (panic)
12859156Seric 	{
12959156Seric #ifdef XLA
13059156Seric 		xla_all_end();
13159156Seric #endif
132*69800Seric 		if (tTd(0, 1))
133*69800Seric 			abort();
13458690Seric 		exit(EX_OSERR);
13559156Seric 	}
136295Seric 	errno = 0;
1377762Seric 	if (QuickAbort)
1387762Seric 		longjmp(TopFrame, 2);
139295Seric }
140295Seric /*
141295Seric **  USRERR -- Signal user error.
142295Seric **
143295Seric **	This is much like syserr except it is for user errors.
144295Seric **
145295Seric **	Parameters:
14667818Seric **		fmt -- the format string.  If it does not begin with
14767818Seric **			a three-digit SMTP reply code, 501 is assumed.
14867818Seric **		(others) -- printf strings
149295Seric **
150295Seric **	Returns:
1514084Seric **		none
1527762Seric **		Through TopFrame if QuickAbort is set.
153295Seric **
154295Seric **	Side Effects:
1551514Seric **		increments Errors.
156295Seric */
157295Seric 
158295Seric /*VARARGS1*/
15958824Seric void
16057642Seric #ifdef __STDC__
usrerr(const char * fmt,...)16160094Seric usrerr(const char *fmt, ...)
16257642Seric #else
16357642Seric usrerr(fmt, va_alist)
16460094Seric 	const char *fmt;
16557642Seric 	va_dcl
16657642Seric #endif
167295Seric {
16856852Seric 	VA_LOCAL_DECL
169295Seric 
170295Seric 	if (SuprErrs)
1714084Seric 		return;
172295Seric 
17356852Seric 	VA_START(fmt);
17458524Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
17556852Seric 	VA_END;
1769389Seric 	puterrmsg(MsgBuf);
1778239Seric 
17867818Seric 	/* save this message for mailq printing */
17967818Seric 	if (MsgBuf[0] == '5' || (CurEnv->e_message == NULL && MsgBuf[0] == '4'))
18067818Seric 	{
18167818Seric 		if (CurEnv->e_message != NULL)
18267818Seric 			free(CurEnv->e_message);
18367818Seric 		CurEnv->e_message = newstr(MsgBuf + 4);
18467818Seric 	}
18567818Seric 
18651951Seric # ifdef LOG
18758020Seric 	if (LogLevel > 3 && LogUsrErrs)
18851951Seric 		syslog(LOG_NOTICE, "%s: %s",
18951951Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
19051951Seric 			&MsgBuf[4]);
19156795Seric # endif /* LOG */
19251951Seric 
1937762Seric 	if (QuickAbort)
1947762Seric 		longjmp(TopFrame, 1);
1954063Seric }
1964063Seric /*
1974063Seric **  MESSAGE -- print message (not necessarily an error)
1984063Seric **
1994063Seric **	Parameters:
20059581Seric **		msg -- the message (printf fmt) -- it can begin with
20159581Seric **			an SMTP reply code.  If not, 050 is assumed.
20267818Seric **		(others) -- printf arguments
2034063Seric **
2044063Seric **	Returns:
2054063Seric **		none
2064063Seric **
2074063Seric **	Side Effects:
2084063Seric **		none.
2094063Seric */
2104063Seric 
2114084Seric /*VARARGS2*/
21258826Seric void
21357642Seric #ifdef __STDC__
message(const char * msg,...)21460094Seric message(const char *msg, ...)
21557642Seric #else
21658151Seric message(msg, va_alist)
21760094Seric 	const char *msg;
21857642Seric 	va_dcl
21957642Seric #endif
2204063Seric {
22156852Seric 	VA_LOCAL_DECL
22256852Seric 
2234711Seric 	errno = 0;
22456852Seric 	VA_START(msg);
22558151Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
22656852Seric 	VA_END;
22768692Seric 	putoutmsg(MsgBuf, FALSE, FALSE);
22867818Seric 
22967818Seric 	/* save this message for mailq printing */
23067818Seric 	if (MsgBuf[0] == '5' || (CurEnv->e_message == NULL && MsgBuf[0] == '4'))
23167818Seric 	{
23267818Seric 		if (CurEnv->e_message != NULL)
23367818Seric 			free(CurEnv->e_message);
23467818Seric 		CurEnv->e_message = newstr(MsgBuf + 4);
23567818Seric 	}
2367613Seric }
2377613Seric /*
2388239Seric **  NMESSAGE -- print message (not necessarily an error)
2398239Seric **
2408239Seric **	Just like "message" except it never puts the to... tag on.
2418239Seric **
2428239Seric **	Parameters:
2438239Seric **		msg -- the message (printf fmt) -- if it begins
24467818Seric **			with a three digit SMTP reply code, that is used,
24567818Seric **			otherwise 050 is assumed.
24667818Seric **		(others) -- printf arguments
2478239Seric **
2488239Seric **	Returns:
2498239Seric **		none
2508239Seric **
2518239Seric **	Side Effects:
2528239Seric **		none.
2538239Seric */
2548239Seric 
2558239Seric /*VARARGS2*/
25658826Seric void
25757642Seric #ifdef __STDC__
nmessage(const char * msg,...)25860094Seric nmessage(const char *msg, ...)
25957642Seric #else
26058151Seric nmessage(msg, va_alist)
26160094Seric 	const char *msg;
26257642Seric 	va_dcl
26357642Seric #endif
2648239Seric {
26556852Seric 	VA_LOCAL_DECL
26656852Seric 
2678239Seric 	errno = 0;
26856852Seric 	VA_START(msg);
26958151Seric 	fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
27056852Seric 	VA_END;
27168692Seric 	putoutmsg(MsgBuf, FALSE, FALSE);
2728239Seric }
2738239Seric /*
27463753Seric **  PUTOUTMSG -- output error message to transcript and channel
2757613Seric **
2767613Seric **	Parameters:
2777613Seric **		msg -- message to output (in SMTP format).
2789108Seric **		holdmsg -- if TRUE, don't output a copy of the message to
2799108Seric **			our output channel.
28068692Seric **		heldmsg -- if TRUE, this is a previously held message;
28168692Seric **			don't log it to the transcript file.
2827613Seric **
2837613Seric **	Returns:
2847613Seric **		none.
2857613Seric **
2867613Seric **	Side Effects:
2877613Seric **		Outputs msg to the transcript.
2887613Seric **		If appropriate, outputs it to the channel.
2897613Seric **		Deletes SMTP reply code number as appropriate.
2907613Seric */
2914711Seric 
29269748Seric void
putoutmsg(msg,holdmsg,heldmsg)29368692Seric putoutmsg(msg, holdmsg, heldmsg)
2947613Seric 	char *msg;
2959108Seric 	bool holdmsg;
29668692Seric 	bool heldmsg;
2977613Seric {
29864249Seric 	/* display for debugging */
29964249Seric 	if (tTd(54, 8))
30068692Seric 		printf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
30168692Seric 			heldmsg ? " (held)" : "");
30264249Seric 
30314900Seric 	/* output to transcript if serious */
30468692Seric 	if (!heldmsg && CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL)
30514900Seric 		fprintf(CurEnv->e_xfp, "%s\n", msg);
3064711Seric 
3074711Seric 	/* output to channel if appropriate */
30868692Seric 	if (!Verbose && msg[0] == '0')
30960421Seric 		return;
31068692Seric 	if (holdmsg)
31168692Seric 	{
31268692Seric 		/* save for possible future display */
31368692Seric 		strcpy(HeldMessageBuf, msg);
31468692Seric 		return;
31568692Seric 	}
31660421Seric 
31763848Seric 	/* map warnings to something SMTP can handle */
31863848Seric 	if (msg[0] == '6')
31963848Seric 		msg[0] = '5';
32063848Seric 
32160421Seric 	(void) fflush(stdout);
32266017Seric 
32366017Seric 	/* if DisConnected, OutChannel now points to the transcript */
32466017Seric 	if (!DisConnected &&
32566017Seric 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
32660421Seric 		fprintf(OutChannel, "%s\r\n", msg);
32760421Seric 	else
32860421Seric 		fprintf(OutChannel, "%s\n", &msg[4]);
32963753Seric 	if (TrafficLogFile != NULL)
33063753Seric 		fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(),
33165580Seric 			(OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]);
33260421Seric 	if (msg[3] == ' ')
33360421Seric 		(void) fflush(OutChannel);
33466017Seric 	if (!ferror(OutChannel) || DisConnected)
33560421Seric 		return;
33660421Seric 
33764499Seric 	/*
33864499Seric 	**  Error on output -- if reporting lost channel, just ignore it.
33964499Seric 	**  Also, ignore errors from QUIT response (221 message) -- some
34064499Seric 	**	rude servers don't read result.
34164499Seric 	*/
34264499Seric 
34364499Seric 	if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0)
34460421Seric 		return;
34560421Seric 
34660421Seric 	/* can't call syserr, 'cause we are using MsgBuf */
34760421Seric 	HoldErrs = TRUE;
34860283Seric #ifdef LOG
34960421Seric 	if (LogLevel > 0)
35060421Seric 		syslog(LOG_CRIT,
35166864Seric 			"%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
35260421Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
35364123Seric 			CurHostName == NULL ? "NO-HOST" : CurHostName,
35466864Seric 			msg, errstring(errno));
35560283Seric #endif
3569389Seric }
3579389Seric /*
35863753Seric **  PUTERRMSG -- like putoutmsg, but does special processing for error messages
3599389Seric **
3609389Seric **	Parameters:
3619389Seric **		msg -- the message to output.
3629389Seric **
3639389Seric **	Returns:
3649389Seric **		none.
3659389Seric **
3669389Seric **	Side Effects:
3679389Seric **		Sets the fatal error bit in the envelope as appropriate.
3689389Seric */
3698239Seric 
37069748Seric void
puterrmsg(msg)3719389Seric puterrmsg(msg)
3729389Seric 	char *msg;
3739389Seric {
37463848Seric 	char msgcode = msg[0];
37563848Seric 
3769389Seric 	/* output the message as usual */
37768692Seric 	putoutmsg(msg, HoldErrs, FALSE);
3789389Seric 
3799389Seric 	/* signal the error */
38064773Seric 	Errors++;
38163848Seric 	if (msgcode == '6')
38263848Seric 	{
38363848Seric 		/* notify the postmaster */
38463848Seric 		CurEnv->e_flags |= EF_PM_NOTIFY;
38563848Seric 	}
38667786Seric 	else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
38764773Seric 	{
38864773Seric 		/* mark long-term fatal errors */
38964773Seric 		CurEnv->e_flags |= EF_FATALERRS;
39064773Seric 	}
3914711Seric }
3924711Seric /*
3934711Seric **  FMTMSG -- format a message into buffer.
3944711Seric **
3954711Seric **	Parameters:
3964711Seric **		eb -- error buffer to get result.
3974711Seric **		to -- the recipient tag for this message.
3984711Seric **		num -- arpanet error number.
39916901Seric **		en -- the error number to display.
4004711Seric **		fmt -- format of string.
4014711Seric **		a, b, c, d, e -- arguments.
4024711Seric **
4034711Seric **	Returns:
4044711Seric **		none.
4054711Seric **
4064711Seric **	Side Effects:
4074711Seric **		none.
4084711Seric */
4094063Seric 
41046928Sbostic static void
fmtmsg(eb,to,num,eno,fmt,ap)41156852Seric fmtmsg(eb, to, num, eno, fmt, ap)
4124711Seric 	register char *eb;
41369748Seric 	const char *to;
41469748Seric 	const char *num;
41516904Seric 	int eno;
41669748Seric 	const char *fmt;
41756852Seric 	va_list ap;
4184711Seric {
4194711Seric 	char del;
42059596Seric 	char *meb;
4214711Seric 
4224711Seric 	/* output the reply code */
42324943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
4244577Seric 	{
4254711Seric 		num = fmt;
4264711Seric 		fmt += 4;
4274711Seric 	}
4284711Seric 	if (num[3] == '-')
4294711Seric 		del = '-';
4304711Seric 	else
4314711Seric 		del = ' ';
4324711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
4334711Seric 	eb += 4;
4344063Seric 
4359372Seric 	/* output the file name and line number */
4369372Seric 	if (FileName != NULL)
4379372Seric 	{
4389372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
4399372Seric 		eb += strlen(eb);
4409372Seric 	}
4419372Seric 
4424711Seric 	/* output the "to" person */
4434711Seric 	if (to != NULL && to[0] != '\0')
4444711Seric 	{
44566297Seric 		(void) sprintf(eb, "%s... ", shortenstring(to, 203));
4465201Seric 		while (*eb != '\0')
4475201Seric 			*eb++ &= 0177;
4484711Seric 	}
4494711Seric 
45059596Seric 	meb = eb;
45159596Seric 
4524711Seric 	/* output the message */
45356852Seric 	(void) vsprintf(eb, fmt, ap);
4545201Seric 	while (*eb != '\0')
4555201Seric 		*eb++ &= 0177;
4564711Seric 
4574711Seric 	/* output the error code, if any */
45816904Seric 	if (eno != 0)
4594711Seric 	{
46016904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
4614711Seric 		eb += strlen(eb);
4624577Seric 	}
463295Seric }
46415136Seric /*
46568692Seric **  BUFFER_ERRORS -- arrange to buffer future error messages
46668692Seric **
46768692Seric **	Parameters:
46868692Seric **		none
46968692Seric **
47068692Seric **	Returns:
47168692Seric **		none.
47268692Seric */
47368692Seric 
47468692Seric void
buffer_errors()47568692Seric buffer_errors()
47668692Seric {
47768692Seric 	HeldMessageBuf[0] = '\0';
47868692Seric 	HoldErrs = TRUE;
47968692Seric }
48068692Seric /*
48168692Seric **  FLUSH_ERRORS -- flush the held error message buffer
48268692Seric **
48368692Seric **	Parameters:
48468692Seric **		print -- if set, print the message, otherwise just
48568692Seric **			delete it.
48668692Seric **
48768692Seric **	Returns:
48868692Seric **		none.
48968692Seric */
49068692Seric 
49168692Seric void
flush_errors(print)49268692Seric flush_errors(print)
49368692Seric 	bool print;
49468692Seric {
49568692Seric 	if (print && HeldMessageBuf[0] != '\0')
49668692Seric 		putoutmsg(HeldMessageBuf, FALSE, TRUE);
49768692Seric 	HeldMessageBuf[0] = '\0';
49868692Seric 	HoldErrs = FALSE;
49968692Seric }
50068692Seric /*
50115136Seric **  ERRSTRING -- return string description of error code
50215136Seric **
50315136Seric **	Parameters:
50465751Seric **		errnum -- the error number to translate
50515136Seric **
50615136Seric **	Returns:
50765751Seric **		A string description of errnum.
50815136Seric **
50915136Seric **	Side Effects:
51015136Seric **		none.
51115136Seric */
51215136Seric 
51360089Seric const char *
errstring(errnum)51465751Seric errstring(errnum)
51565751Seric 	int errnum;
51615136Seric {
51765168Seric 	char *dnsmsg;
51863839Seric 	static char buf[MAXLINE];
51963839Seric # ifndef ERRLIST_PREDEFINED
52063839Seric 	extern char *sys_errlist[];
52115136Seric 	extern int sys_nerr;
52263839Seric # endif
52324943Seric # ifdef SMTP
52424943Seric 	extern char *SmtpPhase;
52556795Seric # endif /* SMTP */
52615136Seric 
52724943Seric 	/*
52824943Seric 	**  Handle special network error codes.
52924943Seric 	**
53024943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
53124943Seric 	*/
53224943Seric 
53365168Seric 	dnsmsg = NULL;
53465751Seric 	switch (errnum)
53524943Seric 	{
53665067Seric # if defined(DAEMON) && defined(ETIMEDOUT)
53724943Seric 	  case ETIMEDOUT:
53824943Seric 	  case ECONNRESET:
53965751Seric 		(void) strcpy(buf, sys_errlist[errnum]);
54024943Seric 		if (SmtpPhase != NULL)
54124943Seric 		{
54224943Seric 			(void) strcat(buf, " during ");
54324943Seric 			(void) strcat(buf, SmtpPhase);
54424943Seric 		}
54525050Seric 		if (CurHostName != NULL)
54624943Seric 		{
54724943Seric 			(void) strcat(buf, " with ");
54825050Seric 			(void) strcat(buf, CurHostName);
54924943Seric 		}
55024943Seric 		return (buf);
55124943Seric 
55224943Seric 	  case EHOSTDOWN:
55325050Seric 		if (CurHostName == NULL)
55424943Seric 			break;
55525050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
55624943Seric 		return (buf);
55724943Seric 
55824943Seric 	  case ECONNREFUSED:
55925050Seric 		if (CurHostName == NULL)
56024943Seric 			break;
56125050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
56224943Seric 		return (buf);
56365067Seric # endif
56425526Smiriam 
56563993Seric 	  case EOPENTIMEOUT:
56663993Seric 		return "Timeout on file open";
56763993Seric 
56866334Seric # if NAMED_BIND
56963993Seric 	  case HOST_NOT_FOUND + E_DNSBASE:
57065168Seric 		dnsmsg = "host not found";
57165168Seric 		break;
57258010Seric 
57363993Seric 	  case TRY_AGAIN + E_DNSBASE:
57465168Seric 		dnsmsg = "host name lookup failure";
57565168Seric 		break;
57658010Seric 
57763993Seric 	  case NO_RECOVERY + E_DNSBASE:
57865168Seric 		dnsmsg = "non-recoverable error";
57965168Seric 		break;
58058010Seric 
58163993Seric 	  case NO_DATA + E_DNSBASE:
58265168Seric 		dnsmsg = "no data known";
58365168Seric 		break;
58457736Seric # endif
58565067Seric 
58665067Seric 	  case EPERM:
58765067Seric 		/* SunOS gives "Not owner" -- this is the POSIX message */
58865067Seric 		return "Operation not permitted";
58924943Seric 	}
59024943Seric 
59165168Seric 	if (dnsmsg != NULL)
59265168Seric 	{
59365168Seric 		(void) strcpy(buf, "Name server: ");
59465168Seric 		if (CurHostName != NULL)
59565168Seric 		{
59665168Seric 			(void) strcat(buf, CurHostName);
59765168Seric 			(void) strcat(buf, ": ");
59865168Seric 		}
59965168Seric 		(void) strcat(buf, dnsmsg);
60065168Seric 		return buf;
60165168Seric 	}
60265168Seric 
60365751Seric 	if (errnum > 0 && errnum < sys_nerr)
60465751Seric 		return (sys_errlist[errnum]);
60515136Seric 
60665751Seric 	(void) sprintf(buf, "Error %d", errnum);
60715136Seric 	return (buf);
60815136Seric }
609