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 .llseek = generic_file_llseek, 171 }; 172 173 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *); 174 175 static const struct inode_operations openprom_inode_operations = { 176 .lookup = openpromfs_lookup, 177 }; 178 179 static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 180 { 181 struct op_inode_info *ent_oi, *oi = OP_I(dir); 182 struct device_node *dp, *child; 183 struct property *prop; 184 enum op_inode_type ent_type; 185 union op_inode_data ent_data; 186 const char *name; 187 struct inode *inode; 188 unsigned int ino; 189 int len; 190 191 BUG_ON(oi->type != op_inode_node); 192 193 dp = oi->u.node; 194 195 name = dentry->d_name.name; 196 len = dentry->d_name.len; 197 198 mutex_lock(&op_mutex); 199 200 child = dp->child; 201 while (child) { 202 int n = strlen(child->path_component_name); 203 204 if (len == n && 205 !strncmp(child->path_component_name, name, len)) { 206 ent_type = op_inode_node; 207 ent_data.node = child; 208 ino = child->unique_id; 209 goto found; 210 } 211 child = child->sibling; 212 } 213 214 prop = dp->properties; 215 while (prop) { 216 int n = strlen(prop->name); 217 218 if (len == n && !strncmp(prop->name, name, len)) { 219 ent_type = op_inode_prop; 220 ent_data.prop = prop; 221 ino = prop->unique_id; 222 goto found; 223 } 224 225 prop = prop->next; 226 } 227 228 mutex_unlock(&op_mutex); 229 return ERR_PTR(-ENOENT); 230 231 found: 232 inode = openprom_iget(dir->i_sb, ino); 233 mutex_unlock(&op_mutex); 234 if (IS_ERR(inode)) 235 return ERR_CAST(inode); 236 ent_oi = OP_I(inode); 237 ent_oi->type = ent_type; 238 ent_oi->u = ent_data; 239 240 switch (ent_type) { 241 case op_inode_node: 242 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 243 inode->i_op = &openprom_inode_operations; 244 inode->i_fop = &openprom_operations; 245 inode->i_nlink = 2; 246 break; 247 case op_inode_prop: 248 if (!strcmp(dp->name, "options") && (len == 17) && 249 !strncmp (name, "security-password", 17)) 250 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 251 else 252 inode->i_mode = S_IFREG | S_IRUGO; 253 inode->i_fop = &openpromfs_prop_ops; 254 inode->i_nlink = 1; 255 inode->i_size = ent_oi->u.prop->length; 256 break; 257 } 258 259 inode->i_gid = 0; 260 inode->i_uid = 0; 261 262 d_add(dentry, inode); 263 return NULL; 264 } 265 266 static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 267 { 268 struct inode *inode = filp->f_path.dentry->d_inode; 269 struct op_inode_info *oi = OP_I(inode); 270 struct device_node *dp = oi->u.node; 271 struct device_node *child; 272 struct property *prop; 273 unsigned int ino; 274 int i; 275 276 mutex_lock(&op_mutex); 277 278 ino = inode->i_ino; 279 i = filp->f_pos; 280 switch (i) { 281 case 0: 282 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) 283 goto out; 284 i++; 285 filp->f_pos++; 286 /* fall thru */ 287 case 1: 288 if (filldir(dirent, "..", 2, i, 289 (dp->parent == NULL ? 290 OPENPROM_ROOT_INO : 291 dp->parent->unique_id), DT_DIR) < 0) 292 goto out; 293 i++; 294 filp->f_pos++; 295 /* fall thru */ 296 default: 297 i -= 2; 298 299 /* First, the children nodes as directories. */ 300 child = dp->child; 301 while (i && child) { 302 child = child->sibling; 303 i--; 304 } 305 while (child) { 306 if (filldir(dirent, 307 child->path_component_name, 308 strlen(child->path_component_name), 309 filp->f_pos, child->unique_id, DT_DIR) < 0) 310 goto out; 311 312 filp->f_pos++; 313 child = child->sibling; 314 } 315 316 /* Next, the properties as files. */ 317 prop = dp->properties; 318 while (i && prop) { 319 prop = prop->next; 320 i--; 321 } 322 while (prop) { 323 if (filldir(dirent, prop->name, strlen(prop->name), 324 filp->f_pos, prop->unique_id, DT_REG) < 0) 325 goto out; 326 327 filp->f_pos++; 328 prop = prop->next; 329 } 330 } 331 out: 332 mutex_unlock(&op_mutex); 333 return 0; 334 } 335 336 static struct kmem_cache *op_inode_cachep; 337 338 static struct inode *openprom_alloc_inode(struct super_block *sb) 339 { 340 struct op_inode_info *oi; 341 342 oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL); 343 if (!oi) 344 return NULL; 345 346 return &oi->vfs_inode; 347 } 348 349 static void openprom_destroy_inode(struct inode *inode) 350 { 351 kmem_cache_free(op_inode_cachep, OP_I(inode)); 352 } 353 354 static struct inode *openprom_iget(struct super_block *sb, ino_t ino) 355 { 356 struct inode *inode; 357 358 inode = iget_locked(sb, ino); 359 if (!inode) 360 return ERR_PTR(-ENOMEM); 361 if (inode->i_state & I_NEW) { 362 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 363 if (inode->i_ino == OPENPROM_ROOT_INO) { 364 inode->i_op = &openprom_inode_operations; 365 inode->i_fop = &openprom_operations; 366 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 367 } 368 unlock_new_inode(inode); 369 } 370 return inode; 371 } 372 373 static int openprom_remount(struct super_block *sb, int *flags, char *data) 374 { 375 *flags |= MS_NOATIME; 376 return 0; 377 } 378 379 static const struct super_operations openprom_sops = { 380 .alloc_inode = openprom_alloc_inode, 381 .destroy_inode = openprom_destroy_inode, 382 .statfs = simple_statfs, 383 .remount_fs = openprom_remount, 384 }; 385 386 static int openprom_fill_super(struct super_block *s, void *data, int silent) 387 { 388 struct inode *root_inode; 389 struct op_inode_info *oi; 390 int ret; 391 392 s->s_flags |= MS_NOATIME; 393 s->s_blocksize = 1024; 394 s->s_blocksize_bits = 10; 395 s->s_magic = OPENPROM_SUPER_MAGIC; 396 s->s_op = &openprom_sops; 397 s->s_time_gran = 1; 398 root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 399 if (IS_ERR(root_inode)) { 400 ret = PTR_ERR(root_inode); 401 goto out_no_root; 402 } 403 404 oi = OP_I(root_inode); 405 oi->type = op_inode_node; 406 oi->u.node = of_find_node_by_path("/"); 407 408 s->s_root = d_alloc_root(root_inode); 409 if (!s->s_root) 410 goto out_no_root_dentry; 411 return 0; 412 413 out_no_root_dentry: 414 iput(root_inode); 415 ret = -ENOMEM; 416 out_no_root: 417 printk("openprom_fill_super: get root inode failed\n"); 418 return ret; 419 } 420 421 static int openprom_get_sb(struct file_system_type *fs_type, 422 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 423 { 424 return get_sb_single(fs_type, flags, data, openprom_fill_super, mnt); 425 } 426 427 static struct file_system_type openprom_fs_type = { 428 .owner = THIS_MODULE, 429 .name = "openpromfs", 430 .get_sb = openprom_get_sb, 431 .kill_sb = kill_anon_super, 432 }; 433 434 static void op_inode_init_once(void *data) 435 { 436 struct op_inode_info *oi = (struct op_inode_info *) data; 437 438 inode_init_once(&oi->vfs_inode); 439 } 440 441 static int __init init_openprom_fs(void) 442 { 443 int err; 444 445 op_inode_cachep = kmem_cache_create("op_inode_cache", 446 sizeof(struct op_inode_info), 447 0, 448 (SLAB_RECLAIM_ACCOUNT | 449 SLAB_MEM_SPREAD), 450 op_inode_init_once); 451 if (!op_inode_cachep) 452 return -ENOMEM; 453 454 err = register_filesystem(&openprom_fs_type); 455 if (err) 456 kmem_cache_destroy(op_inode_cachep); 457 458 return err; 459 } 460 461 static void __exit exit_openprom_fs(void) 462 { 463 unregister_filesystem(&openprom_fs_type); 464 kmem_cache_destroy(op_inode_cachep); 465 } 466 467 module_init(init_openprom_fs) 468 module_exit(exit_openprom_fs) 469 MODULE_LICENSE("GPL"); 470