diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 06:03:02 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 06:03:02 +0000 |
commit | 4897093455a2bf08f3db3a1132cc2f6f5484d77c (patch) | |
tree | 9e6373544263f003139431fb4b08f9766e1ed530 /utils/mount/error.c | |
parent | Initial commit. (diff) | |
download | nfs-utils-4897093455a2bf08f3db3a1132cc2f6f5484d77c.tar.xz nfs-utils-4897093455a2bf08f3db3a1132cc2f6f5484d77c.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.c | 360 |
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; +} |