]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/error.c
83ad1d2f796a29551e5beb797966ff17e475c8e9
[nfs-utils.git] / utils / mount / error.c
1 /*
2  * error.c -- Common error handling functions
3  *
4  * Copyright (C) 2007 Oracle.  All rights reserved.
5  * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
21  *
22  * To Do:
23  *  + Proper support for internationalization
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <syslog.h>
37 #include <rpc/rpc.h>
38
39 #include "xcommon.h"
40 #include "nls.h"
41 #include "mount.h"
42 #include "error.h"
43
44 #ifdef HAVE_RPCSVC_NFS_PROT_H
45 #include <rpcsvc/nfs_prot.h>
46 #else
47 #include <linux/nfs.h>
48 #define nfsstat nfs_stat
49 #endif
50
51 extern char *progname;
52
53 static char errbuf[BUFSIZ];
54 static char *erreob = &errbuf[BUFSIZ];
55
56 /* Convert RPC errors into strings */
57 static int rpc_strerror(int spos)
58 {
59         int cf_stat = rpc_createerr.cf_stat;
60         int pos = 0, cf_errno = rpc_createerr.cf_error.re_errno;
61         char *ptr, *estr = clnt_sperrno(cf_stat);
62         char *tmp;
63
64         if (estr) {
65                 if ((ptr = index(estr, ':')))
66                         estr = ++ptr;
67
68                 tmp = &errbuf[spos];
69                 if (cf_stat == RPC_SYSTEMERROR)
70                         pos = snprintf(tmp, (erreob - tmp),
71                                         _("System Error: %s"),
72                                                 strerror(cf_errno));
73                 else {
74                         if (cf_errno) 
75                                 pos = snprintf(tmp, (erreob - tmp),
76                                         _("RPC Error:%s; errno = %s"), 
77                                         estr, strerror(cf_errno));
78                         else
79                                 pos = snprintf(tmp, (erreob - tmp),
80                                                 _("RPC Error:%s"), estr);
81                 }
82         }
83         return pos;
84 }
85
86 /**
87  * rpc_mount_errors - log an RPC error that occurred during a user-space mount
88  * @server: C string containing name of server we are attempting to mount
89  * @will_retry: one indicates mount will retry at some later point
90  * @bg: one indicates this is a background mount
91  *
92  * Extracts the error code from the user-space RPC library, and reports it
93  * on stderr (fg mount) or in the system log (bg mount).
94  */
95 void rpc_mount_errors(char *server, int will_retry, int bg)
96 {
97         int pos = 0;
98         char *tmp;
99         static int onlyonce = 0;
100
101         tmp = &errbuf[pos];
102         if (bg)
103                 pos = snprintf(tmp, (erreob - tmp),
104                                 _("mount to NFS server '%s' failed: "),
105                                         server);
106         else
107                 pos = snprintf(tmp, (erreob - tmp),
108                                 _("%s: mount to NFS server '%s' failed: "),
109                                         progname, server);
110
111         tmp = &errbuf[pos];
112         if (rpc_createerr.cf_stat == RPC_TIMEDOUT) {
113                 if (will_retry)
114                         pos = snprintf(tmp, (erreob - tmp),
115                                         _("timed out, retrying"));
116                 else
117                         pos = snprintf(tmp, (erreob - tmp),
118                                         _("timed out, giving up"));
119         } else {
120                 pos += rpc_strerror(pos);
121                 tmp = &errbuf[pos];
122                 if (bg) {
123                         if (will_retry)
124                                 pos = snprintf(tmp, (erreob - tmp),
125                                                 _(", retrying"));
126                         else
127                                 pos = snprintf(tmp, (erreob - tmp),
128                                                 _(", giving up"));
129                 }
130         }
131
132         if (bg) {
133                 if (onlyonce++ < 1)
134                         openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
135                 syslog(LOG_ERR, "%s", errbuf);
136         } else
137                 fprintf(stderr, "%s\n", errbuf);
138 }
139
140 /**
141  * sys_mount_errors - log an error that occurred during a mount system call
142  * @server: C string containing name of server we are attempting to mount
143  * @error: errno value to report
144  * @will_retry: one indicates mount will retry at some later point
145  * @bg: one indicates this is a background mount
146  *
147  * Passed an errno value generated by a mount system call, and reports it
148  * on stderr (fg mount) or in the system log (bg mount).
149  */
150 void sys_mount_errors(char *server, int error, int will_retry, int bg)
151 {
152         int pos = 0;
153         char *tmp;
154         static int onlyonce = 0;
155
156         tmp = &errbuf[pos];
157         if (bg)
158                 pos = snprintf(tmp, (erreob - tmp),
159                                 _("mount to NFS server '%s' failed: "),
160                                         server);
161         else
162                 pos = snprintf(tmp, (erreob - tmp),
163                                 _("%s: mount to NFS server '%s' failed: "),
164                                         progname, server);
165
166         tmp = &errbuf[pos];
167         if (error == ETIMEDOUT) {
168                 if (will_retry)
169                         pos = snprintf(tmp, (erreob - tmp),
170                                         _("timed out, retrying"));
171                 else
172                         pos = snprintf(tmp, (erreob - tmp),
173                                         _("timed out, giving up"));
174         } else {
175                 if (bg) {
176                         if (will_retry)
177                                 pos = snprintf(tmp, (erreob - tmp),
178                                                 _("%s, retrying"),
179                                                 strerror(error));
180                         else
181                                 pos = snprintf(tmp, (erreob - tmp),
182                                                 _("%s, giving up"),
183                                                 strerror(error));
184                 }
185         }
186
187         if (bg) {
188                 if (onlyonce++ < 1)
189                         openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
190                 syslog(LOG_ERR, "%s", errbuf);
191         } else
192                 fprintf(stderr, "%s\n", errbuf);
193 }
194
195 /**
196  * mount_error - report a foreground mount error
197  * @spec: C string containing the device name being mounted
198  * @mount_point: C string containing the pathname of the local mounted on dir
199  * @error: errno value to report
200  *
201  */
202 void mount_error(const char *spec, const char *mount_point, int error)
203 {
204         switch(error) {
205         case EACCES:
206                 nfs_error(_("%s: access denied by server while mounting %s"),
207                                 progname, spec);
208                 break;
209         case EINVAL:
210                 nfs_error(_("%s: an incorrect mount option was specified"), progname);
211                 break;
212         case EOPNOTSUPP:
213                 nfs_error(_("%s: requested NFS version or transport"
214                                 " protocol is not supported"),
215                                 progname);
216                 break;
217         case ENOTDIR:
218                 nfs_error(_("%s: mount point %s is not a directory"),
219                                 progname, mount_point);
220                 break;
221         case EBUSY:
222                 nfs_error(_("%s: %s is busy or already mounted"),
223                         progname, mount_point);
224                 break;
225         case ENOENT:
226                 if (spec)
227                         nfs_error(_("%s: mounting %s failed, "
228                                 "reason given by server:\n  %s"),
229                                 progname, spec, strerror(error));
230                 else
231                         nfs_error(_("%s: mount point %s does not exist"),
232                                 progname, mount_point);
233                 break;
234         case ESPIPE:
235                 rpc_mount_errors((char *)spec, 0, 0);
236                 break;
237         case EIO:
238                 nfs_error(_("%s: mount system call failed"), progname);
239                 break;
240         case EFAULT:
241                 nfs_error(_("%s: encountered unexpected error condition."),
242                                 progname);
243                 nfs_error(_("%s: please report the error to" PACKAGE_BUGREPORT),
244                                 progname);
245                 break;
246         default:
247                 nfs_error(_("%s: %s"),
248                         progname, strerror(error));
249         }
250 }
251
252 /*
253  * umount_error - report a failed umount request
254  * @err: errno value to report
255  * @dev: C string containing the pathname of the local mounted on dir
256  *
257  */
258 void umount_error(int err, const char *dev)
259 {
260         switch (err) {
261         case ENXIO:
262                 nfs_error(_("%s: %s: invalid block device"),
263                         progname, dev);
264                 break;
265         case EINVAL:
266                 nfs_error(_("%s: %s: not mounted"),
267                         progname, dev);
268                 break;
269         case EIO:
270                 nfs_error(_("%s: %s: can't write superblock"),
271                         progname, dev);
272                 break;
273         case EBUSY:
274                 nfs_error(_("%s: %s: device is busy"),
275                         progname, dev);
276                 break;
277         case ENOENT:
278                 nfs_error(_("%s: %s: not found"),
279                         progname, dev);
280                 break;
281         case EPERM:
282                 nfs_error(_("%s: %s: must be superuser to umount"),
283                         progname, dev);
284                 break;
285         case EACCES:
286                 nfs_error(_("%s: %s: block devices not permitted on fs"),
287                         progname, dev);
288                 break;
289         default:
290                 nfs_error(_("%s: %s: %s"),
291                         progname, dev, strerror(err));
292                 break;
293         }
294 }
295
296 /*
297  * We need to translate between nfs status return values and
298  * the local errno values which may not be the same.
299  *
300  * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
301  * "after #include <errno.h> the symbol errno is reserved for any use,
302  *  it cannot even be used as a struct tag or field name".
303  */
304
305 #ifndef EDQUOT
306 #define EDQUOT  ENOSPC
307 #endif
308
309 #define ARRAY_SIZE(x)           (sizeof(x) / sizeof((x)[0])) 
310
311 static struct {
312         enum nfsstat stat;
313         int errnum;
314 } nfs_errtbl[] = {
315         { NFS_OK,               0               },
316         { NFSERR_PERM,          EPERM           },
317         { NFSERR_NOENT,         ENOENT          },
318         { NFSERR_IO,            EIO             },
319         { NFSERR_NXIO,          ENXIO           },
320         { NFSERR_ACCES,         EACCES          },
321         { NFSERR_EXIST,         EEXIST          },
322         { NFSERR_NODEV,         ENODEV          },
323         { NFSERR_NOTDIR,        ENOTDIR         },
324         { NFSERR_ISDIR,         EISDIR          },
325 #ifdef NFSERR_INVAL
326         { NFSERR_INVAL,         EINVAL          },      /* that Sun forgot */
327 #endif
328         { NFSERR_FBIG,          EFBIG           },
329         { NFSERR_NOSPC,         ENOSPC          },
330         { NFSERR_ROFS,          EROFS           },
331         { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
332         { NFSERR_NOTEMPTY,      ENOTEMPTY       },
333         { NFSERR_DQUOT,         EDQUOT          },
334         { NFSERR_STALE,         ESTALE          },
335 #ifdef EWFLUSH
336         { NFSERR_WFLUSH,        EWFLUSH         },
337 #endif
338         /* Throw in some NFSv3 values for even more fun (HP returns these) */
339         { 71,                   EREMOTE         },
340 };
341
342 char *nfs_strerror(unsigned int stat)
343 {
344         unsigned int i;
345         static char buf[256];
346
347         for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
348                 if (nfs_errtbl[i].stat == stat)
349                         return strerror(nfs_errtbl[i].errnum);
350         }
351         sprintf(buf, _("unknown nfs status return value: %u"), stat);
352         return buf;
353 }