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