#include <errno.h>
#include <fcntl.h>
#include <sys/mount.h>
+#include <sys/utsname.h>
#include <getopt.h>
#include <mntent.h>
#include <pwd.h>
#include "fstab.h"
#include "xcommon.h"
+#include "nls.h"
#include "mount_constants.h"
#include "nfs_paths.h"
#include "nfs4_mount.h"
#include "nfsumount.h"
#include "mount.h"
+#include "error.h"
+#include "network.h"
char *progname;
+int nfs_mount_data_version;
int nomtab;
int verbose;
int sloppy;
{ NULL, 0, 0, 0 }
};
+#define MAKE_VERSION(p,q,r) (65536 * (p) + 256 * (q) + (r))
+
+int linux_version_code(void)
+{
+ struct utsname my_utsname;
+ int p, q, r;
+
+ if (uname(&my_utsname) == 0) {
+ p = atoi(strtok(my_utsname.release, "."));
+ q = atoi(strtok(NULL, "."));
+ r = atoi(strtok(NULL, "."));
+ return MAKE_VERSION(p,q,r);
+ }
+ return 0;
+}
+
+/*
+ * Choose the version of the nfs_mount_data structure that is appropriate
+ * for the kernel that is doing the mount.
+ *
+ * NFS_MOUNT_VERSION: maximum version supported by these sources
+ * nfs_mount_data_version: maximum version supported by the running kernel
+ */
+static void discover_nfs_mount_data_version(void)
+{
+ int kernel_version = linux_version_code();
+
+ if (kernel_version) {
+ if (kernel_version < MAKE_VERSION(2, 1, 32))
+ nfs_mount_data_version = 1;
+ else if (kernel_version < MAKE_VERSION(2, 2, 18))
+ nfs_mount_data_version = 3;
+ else if (kernel_version < MAKE_VERSION(2, 3, 0))
+ nfs_mount_data_version = 4;
+ else if (kernel_version < MAKE_VERSION(2, 3, 99))
+ nfs_mount_data_version = 3;
+ else if (kernel_version < MAKE_VERSION(2, 6, 3))
+ nfs_mount_data_version = 4;
+ else
+ nfs_mount_data_version = 6;
+ }
+ if (nfs_mount_data_version > NFS_MOUNT_VERSION)
+ nfs_mount_data_version = NFS_MOUNT_VERSION;
+}
+
/* Try to build a canonical options string. */
static char * fix_opts_string (int flags, const char *extra_opts) {
const struct opt_map *om;
return new_opts;
}
-
-int add_mtab(char *fsname, char *mount_point, char *fstype, int flags, char *opts, int freq, int passno)
+static int add_mtab(char *spec, char *mount_point, char *fstype,
+ int flags, char *opts, int freq, int pass)
{
struct mntent ment;
FILE *mtab;
+ int result = EX_FILEIO;
- ment.mnt_fsname = fsname;
+ ment.mnt_fsname = spec;
ment.mnt_dir = mount_point;
ment.mnt_type = fstype;
ment.mnt_opts = fix_opts_string(flags, opts);
- ment.mnt_freq = 0;
- ment.mnt_passno= 0;
+ ment.mnt_freq = freq;
+ ment.mnt_passno = pass;
- if(flags & MS_REMOUNT) {
+ if (flags & MS_REMOUNT) {
update_mtab(ment.mnt_dir, &ment);
return 0;
}
lock_mtab();
- if ((mtab = setmntent(MOUNTED, "a+")) == NULL) {
+ if ((mtab = setmntent(MOUNTED, "a+")) == NULL) {
unlock_mtab();
- fprintf(stderr, "Can't open " MOUNTED);
- return 1;
+ nfs_error(_("Can't open mtab: %s"),
+ strerror(errno));
+ goto fail_unlock;
}
- if (addmntent(mtab, &ment) == 1) {
- endmntent(mtab);
- unlock_mtab();
- fprintf(stderr, "Can't write mount entry");
- return 1;
+ if (addmntent(mtab, &ment) == 1) {
+ nfs_error(_("Can't write mount entry to mtab: %s"),
+ strerror(errno));
+ goto fail_close;
}
- if (fchmod(fileno(mtab), 0644) == -1) {
- endmntent(mtab);
- unlock_mtab();
- fprintf(stderr, "Can't set perms on " MOUNTED);
- return 1;
+ if (fchmod(fileno(mtab), 0644) == -1) {
+ nfs_error(_("Can't set permissions on mtab: %s"),
+ strerror(errno));
+ goto fail_close;
}
- endmntent(mtab);
+ result = 0;
+fail_close:
+ endmntent(mtab);
+fail_unlock:
unlock_mtab();
- return 0;
+ return result;
}
int do_mount_syscall(char *spec, char *node, char *type, int flags, void *data)
}
}
-static void mount_error(char *mntpnt, char *node)
-{
- switch(errno) {
- case ENOTDIR:
- fprintf(stderr, "%s: mount point %s is not a directory\n",
- progname, mntpnt);
- break;
- case EBUSY:
- fprintf(stderr, "%s: %s is already mounted or busy\n",
- progname, mntpnt);
- break;
- case ENOENT:
- if (node) {
- fprintf(stderr, "%s: %s failed, reason given by server: %s\n",
- progname, node, strerror(errno));
- } else
- fprintf(stderr, "%s: mount point %s does not exist\n",
- progname, mntpnt);
- break;
- default:
- fprintf(stderr, "%s: %s\n", progname, strerror(errno));
- }
-}
static int chk_mountpoint(char *mount_point)
{
struct stat sb;
if (stat(mount_point, &sb) < 0){
- mount_error(mount_point, NULL);
+ mount_error(NULL, mount_point, errno);
return 1;
}
if (S_ISDIR(sb.st_mode) == 0){
- errno = ENOTDIR;
- mount_error(mount_point, NULL);
+ mount_error(NULL, mount_point, ENOTDIR);
return 1;
}
if (access(mount_point, X_OK) < 0) {
- mount_error(mount_point, NULL);
+ mount_error(NULL, mount_point, errno);
return 1;
}
return 0;
}
-extern u_short getport(
- struct sockaddr_in *saddr,
- u_long prog,
- u_long vers,
- u_int prot);
-
-static int probe_statd()
-{
- struct sockaddr_in addr;
- u_short port;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- port = getport(&addr, 100024, 1, IPPROTO_UDP);
-
- if (port == 0)
- return 0;
- addr.sin_port = htons(port);
-
- if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
- return 0;
-
- return 1;
-}
-
-static int start_statd()
-{
- /* If /var/run/rpc.statd.pid exists and is non-empty,
- * assume statd already running.
- * If START_STATD not defined, or defined to a non-existent file,
- * don't bother,
- * else run that file (typically a shell script)
- */
- struct stat stb;
-
- if (probe_statd())
- return 1;
-#ifdef START_STATD
- if (stat(START_STATD, &stb) ==0 &&
- S_ISREG(stb.st_mode) &&
- (stb.st_mode & S_IXUSR)) {
- system(START_STATD);
- if (probe_statd())
- return 1;
- }
-#endif
- return 0;
-}
-
int main(int argc, char *argv[])
{
int c, flags = 0, mnt_err = 1, fake = 0;
progname = basename(argv[0]);
+ discover_nfs_mount_data_version();
+
if(!strncmp(progname, "umount", strlen("umount"))) {
if(argc < 2) {
umount_usage();
if (strcmp(fs_type, "nfs4") == 0)
mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);
- else {
- int need_statd = 0;
+ else
mnt_err = nfsmount(spec, mount_point, &flags,
&extra_opts, &mount_opts,
- 0, &need_statd);
- if (!mnt_err && !fake && need_statd) {
- if (!start_statd()) {
- fprintf(stderr,
- "%s: rpc.statd is not running but is "
- "required for remote locking\n"
- " Either use \"-o nolocks\" to keep "
- "locks local, or start statd.\n",
- progname);
- exit(1);
- }
- }
- }
+ 0, fake);
if (mnt_err)
exit(EX_FAIL);
mount_opts);
if (mnt_err) {
- mount_error(mount_point, spec);
+ mount_error(spec, mount_point, errno);
exit(EX_FAIL);
}
}
if (!nomtab)
- add_mtab(spec, mount_point, fs_type,
- flags, extra_opts, 0, 0);
+ mnt_err = add_mtab(spec, mount_point, fs_type, flags, extra_opts,
+ 0, 0 /* these are always zero for NFS */ );
- return 0;
+ exit(mnt_err);
}