aboutsummaryrefslogtreecommitdiffstats
path: root/kernel4/ioctl.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>1997-10-06 21:29:59 +0000
committerH. Peter Anvin <hpa@zytor.com>1997-10-06 21:29:59 +0000
commit3b7c3119b95b43f970c8784fcc946cdc44f9e56d (patch)
tree4b1e65f09cd0529221d564d57961a5fb8d910799 /kernel4/ioctl.c
parent93aa1d55b4ffe513fb10d897dd52a09165484e4e (diff)
downloadautofs3-3b7c3119b95b43f970c8784fcc946cdc44f9e56d.tar.gz
autofs3-3b7c3119b95b43f970c8784fcc946cdc44f9e56d.tar.xz
autofs3-3b7c3119b95b43f970c8784fcc946cdc44f9e56d.zip
Added kernel v.4 code to the repository.
Diffstat (limited to 'kernel4/ioctl.c')
-rw-r--r--kernel4/ioctl.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/kernel4/ioctl.c b/kernel4/ioctl.c
new file mode 100644
index 0000000..728a6db
--- /dev/null
+++ b/kernel4/ioctl.c
@@ -0,0 +1,161 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/ioctl.c
+ *
+ * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include "autofs_i.h"
+
+/* Get/set timeout ioctl() operation */
+static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi,
+ unsigned long *p)
+{
+ int rv;
+ unsigned long ntimeout;
+
+ if ( (rv = get_user(ntimeout, p)) ||
+ (rv = put_user(sbi->exp_timeout/HZ, p)) )
+ return rv;
+
+ if ( ntimeout > ULONG_MAX/HZ )
+ sbi->exp_timeout = 0;
+ else
+ sbi->exp_timeout = ntimeout * HZ;
+
+ return 0;
+}
+
+/* Return protocol major version */
+static inline int autofs_get_protover(int *p)
+{
+ return put_user(AUTOFS_PROTO_MAJOR_VERSION, p);
+}
+
+/* Return extended protocol information */
+static inline int autofs_get_protoinfo(struct autofs_proto_info *p)
+{
+ static struct autofs_proto_info proto_info = {
+ AUTOFS_PROTO_MAJOR_VERSION,
+ AUTOFS_PROTO_MINOR_VERSION,
+ AUTOFS_PROTO_FEATURES
+ };
+
+ return copy_to_user(&proto_info, arg, sizeof(struct autofs_proto_info))
+ ? -EFAULT : 0;
+}
+
+/* Perform an expiry operation */
+static inline int autofs_expire_run(struct autofs_sb_info *sbi,
+ struct autofs_packet_expire *pkt_p)
+{
+ struct autofs_dir_ent *ent;
+ struct autofs_packet_expire pkt;
+ struct autofs_dirhash *dh = &(sbi->dirhash);
+
+ memset(&pkt,0,sizeof pkt);
+
+ pkt.hdr.body_len = sizeof(struct autofs_packet_expire_body);
+ pkt.hdr.type = autofs_ptype_expire;
+
+ if ( !sbi->exp_timeout ||
+ !(ent = autofs_expire(dh,sbi->exp_timeout)) )
+ return -EAGAIN;
+
+ pkt.body.len = ent->len;
+ memcpy(pkt.body.name, ent->name, pkt.body.len);
+
+ if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+ return -EFAULT;
+
+ autofs_update_usage(dh,ent);
+
+ return 0;
+}
+
+/*
+ * Set the mode on a directory. Since the directory may very well be
+ * hidden under a mount point, we use an ioctl() on the root directory
+ * like everything else for this; passing the inode number down.
+ */
+static inline int autofs_setdirmode(struct super_block *sb,
+ struct autofs_set_dir_mode *mode) {
+ struct autofs_set_dir_mode dm;
+ struct dentry *dent;
+ struct inode *inode;
+ enum autofs_dir_mode oldmode;
+
+ if ( copy_from_user(&dm,mode,sizeof(struct autofs_set_dir_mode))
+ != sizeof(struct autofs_set_dir_mode) )
+ return -EFAULT;
+
+ if ( (unsigned)dm.mode >= AUTOFS_DIR_MODECOUNT )
+ return -EINVARG;
+
+ if ( !(dent = autofs_ino_hash_lookup(sb->u.autofs_sb.inode_hash)) ||
+ !(inode = dent->d_inode) )
+ return -ENOENT;
+
+ if ( ! S_ISDIR(inode->i_mode) )
+ return -ENOTDIR;
+
+ oldmode = inode->u.autofs_i.dir_mode;
+ inode->u.autofs_i.dir_mode = dm.mode;
+ inode->u.autofs_i.dir_cookie = dm.cookie;
+
+ if ( oldmode == dm.mode )
+ return 0;
+
+ if ( oldmode == AUTOFS_DIR_LOCKED )
+ wake_up(&inode->u.autofs_i.dir_queue);
+
+ return 0;
+}
+
+/*
+ * ioctl()'s on the root directory is the chief method for the daemon to
+ * generate kernel actions. We allow the ioctl's on any directory, but the
+ * actions are filesystem, not inode, specific.
+ */
+int autofs_dir_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct super_block *sb = inode->i_sb;
+
+ if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+ _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+ return -ENOTTY;
+
+ if ( !autofs_oz_mode(sb) && !fsuser() )
+ return -EPERM;
+
+ switch(cmd) {
+ case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */
+ return autofs_wait_release(sb, arg, 0);
+ case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */
+ return autofs_wait_release(sb, arg, -ENOENT);
+ case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode */
+ autofs_catatonic_mode(sb);
+ return 0;
+ case AUTOFS_IOC_PROTOVER: /* Get protocol version */
+ return autofs_get_protover((int *)arg);
+ case AUTOFS_IOC_SETTIMEOUT:
+ return autofs_get_set_timeout(sb, (unsigned long *)arg);
+ case AUTOFS_IOC_EXPIRE:
+ return autofs_expire_run(sb, (struct autofs_packet_expire *)arg);
+ case AUTOFS_IOC_PROTOINFO:
+ return autofs_get_protoinfo((struct autofs_proto_info *)arg);
+ case AUTOFS_IOC_ENABLE:
+ /* Currently no "features" supported, so don't enable any */
+ return arg ? -EINVARG : 0;
+ case AUTOFS_IOC_SETDIRMODE:
+ return autofs_setdirmode(sb, (struct autofs_set_dir_mode *)arg);
+ default:
+ return -ENOSYS;
+ }
+}