xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_strerror.c (revision d583b39bfb4e2571d3e41097c5c357ffe353ad45)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file contains code to support better NFS error messages.  Death to
31  * integer codes in user error messages!
32  *
33  * XXX Ideally this code should be more general and available to the entire
34  * kernel (see RFE 1101936).  When this happens, this file can go away.
35  */
36 
37 #include <nfs/nfs.h>
38 #include <sys/systm.h>
39 #include <sys/cmn_err.h>
40 #include <sys/errno.h>
41 #include <sys/varargs.h>
42 
43 #ifndef NULL
44 #define	NULL	0
45 #endif
46 
47 /* size of a temporary printf format buffer. */
48 #define	FMT_BUF_SIZE	1024
49 
50 static void expand_format_string(int, const char *, char *, int);
51 static char *nfs_strerror(int);
52 
53 /*
54  * nfs_perror: Works like printf (format string and variable args) except
55  * that it will substitute an error message for a "%m" string (like
56  * syslog), using the given errno value.
57  */
58 
59 void
60 nfs_perror(int error, char *fmt, ...)
61 {
62 	va_list ap;
63 	char buf[FMT_BUF_SIZE];		/* massaged version of fmt */
64 
65 	/* Expand %m */
66 
67 	expand_format_string(error, fmt, buf, FMT_BUF_SIZE);
68 
69 	/*
70 	 * Now pass the massaged format string and its arguments off to
71 	 * printf.
72 	 */
73 
74 	va_start(ap, fmt);
75 	(void) vzprintf(getzoneid(), buf, ap);
76 	va_end(ap);
77 }
78 
79 /*
80  * nfs_cmn_err: Works like cmn_err (error level, format string, and
81  * variable args) except that it will substitute an error message for a
82  * "%m" string (like syslog), using the given errno value.
83  */
84 
85 void
86 nfs_cmn_err(int error, int level, char *fmt, ...)
87 {
88 	va_list ap;
89 	char buf[FMT_BUF_SIZE];		/* massaged version of fmt */
90 
91 	/* Expand %m */
92 
93 	expand_format_string(error, fmt, buf, FMT_BUF_SIZE);
94 
95 	/*
96 	 * Now pass the massaged format string and its arguments off to
97 	 * cmn_err.
98 	 */
99 
100 	va_start(ap, fmt);
101 	(void) vzcmn_err(getzoneid(), level, buf, ap);
102 	va_end(ap);
103 }
104 
105 /*
106  * expand_format_string: copy the printf format string from "fmt" to "buf",
107  * expanding %m to the error string for "error".
108  */
109 
110 static void
111 expand_format_string(int error, const char *fmt, char *buf, int buf_chars)
112 {
113 	const char *from;		/* pointer into fmt */
114 	char *to;			/* pointer into buf */
115 	char *errmsg;			/* expansion for %m */
116 	char *trunc_msg = "Truncated NFS error message: ";
117 	zoneid_t zoneid = getzoneid();
118 
119 	/*
120 	 * Copy the given format string into the result buffer, expanding
121 	 * %m as we go.  If the result buffer is too short, complain and
122 	 * truncate the message.  (We don't expect this to ever happen,
123 	 * though.)
124 	 */
125 
126 	for (from = fmt, to = buf; *from; from++) {
127 		if (to >= buf + buf_chars - 1) {
128 			zprintf(zoneid, trunc_msg);
129 			break;
130 		}
131 		if (*from == '%' && *(from+1) == 'm') {
132 			errmsg = nfs_strerror(error);
133 			/*
134 			 * If there's an error message and room to display
135 			 * it, copy it in.  If there's no message or not
136 			 * enough room, try just printing an error number.
137 			 * (We assume that the error value is in a
138 			 * reasonable range.)  If there's no room for
139 			 * anything, bail out.
140 			 */
141 			if (errmsg != NULL &&
142 			    strlen(buf) + strlen(errmsg) < buf_chars) {
143 				(void) strcpy(to, errmsg);
144 				to += strlen(errmsg);
145 			} else if (strlen(buf) + strlen("error XXX") <
146 			    buf_chars) {
147 				(void) sprintf(to, "error %d", error);
148 				/*
149 				 * Don't try to guess how many characters
150 				 * were laid down.
151 				 */
152 				to = buf + strlen(buf);
153 			} else {
154 				zprintf(zoneid, trunc_msg);
155 				break;
156 			}
157 			from++;
158 		} else {
159 			*to++ = *from;
160 		}
161 	}
162 	*to = '\0';
163 }
164 
165 /*
166  * nfs_strerror: map an errno value to a string.  Not all possible errno
167  * values are supported.
168  *
169  * If there is no string for the given errno value, return NULL.
170  */
171 
172 static char *
173 nfs_strerror(int errcode)
174 {
175 	char *result;
176 
177 	switch (errcode) {
178 	case EPERM:
179 		result = "Not owner";
180 		break;
181 	case ENOENT:
182 		result = "No such file or directory";
183 		break;
184 	case EIO:
185 		result = "I/O error";
186 		break;
187 	case EACCES:
188 		result = "Permission denied";
189 		break;
190 	case EEXIST:
191 		result = "File exists";
192 		break;
193 	case ENOTDIR:
194 		result = "Not a directory";
195 		break;
196 	case EISDIR:
197 		result = "Is a directory";
198 		break;
199 	case EINVAL:
200 		result = "Invalid argument";
201 		break;
202 	case EFBIG:
203 		result = "File too large";
204 		break;
205 	case ENOSPC:
206 		result = "No space left on device";
207 		break;
208 	case EROFS:
209 		result = "Read-only file system";
210 		break;
211 	case EDQUOT:
212 		result = "Disc quota exceeded";
213 		break;
214 	case ENOTEMPTY:
215 		result = "Directory not empty";
216 		break;
217 	case ESTALE:
218 		result = "Stale NFS file handle";
219 		break;
220 	case ENOMEM:
221 		result = "Not enough memory";
222 		break;
223 	default:
224 		result = NULL;
225 		break;
226 	}
227 
228 	return (result);
229 }
230