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