diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /fs/devpts/root.c | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff) |
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash.
o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'fs/devpts/root.c')
-rw-r--r-- | fs/devpts/root.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/fs/devpts/root.c b/fs/devpts/root.c new file mode 100644 index 000000000..1ee855bb4 --- /dev/null +++ b/fs/devpts/root.c @@ -0,0 +1,170 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/devpts/root.c + * + * Copyright 1998 H. Peter Anvin -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include <linux/errno.h> +#include <linux/stat.h> +#include <linux/param.h> +#include <linux/string.h> +#include "devpts_i.h" + +static int devpts_root_readdir(struct file *,void *,filldir_t); +static int devpts_root_lookup(struct inode *,struct dentry *); +static int devpts_revalidate(struct dentry *); + +static struct file_operations devpts_root_operations = { + NULL, /* llseek */ + NULL, /* read */ + NULL, /* write */ + devpts_root_readdir, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +struct inode_operations devpts_root_inode_operations = { + &devpts_root_operations, /* file operations */ + NULL, /* create */ + devpts_root_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ +}; + +static struct dentry_operations devpts_dentry_operations = { + devpts_revalidate, /* d_revalidate */ + NULL, /* d_hash */ + NULL, /* d_compare */ +}; + +/* + * The normal naming convention is simply /dev/pts/<number>; this conforms + * to the System V naming convention + */ + +#define genptsname(buf,num) sprintf(buf, "%d", num) + +static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct devpts_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb); + off_t nr; + char numbuf[16]; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -ENOTDIR; + + nr = filp->f_pos; + + switch(nr) + { + case 0: + if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + default: + while ( nr < NR_PTYS+2 ) { + int ptynr = nr - 2; + if ( sbi->inodes[ptynr] ) { + genptsname(numbuf, ptynr); + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + return 0; + } + filp->f_pos = ++nr; + } + break; + } + + return 0; +} + +/* + * Revalidate is called on every cache lookup. We use it to check that + * the pty really does still exist. Never revalidate negative dentries; + * for simplicity (fix later?) + */ +static int devpts_revalidate(struct dentry * dentry) +{ + struct devpts_sb_info *sbi; + + if ( !dentry->d_inode ) + return 0; + + sbi = SBI(dentry->d_inode->i_sb); + + return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode ); +} + +static int devpts_root_lookup(struct inode * dir, struct dentry * dentry) +{ + struct devpts_sb_info *sbi = SBI(dir->i_sb); + int entry, i; + const char *p; + + if (!S_ISDIR(dir->i_mode)) + return -ENOTDIR; + + dentry->d_inode = NULL; /* Assume failure */ + dentry->d_op = &devpts_dentry_operations; + + if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) { + entry = 0; + } else if ( dentry->d_name.len < 1 ) { + return 0; + } else { + p = dentry->d_name.name; + if ( *p < '1' || *p > '9' ) + return 0; + entry = *p++ - '0'; + + for ( i = dentry->d_name.len-1 ; i ; i-- ) { + if ( *p < '0' || *p > '9' ) + return 0; + entry *= 10; + entry += (*p++ - '0'); + } + } + + dentry->d_inode = sbi->inodes[entry]; + if ( dentry->d_inode ) + dentry->d_inode->i_count++; + + d_add(dentry, dentry->d_inode); + + return 0; +} |