1 /* inode.c: /proc/openprom handling routines 2 * 3 * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) 4 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 5 */ 6 7 #include <linux/module.h> 8 #include <linux/types.h> 9 #include <linux/string.h> 10 #include <linux/fs.h> 11 #include <linux/init.h> 12 #include <linux/slab.h> 13 #include <linux/seq_file.h> 14 #include <linux/magic.h> 15 16 #include <asm/openprom.h> 17 #include <asm/oplib.h> 18 #include <asm/prom.h> 19 #include <asm/uaccess.h> 20 21 static DEFINE_MUTEX(op_mutex); 22 23 #define OPENPROM_ROOT_INO 0 24 25 enum op_inode_type { 26 op_inode_node, 27 op_inode_prop, 28 }; 29 30 union op_inode_data { 31 struct device_node *node; 32 struct property *prop; 33 }; 34 35 struct op_inode_info { 36 struct inode vfs_inode; 37 enum op_inode_type type; 38 union op_inode_data u; 39 }; 40 41 static inline struct op_inode_info *OP_I(struct inode *inode) 42 { 43 return container_of(inode, struct op_inode_info, vfs_inode); 44 } 45 46 static int is_string(unsigned char *p, int len) 47 { 48 int i; 49 50 for (i = 0; i < len; i++) { 51 unsigned char val = p[i]; 52 53 if ((i && !val) || 54 (val >= ' ' && val <= '~')) 55 continue; 56 57 return 0; 58 } 59 60 return 1; 61 } 62 63 static int property_show(struct seq_file *f, void *v) 64 { 65 struct property *prop = f->private; 66 void *pval; 67 int len; 68 69 len = prop->length; 70 pval = prop->value; 71 72 if (is_string(pval, len)) { 73 while (len > 0) { 74 int n = strlen(pval); 75 76 seq_printf(f, "%s", (char *) pval); 77 78 /* Skip over the NULL byte too. */ 79 pval += n + 1; 80 len -= n + 1; 81 82 if (len > 0) 83 seq_printf(f, " + "); 84 } 85 } else { 86 if (len & 3) { 87 while (len) { 88 len--; 89 if (len) 90 seq_printf(f, "%02x.", 91 *(unsigned char *) pval); 92 else 93 seq_printf(f, "%02x", 94 *(unsigned char *) pval); 95 pval++; 96 } 97 } else { 98 while (len >= 4) { 99 len -= 4; 100 101 if (len) 102 seq_printf(f, "%08x.", 103 *(unsigned int *) pval); 104 else 105 seq_printf(f, "%08x", 106 *(unsigned int *) pval); 107 pval += 4; 108 } 109 } 110 } 111 seq_printf(f, "\n"); 112 113 return 0; 114 } 115 116 static void *property_start(struct seq_file *f, loff_t *pos) 117 { 118 if (*pos == 0) 119 return pos; 120 return NULL; 121 } 122 123 static void *property_next(struct seq_file *f, void *v, loff_t *pos) 124 { 125 (*pos)++; 126 return NULL; 127 } 128 129 static void property_stop(struct seq_file *f, void *v) 130 { 131 /* Nothing to do */ 132 } 133 134 static struct seq_operations property_op = { 135 .start = property_start, 136 .next = property_next, 137 .stop = property_stop, 138 .show = property_show 139 }; 140 141 static int property_open(struct inode *inode, struct file *file) 142 { 143 struct op_inode_info *oi = OP_I(inode); 144 int ret; 145 146 BUG_ON(oi->type != op_inode_prop); 147 148 ret = seq_open(file, &property_op); 149 if (!ret) { 150 struct seq_file *m = file->private_data; 151 m->private = oi->u.prop; 152 } 153 return ret; 154 } 155 156 static const struct file_operations openpromfs_prop_ops = { 157 .open = property_open, 158 .read = seq_read, 159 .llseek = seq_lseek, 160 .release = seq_release, 161 }; 162 163 static int openpromfs_readdir(struct file *, void *, filldir_t); 164 165 static const struct file_operations openprom_operations = { 166 .read = generic_read_dir, 167 .readdir = openpromfs_readdir, 168 }; 169 170 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *); 171 172 static const struct inode_operations openprom_inode_operations = { 173 .lookup = openpromfs_lookup, 174 }; 175 176 static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 177 { 178 struct op_inode_info *ent_oi, *oi = OP_I(dir); 179 struct device_node *dp, *child; 180 struct property *prop; 181 enum op_inode_type ent_type; 182 union op_inode_data ent_data; 183 const char *name; 184 struct inode *inode; 185 unsigned int ino; 186 int len; 187 188 BUG_ON(oi->type != op_inode_node); 189 190 dp = oi->u.node; 191 192 name = dentry->d_name.name; 193 len = dentry->d_name.len; 194 195 mutex_lock(&op_mutex); 196 197 child = dp->child; 198 while (child) { 199 int n = strlen(child->path_component_name); 200 201 if (len == n && 202 !strncmp(child->path_component_name, name, len)) { 203 ent_type = op_inode_node; 204 ent_data.node = child; 205 ino = child->unique_id; 206 goto found; 207 } 208 child = child->sibling; 209 } 210 211 prop = dp->properties; 212 while (prop) { 213 int n = strlen(prop->name); 214 215 if (len == n && !strncmp(prop->name, name, len)) { 216 ent_type = op_inode_prop; 217 ent_data.prop = prop; 218 ino = prop->unique_id; 219 goto found; 220 } 221 222 prop = prop->next; 223 } 224 225 mutex_unlock(&op_mutex); 226 return ERR_PTR(-ENOENT); 227 228 found: 229 inode = iget(dir->i_sb, ino); 230 mutex_unlock(&op_mutex); 231 if (!inode) 232 return ERR_PTR(-EINVAL); 233 ent_oi = OP_I(inode); 234 ent_oi->type = ent_type; 235 ent_oi->u = ent_data; 236 237 switch (ent_type) { 238 case op_inode_node: 239 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 240 inode->i_op = &openprom_inode_operations; 241 inode->i_fop = &openprom_operations; 242 inode->i_nlink = 2; 243 break; 244 case op_inode_prop: 245 if (!strcmp(dp->name, "options") && (len == 17) && 246 !strncmp (name, "security-password", 17)) 247 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 248 else 249 inode->i_mode = S_IFREG | S_IRUGO; 250 inode->i_fop = &openpromfs_prop_ops; 251 inode->i_nlink = 1; 252 inode->i_size = ent_oi->u.prop->length; 253 break; 254 } 255 256 inode->i_gid = 0; 257 inode->i_uid = 0; 258 259 d_add(dentry, inode); 260 return NULL; 261 } 262 263 static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 264 { 265 struct inode *inode = filp->f_path.dentry->d_inode; 266 struct op_inode_info *oi = OP_I(inode); 267 struct device_node *dp = oi->u.node; 268 struct device_node *child; 269 struct property *prop; 270 unsigned int ino; 271 int i; 272 273 mutex_lock(&op_mutex); 274 275 ino = inode->i_ino; 276 i = filp->f_pos; 277 switch (i) { 278 case 0: 279 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) 280 goto out; 281 i++; 282 filp->f_pos++; 283 /* fall thru */ 284 case 1: 285 if (filldir(dirent, "..", 2, i, 286 (dp->parent == NULL ? 287 OPENPROM_ROOT_INO : 288 dp->parent->unique_id), DT_DIR) < 0) 289 goto out; 290 i++; 291 filp->f_pos++; 292 /* fall thru */ 293 default: 294 i -= 2; 295 296 /* First, the children nodes as directories. */ 297 child = dp->child; 298 while (i && child) { 299 child = child->sibling; 300 i--; 301 } 302 while (child) { 303 if (filldir(dirent, 304 child->path_component_name, 305 strlen(child->path_component_name), 306 filp->f_pos, child->unique_id, DT_DIR) < 0) 307 goto out; 308 309 filp->f_pos++; 310 child = child->sibling; 311 } 312 313 /* Next, the properties as files. */ 314 prop = dp->properties; 315 while (i && prop) { 316 prop = prop->next; 317 i--; 318 } 319 while (prop) { 320 if (filldir(dirent, prop->name, strlen(prop->name), 321 filp->f_pos, prop->unique_id, DT_REG) < 0) 322 goto out; 323 324 filp->f_pos++; 325 prop = prop->next; 326 } 327 } 328 out: 329 mutex_unlock(&op_mutex); 330 return 0; 331 } 332 333 static struct kmem_cache *op_inode_cachep; 334 335 static struct inode *openprom_alloc_inode(struct super_block *sb) 336 { 337 struct op_inode_info *oi; 338 339 oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL); 340 if (!oi) 341 return NULL; 342 343 return &oi->vfs_inode; 344 } 345 346 static void openprom_destroy_inode(struct inode *inode) 347 { 348 kmem_cache_free(op_inode_cachep, OP_I(inode)); 349 } 350 351 static void openprom_read_inode(struct inode * inode) 352 { 353 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 354 if (inode->i_ino == OPENPROM_ROOT_INO) { 355 inode->i_op = &openprom_inode_operations; 356 inode->i_fop = &openprom_operations; 357 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 358 } 359 } 360 361 static int openprom_remount(struct super_block *sb, int *flags, char *data) 362 { 363 *flags |= MS_NOATIME; 364 return 0; 365 } 366 367 static const struct super_operations openprom_sops = { 368 .alloc_inode = openprom_alloc_inode, 369 .destroy_inode = openprom_destroy_inode, 370 .read_inode = openprom_read_inode, 371 .statfs = simple_statfs, 372 .remount_fs = openprom_remount, 373 }; 374 375 static int openprom_fill_super(struct super_block *s, void *data, int silent) 376 { 377 struct inode *root_inode; 378 struct op_inode_info *oi; 379 380 s->s_flags |= MS_NOATIME; 381 s->s_blocksize = 1024; 382 s->s_blocksize_bits = 10; 383 s->s_magic = OPENPROM_SUPER_MAGIC; 384 s->s_op = &openprom_sops; 385 s->s_time_gran = 1; 386 root_inode = iget(s, OPENPROM_ROOT_INO); 387 if (!root_inode) 388 goto out_no_root; 389 390 oi = OP_I(root_inode); 391 oi->type = op_inode_node; 392 oi->u.node = of_find_node_by_path("/"); 393 394 s->s_root = d_alloc_root(root_inode); 395 if (!s->s_root) 396 goto out_no_root; 397 return 0; 398 399 out_no_root: 400 printk("openprom_fill_super: get root inode failed\n"); 401 iput(root_inode); 402 return -ENOMEM; 403 } 404 405 static int openprom_get_sb(struct file_system_type *fs_type, 406 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 407 { 408 return get_sb_single(fs_type, flags, data, openprom_fill_super, mnt); 409 } 410 411 static struct file_system_type openprom_fs_type = { 412 .owner = THIS_MODULE, 413 .name = "openpromfs", 414 .get_sb = openprom_get_sb, 415 .kill_sb = kill_anon_super, 416 }; 417 418 static void op_inode_init_once(struct kmem_cache * cachep, void *data) 419 { 420 struct op_inode_info *oi = (struct op_inode_info *) data; 421 422 inode_init_once(&oi->vfs_inode); 423 } 424 425 static int __init init_openprom_fs(void) 426 { 427 int err; 428 429 op_inode_cachep = kmem_cache_create("op_inode_cache", 430 sizeof(struct op_inode_info), 431 0, 432 (SLAB_RECLAIM_ACCOUNT | 433 SLAB_MEM_SPREAD), 434 op_inode_init_once); 435 if (!op_inode_cachep) 436 return -ENOMEM; 437 438 err = register_filesystem(&openprom_fs_type); 439 if (err) 440 kmem_cache_destroy(op_inode_cachep); 441 442 return err; 443 } 444 445 static void __exit exit_openprom_fs(void) 446 { 447 unregister_filesystem(&openprom_fs_type); 448 kmem_cache_destroy(op_inode_cachep); 449 } 450 451 module_init(init_openprom_fs) 452 module_exit(exit_openprom_fs) 453 MODULE_LICENSE("GPL"); 454