ptyfs_vfsops.c revision 1.28
1/* $NetBSD: ptyfs_vfsops.c,v 1.28 2007/07/31 21:14:18 pooka Exp $ */ 2 3/* 4 * Copyright (c) 1992, 1993, 1995 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36/* 37 * Pseudo-tty Filesystem 38 */ 39 40#include <sys/cdefs.h> 41__KERNEL_RCSID(0, "$NetBSD: ptyfs_vfsops.c,v 1.28 2007/07/31 21:14:18 pooka Exp $"); 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/sysctl.h> 46#include <sys/conf.h> 47#include <sys/proc.h> 48#include <sys/vnode.h> 49#include <sys/mount.h> 50#include <sys/namei.h> 51#include <sys/stat.h> 52#include <sys/dirent.h> 53#include <sys/malloc.h> 54#include <sys/syslog.h> 55#include <sys/select.h> 56#include <sys/filedesc.h> 57#include <sys/tty.h> 58#include <sys/pty.h> 59#include <sys/kauth.h> 60 61#include <fs/ptyfs/ptyfs.h> 62#include <miscfs/specfs/specdev.h> 63 64MALLOC_JUSTDEFINE(M_PTYFSMNT, "ptyfs mount", "ptyfs mount structures"); 65 66VFS_PROTOS(ptyfs); 67 68static int ptyfs__allocvp(struct ptm_pty *, struct lwp *, struct vnode **, 69 dev_t, char); 70static int ptyfs__makename(struct ptm_pty *, struct lwp *, char *, size_t, 71 dev_t, char); 72static void ptyfs__getvattr(struct ptm_pty *, struct lwp *, struct vattr *); 73 74/* 75 * ptm glue: When we mount, we make ptm point to us. 76 */ 77struct ptm_pty *ptyfs_save_ptm; 78static int ptyfs_count; 79 80struct ptm_pty ptm_ptyfspty = { 81 ptyfs__allocvp, 82 ptyfs__makename, 83 ptyfs__getvattr, 84 NULL 85}; 86 87static const char * 88ptyfs__getpath(struct lwp *l, const struct mount *mp) 89{ 90#define MAXBUF (sizeof(mp->mnt_stat.f_mntonname) + 32) 91 struct cwdinfo *cwdi = l->l_proc->p_cwdi; 92 char *buf; 93 const char *rv; 94 size_t len; 95 char *bp; 96 int error; 97 98 rv = mp->mnt_stat.f_mntonname; 99 if (cwdi->cwdi_rdir == NULL) 100 return rv; 101 102 buf = malloc(MAXBUF, M_TEMP, M_WAITOK); 103 bp = buf + MAXBUF; 104 *--bp = '\0'; 105 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, 106 buf, MAXBUF / 2, 0, l); 107 if (error) /* XXX */ 108 goto out; 109 110 len = strlen(bp); 111 if (len < sizeof(mp->mnt_stat.f_mntonname)) /* XXX */ 112 rv += len; 113out: 114 free(buf, M_TEMP); 115 return rv; 116} 117 118static int 119ptyfs__makename(struct ptm_pty *pt, struct lwp *l, char *tbuf, size_t bufsiz, 120 dev_t dev, char ms) 121{ 122 struct mount *mp = pt->arg; 123 size_t len; 124 125 switch (ms) { 126 case 'p': 127 /* We don't provide access to the master, should we? */ 128 len = snprintf(tbuf, bufsiz, "/dev/null"); 129 break; 130 case 't': 131 len = snprintf(tbuf, bufsiz, "%s/%d", ptyfs__getpath(l, mp), 132 minor(dev)); 133 break; 134 default: 135 return EINVAL; 136 } 137 138 return len >= bufsiz ? ENOSPC : 0; 139} 140 141 142static int 143/*ARGSUSED*/ 144ptyfs__allocvp(struct ptm_pty *pt, struct lwp *l, struct vnode **vpp, 145 dev_t dev, char ms) 146{ 147 struct mount *mp = pt->arg; 148 ptyfstype type; 149 150 switch (ms) { 151 case 'p': 152 type = PTYFSptc; 153 break; 154 case 't': 155 type = PTYFSpts; 156 break; 157 default: 158 return EINVAL; 159 } 160 161 return ptyfs_allocvp(mp, vpp, type, minor(dev), l); 162} 163 164 165static void 166ptyfs__getvattr(struct ptm_pty *pt, struct lwp *l, struct vattr *vattr) 167{ 168 struct mount *mp = pt->arg; 169 struct ptyfsmount *pmnt = VFSTOPTY(mp); 170 VATTR_NULL(vattr); 171 /* get real uid */ 172 vattr->va_uid = kauth_cred_getuid(l->l_cred); 173 vattr->va_gid = pmnt->pmnt_gid; 174 vattr->va_mode = pmnt->pmnt_mode; 175} 176 177 178void 179ptyfs_init(void) 180{ 181 182 malloc_type_attach(M_PTYFSMNT); 183 ptyfs_hashinit(); 184} 185 186void 187ptyfs_reinit(void) 188{ 189 ptyfs_hashreinit(); 190} 191 192void 193ptyfs_done(void) 194{ 195 196 ptyfs_hashdone(); 197 malloc_type_detach(M_PTYFSMNT); 198} 199 200/* 201 * Mount the Pseudo tty params filesystem 202 */ 203int 204ptyfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len, 205 struct lwp *l) 206{ 207 int error = 0; 208 struct ptyfsmount *pmnt; 209 struct ptyfs_args *args = data; 210 211 if (*data_len < sizeof *args) 212 return EINVAL; 213 214 if (UIO_MX & (UIO_MX - 1)) { 215 log(LOG_ERR, "ptyfs: invalid directory entry size"); 216 return EINVAL; 217 } 218 219 if (mp->mnt_flag & MNT_GETARGS) { 220 pmnt = VFSTOPTY(mp); 221 if (pmnt == NULL) 222 return EIO; 223 args->version = PTYFS_ARGSVERSION; 224 args->mode = pmnt->pmnt_mode; 225 args->gid = pmnt->pmnt_gid; 226 *data_len = sizeof *args; 227 return 0; 228 } 229 230 /* Don't allow more than one mount */ 231 if (ptyfs_count) 232 return EBUSY; 233 234 if (mp->mnt_flag & MNT_UPDATE) 235 return EOPNOTSUPP; 236 237 if (args->version != PTYFS_ARGSVERSION) 238 return EINVAL; 239 240 pmnt = malloc(sizeof(struct ptyfsmount), M_UFSMNT, M_WAITOK); 241 242 mp->mnt_data = pmnt; 243 pmnt->pmnt_gid = args->gid; 244 pmnt->pmnt_mode = args->mode; 245 mp->mnt_flag |= MNT_LOCAL; 246 vfs_getnewfsid(mp); 247 248 if ((error = set_statvfs_info(path, UIO_USERSPACE, "ptyfs", 249 UIO_SYSSPACE, mp->mnt_op->vfs_name, mp, l)) != 0) { 250 free(pmnt, M_UFSMNT); 251 return error; 252 } 253 254 /* Point pty access to us */ 255 256 ptm_ptyfspty.arg = mp; 257 ptyfs_save_ptm = pty_sethandler(&ptm_ptyfspty); 258 ptyfs_count++; 259 return 0; 260} 261 262/*ARGSUSED*/ 263int 264ptyfs_start(struct mount *mp, int flags, 265 struct lwp *p) 266{ 267 return 0; 268} 269 270/*ARGSUSED*/ 271int 272ptyfs_unmount(struct mount *mp, int mntflags, struct lwp *p) 273{ 274 int error; 275 int flags = 0; 276 277 if (mntflags & MNT_FORCE) 278 flags |= FORCECLOSE; 279 280 if ((error = vflush(mp, 0, flags)) != 0) 281 return (error); 282 283 /* Restore where pty access was pointing */ 284 (void)pty_sethandler(ptyfs_save_ptm); 285 ptyfs_save_ptm = NULL; 286 ptm_ptyfspty.arg = NULL; 287 288 /* 289 * Finally, throw away the ptyfsmount structure 290 */ 291 free(mp->mnt_data, M_UFSMNT); 292 mp->mnt_data = 0; 293 ptyfs_count--; 294 295 return 0; 296} 297 298int 299ptyfs_root(struct mount *mp, struct vnode **vpp) 300{ 301 /* setup "." */ 302 return ptyfs_allocvp(mp, vpp, PTYFSroot, 0, NULL); 303} 304 305/*ARGSUSED*/ 306int 307ptyfs_quotactl(struct mount *mp, int cmd, uid_t uid, 308 void *arg, struct lwp *p) 309{ 310 return EOPNOTSUPP; 311} 312 313/*ARGSUSED*/ 314int 315ptyfs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *p) 316{ 317 sbp->f_bsize = DEV_BSIZE; 318 sbp->f_frsize = DEV_BSIZE; 319 sbp->f_iosize = DEV_BSIZE; 320 sbp->f_blocks = 2; /* 1K to keep df happy */ 321 sbp->f_bfree = 0; 322 sbp->f_bavail = 0; 323 sbp->f_bresvd = 0; 324 sbp->f_files = 1024; /* XXX lie */ 325 sbp->f_ffree = 128; /* XXX lie */ 326 sbp->f_favail = 128; /* XXX lie */ 327 sbp->f_fresvd = 0; 328 sbp->f_namemax = MAXNAMLEN; 329 copy_statvfs_info(sbp, mp); 330 return 0; 331} 332 333/*ARGSUSED*/ 334int 335ptyfs_sync(struct mount *mp, int waitfor, 336 kauth_cred_t uc, struct lwp *p) 337{ 338 return 0; 339} 340 341/* 342 * Kernfs flat namespace lookup. 343 * Currently unsupported. 344 */ 345/*ARGSUSED*/ 346int 347ptyfs_vget(struct mount *mp, ino_t ino, 348 struct vnode **vpp) 349{ 350 return EOPNOTSUPP; 351} 352 353SYSCTL_SETUP(sysctl_vfs_ptyfs_setup, "sysctl vfs.ptyfs subtree setup") 354{ 355 356 sysctl_createv(clog, 0, NULL, NULL, 357 CTLFLAG_PERMANENT, 358 CTLTYPE_NODE, "vfs", NULL, 359 NULL, 0, NULL, 0, 360 CTL_VFS, CTL_EOL); 361 sysctl_createv(clog, 0, NULL, NULL, 362 CTLFLAG_PERMANENT, 363 CTLTYPE_NODE, "ptyfs", 364 SYSCTL_DESCR("Pty file system"), 365 NULL, 0, NULL, 0, 366 CTL_VFS, 23, CTL_EOL); 367 /* 368 * XXX the "23" above could be dynamic, thereby eliminating 369 * one more instance of the "number to vfs" mapping problem, 370 * but "23" is the order as taken from sys/mount.h 371 */ 372} 373 374 375extern const struct vnodeopv_desc ptyfs_vnodeop_opv_desc; 376 377const struct vnodeopv_desc * const ptyfs_vnodeopv_descs[] = { 378 &ptyfs_vnodeop_opv_desc, 379 NULL, 380}; 381 382struct vfsops ptyfs_vfsops = { 383 MOUNT_PTYFS, 384 sizeof (struct ptyfs_args), 385 ptyfs_mount, 386 ptyfs_start, 387 ptyfs_unmount, 388 ptyfs_root, 389 ptyfs_quotactl, 390 ptyfs_statvfs, 391 ptyfs_sync, 392 ptyfs_vget, 393 (void *)eopnotsupp, /* vfs_fhtovp */ 394 (void *)eopnotsupp, /* vfs_vptofp */ 395 ptyfs_init, 396 ptyfs_reinit, 397 ptyfs_done, 398 NULL, /* vfs_mountroot */ 399 (int (*)(struct mount *, struct vnode *, struct timespec *))eopnotsupp, 400 (int (*)(struct mount *, int, struct vnode *, int, const char *, 401 struct lwp *))eopnotsupp, 402 (void *)eopnotsupp, /* vfs_suspendctl */ 403 ptyfs_vnodeopv_descs, 404 0, 405 { NULL, NULL }, 406}; 407VFS_ATTACH(ptyfs_vfsops); 408