#define DEVPTS_DEFAULT_MODE 0600 /* * ptmx is a new node in /dev/pts and will be unused in legacy (single- * instance) mode. To prevent surprises in user space, set permissions of * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful * permissions.
*/ #define DEVPTS_DEFAULT_PTMX_MODE 0000 #define PTMX_MINOR 2
/* * sysctl support for setting limits on the number of Unix98 ptys allocated. * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
*/ staticint pty_limit = NR_UNIX98_PTY_DEFAULT; staticint pty_reserve = NR_UNIX98_PTY_RESERVE; staticint pty_limit_min; staticint pty_limit_max = INT_MAX; static atomic_t pty_count = ATOMIC_INIT(0);
staticint devpts_ptmx_path(struct path *path)
{ struct super_block *sb; int err;
/* Is a devpts filesystem at "pts" in the same directory? */
err = path_pts(path); if (err) return err;
/* Is the path the root of a devpts filesystem? */
sb = path->mnt->mnt_sb; if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
(path->mnt->mnt_root != sb->s_root)) return -ENODEV;
return 0;
}
/* * Try to find a suitable devpts filesystem. We support the following * scenarios: * - The ptmx device node is located in the same directory as the devpts * mount where the pts device nodes are located. * This is e.g. the case when calling open on the /dev/pts/ptmx device * node when the devpts filesystem is mounted at /dev/pts. * - The ptmx device node is located outside the devpts filesystem mount * where the pts device nodes are located. For example, the ptmx device * is a symlink, separate device node, or bind-mount. * A supported scenario is bind-mounting /dev/pts/ptmx to /dev/ptmx and * then calling open on /dev/ptmx. In this case a suitable pts * subdirectory can be found in the common parent directory /dev of the * devpts mount and the ptmx bind-mount, after resolving the /dev/ptmx * bind-mount. * If no suitable pts subdirectory can be found this function will fail. * This is e.g. the case when bind-mounting /dev/pts/ptmx to /ptmx.
*/ struct vfsmount *devpts_mntget(struct file *filp, struct pts_fs_info *fsi)
{ struct path path; int err = 0;
path = filp->f_path;
path_get(&path);
/* Walk upward while the start point is a bind mount of * a single file.
*/ while (path.mnt->mnt_root == path.dentry) if (follow_up(&path) == 0) break;
/* devpts_ptmx_path() finds a devpts fs or returns an error. */ if ((path.mnt->mnt_sb->s_magic != DEVPTS_SUPER_MAGIC) ||
(DEVPTS_SB(path.mnt->mnt_sb) != fsi))
err = devpts_ptmx_path(&path);
dput(path.dentry); if (!err) { if (DEVPTS_SB(path.mnt->mnt_sb) == fsi) return path.mnt;
/* Has the devpts filesystem already been found? */ if (path.mnt->mnt_sb->s_magic != DEVPTS_SUPER_MAGIC) { int err;
err = devpts_ptmx_path(&path); if (err) {
result = ERR_PTR(err); goto out;
}
}
/* * pty code needs to hold extra references in case of last /dev/tty close
*/
sb = path.mnt->mnt_sb;
atomic_inc(&sb->s_active);
result = DEVPTS_SB(sb);
/* If we have already created ptmx node, return */ if (fsi->ptmx_dentry) {
rc = 0; goto out;
}
dentry = d_alloc_name(root, "ptmx"); if (!dentry) {
pr_err("Unable to alloc dentry for ptmx node\n"); goto out;
}
/* * Create a new 'ptmx' node in this mount of devpts.
*/
inode = new_inode(sb); if (!inode) {
pr_err("Unable to alloc inode for ptmx node\n");
dput(dentry); goto out;
}
/* Apply the revised options. We don't want to change ->reserve. * Ideally, we'd update each option conditionally on it having been * explicitly changed, but the default is to reset everything so that * would break UAPI...
*/
fsi->mount_opts.setuid = new->mount_opts.setuid;
fsi->mount_opts.setgid = new->mount_opts.setgid;
fsi->mount_opts.uid = new->mount_opts.uid;
fsi->mount_opts.gid = new->mount_opts.gid;
fsi->mount_opts.mode = new->mount_opts.mode;
fsi->mount_opts.ptmxmode = new->mount_opts.ptmxmode;
fsi->mount_opts.max = new->mount_opts.max;
/* * parse_mount_options() restores options to default values * before parsing and may have changed ptmxmode. So, update the * mode in the inode too. Bogus options don't fail the remount, * so do this even on error return.
*/
update_ptmx_mode(fsi);
/* * devpts_get_tree() * * Mount a new (private) instance of devpts. PTYs created in this * instance are independent of the PTYs in other devpts instances.
*/ staticint devpts_get_tree(struct fs_context *fc)
{ return get_tree_nodev(fc, devpts_fill_super);
}
/** * devpts_pty_new -- create a new inode in /dev/pts/ * @fsi: Filesystem info for this instance. * @index: used as a name of the node * @priv: what's given back by devpts_get_priv * * The dentry for the created inode is returned. * Remove it from /dev/pts/ with devpts_pty_kill().
*/ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv)
{ struct dentry *dentry; struct super_block *sb = fsi->sb; struct inode *inode; struct dentry *root; struct pts_mount_opts *opts; char s[12];
root = sb->s_root;
opts = &fsi->mount_opts;
inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM);
/** * devpts_get_priv -- get private data for a slave * @dentry: dentry of the slave * * Returns whatever was passed as priv in devpts_pty_new for a given inode.
*/ void *devpts_get_priv(struct dentry *dentry)
{ if (dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC) return NULL; return dentry->d_fsdata;
}
/** * devpts_pty_kill -- remove inode form /dev/pts/ * @dentry: dentry of the slave to be removed * * This is an inverse operation of devpts_pty_new.
*/ void devpts_pty_kill(struct dentry *dentry)
{
WARN_ON_ONCE(dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.