inode.c 25 KB

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