1 /* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $ 2 * openpromfs.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/openprom_fs.h> 13 #include <linux/init.h> 14 #include <linux/slab.h> 15 #include <linux/smp_lock.h> 16 17 #include <asm/openprom.h> 18 #include <asm/oplib.h> 19 #include <asm/uaccess.h> 20 21 #define ALIASES_NNODES 64 22 23 typedef struct { 24 u16 parent; 25 u16 next; 26 u16 child; 27 u16 first_prop; 28 u32 node; 29 } openpromfs_node; 30 31 typedef struct { 32 #define OPP_STRING 0x10 33 #define OPP_STRINGLIST 0x20 34 #define OPP_BINARY 0x40 35 #define OPP_HEXSTRING 0x80 36 #define OPP_DIRTY 0x01 37 #define OPP_QUOTED 0x02 38 #define OPP_NOTQUOTED 0x04 39 #define OPP_ASCIIZ 0x08 40 u32 flag; 41 u32 alloclen; 42 u32 len; 43 char *value; 44 char name[8]; 45 } openprom_property; 46 47 static openpromfs_node *nodes; 48 static int alloced; 49 static u16 last_node; 50 static u16 first_prop; 51 static u16 options = 0xffff; 52 static u16 aliases = 0xffff; 53 static int aliases_nodes; 54 static char *alias_names [ALIASES_NNODES]; 55 56 #define OPENPROM_ROOT_INO 16 57 #define OPENPROM_FIRST_INO OPENPROM_ROOT_INO 58 #define NODE(ino) nodes[ino - OPENPROM_FIRST_INO] 59 #define NODE2INO(node) (node + OPENPROM_FIRST_INO) 60 #define NODEP2INO(no) (no + OPENPROM_FIRST_INO + last_node) 61 62 static int openpromfs_create (struct inode *, struct dentry *, int, struct nameidata *); 63 static int openpromfs_readdir(struct file *, void *, filldir_t); 64 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry, struct nameidata *nd); 65 static int openpromfs_unlink (struct inode *, struct dentry *dentry); 66 67 static ssize_t nodenum_read(struct file *file, char __user *buf, 68 size_t count, loff_t *ppos) 69 { 70 struct inode *inode = file->f_dentry->d_inode; 71 char buffer[10]; 72 73 if (count < 0 || !inode->u.generic_ip) 74 return -EINVAL; 75 sprintf (buffer, "%8.8x\n", (u32)(long)(inode->u.generic_ip)); 76 if (file->f_pos >= 9) 77 return 0; 78 if (count > 9 - file->f_pos) 79 count = 9 - file->f_pos; 80 if (copy_to_user(buf, buffer + file->f_pos, count)) 81 return -EFAULT; 82 *ppos += count; 83 return count; 84 } 85 86 static ssize_t property_read(struct file *filp, char __user *buf, 87 size_t count, loff_t *ppos) 88 { 89 struct inode *inode = filp->f_dentry->d_inode; 90 int i, j, k; 91 u32 node; 92 char *p, *s; 93 u32 *q; 94 openprom_property *op; 95 char buffer[64]; 96 97 if (!filp->private_data) { 98 node = nodes[(u16)((long)inode->u.generic_ip)].node; 99 i = ((u32)(long)inode->u.generic_ip) >> 16; 100 if ((u16)((long)inode->u.generic_ip) == aliases) { 101 if (i >= aliases_nodes) 102 p = NULL; 103 else 104 p = alias_names [i]; 105 } else 106 for (p = prom_firstprop (node, buffer); 107 i && p && *p; 108 p = prom_nextprop (node, p, buffer), i--) 109 /* nothing */ ; 110 if (!p || !*p) 111 return -EIO; 112 i = prom_getproplen (node, p); 113 if (i < 0) { 114 if ((u16)((long)inode->u.generic_ip) == aliases) 115 i = 0; 116 else 117 return -EIO; 118 } 119 k = i; 120 if (i < 64) i = 64; 121 filp->private_data = kmalloc (sizeof (openprom_property) 122 + (j = strlen (p)) + 2 * i, 123 GFP_KERNEL); 124 if (!filp->private_data) 125 return -ENOMEM; 126 op = (openprom_property *)filp->private_data; 127 op->flag = 0; 128 op->alloclen = 2 * i; 129 strcpy (op->name, p); 130 op->value = (char *)(((unsigned long)(op->name + j + 4)) & ~3); 131 op->len = k; 132 if (k && prom_getproperty (node, p, op->value, i) < 0) 133 return -EIO; 134 op->value [k] = 0; 135 if (k) { 136 for (s = NULL, p = op->value; p < op->value + k; p++) { 137 if ((*p >= ' ' && *p <= '~') || *p == '\n') { 138 op->flag |= OPP_STRING; 139 s = p; 140 continue; 141 } 142 if (p > op->value && !*p && s == p - 1) { 143 if (p < op->value + k - 1) 144 op->flag |= OPP_STRINGLIST; 145 else 146 op->flag |= OPP_ASCIIZ; 147 continue; 148 } 149 if (k == 1 && !*p) { 150 op->flag |= (OPP_STRING|OPP_ASCIIZ); 151 break; 152 } 153 op->flag &= ~(OPP_STRING|OPP_STRINGLIST); 154 if (k & 3) 155 op->flag |= OPP_HEXSTRING; 156 else 157 op->flag |= OPP_BINARY; 158 break; 159 } 160 if (op->flag & OPP_STRINGLIST) 161 op->flag &= ~(OPP_STRING); 162 if (op->flag & OPP_ASCIIZ) 163 op->len--; 164 } 165 } else 166 op = (openprom_property *)filp->private_data; 167 if (!count || !(op->len || (op->flag & OPP_ASCIIZ))) 168 return 0; 169 if (*ppos >= 0xffffff || count >= 0xffffff) 170 return -EINVAL; 171 if (op->flag & OPP_STRINGLIST) { 172 for (k = 0, p = op->value; p < op->value + op->len; p++) 173 if (!*p) 174 k++; 175 i = op->len + 4 * k + 3; 176 } else if (op->flag & OPP_STRING) { 177 i = op->len + 3; 178 } else if (op->flag & OPP_BINARY) { 179 i = (op->len * 9) >> 2; 180 } else { 181 i = (op->len << 1) + 1; 182 } 183 k = *ppos; 184 if (k >= i) return 0; 185 if (count > i - k) count = i - k; 186 if (op->flag & OPP_STRING) { 187 if (!k) { 188 if (put_user('\'', buf)) 189 return -EFAULT; 190 k++; 191 count--; 192 } 193 194 if (k + count >= i - 2) 195 j = i - 2 - k; 196 else 197 j = count; 198 199 if (j >= 0) { 200 if (copy_to_user(buf + k - *ppos, 201 op->value + k - 1, j)) 202 return -EFAULT; 203 count -= j; 204 k += j; 205 } 206 207 if (count) { 208 if (put_user('\'', &buf [k++ - *ppos])) 209 return -EFAULT; 210 } 211 if (count > 1) { 212 if (put_user('\n', &buf [k++ - *ppos])) 213 return -EFAULT; 214 } 215 } else if (op->flag & OPP_STRINGLIST) { 216 char *tmp; 217 218 tmp = kmalloc (i, GFP_KERNEL); 219 if (!tmp) 220 return -ENOMEM; 221 222 s = tmp; 223 *s++ = '\''; 224 for (p = op->value; p < op->value + op->len; p++) { 225 if (!*p) { 226 strcpy(s, "' + '"); 227 s += 5; 228 continue; 229 } 230 *s++ = *p; 231 } 232 strcpy(s, "'\n"); 233 234 if (copy_to_user(buf, tmp + k, count)) 235 return -EFAULT; 236 237 kfree(tmp); 238 k += count; 239 240 } else if (op->flag & OPP_BINARY) { 241 char buffer[10]; 242 u32 *first, *last; 243 int first_off, last_cnt; 244 245 first = ((u32 *)op->value) + k / 9; 246 first_off = k % 9; 247 last = ((u32 *)op->value) + (k + count - 1) / 9; 248 last_cnt = (k + count) % 9; 249 if (!last_cnt) last_cnt = 9; 250 251 if (first == last) { 252 sprintf (buffer, "%08x.", *first); 253 if (copy_to_user(buf, buffer + first_off, 254 last_cnt - first_off)) 255 return -EFAULT; 256 buf += last_cnt - first_off; 257 } else { 258 for (q = first; q <= last; q++) { 259 sprintf (buffer, "%08x.", *q); 260 if (q == first) { 261 if (copy_to_user(buf, buffer + first_off, 262 9 - first_off)) 263 return -EFAULT; 264 buf += 9 - first_off; 265 } else if (q == last) { 266 if (copy_to_user(buf, buffer, last_cnt)) 267 return -EFAULT; 268 buf += last_cnt; 269 } else { 270 if (copy_to_user(buf, buffer, 9)) 271 return -EFAULT; 272 buf += 9; 273 } 274 } 275 } 276 277 if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9) { 278 if (put_user('\n', (buf - 1))) 279 return -EFAULT; 280 } 281 282 k += count; 283 284 } else if (op->flag & OPP_HEXSTRING) { 285 char buffer[3]; 286 287 if ((k < i - 1) && (k & 1)) { 288 sprintf (buffer, "%02x", 289 (unsigned char) *(op->value + (k >> 1)) & 0xff); 290 if (put_user(buffer[1], &buf[k++ - *ppos])) 291 return -EFAULT; 292 count--; 293 } 294 295 for (; (count > 1) && (k < i - 1); k += 2) { 296 sprintf (buffer, "%02x", 297 (unsigned char) *(op->value + (k >> 1)) & 0xff); 298 if (copy_to_user(buf + k - *ppos, buffer, 2)) 299 return -EFAULT; 300 count -= 2; 301 } 302 303 if (count && (k < i - 1)) { 304 sprintf (buffer, "%02x", 305 (unsigned char) *(op->value + (k >> 1)) & 0xff); 306 if (put_user(buffer[0], &buf[k++ - *ppos])) 307 return -EFAULT; 308 count--; 309 } 310 311 if (count) { 312 if (put_user('\n', &buf [k++ - *ppos])) 313 return -EFAULT; 314 } 315 } 316 count = k - *ppos; 317 *ppos = k; 318 return count; 319 } 320 321 static ssize_t property_write(struct file *filp, const char __user *buf, 322 size_t count, loff_t *ppos) 323 { 324 int i, j, k; 325 char *p; 326 u32 *q; 327 void *b; 328 openprom_property *op; 329 330 if (*ppos >= 0xffffff || count >= 0xffffff) 331 return -EINVAL; 332 if (!filp->private_data) { 333 i = property_read (filp, NULL, 0, NULL); 334 if (i) 335 return i; 336 } 337 k = *ppos; 338 op = (openprom_property *)filp->private_data; 339 if (!(op->flag & OPP_STRING)) { 340 u32 *first, *last; 341 int first_off, last_cnt; 342 u32 mask, mask2; 343 char tmp [9]; 344 int forcelen = 0; 345 346 j = k % 9; 347 for (i = 0; i < count; i++, j++) { 348 if (j == 9) j = 0; 349 if (!j) { 350 char ctmp; 351 if (get_user(ctmp, &buf[i])) 352 return -EFAULT; 353 if (ctmp != '.') { 354 if (ctmp != '\n') { 355 if (op->flag & OPP_BINARY) 356 return -EINVAL; 357 else 358 goto write_try_string; 359 } else { 360 count = i + 1; 361 forcelen = 1; 362 break; 363 } 364 } 365 } else { 366 char ctmp; 367 if (get_user(ctmp, &buf[i])) 368 return -EFAULT; 369 if (ctmp < '0' || 370 (ctmp > '9' && ctmp < 'A') || 371 (ctmp > 'F' && ctmp < 'a') || 372 ctmp > 'f') { 373 if (op->flag & OPP_BINARY) 374 return -EINVAL; 375 else 376 goto write_try_string; 377 } 378 } 379 } 380 op->flag |= OPP_BINARY; 381 tmp [8] = 0; 382 i = ((count + k + 8) / 9) << 2; 383 if (op->alloclen <= i) { 384 b = kmalloc (sizeof (openprom_property) + 2 * i, 385 GFP_KERNEL); 386 if (!b) 387 return -ENOMEM; 388 memcpy (b, filp->private_data, 389 sizeof (openprom_property) 390 + strlen (op->name) + op->alloclen); 391 memset (((char *)b) + sizeof (openprom_property) 392 + strlen (op->name) + op->alloclen, 393 0, 2 * i - op->alloclen); 394 op = (openprom_property *)b; 395 op->alloclen = 2*i; 396 b = filp->private_data; 397 filp->private_data = (void *)op; 398 kfree (b); 399 } 400 first = ((u32 *)op->value) + (k / 9); 401 first_off = k % 9; 402 last = (u32 *)(op->value + i); 403 last_cnt = (k + count) % 9; 404 if (first + 1 == last) { 405 memset (tmp, '0', 8); 406 if (copy_from_user(tmp + first_off, buf, 407 (count + first_off > 8) ? 408 8 - first_off : count)) 409 return -EFAULT; 410 mask = 0xffffffff; 411 mask2 = 0xffffffff; 412 for (j = 0; j < first_off; j++) 413 mask >>= 1; 414 for (j = 8 - count - first_off; j > 0; j--) 415 mask2 <<= 1; 416 mask &= mask2; 417 if (mask) { 418 *first &= ~mask; 419 *first |= simple_strtoul (tmp, NULL, 16); 420 op->flag |= OPP_DIRTY; 421 } 422 } else { 423 op->flag |= OPP_DIRTY; 424 for (q = first; q < last; q++) { 425 if (q == first) { 426 if (first_off < 8) { 427 memset (tmp, '0', 8); 428 if (copy_from_user(tmp + first_off, 429 buf, 430 8 - first_off)) 431 return -EFAULT; 432 mask = 0xffffffff; 433 for (j = 0; j < first_off; j++) 434 mask >>= 1; 435 *q &= ~mask; 436 *q |= simple_strtoul (tmp,NULL,16); 437 } 438 buf += 9; 439 } else if ((q == last - 1) && last_cnt 440 && (last_cnt < 8)) { 441 memset (tmp, '0', 8); 442 if (copy_from_user(tmp, buf, last_cnt)) 443 return -EFAULT; 444 mask = 0xffffffff; 445 for (j = 0; j < 8 - last_cnt; j++) 446 mask <<= 1; 447 *q &= ~mask; 448 *q |= simple_strtoul (tmp, NULL, 16); 449 buf += last_cnt; 450 } else { 451 char tchars[17]; /* XXX yuck... */ 452 453 if (copy_from_user(tchars, buf, 16)) 454 return -EFAULT; 455 *q = simple_strtoul (tchars, NULL, 16); 456 buf += 9; 457 } 458 } 459 } 460 if (!forcelen) { 461 if (op->len < i) 462 op->len = i; 463 } else 464 op->len = i; 465 *ppos += count; 466 } 467 write_try_string: 468 if (!(op->flag & OPP_BINARY)) { 469 if (!(op->flag & (OPP_QUOTED | OPP_NOTQUOTED))) { 470 char ctmp; 471 472 /* No way, if somebody starts writing from the middle, 473 * we don't know whether he uses quotes around or not 474 */ 475 if (k > 0) 476 return -EINVAL; 477 if (get_user(ctmp, buf)) 478 return -EFAULT; 479 if (ctmp == '\'') { 480 op->flag |= OPP_QUOTED; 481 buf++; 482 count--; 483 (*ppos)++; 484 if (!count) { 485 op->flag |= OPP_STRING; 486 return 1; 487 } 488 } else 489 op->flag |= OPP_NOTQUOTED; 490 } 491 op->flag |= OPP_STRING; 492 if (op->alloclen <= count + *ppos) { 493 b = kmalloc (sizeof (openprom_property) 494 + 2 * (count + *ppos), GFP_KERNEL); 495 if (!b) 496 return -ENOMEM; 497 memcpy (b, filp->private_data, 498 sizeof (openprom_property) 499 + strlen (op->name) + op->alloclen); 500 memset (((char *)b) + sizeof (openprom_property) 501 + strlen (op->name) + op->alloclen, 502 0, 2*(count - *ppos) - op->alloclen); 503 op = (openprom_property *)b; 504 op->alloclen = 2*(count + *ppos); 505 b = filp->private_data; 506 filp->private_data = (void *)op; 507 kfree (b); 508 } 509 p = op->value + *ppos - ((op->flag & OPP_QUOTED) ? 1 : 0); 510 if (copy_from_user(p, buf, count)) 511 return -EFAULT; 512 op->flag |= OPP_DIRTY; 513 for (i = 0; i < count; i++, p++) 514 if (*p == '\n') { 515 *p = 0; 516 break; 517 } 518 if (i < count) { 519 op->len = p - op->value; 520 *ppos += i + 1; 521 if ((p > op->value) && (op->flag & OPP_QUOTED) 522 && (*(p - 1) == '\'')) 523 op->len--; 524 } else { 525 if (p - op->value > op->len) 526 op->len = p - op->value; 527 *ppos += count; 528 } 529 } 530 return *ppos - k; 531 } 532 533 int property_release (struct inode *inode, struct file *filp) 534 { 535 openprom_property *op = (openprom_property *)filp->private_data; 536 int error; 537 u32 node; 538 539 if (!op) 540 return 0; 541 lock_kernel(); 542 node = nodes[(u16)((long)inode->u.generic_ip)].node; 543 if ((u16)((long)inode->u.generic_ip) == aliases) { 544 if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) { 545 char *p = op->name; 546 int i = (op->value - op->name) - strlen (op->name) - 1; 547 op->value [op->len] = 0; 548 *(op->value - 1) = ' '; 549 if (i) { 550 for (p = op->value - i - 2; p >= op->name; p--) 551 p[i] = *p; 552 p = op->name + i; 553 } 554 memcpy (p - 8, "nvalias ", 8); 555 prom_feval (p - 8); 556 } 557 } else if (op->flag & OPP_DIRTY) { 558 if (op->flag & OPP_STRING) { 559 op->value [op->len] = 0; 560 error = prom_setprop (node, op->name, 561 op->value, op->len + 1); 562 if (error <= 0) 563 printk (KERN_WARNING "openpromfs: " 564 "Couldn't write property %s\n", 565 op->name); 566 } else if ((op->flag & OPP_BINARY) || !op->len) { 567 error = prom_setprop (node, op->name, 568 op->value, op->len); 569 if (error <= 0) 570 printk (KERN_WARNING "openpromfs: " 571 "Couldn't write property %s\n", 572 op->name); 573 } else { 574 printk (KERN_WARNING "openpromfs: " 575 "Unknown property type of %s\n", 576 op->name); 577 } 578 } 579 unlock_kernel(); 580 kfree (filp->private_data); 581 return 0; 582 } 583 584 static struct file_operations openpromfs_prop_ops = { 585 .read = property_read, 586 .write = property_write, 587 .release = property_release, 588 }; 589 590 static struct file_operations openpromfs_nodenum_ops = { 591 .read = nodenum_read, 592 }; 593 594 static struct file_operations openprom_operations = { 595 .read = generic_read_dir, 596 .readdir = openpromfs_readdir, 597 }; 598 599 static struct inode_operations openprom_alias_inode_operations = { 600 .create = openpromfs_create, 601 .lookup = openpromfs_lookup, 602 .unlink = openpromfs_unlink, 603 }; 604 605 static struct inode_operations openprom_inode_operations = { 606 .lookup = openpromfs_lookup, 607 }; 608 609 static int lookup_children(u16 n, const char * name, int len) 610 { 611 int ret; 612 u16 node; 613 for (; n != 0xffff; n = nodes[n].next) { 614 node = nodes[n].child; 615 if (node != 0xffff) { 616 char buffer[128]; 617 int i; 618 char *p; 619 620 while (node != 0xffff) { 621 if (prom_getname (nodes[node].node, 622 buffer, 128) >= 0) { 623 i = strlen (buffer); 624 if ((len == i) 625 && !strncmp (buffer, name, len)) 626 return NODE2INO(node); 627 p = strchr (buffer, '@'); 628 if (p && (len == p - buffer) 629 && !strncmp (buffer, name, len)) 630 return NODE2INO(node); 631 } 632 node = nodes[node].next; 633 } 634 } else 635 continue; 636 ret = lookup_children (nodes[n].child, name, len); 637 if (ret) return ret; 638 } 639 return 0; 640 } 641 642 static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) 643 { 644 int ino = 0; 645 #define OPFSL_DIR 0 646 #define OPFSL_PROPERTY 1 647 #define OPFSL_NODENUM 2 648 int type = 0; 649 char buffer[128]; 650 char *p; 651 const char *name; 652 u32 n; 653 u16 dirnode; 654 unsigned int len; 655 int i; 656 struct inode *inode; 657 char buffer2[64]; 658 659 inode = NULL; 660 name = dentry->d_name.name; 661 len = dentry->d_name.len; 662 lock_kernel(); 663 if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) { 664 ino = NODEP2INO(NODE(dir->i_ino).first_prop); 665 type = OPFSL_NODENUM; 666 } 667 if (!ino) { 668 u16 node = NODE(dir->i_ino).child; 669 while (node != 0xffff) { 670 if (prom_getname (nodes[node].node, buffer, 128) >= 0) { 671 i = strlen (buffer); 672 if (len == i && !strncmp (buffer, name, len)) { 673 ino = NODE2INO(node); 674 type = OPFSL_DIR; 675 break; 676 } 677 p = strchr (buffer, '@'); 678 if (p && (len == p - buffer) 679 && !strncmp (buffer, name, len)) { 680 ino = NODE2INO(node); 681 type = OPFSL_DIR; 682 break; 683 } 684 } 685 node = nodes[node].next; 686 } 687 } 688 n = NODE(dir->i_ino).node; 689 dirnode = dir->i_ino - OPENPROM_FIRST_INO; 690 if (!ino) { 691 int j = NODEP2INO(NODE(dir->i_ino).first_prop); 692 if (dirnode != aliases) { 693 for (p = prom_firstprop (n, buffer2); 694 p && *p; 695 p = prom_nextprop (n, p, buffer2)) { 696 j++; 697 if ((len == strlen (p)) 698 && !strncmp (p, name, len)) { 699 ino = j; 700 type = OPFSL_PROPERTY; 701 break; 702 } 703 } 704 } else { 705 int k; 706 for (k = 0; k < aliases_nodes; k++) { 707 j++; 708 if (alias_names [k] 709 && (len == strlen (alias_names [k])) 710 && !strncmp (alias_names [k], name, len)) { 711 ino = j; 712 type = OPFSL_PROPERTY; 713 break; 714 } 715 } 716 } 717 } 718 if (!ino) { 719 ino = lookup_children (NODE(dir->i_ino).child, name, len); 720 if (ino) 721 type = OPFSL_DIR; 722 else { 723 unlock_kernel(); 724 return ERR_PTR(-ENOENT); 725 } 726 } 727 inode = iget (dir->i_sb, ino); 728 unlock_kernel(); 729 if (!inode) 730 return ERR_PTR(-EINVAL); 731 switch (type) { 732 case OPFSL_DIR: 733 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 734 if (ino == OPENPROM_FIRST_INO + aliases) { 735 inode->i_mode |= S_IWUSR; 736 inode->i_op = &openprom_alias_inode_operations; 737 } else 738 inode->i_op = &openprom_inode_operations; 739 inode->i_fop = &openprom_operations; 740 inode->i_nlink = 2; 741 break; 742 case OPFSL_NODENUM: 743 inode->i_mode = S_IFREG | S_IRUGO; 744 inode->i_fop = &openpromfs_nodenum_ops; 745 inode->i_nlink = 1; 746 inode->u.generic_ip = (void *)(long)(n); 747 break; 748 case OPFSL_PROPERTY: 749 if ((dirnode == options) && (len == 17) 750 && !strncmp (name, "security-password", 17)) 751 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 752 else { 753 inode->i_mode = S_IFREG | S_IRUGO; 754 if (dirnode == options || dirnode == aliases) { 755 if (len != 4 || strncmp (name, "name", 4)) 756 inode->i_mode |= S_IWUSR; 757 } 758 } 759 inode->i_fop = &openpromfs_prop_ops; 760 inode->i_nlink = 1; 761 if (inode->i_size < 0) 762 inode->i_size = 0; 763 inode->u.generic_ip = (void *)(long)(((u16)dirnode) | 764 (((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16)); 765 break; 766 } 767 768 inode->i_gid = 0; 769 inode->i_uid = 0; 770 771 d_add(dentry, inode); 772 return NULL; 773 } 774 775 static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 776 { 777 struct inode *inode = filp->f_dentry->d_inode; 778 unsigned int ino; 779 u32 n; 780 int i, j; 781 char buffer[128]; 782 u16 node; 783 char *p; 784 char buffer2[64]; 785 786 lock_kernel(); 787 788 ino = inode->i_ino; 789 i = filp->f_pos; 790 switch (i) { 791 case 0: 792 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) goto out; 793 i++; 794 filp->f_pos++; 795 /* fall thru */ 796 case 1: 797 if (filldir(dirent, "..", 2, i, 798 (NODE(ino).parent == 0xffff) ? 799 OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0) 800 goto out; 801 i++; 802 filp->f_pos++; 803 /* fall thru */ 804 default: 805 i -= 2; 806 node = NODE(ino).child; 807 while (i && node != 0xffff) { 808 node = nodes[node].next; 809 i--; 810 } 811 while (node != 0xffff) { 812 if (prom_getname (nodes[node].node, buffer, 128) < 0) 813 goto out; 814 if (filldir(dirent, buffer, strlen(buffer), 815 filp->f_pos, NODE2INO(node), DT_DIR) < 0) 816 goto out; 817 filp->f_pos++; 818 node = nodes[node].next; 819 } 820 j = NODEP2INO(NODE(ino).first_prop); 821 if (!i) { 822 if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0) 823 goto out; 824 filp->f_pos++; 825 } else 826 i--; 827 n = NODE(ino).node; 828 if (ino == OPENPROM_FIRST_INO + aliases) { 829 for (j++; i < aliases_nodes; i++, j++) { 830 if (alias_names [i]) { 831 if (filldir (dirent, alias_names [i], 832 strlen (alias_names [i]), 833 filp->f_pos, j, DT_REG) < 0) goto out; 834 filp->f_pos++; 835 } 836 } 837 } else { 838 for (p = prom_firstprop (n, buffer2); 839 p && *p; 840 p = prom_nextprop (n, p, buffer2)) { 841 j++; 842 if (i) i--; 843 else { 844 if (filldir(dirent, p, strlen(p), 845 filp->f_pos, j, DT_REG) < 0) 846 goto out; 847 filp->f_pos++; 848 } 849 } 850 } 851 } 852 out: 853 unlock_kernel(); 854 return 0; 855 } 856 857 static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode, 858 struct nameidata *nd) 859 { 860 char *p; 861 struct inode *inode; 862 863 if (!dir) 864 return -ENOENT; 865 if (dentry->d_name.len > 256) 866 return -EINVAL; 867 p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL); 868 if (!p) 869 return -ENOMEM; 870 strncpy (p, dentry->d_name.name, dentry->d_name.len); 871 p [dentry->d_name.len] = 0; 872 lock_kernel(); 873 if (aliases_nodes == ALIASES_NNODES) { 874 kfree(p); 875 unlock_kernel(); 876 return -EIO; 877 } 878 alias_names [aliases_nodes++] = p; 879 inode = iget (dir->i_sb, 880 NODEP2INO(NODE(dir->i_ino).first_prop) + aliases_nodes); 881 if (!inode) { 882 unlock_kernel(); 883 return -EINVAL; 884 } 885 inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR; 886 inode->i_fop = &openpromfs_prop_ops; 887 inode->i_nlink = 1; 888 if (inode->i_size < 0) inode->i_size = 0; 889 inode->u.generic_ip = (void *)(long)(((u16)aliases) | 890 (((u16)(aliases_nodes - 1)) << 16)); 891 unlock_kernel(); 892 d_instantiate(dentry, inode); 893 return 0; 894 } 895 896 static int openpromfs_unlink (struct inode *dir, struct dentry *dentry) 897 { 898 unsigned int len; 899 char *p; 900 const char *name; 901 int i; 902 903 name = dentry->d_name.name; 904 len = dentry->d_name.len; 905 lock_kernel(); 906 for (i = 0; i < aliases_nodes; i++) 907 if ((strlen (alias_names [i]) == len) 908 && !strncmp (name, alias_names[i], len)) { 909 char buffer[512]; 910 911 p = alias_names [i]; 912 alias_names [i] = NULL; 913 kfree (p); 914 strcpy (buffer, "nvunalias "); 915 memcpy (buffer + 10, name, len); 916 buffer [10 + len] = 0; 917 prom_feval (buffer); 918 } 919 unlock_kernel(); 920 return 0; 921 } 922 923 /* {{{ init section */ 924 static int __init check_space (u16 n) 925 { 926 unsigned long pages; 927 928 if ((1 << alloced) * PAGE_SIZE < (n + 2) * sizeof(openpromfs_node)) { 929 pages = __get_free_pages (GFP_KERNEL, alloced + 1); 930 if (!pages) 931 return -1; 932 933 if (nodes) { 934 memcpy ((char *)pages, (char *)nodes, 935 (1 << alloced) * PAGE_SIZE); 936 free_pages ((unsigned long)nodes, alloced); 937 } 938 alloced++; 939 nodes = (openpromfs_node *)pages; 940 } 941 return 0; 942 } 943 944 static u16 __init get_nodes (u16 parent, u32 node) 945 { 946 char *p; 947 u16 n = last_node++, i; 948 char buffer[64]; 949 950 if (check_space (n) < 0) 951 return 0xffff; 952 nodes[n].parent = parent; 953 nodes[n].node = node; 954 nodes[n].next = 0xffff; 955 nodes[n].child = 0xffff; 956 nodes[n].first_prop = first_prop++; 957 if (!parent) { 958 char buffer[8]; 959 int j; 960 961 if ((j = prom_getproperty (node, "name", buffer, 8)) >= 0) { 962 buffer[j] = 0; 963 if (!strcmp (buffer, "options")) 964 options = n; 965 else if (!strcmp (buffer, "aliases")) 966 aliases = n; 967 } 968 } 969 if (n != aliases) 970 for (p = prom_firstprop (node, buffer); 971 p && p != (char *)-1 && *p; 972 p = prom_nextprop (node, p, buffer)) 973 first_prop++; 974 else { 975 char *q; 976 for (p = prom_firstprop (node, buffer); 977 p && p != (char *)-1 && *p; 978 p = prom_nextprop (node, p, buffer)) { 979 if (aliases_nodes == ALIASES_NNODES) 980 break; 981 for (i = 0; i < aliases_nodes; i++) 982 if (!strcmp (p, alias_names [i])) 983 break; 984 if (i < aliases_nodes) 985 continue; 986 q = kmalloc (strlen (p) + 1, GFP_KERNEL); 987 if (!q) 988 return 0xffff; 989 strcpy (q, p); 990 alias_names [aliases_nodes++] = q; 991 } 992 first_prop += ALIASES_NNODES; 993 } 994 node = prom_getchild (node); 995 if (node) { 996 parent = get_nodes (n, node); 997 if (parent == 0xffff) 998 return 0xffff; 999 nodes[n].child = parent; 1000 while ((node = prom_getsibling (node)) != 0) { 1001 i = get_nodes (n, node); 1002 if (i == 0xffff) 1003 return 0xffff; 1004 nodes[parent].next = i; 1005 parent = i; 1006 } 1007 } 1008 return n; 1009 } 1010 1011 static void openprom_read_inode(struct inode * inode) 1012 { 1013 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 1014 if (inode->i_ino == OPENPROM_ROOT_INO) { 1015 inode->i_op = &openprom_inode_operations; 1016 inode->i_fop = &openprom_operations; 1017 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 1018 } 1019 } 1020 1021 static int openprom_remount(struct super_block *sb, int *flags, char *data) 1022 { 1023 *flags |= MS_NOATIME; 1024 return 0; 1025 } 1026 1027 static struct super_operations openprom_sops = { 1028 .read_inode = openprom_read_inode, 1029 .statfs = simple_statfs, 1030 .remount_fs = openprom_remount, 1031 }; 1032 1033 static int openprom_fill_super(struct super_block *s, void *data, int silent) 1034 { 1035 struct inode * root_inode; 1036 1037 s->s_flags |= MS_NOATIME; 1038 s->s_blocksize = 1024; 1039 s->s_blocksize_bits = 10; 1040 s->s_magic = OPENPROM_SUPER_MAGIC; 1041 s->s_op = &openprom_sops; 1042 s->s_time_gran = 1; 1043 root_inode = iget(s, OPENPROM_ROOT_INO); 1044 if (!root_inode) 1045 goto out_no_root; 1046 s->s_root = d_alloc_root(root_inode); 1047 if (!s->s_root) 1048 goto out_no_root; 1049 return 0; 1050 1051 out_no_root: 1052 printk("openprom_fill_super: get root inode failed\n"); 1053 iput(root_inode); 1054 return -ENOMEM; 1055 } 1056 1057 static struct super_block *openprom_get_sb(struct file_system_type *fs_type, 1058 int flags, const char *dev_name, void *data) 1059 { 1060 return get_sb_single(fs_type, flags, data, openprom_fill_super); 1061 } 1062 1063 static struct file_system_type openprom_fs_type = { 1064 .owner = THIS_MODULE, 1065 .name = "openpromfs", 1066 .get_sb = openprom_get_sb, 1067 .kill_sb = kill_anon_super, 1068 }; 1069 1070 static int __init init_openprom_fs(void) 1071 { 1072 nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0); 1073 if (!nodes) { 1074 printk (KERN_WARNING "openpromfs: can't get free page\n"); 1075 return -EIO; 1076 } 1077 if (get_nodes (0xffff, prom_root_node) == 0xffff) { 1078 printk (KERN_WARNING "openpromfs: couldn't setup tree\n"); 1079 return -EIO; 1080 } 1081 nodes[last_node].first_prop = first_prop; 1082 return register_filesystem(&openprom_fs_type); 1083 } 1084 1085 static void __exit exit_openprom_fs(void) 1086 { 1087 int i; 1088 unregister_filesystem(&openprom_fs_type); 1089 free_pages ((unsigned long)nodes, alloced); 1090 for (i = 0; i < aliases_nodes; i++) 1091 if (alias_names [i]) 1092 kfree (alias_names [i]); 1093 nodes = NULL; 1094 } 1095 1096 module_init(init_openprom_fs) 1097 module_exit(exit_openprom_fs) 1098 MODULE_LICENSE("GPL"); 1099