[BACK]Return to ptyfs_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / ptyfs

Annotation of src/sys/fs/ptyfs/ptyfs_vnops.c, Revision 1.12.4.1

1.12.4.1! rpaulo      1: /*     $NetBSD: ptyfs_vnops.c,v 1.16 2006/07/23 22:06:10 ad Exp $      */
1.1       jdolecek    2:
                      3: /*
                      4:  * Copyright (c) 1993, 1995
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed 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:  *     @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
                     35:  */
                     36:
                     37: /*
                     38:  * Copyright (c) 1993 Jan-Simon Pendry
                     39:  *
                     40:  * This code is derived from software contributed to Berkeley by
                     41:  * Jan-Simon Pendry.
                     42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
                     51:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
                     53:  *     This product includes software developed by the University of
                     54:  *     California, Berkeley and its contributors.
                     55:  * 4. Neither the name of the University nor the names of its contributors
                     56:  *    may be used to endorse or promote products derived from this software
                     57:  *    without specific prior written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     61:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     62:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     63:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     64:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     65:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     66:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     67:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     68:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     69:  * SUCH DAMAGE.
                     70:  *
                     71:  *     @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
                     72:  */
                     73:
                     74: /*
                     75:  * ptyfs vnode interface
                     76:  */
                     77:
                     78: #include <sys/cdefs.h>
1.12.4.1! rpaulo     79: __KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.16 2006/07/23 22:06:10 ad Exp $");
1.1       jdolecek   80:
                     81: #include <sys/param.h>
                     82: #include <sys/systm.h>
                     83: #include <sys/time.h>
                     84: #include <sys/kernel.h>
                     85: #include <sys/file.h>
                     86: #include <sys/filedesc.h>
                     87: #include <sys/proc.h>
                     88: #include <sys/vnode.h>
                     89: #include <sys/namei.h>
                     90: #include <sys/malloc.h>
                     91: #include <sys/mount.h>
                     92: #include <sys/select.h>
                     93: #include <sys/dirent.h>
                     94: #include <sys/resourcevar.h>
                     95: #include <sys/stat.h>
                     96: #include <sys/conf.h>
                     97: #include <sys/tty.h>
                     98: #include <sys/pty.h>
1.12.4.1! rpaulo     99: #include <sys/kauth.h>
1.1       jdolecek  100:
                    101: #include <uvm/uvm_extern.h>    /* for PAGE_SIZE */
                    102:
                    103: #include <machine/reg.h>
                    104:
1.2       jdolecek  105: #include <fs/ptyfs/ptyfs.h>
1.1       jdolecek  106: #include <miscfs/genfs/genfs.h>
                    107: #include <miscfs/specfs/specdev.h>
                    108:
                    109: /*
                    110:  * Vnode Operations.
                    111:  *
                    112:  */
                    113:
                    114: int    ptyfs_lookup    (void *);
                    115: #define        ptyfs_create    genfs_eopnotsupp
                    116: #define        ptyfs_mknod     genfs_eopnotsupp
                    117: int    ptyfs_open      (void *);
                    118: int    ptyfs_close     (void *);
                    119: int    ptyfs_access    (void *);
                    120: int    ptyfs_getattr   (void *);
                    121: int    ptyfs_setattr   (void *);
                    122: int    ptyfs_read      (void *);
                    123: int    ptyfs_write     (void *);
                    124: #define        ptyfs_fcntl     genfs_fcntl
                    125: int    ptyfs_ioctl     (void *);
                    126: int    ptyfs_poll      (void *);
                    127: int    ptyfs_kqfilter  (void *);
                    128: #define ptyfs_revoke   genfs_revoke
                    129: #define        ptyfs_mmap      genfs_eopnotsupp
                    130: #define        ptyfs_fsync     genfs_nullop
                    131: #define        ptyfs_seek      genfs_nullop
                    132: #define        ptyfs_remove    genfs_eopnotsupp
                    133: #define        ptyfs_link      genfs_abortop
                    134: #define        ptyfs_rename    genfs_eopnotsupp
                    135: #define        ptyfs_mkdir     genfs_eopnotsupp
                    136: #define        ptyfs_rmdir     genfs_eopnotsupp
                    137: #define        ptyfs_symlink   genfs_abortop
                    138: int    ptyfs_readdir   (void *);
                    139: #define        ptyfs_readlink  genfs_eopnotsupp
                    140: #define        ptyfs_abortop   genfs_abortop
                    141: int    ptyfs_reclaim   (void *);
                    142: #define        ptyfs_lock      genfs_lock
                    143: #define        ptyfs_unlock    genfs_unlock
                    144: #define        ptyfs_bmap      genfs_badop
                    145: #define        ptyfs_strategy  genfs_badop
                    146: int    ptyfs_print     (void *);
                    147: int    ptyfs_pathconf  (void *);
                    148: #define        ptyfs_islocked  genfs_islocked
                    149: #define        ptyfs_advlock   genfs_einval
                    150: #define        ptyfs_bwrite    genfs_eopnotsupp
                    151: #define ptyfs_putpages genfs_null_putpages
                    152:
1.11      yamt      153: static int ptyfs_update(struct vnode *, const struct timespec *,
                    154:     const struct timespec *, int);
1.12.4.1! rpaulo    155: static int ptyfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
        !           156:     struct lwp *);
        !           157: static int ptyfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
1.1       jdolecek  158: static int atoi(const char *, size_t);
                    159:
                    160: extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
                    161:
                    162: /*
                    163:  * ptyfs vnode operations.
                    164:  */
                    165: int (**ptyfs_vnodeop_p)(void *);
                    166: const struct vnodeopv_entry_desc ptyfs_vnodeop_entries[] = {
                    167:        { &vop_default_desc, vn_default_error },
                    168:        { &vop_lookup_desc, ptyfs_lookup },             /* lookup */
                    169:        { &vop_create_desc, ptyfs_create },             /* create */
                    170:        { &vop_mknod_desc, ptyfs_mknod },               /* mknod */
                    171:        { &vop_open_desc, ptyfs_open },                 /* open */
                    172:        { &vop_close_desc, ptyfs_close },               /* close */
                    173:        { &vop_access_desc, ptyfs_access },             /* access */
                    174:        { &vop_getattr_desc, ptyfs_getattr },           /* getattr */
                    175:        { &vop_setattr_desc, ptyfs_setattr },           /* setattr */
                    176:        { &vop_read_desc, ptyfs_read },                 /* read */
                    177:        { &vop_write_desc, ptyfs_write },               /* write */
                    178:        { &vop_ioctl_desc, ptyfs_ioctl },               /* ioctl */
                    179:        { &vop_fcntl_desc, ptyfs_fcntl },               /* fcntl */
                    180:        { &vop_poll_desc, ptyfs_poll },                 /* poll */
                    181:        { &vop_kqfilter_desc, ptyfs_kqfilter },         /* kqfilter */
                    182:        { &vop_revoke_desc, ptyfs_revoke },             /* revoke */
                    183:        { &vop_mmap_desc, ptyfs_mmap },                 /* mmap */
                    184:        { &vop_fsync_desc, ptyfs_fsync },               /* fsync */
                    185:        { &vop_seek_desc, ptyfs_seek },                 /* seek */
                    186:        { &vop_remove_desc, ptyfs_remove },             /* remove */
                    187:        { &vop_link_desc, ptyfs_link },                 /* link */
                    188:        { &vop_rename_desc, ptyfs_rename },             /* rename */
                    189:        { &vop_mkdir_desc, ptyfs_mkdir },               /* mkdir */
                    190:        { &vop_rmdir_desc, ptyfs_rmdir },               /* rmdir */
                    191:        { &vop_symlink_desc, ptyfs_symlink },           /* symlink */
                    192:        { &vop_readdir_desc, ptyfs_readdir },           /* readdir */
                    193:        { &vop_readlink_desc, ptyfs_readlink },         /* readlink */
                    194:        { &vop_abortop_desc, ptyfs_abortop },           /* abortop */
1.6       christos  195:        { &vop_inactive_desc, spec_inactive },          /* inactive */
1.1       jdolecek  196:        { &vop_reclaim_desc, ptyfs_reclaim },           /* reclaim */
                    197:        { &vop_lock_desc, ptyfs_lock },                 /* lock */
                    198:        { &vop_unlock_desc, ptyfs_unlock },             /* unlock */
                    199:        { &vop_bmap_desc, ptyfs_bmap },                 /* bmap */
                    200:        { &vop_strategy_desc, ptyfs_strategy },         /* strategy */
                    201:        { &vop_print_desc, ptyfs_print },               /* print */
                    202:        { &vop_islocked_desc, ptyfs_islocked },         /* islocked */
                    203:        { &vop_pathconf_desc, ptyfs_pathconf },         /* pathconf */
                    204:        { &vop_advlock_desc, ptyfs_advlock },           /* advlock */
                    205:        { &vop_bwrite_desc, ptyfs_bwrite },             /* bwrite */
                    206:        { &vop_putpages_desc, ptyfs_putpages },         /* putpages */
                    207:        { NULL, NULL }
                    208: };
                    209: const struct vnodeopv_desc ptyfs_vnodeop_opv_desc =
                    210:        { &ptyfs_vnodeop_p, ptyfs_vnodeop_entries };
                    211:
                    212: /*
                    213:  * _reclaim is called when getnewvnode()
                    214:  * wants to make use of an entry on the vnode
                    215:  * free list.  at this time the filesystem needs
                    216:  * to free any private data and remove the node
                    217:  * from any private lists.
                    218:  */
                    219: int
                    220: ptyfs_reclaim(void *v)
                    221: {
                    222:        struct vop_reclaim_args /* {
                    223:                struct vnode *a_vp;
                    224:        } */ *ap = v;
                    225:        return ptyfs_freevp(ap->a_vp);
                    226: }
                    227:
                    228: /*
                    229:  * Return POSIX pathconf information applicable to special devices.
                    230:  */
                    231: int
                    232: ptyfs_pathconf(void *v)
                    233: {
                    234:        struct vop_pathconf_args /* {
                    235:                struct vnode *a_vp;
                    236:                int a_name;
                    237:                register_t *a_retval;
                    238:        } */ *ap = v;
                    239:
                    240:        switch (ap->a_name) {
                    241:        case _PC_LINK_MAX:
                    242:                *ap->a_retval = LINK_MAX;
                    243:                return 0;
                    244:        case _PC_MAX_CANON:
                    245:                *ap->a_retval = MAX_CANON;
                    246:                return 0;
                    247:        case _PC_MAX_INPUT:
                    248:                *ap->a_retval = MAX_INPUT;
                    249:                return 0;
                    250:        case _PC_PIPE_BUF:
                    251:                *ap->a_retval = PIPE_BUF;
                    252:                return 0;
                    253:        case _PC_CHOWN_RESTRICTED:
                    254:                *ap->a_retval = 1;
                    255:                return 0;
                    256:        case _PC_VDISABLE:
                    257:                *ap->a_retval = _POSIX_VDISABLE;
                    258:                return 0;
                    259:        case _PC_SYNC_IO:
                    260:                *ap->a_retval = 1;
                    261:                return 0;
                    262:        default:
                    263:                return EINVAL;
                    264:        }
                    265: }
                    266:
                    267: /*
                    268:  * _print is used for debugging.
                    269:  * just print a readable description
                    270:  * of (vp).
                    271:  */
                    272: int
                    273: ptyfs_print(void *v)
                    274: {
                    275:        struct vop_print_args /* {
                    276:                struct vnode *a_vp;
                    277:        } */ *ap = v;
                    278:        struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
                    279:
                    280:        printf("tag VT_PTYFS, type %d, pty %d\n",
                    281:            ptyfs->ptyfs_type, ptyfs->ptyfs_pty);
                    282:        return 0;
                    283: }
                    284:
                    285: /*
                    286:  * Invent attributes for ptyfsnode (vp) and store
                    287:  * them in (vap).
                    288:  * Directories lengths are returned as zero since
                    289:  * any real length would require the genuine size
                    290:  * to be computed, and nothing cares anyway.
                    291:  *
                    292:  * this is relatively minimal for ptyfs.
                    293:  */
                    294: int
                    295: ptyfs_getattr(void *v)
                    296: {
                    297:        struct vop_getattr_args /* {
                    298:                struct vnode *a_vp;
                    299:                struct vattr *a_vap;
1.12.4.1! rpaulo    300:                kauth_cred_t a_cred;
1.12      christos  301:                struct lwp *a_l;
1.1       jdolecek  302:        } */ *ap = v;
                    303:        struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
                    304:        struct vattr *vap = ap->a_vap;
                    305:
1.9       christos  306:        PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
1.1       jdolecek  307:
                    308:        /* start by zeroing out the attributes */
                    309:        VATTR_NULL(vap);
                    310:
                    311:        /* next do all the common fields */
                    312:        vap->va_type = ap->a_vp->v_type;
1.4       atatat    313:        vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.1       jdolecek  314:        vap->va_fileid = ptyfs->ptyfs_fileno;
                    315:        vap->va_gen = 0;
                    316:        vap->va_flags = 0;
                    317:        vap->va_nlink = 1;
                    318:        vap->va_blocksize = PAGE_SIZE;
                    319:
                    320:        vap->va_atime = ptyfs->ptyfs_atime;
                    321:        vap->va_mtime = ptyfs->ptyfs_mtime;
                    322:        vap->va_ctime = ptyfs->ptyfs_ctime;
                    323:        vap->va_birthtime = ptyfs->ptyfs_birthtime;
                    324:        vap->va_mode = ptyfs->ptyfs_mode;
                    325:        vap->va_flags = ptyfs->ptyfs_flags;
                    326:        vap->va_uid = ptyfs->ptyfs_uid;
                    327:        vap->va_gid = ptyfs->ptyfs_gid;
                    328:
                    329:        switch (ptyfs->ptyfs_type) {
                    330:        case PTYFSpts:
                    331:        case PTYFSptc:
                    332:                if (pty_isfree(ptyfs->ptyfs_pty, 1))
                    333:                        return ENOENT;
1.5       atatat    334:                vap->va_bytes = vap->va_size = 0;
1.7       perry     335:                vap->va_rdev = ap->a_vp->v_rdev;
1.1       jdolecek  336:                break;
                    337:        case PTYFSroot:
                    338:                vap->va_rdev = 0;
                    339:                vap->va_bytes = vap->va_size = DEV_BSIZE;
                    340:                break;
                    341:
                    342:        default:
                    343:                return EOPNOTSUPP;
                    344:        }
                    345:
                    346:        return 0;
                    347: }
                    348:
                    349: /*ARGSUSED*/
                    350: int
                    351: ptyfs_setattr(void *v)
                    352: {
                    353:        struct vop_setattr_args /* {
                    354:                struct vnodeop_desc *a_desc;
                    355:                struct vnode *a_vp;
                    356:                struct vattr *a_vap;
1.12.4.1! rpaulo    357:                kauth_cred_t a_cred;
1.12      christos  358:                struct lwp *a_l;
1.1       jdolecek  359:        } */ *ap = v;
                    360:        struct vnode *vp = ap->a_vp;
                    361:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    362:        struct vattr *vap = ap->a_vap;
1.12.4.1! rpaulo    363:        kauth_cred_t cred = ap->a_cred;
1.12      christos  364:        struct lwp *l = ap->a_l;
1.1       jdolecek  365:        int error;
                    366:
                    367:        if (vap->va_size != VNOVAL) {
                    368:                switch (ptyfs->ptyfs_type) {
                    369:                case PTYFSroot:
                    370:                        return EISDIR;
                    371:                case PTYFSpts:
                    372:                case PTYFSptc:
                    373:                        break;
                    374:                default:
                    375:                        return EINVAL;
                    376:                }
                    377:        }
                    378:
                    379:        if (vap->va_flags != VNOVAL) {
                    380:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    381:                        return EROFS;
1.12.4.1! rpaulo    382:                if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
        !           383:                    (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
        !           384:                    &l->l_acflag)) != 0)
1.1       jdolecek  385:                        return error;
1.12.4.1! rpaulo    386:                if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) {
1.1       jdolecek  387:                        if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) &&
                    388:                            securelevel > 0)
                    389:                                return EPERM;
                    390:                        /* Snapshot flag cannot be set or cleared */
1.7       perry     391:                        if ((vap->va_flags & SF_SNAPSHOT) !=
1.1       jdolecek  392:                            (ptyfs->ptyfs_flags & SF_SNAPSHOT))
                    393:                                return EPERM;
                    394:                        ptyfs->ptyfs_flags = vap->va_flags;
                    395:                } else {
                    396:                        if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) ||
                    397:                            (vap->va_flags & UF_SETTABLE) != vap->va_flags)
                    398:                                return EPERM;
                    399:                        if ((ptyfs->ptyfs_flags & SF_SETTABLE) !=
                    400:                            (vap->va_flags & SF_SETTABLE))
                    401:                                return EPERM;
                    402:                        ptyfs->ptyfs_flags &= SF_SETTABLE;
                    403:                        ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE);
                    404:                }
                    405:                ptyfs->ptyfs_flag |= PTYFS_CHANGE;
                    406:                if (vap->va_flags & (IMMUTABLE | APPEND))
                    407:                        return 0;
                    408:        }
                    409:        if (ptyfs->ptyfs_flags & (IMMUTABLE | APPEND))
                    410:                return EPERM;
                    411:        /*
                    412:         * Go through the fields and update iff not VNOVAL.
                    413:         */
                    414:        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
                    415:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    416:                        return EROFS;
                    417:                if (ptyfs->ptyfs_type == PTYFSroot)
                    418:                        return EPERM;
1.12.4.1! rpaulo    419:                error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1       jdolecek  420:                if (error)
                    421:                        return error;
                    422:        }
                    423:
                    424:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
                    425:            vap->va_birthtime.tv_sec != VNOVAL) {
                    426:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    427:                        return EROFS;
                    428:                if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
                    429:                        return EPERM;
1.12.4.1! rpaulo    430:                if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
        !           431:                    (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
        !           432:                    &l->l_acflag)) &&
1.7       perry     433:                    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
1.12      christos  434:                    (error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0))
1.1       jdolecek  435:                        return (error);
                    436:                if (vap->va_atime.tv_sec != VNOVAL)
                    437:                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
                    438:                                ptyfs->ptyfs_flag |= PTYFS_ACCESS;
                    439:                if (vap->va_mtime.tv_sec != VNOVAL)
                    440:                        ptyfs->ptyfs_flag |= PTYFS_CHANGE | PTYFS_MODIFY;
                    441:                if (vap->va_birthtime.tv_sec != VNOVAL)
                    442:                        ptyfs->ptyfs_birthtime = vap->va_birthtime;
                    443:                ptyfs->ptyfs_flag |= PTYFS_CHANGE;
1.11      yamt      444:                error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
1.1       jdolecek  445:                if (error)
                    446:                        return error;
                    447:        }
                    448:        if (vap->va_mode != (mode_t)VNOVAL) {
                    449:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    450:                        return EROFS;
                    451:                if (ptyfs->ptyfs_type == PTYFSroot)
                    452:                        return EPERM;
                    453:                if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 &&
                    454:                    (vap->va_mode &
                    455:                    (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH)))
                    456:                        return EPERM;
1.12.4.1! rpaulo    457:                error = ptyfs_chmod(vp, vap->va_mode, cred, l);
1.1       jdolecek  458:                if (error)
                    459:                        return error;
                    460:        }
                    461:        VN_KNOTE(vp, NOTE_ATTRIB);
                    462:        return 0;
                    463: }
                    464:
                    465: /*
                    466:  * Change the mode on a file.
                    467:  * Inode must be locked before calling.
                    468:  */
                    469: static int
1.12.4.1! rpaulo    470: ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l)
1.1       jdolecek  471: {
                    472:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    473:        int error;
                    474:
1.12.4.1! rpaulo    475:        if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
        !           476:            (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
        !           477:            &l->l_acflag)) != 0)
1.1       jdolecek  478:                return error;
                    479:        ptyfs->ptyfs_mode &= ~ALLPERMS;
                    480:        ptyfs->ptyfs_mode |= (mode & ALLPERMS);
                    481:        return 0;
                    482: }
                    483:
                    484: /*
                    485:  * Perform chown operation on inode ip;
                    486:  * inode must be locked prior to call.
                    487:  */
                    488: static int
1.12.4.1! rpaulo    489: ptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
        !           490:     struct lwp *l)
1.1       jdolecek  491: {
                    492:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.12.4.1! rpaulo    493:        int             error, ismember = 0;
1.1       jdolecek  494:
                    495:        if (uid == (uid_t)VNOVAL)
                    496:                uid = ptyfs->ptyfs_uid;
                    497:        if (gid == (gid_t)VNOVAL)
                    498:                gid = ptyfs->ptyfs_gid;
                    499:        /*
                    500:         * If we don't own the file, are trying to change the owner
                    501:         * of the file, or are not a member of the target group,
                    502:         * the caller's credentials must imply super-user privilege
                    503:         * or the call fails.
                    504:         */
1.12.4.1! rpaulo    505:        if ((kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid || uid != ptyfs->ptyfs_uid ||
1.1       jdolecek  506:            (gid != ptyfs->ptyfs_gid &&
1.12.4.1! rpaulo    507:            !(kauth_cred_getegid(cred) == gid ||
        !           508:            (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) &&
        !           509:            ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
        !           510:            &l->l_acflag)) != 0))
1.1       jdolecek  511:                return error;
                    512:
                    513:        ptyfs->ptyfs_gid = gid;
                    514:        ptyfs->ptyfs_uid = uid;
                    515:        return 0;
                    516: }
                    517:
                    518: /*
                    519:  * implement access checking.
                    520:  *
                    521:  * actually, the check for super-user is slightly
                    522:  * broken since it will allow read access to write-only
                    523:  * objects.  this doesn't cause any particular trouble
                    524:  * but does mean that the i/o entry points need to check
                    525:  * that the operation really does make sense.
                    526:  */
                    527: int
                    528: ptyfs_access(void *v)
                    529: {
                    530:        struct vop_access_args /* {
                    531:                struct vnode *a_vp;
                    532:                int a_mode;
1.12.4.1! rpaulo    533:                kauth_cred_t a_cred;
1.12      christos  534:                struct lwp *a_l;
1.1       jdolecek  535:        } */ *ap = v;
                    536:        struct vattr va;
                    537:        int error;
                    538:
1.12      christos  539:        if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
1.1       jdolecek  540:                return error;
                    541:
                    542:        return vaccess(va.va_type, va.va_mode,
                    543:            va.va_uid, va.va_gid, ap->a_mode, ap->a_cred);
                    544: }
                    545:
                    546: /*
                    547:  * lookup.  this is incredibly complicated in the
                    548:  * general case, however for most pseudo-filesystems
                    549:  * very little needs to be done.
                    550:  *
                    551:  * Locking isn't hard here, just poorly documented.
                    552:  *
1.7       perry     553:  * If we're looking up ".", just vref the parent & return it.
1.1       jdolecek  554:  *
                    555:  * If we're looking up "..", unlock the parent, and lock "..". If everything
                    556:  * went ok, and we're on the last component and the caller requested the
                    557:  * parent locked, try to re-lock the parent. We do this to prevent lock
                    558:  * races.
                    559:  *
                    560:  * For anything else, get the needed node. Then unlock the parent if not
                    561:  * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
                    562:  * parent in the .. case).
                    563:  *
                    564:  * We try to exit with the parent locked in error cases.
                    565:  */
                    566: int
                    567: ptyfs_lookup(void *v)
                    568: {
                    569:        struct vop_lookup_args /* {
                    570:                struct vnode * a_dvp;
                    571:                struct vnode ** a_vpp;
                    572:                struct componentname * a_cnp;
                    573:        } */ *ap = v;
                    574:        struct componentname *cnp = ap->a_cnp;
                    575:        struct vnode **vpp = ap->a_vpp;
                    576:        struct vnode *dvp = ap->a_dvp;
                    577:        const char *pname = cnp->cn_nameptr;
                    578:        struct ptyfsnode *ptyfs;
                    579:        int pty, error, wantpunlock;
                    580:
                    581:        *vpp = NULL;
                    582:        cnp->cn_flags &= ~PDIRUNLOCK;
                    583:
                    584:        if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
                    585:                return EROFS;
                    586:
                    587:        if (cnp->cn_namelen == 1 && *pname == '.') {
                    588:                *vpp = dvp;
                    589:                VREF(dvp);
                    590:                return 0;
                    591:        }
                    592:
                    593:        wantpunlock = ~cnp->cn_flags & (LOCKPARENT | ISLASTCN);
                    594:        ptyfs = VTOPTYFS(dvp);
                    595:        switch (ptyfs->ptyfs_type) {
                    596:        case PTYFSroot:
                    597:                /*
                    598:                 * Shouldn't get here with .. in the root node.
                    599:                 */
1.7       perry     600:                if (cnp->cn_flags & ISDOTDOT)
1.1       jdolecek  601:                        return EIO;
                    602:
                    603:                pty = atoi(pname, cnp->cn_namelen);
                    604:
                    605:                if (pty < 0 || pty >= npty || pty_isfree(pty, 1))
                    606:                        break;
                    607:
                    608:                error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty,
1.12      christos  609:                    curlwp);
1.1       jdolecek  610:                if (error == 0 && wantpunlock) {
                    611:                        VOP_UNLOCK(dvp, 0);
                    612:                        cnp->cn_flags |= PDIRUNLOCK;
                    613:                }
                    614:                return error;
                    615:
                    616:        default:
                    617:                return ENOTDIR;
                    618:        }
                    619:
                    620:        return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS;
                    621: }
                    622:
                    623: /*
                    624:  * readdir returns directory entries from ptyfsnode (vp).
                    625:  *
                    626:  * the strategy here with ptyfs is to generate a single
                    627:  * directory entry at a time (struct dirent) and then
                    628:  * copy that out to userland using uiomove.  a more efficent
                    629:  * though more complex implementation, would try to minimize
                    630:  * the number of calls to uiomove().  for ptyfs, this is
                    631:  * hardly worth the added code complexity.
                    632:  *
                    633:  * this should just be done through read()
                    634:  */
                    635: int
                    636: ptyfs_readdir(void *v)
                    637: {
                    638:        struct vop_readdir_args /* {
                    639:                struct vnode *a_vp;
                    640:                struct uio *a_uio;
1.12.4.1! rpaulo    641:                kauth_cred_t a_cred;
1.1       jdolecek  642:                int *a_eofflag;
                    643:                off_t **a_cookies;
                    644:                int *a_ncookies;
                    645:        } */ *ap = v;
                    646:        struct uio *uio = ap->a_uio;
                    647:        struct dirent d;
                    648:        struct ptyfsnode *ptyfs;
                    649:        off_t i;
                    650:        int error;
                    651:        off_t *cookies = NULL;
                    652:        int ncookies;
                    653:        struct vnode *vp;
                    654:        int nc = 0;
                    655:
                    656:        vp = ap->a_vp;
                    657:        ptyfs = VTOPTYFS(vp);
                    658:
                    659:        if (uio->uio_resid < UIO_MX)
                    660:                return EINVAL;
                    661:        if (uio->uio_offset < 0)
                    662:                return EINVAL;
                    663:
                    664:        error = 0;
                    665:        i = uio->uio_offset;
                    666:        (void)memset(&d, 0, sizeof(d));
                    667:        d.d_reclen = UIO_MX;
                    668:        ncookies = uio->uio_resid / UIO_MX;
                    669:
                    670:        switch (ptyfs->ptyfs_type) {
                    671:        case PTYFSroot: /* root */
                    672:
                    673:                if (i >= npty)
                    674:                        return 0;
                    675:
                    676:                if (ap->a_ncookies) {
                    677:                        ncookies = min(ncookies, (npty + 2 - i));
                    678:                        cookies = malloc(ncookies * sizeof (off_t),
                    679:                            M_TEMP, M_WAITOK);
                    680:                        *ap->a_cookies = cookies;
                    681:                }
                    682:
                    683:                for (; i < 2; i++) {
                    684:                        switch (i) {
                    685:                        case 0:         /* `.' */
                    686:                        case 1:         /* `..' */
                    687:                                d.d_fileno = PTYFS_FILENO(0, PTYFSroot);
                    688:                                d.d_namlen = i + 1;
                    689:                                (void)memcpy(d.d_name, "..", d.d_namlen);
                    690:                                d.d_name[i + 1] = '\0';
                    691:                                d.d_type = DT_DIR;
                    692:                                break;
                    693:                        }
                    694:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
                    695:                                break;
                    696:                        if (cookies)
                    697:                                *cookies++ = i + 1;
                    698:                        nc++;
                    699:                }
                    700:                if (error) {
                    701:                        ncookies = nc;
                    702:                        break;
                    703:                }
                    704:                for (; uio->uio_resid >= UIO_MX && i < npty; i++) {
                    705:                        /* check for used ptys */
                    706:                        if (pty_isfree(i - 2, 1))
                    707:                                continue;
                    708:
                    709:                        d.d_fileno = PTYFS_FILENO(i - 2, PTYFSpts);
                    710:                        d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
                    711:                            "%lld", (long long)(i - 2));
                    712:                        d.d_type = DT_CHR;
                    713:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
                    714:                                break;
                    715:                        if (cookies)
                    716:                                *cookies++ = i + 1;
                    717:                        nc++;
                    718:                }
                    719:                ncookies = nc;
                    720:                break;
                    721:
                    722:        default:
                    723:                error = ENOTDIR;
                    724:                break;
                    725:        }
                    726:
                    727:        if (ap->a_ncookies) {
                    728:                if (error) {
                    729:                        if (cookies)
                    730:                                free(*ap->a_cookies, M_TEMP);
                    731:                        *ap->a_ncookies = 0;
                    732:                        *ap->a_cookies = NULL;
                    733:                } else
                    734:                        *ap->a_ncookies = ncookies;
                    735:        }
                    736:        uio->uio_offset = i;
                    737:        return error;
                    738: }
                    739:
                    740: int
                    741: ptyfs_open(void *v)
                    742: {
                    743:        struct vop_open_args /* {
                    744:                struct vnode *a_vp;
                    745:                int  a_mode;
1.12.4.1! rpaulo    746:                kauth_cred_t a_cred;
1.12      christos  747:                struct lwp *a_l;
1.1       jdolecek  748:        } */ *ap = v;
                    749:        struct vnode *vp = ap->a_vp;
                    750:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    751:
                    752:        ptyfs->ptyfs_flag |= PTYFS_CHANGE|PTYFS_ACCESS;
                    753:        switch (ptyfs->ptyfs_type) {
                    754:        case PTYFSpts:
                    755:        case PTYFSptc:
                    756:                return spec_open(v);
                    757:        case PTYFSroot:
                    758:                return 0;
                    759:        default:
                    760:                return EINVAL;
                    761:        }
                    762: }
                    763:
                    764: int
                    765: ptyfs_close(void *v)
                    766: {
                    767:        struct vop_close_args /* {
                    768:                struct vnode *a_vp;
                    769:                int  a_fflag;
1.12.4.1! rpaulo    770:                kauth_cred_t a_cred;
1.12      christos  771:                struct lwp *a_l;
1.1       jdolecek  772:        } */ *ap = v;
                    773:        struct vnode *vp = ap->a_vp;
                    774:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.7       perry     775:
1.12.4.1! rpaulo    776:        simple_lock(&vp->v_interlock);
        !           777:        if (vp->v_usecount > 1)
1.9       christos  778:                PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
1.12.4.1! rpaulo    779:        simple_unlock(&vp->v_interlock);
1.1       jdolecek  780:
                    781:        switch (ptyfs->ptyfs_type) {
                    782:        case PTYFSpts:
                    783:        case PTYFSptc:
                    784:                return spec_close(v);
                    785:        case PTYFSroot:
                    786:                return 0;
                    787:        default:
                    788:                return EINVAL;
                    789:        }
                    790: }
                    791:
                    792: int
                    793: ptyfs_read(void *v)
                    794: {
                    795:        struct vop_read_args /* {
                    796:                struct vnode *a_vp;
                    797:                struct uio *a_uio;
                    798:                int  a_ioflag;
1.12.4.1! rpaulo    799:                kauth_cred_t a_cred;
1.1       jdolecek  800:        } */ *ap = v;
1.10      simonb    801:        struct timespec ts;
1.1       jdolecek  802:        struct vnode *vp = ap->a_vp;
                    803:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    804:        int error;
                    805:
                    806:        ptyfs->ptyfs_flag |= PTYFS_ACCESS;
1.10      simonb    807:        /* hardclock() resolution is good enough for ptyfs */
1.12.4.1! rpaulo    808:        getnanotime(&ts);
1.11      yamt      809:        (void)ptyfs_update(vp, &ts, &ts, 0);
1.10      simonb    810:
1.1       jdolecek  811:        switch (ptyfs->ptyfs_type) {
                    812:        case PTYFSpts:
                    813:                VOP_UNLOCK(vp, 0);
                    814:                error = (*pts_cdevsw.d_read)(vp->v_rdev, ap->a_uio,
                    815:                    ap->a_ioflag);
                    816:                vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
                    817:                return error;
                    818:        case PTYFSptc:
                    819:                VOP_UNLOCK(vp, 0);
                    820:                error = (*ptc_cdevsw.d_read)(vp->v_rdev, ap->a_uio,
                    821:                    ap->a_ioflag);
                    822:                vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
                    823:                return error;
                    824:        default:
                    825:                return EOPNOTSUPP;
                    826:        }
                    827: }
                    828:
                    829: int
                    830: ptyfs_write(void *v)
                    831: {
                    832:        struct vop_write_args /* {
                    833:                struct vnode *a_vp;
                    834:                struct uio *a_uio;
                    835:                int  a_ioflag;
1.12.4.1! rpaulo    836:                kauth_cred_t a_cred;
1.1       jdolecek  837:        } */ *ap = v;
1.10      simonb    838:        struct timespec ts;
1.1       jdolecek  839:        struct vnode *vp = ap->a_vp;
                    840:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.10      simonb    841:        int error;
1.1       jdolecek  842:
                    843:        ptyfs->ptyfs_flag |= PTYFS_MODIFY;
1.12.4.1! rpaulo    844:        getnanotime(&ts);
1.11      yamt      845:        (void)ptyfs_update(vp, &ts, &ts, 0);
1.10      simonb    846:
1.1       jdolecek  847:        switch (ptyfs->ptyfs_type) {
                    848:        case PTYFSpts:
                    849:                VOP_UNLOCK(vp, 0);
                    850:                error = (*pts_cdevsw.d_write)(vp->v_rdev, ap->a_uio,
                    851:                    ap->a_ioflag);
                    852:                vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
                    853:                return error;
                    854:        case PTYFSptc:
                    855:                VOP_UNLOCK(vp, 0);
                    856:                error = (*ptc_cdevsw.d_write)(vp->v_rdev, ap->a_uio,
                    857:                    ap->a_ioflag);
                    858:                vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
                    859:                return error;
                    860:        default:
                    861:                return EOPNOTSUPP;
                    862:        }
                    863: }
                    864:
                    865: int
                    866: ptyfs_ioctl(void *v)
                    867: {
                    868:        struct vop_ioctl_args /* {
                    869:                struct vnode *a_vp;
                    870:                u_long a_command;
                    871:                void *a_data;
                    872:                int  a_fflag;
1.12.4.1! rpaulo    873:                kauth_cred_t a_cred;
1.12      christos  874:                struct lwp *a_l;
1.1       jdolecek  875:        } */ *ap = v;
                    876:        struct vnode *vp = ap->a_vp;
                    877:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    878:
                    879:        switch (ptyfs->ptyfs_type) {
                    880:        case PTYFSpts:
                    881:                return (*pts_cdevsw.d_ioctl)(vp->v_rdev, ap->a_command,
1.12      christos  882:                    ap->a_data, ap->a_fflag, ap->a_l);
1.1       jdolecek  883:        case PTYFSptc:
                    884:                return (*ptc_cdevsw.d_ioctl)(vp->v_rdev, ap->a_command,
1.12      christos  885:                    ap->a_data, ap->a_fflag, ap->a_l);
1.1       jdolecek  886:        default:
                    887:                return EOPNOTSUPP;
                    888:        }
                    889: }
                    890:
                    891: int
                    892: ptyfs_poll(void *v)
                    893: {
                    894:        struct vop_poll_args /* {
                    895:                struct vnode *a_vp;
                    896:                int a_events;
1.12      christos  897:                struct lwp *a_l;
1.1       jdolecek  898:        } */ *ap = v;
                    899:        struct vnode *vp = ap->a_vp;
                    900:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    901:
                    902:        switch (ptyfs->ptyfs_type) {
                    903:        case PTYFSpts:
1.12      christos  904:                return (*pts_cdevsw.d_poll)(vp->v_rdev, ap->a_events, ap->a_l);
1.1       jdolecek  905:        case PTYFSptc:
1.12      christos  906:                return (*ptc_cdevsw.d_poll)(vp->v_rdev, ap->a_events, ap->a_l);
1.1       jdolecek  907:        default:
                    908:                return genfs_poll(v);
                    909:        }
                    910: }
                    911:
                    912: int
                    913: ptyfs_kqfilter(void *v)
                    914: {
                    915:        struct vop_kqfilter_args /* {
                    916:                struct vnode *a_vp;
                    917:                struct knote *a_kn;
                    918:        } */ *ap = v;
                    919:        struct vnode *vp = ap->a_vp;
                    920:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
                    921:
                    922:        switch (ptyfs->ptyfs_type) {
                    923:        case PTYFSpts:
                    924:                return (*pts_cdevsw.d_kqfilter)(vp->v_rdev, ap->a_kn);
                    925:        case PTYFSptc:
                    926:                return (*ptc_cdevsw.d_kqfilter)(vp->v_rdev, ap->a_kn);
                    927:        default:
                    928:                return genfs_kqfilter(v);
                    929:        }
                    930: }
                    931:
1.11      yamt      932: static int
                    933: ptyfs_update(struct vnode *vp, const struct timespec *acc,
                    934:     const struct timespec *mod, int flags)
1.1       jdolecek  935: {
1.11      yamt      936:        struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.1       jdolecek  937:
1.11      yamt      938:        if (vp->v_mount->mnt_flag & MNT_RDONLY)
1.1       jdolecek  939:                return 0;
                    940:
1.11      yamt      941:        PTYFS_ITIMES(ptyfs, acc, mod, NULL);
1.1       jdolecek  942:        return 0;
                    943: }
                    944:
1.8       christos  945: void
                    946: ptyfs_itimes(struct ptyfsnode *ptyfs, const struct timespec *acc,
                    947:     const struct timespec *mod, const struct timespec *cre)
                    948: {
1.12.4.1! rpaulo    949:        struct timespec now;
        !           950:
1.9       christos  951:        KASSERT(ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY));
1.12.4.1! rpaulo    952:
        !           953:        getnanotime(&now);
1.8       christos  954:        if (ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_MODIFY)) {
                    955:                if (acc == NULL)
1.12.4.1! rpaulo    956:                        acc = &now;
1.8       christos  957:                ptyfs->ptyfs_atime = *acc;
                    958:        }
1.1       jdolecek  959:        if (ptyfs->ptyfs_flag & PTYFS_MODIFY) {
1.8       christos  960:                if (mod == NULL)
1.12.4.1! rpaulo    961:                        mod = &now;
1.8       christos  962:                ptyfs->ptyfs_mtime = *mod;
                    963:        }
                    964:        if (ptyfs->ptyfs_flag & PTYFS_CHANGE) {
                    965:                if (cre == NULL)
1.12.4.1! rpaulo    966:                        cre = &now;
1.9       christos  967:                ptyfs->ptyfs_ctime = *cre;
1.8       christos  968:        }
1.9       christos  969:        ptyfs->ptyfs_flag &= ~(PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY);
1.1       jdolecek  970: }
1.7       perry     971:
1.1       jdolecek  972: /*
                    973:  * convert decimal ascii to int
                    974:  */
                    975: static int
                    976: atoi(const char *b, size_t len)
                    977: {
                    978:        int p = 0;
                    979:
                    980:        while (len--) {
                    981:                char c = *b++;
                    982:                if (c < '0' || c > '9')
                    983:                        return -1;
                    984:                p = 10 * p + (c - '0');
                    985:        }
                    986:
                    987:        return p;
                    988: }

CVSweb <webmaster@jp.NetBSD.org>