0
|
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 |
}
|