summaryrefslogtreecommitdiffstats
path: root/fs/proc/openpromfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/openpromfs.c')
-rw-r--r--fs/proc/openpromfs.c124
1 files changed, 104 insertions, 20 deletions
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index b3871059e..2c2c84784 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,7 +1,8 @@
-/* $Id: openpromfs.c,v 1.26 1998/01/28 09:55:32 ecd Exp $
+/* $Id: openpromfs.c,v 1.32 1998/11/18 06:15:20 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/module.h>
@@ -27,7 +28,9 @@ typedef struct {
typedef struct {
#define OPP_STRING 0x10
-#define OPP_BINARY 0x20
+#define OPP_STRINGLIST 0x20
+#define OPP_BINARY 0x40
+#define OPP_HEXSTRING 0x80
#define OPP_DIRTY 0x01
#define OPP_QUOTED 0x02
#define OPP_NOTQUOTED 0x04
@@ -83,7 +86,7 @@ static ssize_t property_read(struct file *filp, char *buf,
struct inode *inode = filp->f_dentry->d_inode;
int i, j, k;
u32 node;
- char *p;
+ char *p, *s;
u32 *q;
openprom_property *op;
char buffer[64];
@@ -129,28 +132,51 @@ static ssize_t property_read(struct file *filp, char *buf,
return -EIO;
op->value [k] = 0;
if (k) {
- for (p = op->value; *p >= ' ' && *p <= '~'; p++);
- if (p >= op->value + k - 1 && !*p) {
- op->flag |= OPP_STRING;
- if (p == op->value + k - 1) {
- op->flag |= OPP_ASCIIZ;
- op->len--;
+ for (s = 0, p = op->value; p < op->value + k; p++) {
+ if ((*p >= ' ' && *p <= '~') || *p == '\n') {
+ op->flag |= OPP_STRING;
+ s = p;
+ continue;
}
- } else if (!(k & 3))
- op->flag |= OPP_BINARY;
- else {
- printk ("/proc/openprom: Strange property "
- "size %d\n", i);
- return -EIO;
+ if (p > op->value && !*p && s == p - 1) {
+ if (p < op->value + k - 1)
+ op->flag |= OPP_STRINGLIST;
+ else
+ op->flag |= OPP_ASCIIZ;
+ continue;
+ }
+ if (k == 1 && !*p) {
+ op->flag |= (OPP_STRING|OPP_ASCIIZ);
+ break;
+ }
+ op->flag &= ~(OPP_STRING|OPP_STRINGLIST);
+ if (k & 3)
+ op->flag |= OPP_HEXSTRING;
+ else
+ op->flag |= OPP_BINARY;
+ break;
}
+ if (op->flag & OPP_STRINGLIST)
+ op->flag &= ~(OPP_STRING);
+ if (op->flag & OPP_ASCIIZ)
+ op->len--;
}
} else
op = (openprom_property *)filp->private_data;
- if (!count || !op->len) return 0;
- if (op->flag & OPP_STRING)
+ if (!count || !(op->len || (op->flag & OPP_ASCIIZ)))
+ return 0;
+ if (op->flag & OPP_STRINGLIST) {
+ for (k = 0, p = op->value; p < op->value + op->len; p++)
+ if (!*p)
+ k++;
+ i = op->len + 4 * k + 3;
+ } else if (op->flag & OPP_STRING) {
i = op->len + 3;
- else
- i = (op->len * 9)>>2;
+ } else if (op->flag & OPP_BINARY) {
+ i = (op->len * 9) >> 2;
+ } else {
+ i = (op->len << 1) + 1;
+ }
k = filp->f_pos;
if (k >= i) return 0;
if (count > i - k) count = i - k;
@@ -160,20 +186,48 @@ static ssize_t property_read(struct file *filp, char *buf,
k++;
count--;
}
+
if (k + count >= i - 2)
j = i - 2 - k;
else
j = count;
+
if (j >= 0) {
copy_to_user(buf + k - filp->f_pos,
op->value + k - 1, j);
count -= j;
k += j;
}
+
if (count)
__put_user('\'', &buf [k++ - filp->f_pos]);
if (count > 1)
__put_user('\n', &buf [k++ - filp->f_pos]);
+
+ } else if (op->flag & OPP_STRINGLIST) {
+ char *tmp;
+
+ tmp = kmalloc (i, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ s = tmp;
+ *s++ = '\'';
+ for (p = op->value; p < op->value + op->len; p++) {
+ if (!*p) {
+ strcpy(s, "' + '");
+ s += 5;
+ continue;
+ }
+ *s++ = *p;
+ }
+ strcpy(s, "'\n");
+
+ copy_to_user(buf, tmp + k, count);
+
+ kfree(tmp);
+ k += count;
+
} else if (op->flag & OPP_BINARY) {
char buffer[10];
u32 *first, *last;
@@ -205,9 +259,35 @@ static ssize_t property_read(struct file *filp, char *buf,
}
}
}
+
if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9)
__put_user('\n', (buf - 1));
+
k += count;
+
+ } else if (op->flag & OPP_HEXSTRING) {
+ char buffer[2];
+
+ if ((k < i - 1) && (k & 1)) {
+ sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+ __put_user(buffer[1], &buf[k++ - filp->f_pos]);
+ count--;
+ }
+
+ for (; (count > 1) && (k < i - 1); k += 2) {
+ sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+ copy_to_user (buf + k - filp->f_pos, buffer, 2);
+ count -= 2;
+ }
+
+ if (count && (k < i - 1)) {
+ sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+ __put_user(buffer[0], &buf[k++ - filp->f_pos]);
+ count--;
+ }
+
+ if (count)
+ __put_user('\n', &buf [k++ - filp->f_pos]);
}
count = k - filp->f_pos;
filp->f_pos = k;
@@ -742,6 +822,10 @@ static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
inode->i_rdev = d->rdev;
break;
}
+
+ inode->i_gid = 0;
+ inode->i_uid = 0;
+
d_add(dentry, inode);
return 0;
}