1 // SPDX-License-Identifier: GPL-2.0-only 2 /* inode.c: /proc/openprom handling routines 3 * 4 * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) 5 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 6 */ 7 8 #include <linux/module.h> 9 #include <linux/types.h> 10 #include <linux/string.h> 11 #include <linux/fs.h> 12 #include <linux/fs_context.h> 13 #include <linux/init.h> 14 #include <linux/slab.h> 15 #include <linux/seq_file.h> 16 #include <linux/magic.h> 17 18 #include <asm/openprom.h> 19 #include <asm/oplib.h> 20 #include <asm/prom.h> 21 #include <linux/uaccess.h> 22 23 static DEFINE_MUTEX(op_mutex); 24 25 #define OPENPROM_ROOT_INO 0 26 27 enum op_inode_type { 28 op_inode_node, 29 op_inode_prop, 30 }; 31 32 union op_inode_data { 33 struct device_node *node; 34 struct property *prop; 35 }; 36 37 struct op_inode_info { 38 struct inode vfs_inode; 39 enum op_inode_type type; 40 union op_inode_data u; 41 }; 42 43 static struct inode *openprom_iget(struct super_block *sb, ino_t ino); 44 45 static inline struct op_inode_info *OP_I(struct inode *inode) 46 { 47 return container_of(inode, struct op_inode_info, vfs_inode); 48 } 49 50 static int is_string(unsigned char *p, int len) 51 { 52 int i; 53 54 for (i = 0; i < len; i++) { 55 unsigned char val = p[i]; 56 57 if ((i && !val) || 58 (val >= ' ' && val <= '~')) 59 continue; 60 61 return 0; 62 } 63 64 return 1; 65 } 66 67 static int property_show(struct seq_file *f, void *v) 68 { 69 struct property *prop = f->private; 70 void *pval; 71 int len; 72 73 len = prop->length; 74 pval = prop->value; 75 76 if (is_string(pval, len)) { 77 while (len > 0) { 78 int n = strlen(pval); 79 80 seq_printf(f, "%s", (char *) pval); 81 82 /* Skip over the NULL byte too. */ 83 pval += n + 1; 84 len -= n + 1; 85 86 if (len > 0) 87 seq_printf(f, " + "); 88 } 89 } else { 90 if (len & 3) { 91 while (len) { 92 len--; 93 if (len) 94 seq_printf(f, "%02x.", 95 *(unsigned char *) pval); 96 else 97 seq_printf(f, "%02x", 98 *(unsigned char *) pval); 99 pval++; 100 } 101 } else { 102 while (len >= 4) { 103 len -= 4; 104 105 if (len) 106 seq_printf(f, "%08x.", 107 *(unsigned int *) pval); 108 else 109 seq_printf(f, "%08x", 110 *(unsigned int *) pval); 111 pval += 4; 112 } 113 } 114 } 115 seq_printf(f, "\n"); 116 117 return 0; 118 } 119 120 static void *property_start(struct seq_file *f, loff_t *pos) 121 { 122 if (*pos == 0) 123 return pos; 124 return NULL; 125 } 126 127 static void *property_next(struct seq_file *f, void *v, loff_t *pos) 128 { 129 (*pos)++; 130 return NULL; 131 } 132 133 static void property_stop(struct seq_file *f, void *v) 134 { 135 /* Nothing to do */ 136 } 137 138 static const struct seq_operations property_op = { 139 .start = property_start, 140 .next = property_next, 141 .stop = property_stop, 142 .show = property_show 143 }; 144 145 static int property_open(struct inode *inode, struct file *file) 146 { 147 struct op_inode_info *oi = OP_I(inode); 148 int ret; 149 150 BUG_ON(oi->type != op_inode_prop); 151 152 ret = seq_open(file, &property_op); 153 if (!ret) { 154 struct seq_file *m = file->private_data; 155 m->private = oi->u.prop; 156 } 157 return ret; 158 } 159 160 static const struct file_operations openpromfs_prop_ops = { 161 .open = property_open, 162 .read = seq_read, 163 .llseek = seq_lseek, 164 .release = seq_release, 165 }; 166 167 static int openpromfs_readdir(struct file *, struct dir_context *); 168 169 static const struct file_operations openprom_operations = { 170 .read = generic_read_dir, 171 .iterate_shared = openpromfs_readdir, 172 .llseek = generic_file_llseek, 173 }; 174 175 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int); 176 177 static const struct inode_operations openprom_inode_operations = { 178 .lookup = openpromfs_lookup, 179 }; 180 181 static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 182 { 183 struct op_inode_info *ent_oi, *oi = OP_I(dir); 184 struct device_node *dp, *child; 185 struct property *prop; 186 enum op_inode_type ent_type; 187 union op_inode_data ent_data; 188 const char *name; 189 struct inode *inode; 190 unsigned int ino; 191 int len; 192 193 BUG_ON(oi->type != op_inode_node); 194 195 dp = oi->u.node; 196 197 name = dentry->d_name.name; 198 len = dentry->d_name.len; 199 200 mutex_lock(&op_mutex); 201 202 child = dp->child; 203 while (child) { 204 const char *node_name = kbasename(child->full_name); 205 int n = strlen(node_name); 206 207 if (len == n && 208 !strncmp(node_name, name, len)) { 209 ent_type = op_inode_node; 210 ent_data.node = child; 211 ino = child->unique_id; 212 goto found; 213 } 214 child = child->sibling; 215 } 216 217 prop = dp->properties; 218 while (prop) { 219 int n = strlen(prop->name); 220 221 if (len == n && !strncmp(prop->name, name, len)) { 222 ent_type = op_inode_prop; 223 ent_data.prop = prop; 224 ino = prop->unique_id; 225 goto found; 226 } 227 228 prop = prop->next; 229 } 230 231 mutex_unlock(&op_mutex); 232 return ERR_PTR(-ENOENT); 233 234 found: 235 inode = openprom_iget(dir->i_sb, ino); 236 mutex_unlock(&op_mutex); 237 if (IS_ERR(inode)) 238 return ERR_CAST(inode); 239 if (inode->i_state & I_NEW) { 240 simple_inode_init_ts(inode); 241 ent_oi = OP_I(inode); 242 ent_oi->type = ent_type; 243 ent_oi->u = ent_data; 244 245 switch (ent_type) { 246 case op_inode_node: 247 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 248 inode->i_op = &openprom_inode_operations; 249 inode->i_fop = &openprom_operations; 250 set_nlink(inode, 2); 251 break; 252 case op_inode_prop: 253 if (of_node_name_eq(dp, "options") && (len == 17) && 254 !strncmp (name, "security-password", 17)) 255 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 256 else 257 inode->i_mode = S_IFREG | S_IRUGO; 258 inode->i_fop = &openpromfs_prop_ops; 259 set_nlink(inode, 1); 260 inode->i_size = ent_oi->u.prop->length; 261 break; 262 } 263 unlock_new_inode(inode); 264 } 265 266 return d_splice_alias(inode, dentry); 267 } 268 269 static int openpromfs_readdir(struct file *file, struct dir_context *ctx) 270 { 271 struct inode *inode = file_inode(file); 272 struct op_inode_info *oi = OP_I(inode); 273 struct device_node *dp = oi->u.node; 274 struct device_node *child; 275 struct property *prop; 276 int i; 277 278 mutex_lock(&op_mutex); 279 280 if (ctx->pos == 0) { 281 if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) 282 goto out; 283 ctx->pos = 1; 284 } 285 if (ctx->pos == 1) { 286 if (!dir_emit(ctx, "..", 2, 287 (dp->parent == NULL ? 288 OPENPROM_ROOT_INO : 289 dp->parent->unique_id), DT_DIR)) 290 goto out; 291 ctx->pos = 2; 292 } 293 i = ctx->pos - 2; 294 295 /* First, the children nodes as directories. */ 296 child = dp->child; 297 while (i && child) { 298 child = child->sibling; 299 i--; 300 } 301 while (child) { 302 if (!dir_emit(ctx, 303 kbasename(child->full_name), 304 strlen(kbasename(child->full_name)), 305 child->unique_id, DT_DIR)) 306 goto out; 307 308 ctx->pos++; 309 child = child->sibling; 310 } 311 312 /* Next, the properties as files. */ 313 prop = dp->properties; 314 while (i && prop) { 315 prop = prop->next; 316 i--; 317 } 318 while (prop) { 319 if (!dir_emit(ctx, prop->name, strlen(prop->name), 320 prop->unique_id, DT_REG)) 321 goto out; 322 323 ctx->pos++; 324 prop = prop->next; 325 } 326 327 out: 328 mutex_unlock(&op_mutex); 329 return 0; 330 } 331 332 static struct kmem_cache *op_inode_cachep; 333 334 static struct inode *openprom_alloc_inode(struct super_block *sb) 335 { 336 struct op_inode_info *oi; 337 338 oi = alloc_inode_sb(sb, op_inode_cachep, GFP_KERNEL); 339 if (!oi) 340 return NULL; 341 342 return &oi->vfs_inode; 343 } 344 345 static void openprom_free_inode(struct inode *inode) 346 { 347 kmem_cache_free(op_inode_cachep, OP_I(inode)); 348 } 349 350 static struct inode *openprom_iget(struct super_block *sb, ino_t ino) 351 { 352 struct inode *inode = iget_locked(sb, ino); 353 if (!inode) 354 inode = ERR_PTR(-ENOMEM); 355 return inode; 356 } 357 358 static int openpromfs_reconfigure(struct fs_context *fc) 359 { 360 sync_filesystem(fc->root->d_sb); 361 fc->sb_flags |= SB_NOATIME; 362 return 0; 363 } 364 365 static const struct super_operations openprom_sops = { 366 .alloc_inode = openprom_alloc_inode, 367 .free_inode = openprom_free_inode, 368 .statfs = simple_statfs, 369 }; 370 371 static int openprom_fill_super(struct super_block *s, struct fs_context *fc) 372 { 373 struct inode *root_inode; 374 struct op_inode_info *oi; 375 int ret; 376 377 s->s_flags |= SB_NOATIME; 378 s->s_blocksize = 1024; 379 s->s_blocksize_bits = 10; 380 s->s_magic = OPENPROM_SUPER_MAGIC; 381 s->s_op = &openprom_sops; 382 s->s_time_gran = 1; 383 root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 384 if (IS_ERR(root_inode)) { 385 ret = PTR_ERR(root_inode); 386 goto out_no_root; 387 } 388 389 simple_inode_init_ts(root_inode); 390 root_inode->i_op = &openprom_inode_operations; 391 root_inode->i_fop = &openprom_operations; 392 root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 393 oi = OP_I(root_inode); 394 oi->type = op_inode_node; 395 oi->u.node = of_find_node_by_path("/"); 396 unlock_new_inode(root_inode); 397 398 s->s_root = d_make_root(root_inode); 399 if (!s->s_root) 400 goto out_no_root_dentry; 401 return 0; 402 403 out_no_root_dentry: 404 ret = -ENOMEM; 405 out_no_root: 406 printk("openprom_fill_super: get root inode failed\n"); 407 return ret; 408 } 409 410 static int openpromfs_get_tree(struct fs_context *fc) 411 { 412 return get_tree_single(fc, openprom_fill_super); 413 } 414 415 static const struct fs_context_operations openpromfs_context_ops = { 416 .get_tree = openpromfs_get_tree, 417 .reconfigure = openpromfs_reconfigure, 418 }; 419 420 static int openpromfs_init_fs_context(struct fs_context *fc) 421 { 422 fc->ops = &openpromfs_context_ops; 423 return 0; 424 } 425 426 static struct file_system_type openprom_fs_type = { 427 .owner = THIS_MODULE, 428 .name = "openpromfs", 429 .init_fs_context = openpromfs_init_fs_context, 430 .kill_sb = kill_anon_super, 431 }; 432 MODULE_ALIAS_FS("openpromfs"); 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_ACCOUNT), 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 /* 465 * Make sure all delayed rcu free inodes are flushed before we 466 * destroy cache. 467 */ 468 rcu_barrier(); 469 kmem_cache_destroy(op_inode_cachep); 470 } 471 472 module_init(init_openprom_fs) 473 module_exit(exit_openprom_fs) 474 MODULE_DESCRIPTION("OpenPROM filesystem support"); 475 MODULE_LICENSE("GPL"); 476
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.