summaryrefslogtreecommitdiffstats
path: root/utils/mount/error.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 06:03:02 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 06:03:02 +0000
commit4897093455a2bf08f3db3a1132cc2f6f5484d77c (patch)
tree9e6373544263f003139431fb4b08f9766e1ed530 /utils/mount/error.c
parentInitial commit. (diff)
downloadnfs-utils-upstream.tar.xz
nfs-utils-upstream.zip
Adding upstream version 1:2.6.4.upstream/1%2.6.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'utils/mount/error.c')
-rw-r--r--utils/mount/error.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/utils/mount/error.c b/utils/mount/error.c
new file mode 100644
index 0000000..9ddbcc0
--- /dev/null
+++ b/utils/mount/error.c
@@ -0,0 +1,360 @@
+/*
+ * error.c -- Common error handling functions
+ *
+ * Copyright (C) 2007 Oracle. All rights reserved.
+ * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
+ *
+ * To Do:
+ * + Proper support for internationalization
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <rpc/rpc.h>
+
+#include "xcommon.h"
+#include "nls.h"
+#include "mount.h"
+#include "error.h"
+
+#ifdef HAVE_RPCSVC_NFS_PROT_H
+#include <rpcsvc/nfs_prot.h>
+#else
+#include <linux/nfs.h>
+#define nfsstat nfs_stat
+#endif
+
+extern char *progname;
+
+static char errbuf[PATH_MAX];
+static char *erreob = &errbuf[PATH_MAX];
+
+/* Convert RPC errors into strings */
+static int rpc_strerror(int spos)
+{
+ int cf_stat = rpc_createerr.cf_stat;
+ int pos = 0, cf_errno = rpc_createerr.cf_error.re_errno;
+ char *ptr, *estr = clnt_sperrno(cf_stat);
+ char *tmp;
+
+ if (estr) {
+ if ((ptr = strchr(estr, ':')))
+ estr = ++ptr;
+
+ tmp = &errbuf[spos];
+ if (cf_stat == RPC_SYSTEMERROR)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("System Error: %s"),
+ strerror(cf_errno));
+ else {
+ if (cf_errno)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("RPC Error:%s; errno = %s"),
+ estr, strerror(cf_errno));
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _("RPC Error:%s"), estr);
+ }
+ }
+ return pos;
+}
+
+/**
+ * rpc_mount_errors - log an RPC error that occurred during a user-space mount
+ * @server: C string containing name of server we are attempting to mount
+ * @will_retry: one indicates mount will retry at some later point
+ * @bg: one indicates this is a background mount
+ *
+ * Extracts the error code from the user-space RPC library, and reports it
+ * on stderr (fg mount) or in the system log (bg mount).
+ */
+void rpc_mount_errors(char *server, int will_retry, int bg)
+{
+ int pos = 0;
+ char *tmp;
+ static int onlyonce = 0;
+
+ tmp = &errbuf[pos];
+ if (bg)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("mount to NFS server '%s' failed: "),
+ server);
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _("%s: mount to NFS server '%s' failed: "),
+ progname, server);
+
+ tmp = &errbuf[pos];
+ if (rpc_createerr.cf_stat == RPC_TIMEDOUT) {
+ if (will_retry)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("timed out, retrying"));
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _("timed out, giving up"));
+ } else {
+ pos += rpc_strerror(pos);
+ tmp = &errbuf[pos];
+ if (bg) {
+ if (will_retry)
+ pos = snprintf(tmp, (erreob - tmp),
+ _(", retrying"));
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _(", giving up"));
+ }
+ }
+
+ if (bg) {
+ if (onlyonce++ < 1)
+ openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
+ syslog(LOG_ERR, "%s", errbuf);
+ } else
+ fprintf(stderr, "%s\n", errbuf);
+}
+
+/**
+ * sys_mount_errors - log an error that occurred during a mount system call
+ * @server: C string containing name of server we are attempting to mount
+ * @error: errno value to report
+ * @will_retry: one indicates mount will retry at some later point
+ * @bg: one indicates this is a background mount
+ *
+ * Passed an errno value generated by a mount system call, and reports it
+ * on stderr (fg mount) or in the system log (bg mount).
+ */
+void sys_mount_errors(char *server, int error, int will_retry, int bg)
+{
+ int pos = 0;
+ char *tmp;
+ static int onlyonce = 0;
+
+ tmp = &errbuf[pos];
+ if (bg)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("mount to NFS server '%s' failed: "),
+ server);
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _("%s: mount to NFS server '%s' failed: "),
+ progname, server);
+
+ tmp = &errbuf[pos];
+ if (error == ETIMEDOUT) {
+ if (will_retry)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("timed out, retrying"));
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _("timed out, giving up"));
+ } else {
+ if (bg) {
+ if (will_retry)
+ pos = snprintf(tmp, (erreob - tmp),
+ _("%s, retrying"),
+ strerror(error));
+ else
+ pos = snprintf(tmp, (erreob - tmp),
+ _("%s, giving up"),
+ strerror(error));
+ }
+ }
+
+ if (bg) {
+ if (onlyonce++ < 1)
+ openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
+ syslog(LOG_ERR, "%s", errbuf);
+ } else
+ fprintf(stderr, "%s\n", errbuf);
+}
+
+/**
+ * mount_error - report a foreground mount error
+ * @spec: C string containing the device name being mounted
+ * @mount_point: C string containing the pathname of the local mounted on dir
+ * @error: errno value to report
+ *
+ */
+void mount_error(const char *spec, const char *mount_point, int error)
+{
+ switch(error) {
+ case EACCES:
+ nfs_error(_("%s: access denied by server while mounting %s"),
+ progname, spec);
+ break;
+ case EINVAL:
+ nfs_error(_("%s: an incorrect mount option was specified for %s"),
+ progname, mount_point);
+ break;
+ case EOPNOTSUPP:
+ nfs_error(_("%s: requested NFS version or transport protocol is not supported for %s"),
+ progname, mount_point);
+ break;
+ case ENOTDIR:
+ if (spec)
+ nfs_error(_("%s: mount spec %s or point %s is not a directory"),
+ progname, spec, mount_point);
+ else
+ nfs_error(_("%s: mount point %s is not a directory"),
+ progname, mount_point);
+ break;
+ case EBUSY:
+ nfs_error(_("%s: %s is busy or already mounted or sharecache fail"),
+ progname, mount_point);
+ break;
+ case ENOENT:
+ if (spec)
+ nfs_error(_("%s: mounting %s failed, reason given by server: %s"),
+ progname, spec, strerror(error));
+ else
+ nfs_error(_("%s: mount point %s does not exist"),
+ progname, mount_point);
+ break;
+ case ESPIPE:
+ rpc_mount_errors((char *)spec, 0, 0);
+ break;
+ case EIO:
+ nfs_error(_("%s: mount system call failed for %s"),
+ progname, mount_point);
+ break;
+ case EFAULT:
+ nfs_error(_("%s: encountered unexpected error condition for %s."),
+ progname, mount_point);
+ nfs_error(_("%s: please report the error to" PACKAGE_BUGREPORT),
+ progname);
+ break;
+ case EALREADY:
+ /* Error message has already been provided */
+ break;
+ default:
+ nfs_error(_("%s: %s for %s on %s"),
+ progname, strerror(error), spec, mount_point);
+ }
+}
+
+/*
+ * umount_error - report a failed umount request
+ * @err: errno value to report
+ * @dev: C string containing the pathname of the local mounted on dir
+ *
+ */
+void umount_error(int err, const char *dev)
+{
+ switch (err) {
+ case ENXIO:
+ nfs_error(_("%s: %s: invalid block device"),
+ progname, dev);
+ break;
+ case EINVAL:
+ nfs_error(_("%s: %s: not mounted"),
+ progname, dev);
+ break;
+ case EIO:
+ nfs_error(_("%s: %s: can't write superblock"),
+ progname, dev);
+ break;
+ case EBUSY:
+ nfs_error(_("%s: %s: device is busy"),
+ progname, dev);
+ break;
+ case ENOENT:
+ nfs_error(_("%s: %s: not found"),
+ progname, dev);
+ break;
+ case EPERM:
+ nfs_error(_("%s: %s: must be superuser to umount"),
+ progname, dev);
+ break;
+ case EACCES:
+ nfs_error(_("%s: %s: block devices not permitted on fs"),
+ progname, dev);
+ break;
+ default:
+ nfs_error(_("%s: %s: %s"),
+ progname, dev, strerror(err));
+ break;
+ }
+}
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ *
+ * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
+ * "after #include <errno.h> the symbol errno is reserved for any use,
+ * it cannot even be used as a struct tag or field name".
+ */
+
+#ifndef EDQUOT
+#define EDQUOT ENOSPC
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static struct {
+ enum nfsstat stat;
+ int errnum;
+} nfs_errtbl[] = {
+ { NFS_OK, 0 },
+ { NFSERR_PERM, EPERM },
+ { NFSERR_NOENT, ENOENT },
+ { NFSERR_IO, EIO },
+ { NFSERR_NXIO, ENXIO },
+ { NFSERR_ACCES, EACCES },
+ { NFSERR_EXIST, EEXIST },
+ { NFSERR_NODEV, ENODEV },
+ { NFSERR_NOTDIR, ENOTDIR },
+ { NFSERR_ISDIR, EISDIR },
+#ifdef NFSERR_INVAL
+ { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
+#endif
+ { NFSERR_FBIG, EFBIG },
+ { NFSERR_NOSPC, ENOSPC },
+ { NFSERR_ROFS, EROFS },
+ { NFSERR_NAMETOOLONG, ENAMETOOLONG },
+ { NFSERR_NOTEMPTY, ENOTEMPTY },
+ { NFSERR_DQUOT, EDQUOT },
+ { NFSERR_STALE, ESTALE },
+#ifdef EWFLUSH
+ { NFSERR_WFLUSH, EWFLUSH },
+#endif
+ /* Throw in some NFSv3 values for even more fun (HP returns these) */
+ { 71, EREMOTE },
+};
+
+char *nfs_strerror(unsigned int stat)
+{
+ unsigned int i;
+ static char buf[256];
+
+ for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
+ if (nfs_errtbl[i].stat == stat)
+ return strerror(nfs_errtbl[i].errnum);
+ }
+ sprintf(buf, _("unknown nfs status return value: %u"), stat);
+ return buf;
+}