inode.c 25 KB

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