inode.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:25k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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