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