]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/error.c
mount.nfs: Add more debugging output around nfs_getport()
[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., 59 Temple Place - Suite 330,
20  * Boston, MA 021110-1307, 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                         pos = snprintf(tmp, (erreob - tmp),
75                                         _("RPC Error:%s"), estr);
76         }
77         return pos;
78 }
79
80 /**
81  * rpc_mount_errors - log an RPC error that occurred during a user-space mount
82  * @server: C string containing name of server we are attempting to mount
83  * @will_retry: one indicates mount will retry at some later point
84  * @bg: one indicates this is a background mount
85  *
86  * Extracts the error code from the user-space RPC library, and reports it
87  * on stderr (fg mount) or in the system log (bg mount).
88  */
89 void rpc_mount_errors(char *server, int will_retry, int bg)
90 {
91         int pos = 0;
92         char *tmp;
93         static int onlyonce = 0;
94
95         tmp = &errbuf[pos];
96         if (bg)
97                 pos = snprintf(tmp, (erreob - tmp),
98                                 _("mount to NFS server '%s' failed: "),
99                                         server);
100         else
101                 pos = snprintf(tmp, (erreob - tmp),
102                                 _("%s: mount to NFS server '%s' failed: "),
103                                         progname, server);
104
105         tmp = &errbuf[pos];
106         if (rpc_createerr.cf_stat == RPC_TIMEDOUT) {
107                 if (will_retry)
108                         pos = snprintf(tmp, (erreob - tmp),
109                                         _("timed out, retrying"));
110                 else
111                         pos = snprintf(tmp, (erreob - tmp),
112                                         _("timed out, giving up"));
113         } else {
114                 pos += rpc_strerror(pos);
115                 tmp = &errbuf[pos];
116                 if (bg) {
117                         if (will_retry)
118                                 pos = snprintf(tmp, (erreob - tmp),
119                                                 _(", retrying"));
120                         else
121                                 pos = snprintf(tmp, (erreob - tmp),
122                                                 _(", giving up"));
123                 }
124         }
125
126         if (bg) {
127                 if (onlyonce++ < 1)
128                         openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
129                 syslog(LOG_ERR, "%s", errbuf);
130         } else
131                 fprintf(stderr, "%s\n", errbuf);
132 }
133
134 /**
135  * sys_mount_errors - log an error that occurred during a mount system call
136  * @server: C string containing name of server we are attempting to mount
137  * @error: errno value to report
138  * @will_retry: one indicates mount will retry at some later point
139  * @bg: one indicates this is a background mount
140  *
141  * Passed an errno value generated by a mount system call, and reports it
142  * on stderr (fg mount) or in the system log (bg mount).
143  */
144 void sys_mount_errors(char *server, int error, int will_retry, int bg)
145 {
146         int pos = 0;
147         char *tmp;
148         static int onlyonce = 0;
149
150         tmp = &errbuf[pos];
151         if (bg)
152                 pos = snprintf(tmp, (erreob - tmp),
153                                 _("mount to NFS server '%s' failed: "),
154                                         server);
155         else
156                 pos = snprintf(tmp, (erreob - tmp),
157                                 _("%s: mount to NFS server '%s' failed: "),
158                                         progname, server);
159
160         tmp = &errbuf[pos];
161         if (error == ETIMEDOUT) {
162                 if (will_retry)
163                         pos = snprintf(tmp, (erreob - tmp),
164                                         _("timed out, retrying"));
165                 else
166                         pos = snprintf(tmp, (erreob - tmp),
167                                         _("timed out, giving up"));
168         } else {
169                 if (bg) {
170                         if (will_retry)
171                                 pos = snprintf(tmp, (erreob - tmp),
172                                                 _("%s, retrying"),
173                                                 strerror(error));
174                         else
175                                 pos = snprintf(tmp, (erreob - tmp),
176                                                 _("%s, giving up"),
177                                                 strerror(error));
178                 }
179         }
180
181         if (bg) {
182                 if (onlyonce++ < 1)
183                         openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
184                 syslog(LOG_ERR, "%s", errbuf);
185         } else
186                 fprintf(stderr, "%s\n", errbuf);
187 }
188
189 /**
190  * mount_error - report a foreground mount error
191  * @spec: C string containing the device name being mounted
192  * @mount_point: C string containing the pathname of the local mounted on dir
193  * @error: errno value to report
194  *
195  */
196 void mount_error(const char *spec, const char *mount_point, int error)
197 {
198         switch(error) {
199         case EACCES:
200                 nfs_error(_("%s: access denied by server while mounting %s"),
201                                 progname, spec);
202                 break;
203         case EINVAL:
204                 nfs_error(_("%s: an incorrect mount option was specified"), progname);
205                 break;
206         case EOPNOTSUPP:
207                 nfs_error(_("%s: requested NFS version or transport"
208                                 " protocol is not supported"),
209                                 progname);
210                 break;
211         case ENOTDIR:
212                 nfs_error(_("%s: mount point %s is not a directory"),
213                                 progname, mount_point);
214                 break;
215         case EBUSY:
216                 nfs_error(_("%s: %s is busy or already mounted"),
217                         progname, mount_point);
218                 break;
219         case ENOENT:
220                 if (spec)
221                         nfs_error(_("%s: mounting %s failed, "
222                                 "reason given by server:\n  %s"),
223                                 progname, spec, strerror(error));
224                 else
225                         nfs_error(_("%s: mount point %s does not exist"),
226                                 progname, mount_point);
227                 break;
228         case ESPIPE:
229                 rpc_mount_errors((char *)spec, 0, 0);
230                 break;
231         case EIO:
232                 nfs_error(_("%s: mount system call failed"), progname);
233                 break;
234         case EFAULT:
235                 nfs_error(_("%s: encountered unexpected error condition."),
236                                 progname);
237                 nfs_error(_("%s: please report the error to" PACKAGE_BUGREPORT),
238                                 progname);
239                 break;
240         default:
241                 nfs_error(_("%s: %s"),
242                         progname, strerror(error));
243         }
244 }
245
246 /*
247  * umount_error - report a failed umount request
248  * @err: errno value to report
249  * @dev: C string containing the pathname of the local mounted on dir
250  *
251  */
252 void umount_error(int err, const char *dev)
253 {
254         switch (err) {
255         case ENXIO:
256                 nfs_error(_("%s: %s: invalid block device"),
257                         progname, dev);
258                 break;
259         case EINVAL:
260                 nfs_error(_("%s: %s: not mounted"),
261                         progname, dev);
262                 break;
263         case EIO:
264                 nfs_error(_("%s: %s: can't write superblock"),
265                         progname, dev);
266                 break;
267         case EBUSY:
268                 nfs_error(_("%s: %s: device is busy"),
269                         progname, dev);
270                 break;
271         case ENOENT:
272                 nfs_error(_("%s: %s: not found"),
273                         progname, dev);
274                 break;
275         case EPERM:
276                 nfs_error(_("%s: %s: must be superuser to umount"),
277                         progname, dev);
278                 break;
279         case EACCES:
280                 nfs_error(_("%s: %s: block devices not permitted on fs"),
281                         progname, dev);
282                 break;
283         default:
284                 nfs_error(_("%s: %s: %s"),
285                         progname, dev, strerror(err));
286                 break;
287         }
288 }
289
290 /*
291  * We need to translate between nfs status return values and
292  * the local errno values which may not be the same.
293  *
294  * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
295  * "after #include <errno.h> the symbol errno is reserved for any use,
296  *  it cannot even be used as a struct tag or field name".
297  */
298
299 #ifndef EDQUOT
300 #define EDQUOT  ENOSPC
301 #endif
302
303 static struct {
304         enum nfsstat stat;
305         int errnum;
306 } nfs_errtbl[] = {
307         { NFS_OK,               0               },
308         { NFSERR_PERM,          EPERM           },
309         { NFSERR_NOENT,         ENOENT          },
310         { NFSERR_IO,            EIO             },
311         { NFSERR_NXIO,          ENXIO           },
312         { NFSERR_ACCES,         EACCES          },
313         { NFSERR_EXIST,         EEXIST          },
314         { NFSERR_NODEV,         ENODEV          },
315         { NFSERR_NOTDIR,        ENOTDIR         },
316         { NFSERR_ISDIR,         EISDIR          },
317 #ifdef NFSERR_INVAL
318         { NFSERR_INVAL,         EINVAL          },      /* that Sun forgot */
319 #endif
320         { NFSERR_FBIG,          EFBIG           },
321         { NFSERR_NOSPC,         ENOSPC          },
322         { NFSERR_ROFS,          EROFS           },
323         { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
324         { NFSERR_NOTEMPTY,      ENOTEMPTY       },
325         { NFSERR_DQUOT,         EDQUOT          },
326         { NFSERR_STALE,         ESTALE          },
327 #ifdef EWFLUSH
328         { NFSERR_WFLUSH,        EWFLUSH         },
329 #endif
330         /* Throw in some NFSv3 values for even more fun (HP returns these) */
331         { 71,                   EREMOTE         },
332
333         { -1,                   EIO             }
334 };
335
336 char *nfs_strerror(int stat)
337 {
338         int i;
339         static char buf[256];
340
341         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
342                 if (nfs_errtbl[i].stat == stat)
343                         return strerror(nfs_errtbl[i].errnum);
344         }
345         sprintf(buf, _("unknown nfs status return value: %d"), stat);
346         return buf;
347 }