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