/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/dialects/freebsd/dnode.c
752 строки
22 KB
Jiajie Chen
Fix potential double free for Lf->fsdir and mp->dir
31 мар 2026, 17:13
31 мар 2026, 17:13
53539a9
Код
Авторство
О чём код?
/* * dnode.c - FreeBSD node functions for lsof */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; #endif #include "common.h" #if defined(HAS_LOCKF_ENTRY) # include "./lockf_owner.h" #endif /* defined(HAS_LOCKF_ENTRY) */ #if defined(HASPTSFN) && defined(DTYPE_PTS) # include <sys/tty.h> #endif /* defined(HASPTSFN) && defined(DTYPE_PTS) */ static void get_lock_state_kvm(struct lsof_context *ctx, KA_T f); /* * get_lock_state_*() - get the lock state */ #ifdef KERN_LOCKF static void get_lock_state_sysctl(struct lsof_context *ctx, struct kinfo_file *kf, struct lock_list *locks) { struct kinfo_lockf key, *lock; key.kl_sysid = 0; key.kl_pid = (pid_t)Lp->pid; key.kl_file_fsid = kf->kf_un.kf_file.kf_file_fsid; key.kl_file_fileid = kf->kf_un.kf_file.kf_file_fileid; lock = bsearch(&key, locks->locks, locks->n_locks, sizeof(*locks->locks), cmp_kinfo_lockf); if (lock != NULL) { int whole_file = (lock->kl_start == 0 && lock->kl_len == 0); if (lock->kl_rw == KLOCKF_RW_READ) Lf->lock = whole_file ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL; else if (lock->kl_rw == KLOCKF_RW_WRITE) Lf->lock = whole_file ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL; } } #endif /* KERN_LOCKF */ static void get_lock_state_kvm(struct lsof_context *ctx, /* context */ KA_T f) /* inode's lock pointer */ { struct lockf lf; /* lockf structure */ int lt; /* lock type */ #if defined(HAS_LOCKF_ENTRY) struct lockf_entry le; /* lock_entry structure */ KA_T lef, lep; /* lock_entry pointers */ struct lock_owner lo; /* lock owner structure */ if (!f || kread(ctx, f, (char *)&lf, sizeof(lf))) return; if (!(lef = (KA_T)lf.ls_active.lh_first)) return; lep = lef; do { if (kread(ctx, lep, (char *)&le, sizeof(le))) return; if (!le.lf_owner || kread(ctx, (KA_T)le.lf_owner, (char *)&lo, sizeof(lo))) continue; if (lo.lo_pid == (pid_t)Lp->pid) { if (le.lf_start == (off_t)0 && le.lf_end == 0x7fffffffffffffffLL) lt = 1; else lt = 0; if (le.lf_type == F_RDLCK) Lf->lock = lt ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL; else if (le.lf_type == F_WRLCK) Lf->lock = lt ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL; return; } } while ((lep = (KA_T)le.lf_link.le_next) && (lep != lef)); #else /* !defined(HAS_LOCKF_ENTRY) */ unsigned char l; /* lock status */ KA_T lfp; /* lockf structure pointer */ if ((lfp = f)) { /* * Determine the lock state. */ do { if (kread(ctx, lfp, (char *)&lf, sizeof(lf))) break; l = 0; switch (lf.lf_flags & (F_FLOCK | F_POSIX)) { case F_FLOCK: if (Cfp && (struct file *)lf.lf_id == Cfp) l = 1; break; case F_POSIX: # if defined(P_ADDR) if ((KA_T)lf.lf_id == Kpa) l = 1; # endif /* defined(P_ADDR) */ break; } if (!l) continue; if (lf.lf_start == (off_t)0 && lf.lf_end == 0xffffffffffffffffLL) lt = 1; else lt = 0; if (lf.lf_type == F_RDLCK) Lf->lock = lt ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL; else if (lf.lf_type == F_WRLCK) Lf->lock = lt ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL; break; } while ((lfp = (KA_T)lf.lf_next) && (lfp != f)); } #endif /* defined(HAS_LOCKF_ENTRY) */ } #if defined(HASKQUEUE) /* * process_kf_kqueue() - process kqueue file * * Strictly speaking this function should appear in dfile.c, because it is * a file processing function. However, the Net and Open BSD sources don't * require a dfile.c, so this is the next best location for the function. */ void process_kf_kqueue(struct lsof_context *ctx, /* context */ struct kinfo_file *kf, /* kernel file*/ KA_T ka /* kernel address */) { # if __FreeBSD_version < 1400062 struct kqueue kq; /* kqueue structure */ # endif /* __FreeBSD_version < 1400062 */ Lf->type = LSOF_FILE_KQUEUE; enter_dev_ch(ctx, print_kptr(ka, (char *)NULL, 0)); # if __FreeBSD_version >= 1400062 (void)snpf(Namech, Namechl, "count=%d, state=%#x", kf->kf_un.kf_kqueue.kf_kqueue_count, kf->kf_un.kf_kqueue.kf_kqueue_state); # else /* __FreeBSD_version < 1400062 */ if (!ka || kread(ctx, ka, (char *)&kq, sizeof(kq))) return; (void)snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count, kq.kq_state); # endif /* __FreeBSD_version >= 1400062 */ enter_nm(ctx, Namech); } #endif /* defined(HASKQUEUE) */ #if defined(KF_TYPE_EVENTFD) void process_eventfd(struct lsof_context *ctx, struct kinfo_file *kf) { Lf->type = LSOF_FILE_EVENTFD; # if __FreeBSD_version >= 1400062 enter_dev_ch( ctx, print_kptr(kf->kf_un.kf_eventfd.kf_eventfd_addr, (char *)NULL, 0)); # endif /* __FreeBSD_version >= 1400062 */ (void)snpf(Namech, Namechl, "value=%ju, flags=0x%x", kf->kf_un.kf_eventfd.kf_eventfd_value, kf->kf_un.kf_eventfd.kf_eventfd_flags); enter_nm(ctx, Namech); } #endif /* defined(KF_TYPE_EVENTFD) */ void process_shm(struct lsof_context *ctx, struct kinfo_file *kf) { Lf->type = LSOF_FILE_SHM; Lf->sz = kf->kf_un.kf_file.kf_file_size; Lf->sz_def = 1; Lf->off_def = 0; if (kf->kf_un.kf_file.kf_file_fileid != VNOVAL) { Lf->inode = kf->kf_un.kf_file.kf_file_fileid; Lf->inp_ty = 1; } if (kf->kf_path[0]) { snpf(Namech, Namechl, "%s", kf->kf_path); enter_nm(ctx, Namech); } } void process_procdesc(struct lsof_context *ctx, struct kinfo_file *kf) { char pidstr[50]; Lf->type = LSOF_FILE_PROCDESC; snpf(pidstr, sizeof(pidstr), "pid=%d", kf->kf_un.kf_proc.kf_pid); add_nma(ctx, pidstr, strlen(pidstr)); if (kf->kf_path[0]) { snpf(Namech, Namechl, "%s", kf->kf_path); enter_nm(ctx, Namech); } } static enum lsof_file_type parse_proc_path(struct kinfo_file *kf, int *proc_pid) { enum lsof_file_type ty; char *basename; ty = LSOF_FILE_NONE; basename = strrchr(kf->kf_path, '/'); if (basename) { ++basename; if (!strcmp(basename, "cmdline")) { } else if (!strcmp(basename, "dbregs")) { } else if (!strcmp(basename, "etype")) { ty = LSOF_FILE_PROC_EXEC_TYPE; } else if (!strcmp(basename, "file")) { ty = LSOF_FILE_PROC_FILE; } else if (!strcmp(basename, "fpregs")) { ty = LSOF_FILE_PROC_FP_REGS; } else if (!strcmp(basename, "map")) { ty = LSOF_FILE_PROC_MAP; } else if (!strcmp(basename, "mem")) { ty = LSOF_FILE_PROC_MEMORY; } else if (!strcmp(basename, "note")) { ty = LSOF_FILE_PROC_PROC_NOTIFIER; } else if (!strcmp(basename, "notepg")) { ty = LSOF_FILE_PROC_GROUP_NOTIFIER; } else if (!strcmp(basename, "osrel")) { } else if (!strcmp(basename, "regs")) { ty = LSOF_FILE_PROC_REGS; } else if (!strcmp(basename, "rlimit")) { } else if (!strcmp(basename, "status")) { ty = LSOF_FILE_PROC_STATUS; } else { /* we're excluded all files - must be a directory, either * /proc/<pid> or /proc itself */ ty = LSOF_FILE_PROC_DIR; } if (ty != LSOF_FILE_NONE && ty != LSOF_FILE_PROC_DIR) { char *parent_dir; --basename; *basename = '\0'; parent_dir = strrchr(kf->kf_path, '/'); if (parent_dir) *proc_pid = strtol(++parent_dir, NULL, 10); *basename = '/'; } } return ty; } /* * process_vnode() - process vnode */ void process_vnode(struct lsof_context *ctx, struct kinfo_file *kf, struct xfile *xfile, struct lock_list *locks) { dev_t dev = 0, rdev = 0; unsigned char devs; unsigned char rdevs; KA_T va; struct vnode *v, vb; struct l_vfs *vfs; uint64_t fsid; char vfs_path[PATH_MAX]; #if defined(HASNULLFS) # if !defined(HASPRINTDEV) char dbuf[32]; # endif /* !defined(HASPRINTDEV) */ char *dp, *np, tbuf[1024]; struct null_node nu; int sc = 0; size_t vfs_fsname_len, vfs_dir_len, vfs_path_len; #endif /* defined(HASNULLFS) */ int proc_pid = 0; struct procfsid *pfi; struct stat st; const int kf_vtype = kf->kf_vnode_type; fsid = kf->kf_un.kf_file.kf_file_fsid; va = xfile ? xfile->xf_vnode : 0; strcpy(vfs_path, kf->kf_path); #if defined(HASNULLFS) process_overlaid_node: if (++sc > 1024) { (void)snpf(Namech, Namechl, "too many overlaid nodes"); enter_nm(ctx, Namech); return; } #endif /* defined(HASNULLFS) */ /* * Initialize miscellaneous variables. This is done so that processing an * overlaid node will be a fresh start. */ devs = rdevs = 0; Namech[0] = '\0'; /* * Read the vnode. */ v = NULL; if (va) { v = &vb; if (kread(ctx, (KA_T)va, (char *)v, sizeof(struct vnode))) v = NULL; } if (xfile) { #if defined(HASFSTRUCT) Lf->fna = (KA_T)xfile->xf_vnode; Lf->fsv |= FSV_NI; #endif /* defined(HASFSTRUCT) */ } /* * Get the vnode type. */ vfs = readvfs(ctx, fsid, vfs_path); if (vfs) { fsid = vfs->fsid; #if defined(MOUNT_NONE) switch (vfs->type) { case MOUNT_NFS: Ntype = N_NFS; break; case MOUNT_PROCFS: Ntype = N_PROC; break; } #else /* !defined(MOUNT_NONE) */ if (strcasecmp(vfs->typnm, "nfs") == 0) Ntype = N_NFS; else if (strcasecmp(vfs->typnm, "procfs") == 0) Ntype = N_PROC; # if defined(HASPSEUDOFS) else if (strcasecmp(vfs->typnm, "pseudofs") == 0) Ntype = N_PSEU; # endif /* defined(HASPSEUDOFS) */ # if defined(HAS_TMPFS) else if (strcasecmp(vfs->typnm, "tmpfs") == 0) Ntype = N_TMP; # endif /* defined(HAS_TMPFS) */ #endif /* defined(MOUNT_NONE) */ } if (Ntype == N_REGLR) { switch (kf_vtype) { case KF_VTYPE_VFIFO: Ntype = N_FIFO; break; default: break; } } #ifdef KERN_LOCKF get_lock_state_sysctl(ctx, kf, locks); #elif defined(HAS_V_LOCKF) if (v && v->v_lockf) (void)get_lock_state_kvm(ctx, (KA_T)v->v_lockf); #endif /* KERN_LOCKF */ /* * Deal with special filesystems. */ if (vfs && (!strcmp(vfs->typnm, "null") || !strcmp(vfs->typnm, "nullfs"))) { #if defined(HASNULLFS) if (sc == 1) { /* * If this is the first null_node, enter a name addition containing * the mounted-on directory, the file system name, and the device * number. */ if (vfs && (vfs->dir || vfs->fsname || vfs->fsid != VNOVAL)) { if (vfs->fsid != VNOVAL) { # if defined(HASPRINTDEV) dp = HASPRINTDEV(Lf, &vfs->fsid); # else /* !defined(HASPRINTDEV) */ (void)snpf(dbuf, sizeof(dbuf) - 1, "%d,%d", GET_MAJ_DEV(vfs->fsid), GET_MIN_DEV(vfs->fsid)); dbuf[sizeof(dbuf) - 1] = '\0'; dp = dbuf; # endif /* defined(HASPRINTDEV) */ } else dp = (char *)NULL; (void)snpf(tbuf, sizeof(tbuf) - 1, "(nullfs%s%s%s%s%s%s%s)", (vfs && vfs->fsname) ? " " : "", (vfs && vfs->fsname) ? vfs->fsname : "", (vfs && vfs->dir) ? " on " : "", (vfs && vfs->dir) ? vfs->dir : "", (dp && vfs && vfs->dir) ? " (" : "", (dp && vfs && vfs->dir) ? dp : "", (dp && vfs && vfs->dir) ? ")" : ""); tbuf[sizeof(tbuf) - 1] = '\0'; np = tbuf; } else np = "(nullfs)"; (void)add_nma(ctx, np, (int)strlen(np)); } fsid = VNOVAL; /* -------dir-------- * /nullfs_mountpoint/path/to/file * /original_mountpoint/path/to/file * ------fsname-------- */ vfs_fsname_len = strlen(vfs->fsname); vfs_dir_len = strlen(vfs->dir); vfs_path_len = strlen(vfs_path); if (vfs_path_len >= vfs_dir_len) { memmove(&vfs_path[vfs_fsname_len], &vfs_path[vfs_dir_len], vfs_path_len - vfs_dir_len + 1); memcpy(vfs_path, vfs->fsname, vfs_fsname_len); } goto process_overlaid_node; #endif /* defined(HASNULLFS) */ } /* * Get device and type for printing. */ if (fsid != VNOVAL) { dev = fsid; devs = 1; } if (kf_vtype == KF_VTYPE_VCHR || kf_vtype == KF_VTYPE_VBLK) { rdev = kf->kf_un.kf_file.kf_file_rdev; rdevs = 1; } /* * Obtain the inode number. */ if (kf->kf_un.kf_file.kf_file_fileid != VNOVAL) { Lf->inode = kf->kf_un.kf_file.kf_file_fileid; Lf->inp_ty = 1; } /* * Obtain the file size. */ switch (Ntype) { case N_FIFO: break; case N_PROC: Lf->sz = kf->kf_un.kf_file.kf_file_size; Lf->sz_def = 1; break; #if defined(HASPSEUDOFS) case N_PSEU: Lf->sz = 0; Lf->sz_def = 1; break; #endif /* defined(PSEUDOFS) */ case N_REGLR: #if defined(HAS_TMPFS) case N_TMP: #endif /* defined(HAS_TMPFS) */ if (kf_vtype == KF_VTYPE_VREG || kf_vtype == KF_VTYPE_VDIR) { Lf->sz = kf->kf_un.kf_file.kf_file_size; Lf->sz_def = 1; } break; default: Lf->sz = kf->kf_un.kf_file.kf_file_size; Lf->sz_def = 1; } /* * Record the link count. */ /* Read nlink from kernel if provided, otherwise call stat() */ #if defined(HAS_KF_FILE_NLINK) Lf->nlink = kf->kf_un.kf_file.kf_file_nlink; Lf->nlink_def = 1; #else if (kf->kf_path[0] && stat(kf->kf_path, &st) == 0) { Lf->nlink = st.st_nlink; Lf->nlink_def = 1; } #endif if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink)) Lf->sf |= SELNLINK; /* * Record an NFS file selection. */ if (Ntype == N_NFS && Fnfs) Lf->sf |= SELNFS; /* * Save the file system names. */ if (vfs) { Lf->fsdir = mkstrcpy(vfs->dir, (MALLOC_S *)NULL); Lf->fsdev = mkstrcpy(vfs->fsname, (MALLOC_S *)NULL); } /* * Save the device numbers and their states. * * Format the vnode type, and possibly the device name. */ Lf->dev = dev; Lf->dev_def = devs; Lf->rdev = rdev; Lf->rdev_def = rdevs; switch (kf_vtype) { case KF_VTYPE_VNON: Lf->type = LSOF_FILE_VNODE_VNON; break; case KF_VTYPE_VREG: case KF_VTYPE_VDIR: Lf->type = (kf_vtype == KF_VTYPE_VREG) ? LSOF_FILE_VNODE_VREG : LSOF_FILE_VNODE_VDIR; break; case KF_VTYPE_VBLK: Lf->type = LSOF_FILE_VNODE_VBLK; Ntype = N_BLK; break; case KF_VTYPE_VCHR: Lf->type = LSOF_FILE_VNODE_VCHR; Ntype = N_CHR; break; case KF_VTYPE_VLNK: Lf->type = LSOF_FILE_VNODE_VLNK; break; case KF_VTYPE_VSOCK: Lf->type = LSOF_FILE_VNODE_VSOCK; break; case KF_VTYPE_VBAD: Lf->type = LSOF_FILE_VNODE_VBAD; break; case KF_VTYPE_VFIFO: Lf->type = LSOF_FILE_VNODE_VFIFO; break; default: Lf->type = LSOF_FILE_UNKNOWN_RAW; Lf->unknown_file_type_number = kf_vtype; } Lf->ntype = Ntype; /* * Handle some special cases: * * ioctl(fd, TIOCNOTTY) files; * memory node files; * /proc files. */ if (kf_vtype == KF_VTYPE_VBAD) (void)snpf(Namech, Namechl, "(revoked)"); else if (Ntype == N_PROC) { Lf->type = parse_proc_path(kf, &proc_pid); } #if defined(HASBLKDEV) /* * If this is a VBLK file and it's missing an inode number, try to * supply one. */ if ((Lf->inp_ty == 0) && (kf_vtype == KF_VTYPE_VBLK)) find_bl_ino(); #endif /* defined(HASBLKDEV) */ /* * If this is a VCHR file and it's missing an inode number, try to * supply one. */ if ((Lf->inp_ty == 0) && (kf_vtype == KF_VTYPE_VCHR)) find_ch_ino(ctx); /* * Test for specified file. */ if (Ntype == N_PROC && (Procsrch || Procfsid)) { if (Procsrch) { Procfind = 1; Lf->sf |= SELNM; } else { for (pfi = Procfsid; pfi; pfi = pfi->next) { if ((pfi->pid && proc_pid && pfi->pid == proc_pid) #if defined(HASPINODEN) || (Lf->inp_ty == 1 && Lf->inode == pfi->inode) #else /* !defined(HASPINODEN) */ if (pfi->pid == p->pfs_pid) #endif /* defined(HASPINODEN) */ ) { pfi->f = 1; if (!Namech[0]) (void)snpf(Namech, Namechl, "%s", pfi->nm); Lf->sf |= SELNM; break; } } } } else { if (Sfile && is_file_named(ctx, (char *)NULL, ((kf_vtype == KF_VTYPE_VCHR) || (kf_vtype == KF_VTYPE_VBLK)) ? 1 : 0)) Lf->sf |= SELNM; } /* * Enter name characters. */ if (Namech[0]) enter_nm(ctx, Namech); else if (kf->kf_path[0]) { snpf(Namech, Namechl, "%s", kf->kf_path); if (vfs && vfs->fsname) { char *cp; size_t sz; cp = endnm(ctx, &sz); snpf(cp, sz, " (%s)", vfs->fsname); } enter_nm(ctx, Namech); } } /* * process_pipe() - process a file structure whose type is DTYPE_PIPE */ void process_pipe(struct lsof_context *ctx, struct kinfo_file *kf, KA_T pa) { char dev_ch[32], *ep; size_t sz; #if __FreeBSD_version < 1400062 struct pipe p; int have_kpipe = (pa && kread(ctx, pa, (char *)&p, sizeof(p)) == 0); #endif Lf->type = LSOF_FILE_PIPE; (void)snpf(dev_ch, sizeof(dev_ch), "%s", print_kptr(kf->kf_un.kf_pipe.kf_pipe_addr, (char *)NULL, 0)); enter_dev_ch(ctx, dev_ch); #if __FreeBSD_version >= 1400062 Lf->sz = (SZOFFTYPE)kf->kf_un.kf_pipe.kf_pipe_buffer_size; Lf->sz_def = 1; #else /* __FreeBSD_version < 1400062 */ if (have_kpipe) { Lf->sz = (SZOFFTYPE)p.pipe_buffer.size; Lf->sz_def = 1; } #endif /* __FreeBSD_version >= 1400062 */ if (kf->kf_un.kf_pipe.kf_pipe_peer) (void)snpf( Namech, Namechl, "->%s", print_kptr((KA_T)kf->kf_un.kf_pipe.kf_pipe_peer, (char *)NULL, 0)); else Namech[0] = '\0'; if (kf->kf_un.kf_pipe.kf_pipe_buffer_cnt) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, ", cnt=%d", kf->kf_un.kf_pipe.kf_pipe_buffer_cnt); } #if __FreeBSD_version >= 1400062 if (kf->kf_un.kf_pipe.kf_pipe_buffer_in) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, ", in=%d", kf->kf_un.kf_pipe.kf_pipe_buffer_in); } if (kf->kf_un.kf_pipe.kf_pipe_buffer_out) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, ", out=%d", kf->kf_un.kf_pipe.kf_pipe_buffer_out); } #else /* __FreeBSD_version < 1400062 */ if (have_kpipe && p.pipe_buffer.in) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, ", in=%d", p.pipe_buffer.in); } if (have_kpipe && p.pipe_buffer.out) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, ", out=%d", p.pipe_buffer.out); } #endif /* __FreeBSD_version >= 1400062 */ /* * Enter name characters. */ if (Namech[0]) enter_nm(ctx, Namech); } #if defined(DTYPE_PTS) /* * process_pts - process a file structure whose type is DTYPE_PTS */ void process_pts(struct lsof_context *ctx, struct kinfo_file *kf) { Lf->type = LSOF_FILE_PTS; /* * Convert the tty's cdev from kernel to user form. * -- already done in the kernel, file sys/kern/tty_pts.c, function * ptsdev_fill_kinfo(). * * Set the device number to DevDev, the device number of /dev. * * Set the inode number to the device number. * * Set the file type to N_CHR for a character device (That's what a PTS is.) * * Force the use of offset from file structure. * * Set rdev to the converted device. * * Force the reloading of the device cache. */ Lf->dev = DevDev; Lf->inode = (INODETYPE)kf->kf_un.kf_pts.kf_pts_dev; Lf->inp_ty = Lf->dev_def = Lf->rdev_def = 1; Lf->ntype = N_CHR; Lf->rdev = kf->kf_un.kf_pts.kf_pts_dev; DCunsafe = 1; } #endif /* defined(DTYPE_PTS) */