1/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 Exp $ 2 * 3 * Copyright 2000 by Carsten Paeth <calle@calle.de> 4 * 5 * Heavily based on devpts filesystem from H. Peter Anvin 6 * 7 * This software may be used and distributed according to the terms 8 * of the GNU General Public License, incorporated herein by reference. 9 * 10 */ 11 12#include <linux/fs.h> 13#include <linux/mount.h> 14#include <linux/slab.h> 15#include <linux/namei.h> 16#include <linux/module.h> 17#include <linux/init.h> 18#include <linux/ctype.h> 19#include <linux/sched.h> /* current */ 20 21#include "capifs.h" 22 23MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); 24MODULE_AUTHOR("Carsten Paeth"); 25MODULE_LICENSE("GPL"); 26 27/* ------------------------------------------------------------------ */ 28 29#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') 30 31static struct vfsmount *capifs_mnt; 32static int capifs_mnt_count; 33 34static struct { 35 int setuid; 36 int setgid; 37 uid_t uid; 38 gid_t gid; 39 umode_t mode; 40} config = {.mode = 0600}; 41 42/* ------------------------------------------------------------------ */ 43 44static int capifs_remount(struct super_block *s, int *flags, char *data) 45{ 46 int setuid = 0; 47 int setgid = 0; 48 uid_t uid = 0; 49 gid_t gid = 0; 50 umode_t mode = 0600; 51 char *this_char; 52 char *new_opt = kstrdup(data, GFP_KERNEL); 53 54 this_char = NULL; 55 while ((this_char = strsep(&data, ",")) != NULL) { 56 int n; 57 char dummy; 58 if (!*this_char) 59 continue; 60 if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) { 61 setuid = 1; 62 uid = n; 63 } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) { 64 setgid = 1; 65 gid = n; 66 } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) 67 mode = n & ~S_IFMT; 68 else { 69 kfree(new_opt); 70 printk("capifs: called with bogus options\n"); 71 return -EINVAL; 72 } 73 } 74 75 mutex_lock(&s->s_root->d_inode->i_mutex); 76 77 replace_mount_options(s, new_opt); 78 config.setuid = setuid; 79 config.setgid = setgid; 80 config.uid = uid; 81 config.gid = gid; 82 config.mode = mode; 83 84 mutex_unlock(&s->s_root->d_inode->i_mutex); 85 86 return 0; 87} 88 89static const struct super_operations capifs_sops = 90{ 91 .statfs = simple_statfs, 92 .remount_fs = capifs_remount, 93 .show_options = generic_show_options, 94}; 95 96 97static int 98capifs_fill_super(struct super_block *s, void *data, int silent) 99{ 100 struct inode * inode; 101 102 s->s_blocksize = 1024; 103 s->s_blocksize_bits = 10; 104 s->s_magic = CAPIFS_SUPER_MAGIC; 105 s->s_op = &capifs_sops; 106 s->s_time_gran = 1; 107 108 inode = new_inode(s); 109 if (!inode) 110 goto fail; 111 inode->i_ino = 1; 112 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 113 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; 114 inode->i_op = &simple_dir_inode_operations; 115 inode->i_fop = &simple_dir_operations; 116 inode->i_nlink = 2; 117 118 s->s_root = d_alloc_root(inode); 119 if (s->s_root) 120 return 0; 121 122 printk("capifs: get root dentry failed\n"); 123 iput(inode); 124fail: 125 return -ENOMEM; 126} 127 128static int capifs_get_sb(struct file_system_type *fs_type, 129 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 130{ 131 return get_sb_single(fs_type, flags, data, capifs_fill_super, mnt); 132} 133 134static struct file_system_type capifs_fs_type = { 135 .owner = THIS_MODULE, 136 .name = "capifs", 137 .get_sb = capifs_get_sb, 138 .kill_sb = kill_anon_super, 139}; 140 141static struct dentry *new_ncci(unsigned int number, dev_t device) 142{ 143 struct super_block *s = capifs_mnt->mnt_sb; 144 struct dentry *root = s->s_root; 145 struct dentry *dentry; 146 struct inode *inode; 147 char name[10]; 148 int namelen; 149 150 mutex_lock(&root->d_inode->i_mutex); 151 152 namelen = sprintf(name, "%d", number); 153 dentry = lookup_one_len(name, root, namelen); 154 if (IS_ERR(dentry)) { 155 dentry = NULL; 156 goto unlock_out; 157 } 158 159 if (dentry->d_inode) { 160 dput(dentry); 161 dentry = NULL; 162 goto unlock_out; 163 } 164 165 inode = new_inode(s); 166 if (!inode) { 167 dput(dentry); 168 dentry = NULL; 169 goto unlock_out; 170 } 171 172 /* config contents is protected by root's i_mutex */ 173 inode->i_uid = config.setuid ? config.uid : current_fsuid(); 174 inode->i_gid = config.setgid ? config.gid : current_fsgid(); 175 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 176 inode->i_ino = number + 2; 177 init_special_inode(inode, S_IFCHR|config.mode, device); 178 179 d_instantiate(dentry, inode); 180 dget(dentry); 181 182unlock_out: 183 mutex_unlock(&root->d_inode->i_mutex); 184 185 return dentry; 186} 187 188struct dentry *capifs_new_ncci(unsigned int number, dev_t device) 189{ 190 struct dentry *dentry; 191 192 if (simple_pin_fs(&capifs_fs_type, &capifs_mnt, &capifs_mnt_count) < 0) 193 return NULL; 194 195 dentry = new_ncci(number, device); 196 if (!dentry) 197 simple_release_fs(&capifs_mnt, &capifs_mnt_count); 198 199 return dentry; 200} 201 202void capifs_free_ncci(struct dentry *dentry) 203{ 204 struct dentry *root = capifs_mnt->mnt_sb->s_root; 205 struct inode *inode; 206 207 if (!dentry) 208 return; 209 210 mutex_lock(&root->d_inode->i_mutex); 211 212 inode = dentry->d_inode; 213 if (inode) { 214 drop_nlink(inode); 215 d_delete(dentry); 216 dput(dentry); 217 } 218 dput(dentry); 219 220 mutex_unlock(&root->d_inode->i_mutex); 221 222 simple_release_fs(&capifs_mnt, &capifs_mnt_count); 223} 224 225static int __init capifs_init(void) 226{ 227 return register_filesystem(&capifs_fs_type); 228} 229 230static void __exit capifs_exit(void) 231{ 232 unregister_filesystem(&capifs_fs_type); 233} 234 235EXPORT_SYMBOL(capifs_new_ncci); 236EXPORT_SYMBOL(capifs_free_ncci); 237 238module_init(capifs_init); 239module_exit(capifs_exit); 240